[gradle-1.12] 13/211: upstream import 0.9.1

Kai-Chung Yan seamlik-guest at moszumanska.debian.org
Wed Jul 1 14:17:49 UTC 2015


This is an automated email from the git hooks/post-receive script.

seamlik-guest pushed a commit to branch master
in repository gradle-1.12.

commit 71ded6eacad56bd0c53218f777d42567447440bf
Author: Miguel Landaeta <miguel at miguel.cc>
Date:   Tue Jan 4 19:41:18 2011 -0430

    upstream import 0.9.1
---
 build.gradle                                       |  17 +-
 .../main/groovy/org/gradle/build/Version.groovy    |   4 +-
 .../gradle/build/docs/BuildableDOMCategory.groovy  |  17 +-
 .../groovy/org/gradle/build/docs/DomBuilder.groovy |   6 +-
 .../build/docs/SampleElementLocationHandler.groovy |   5 +-
 .../gradle/build/docs/SampleLayoutHandler.groovy   | 146 +++++++++++++
 .../build/docs/UserGuideTransformTask.groovy       | 207 ++++++++----------
 .../build/docs/XIncludeAwareXmlProvider.groovy     |  19 +-
 .../build/docs/SampleLayoutHandlerTest.groovy      | 156 ++++++++++++++
 .../build/docs/{dsl => }/XmlSpecification.groovy   |  15 +-
 .../docs/dsl/docbook/ClassDocRendererTest.groovy   |   2 +-
 .../build/docs/dsl/docbook/ClassDocTest.groovy     |   2 +-
 .../docs/dsl/docbook/JavadocConverterTest.groovy   |   2 +-
 .../dsl/docbook/JavadocLinkConverterTest.groovy    |   2 +-
 .../build/docs/dsl/docbook/LinkRendererTest.groovy |   2 +-
 gradle.properties                                  |   4 +-
 src/toplevel/changelog.txt                         |   4 +-
 subprojects/gradle-core/core.gradle                |   2 +-
 .../gradle/integtests/AbstractIntegrationTest.java |   4 +-
 ...CrossVersionCompatibilityIntegrationTest.groovy |   7 +-
 ...ementalGroovyProjectBuildIntegrationTest.groovy |  55 +++++
 ...crementalJavaProjectBuildIntegrationTest.groovy |   1 -
 .../gradle/integtests/JUnitIntegrationTest.groovy  |   3 +-
 .../integtests/ProjectLayoutIntegrationTest.groovy |   6 +-
 .../integtests/UserGuideSamplesRunner.groovy       |  48 ++++-
 .../fixtures/AbstractGradleExecuter.java           |  16 +-
 .../gradle/integtests/fixtures/GradleExecuter.java |  12 +-
 .../fixtures/InProcessGradleExecuter.java          |  10 +-
 .../fixtures/PreviousGradleVersionExecuter.groovy  |  24 ++-
 .../maven/MavenSnapshotIntegrationTest.groovy      |  78 ++++++-
 .../recompilesDependentClasses/build.gradle        |   6 +-
 .../build.gradle                                   |   6 +-
 .../src/test/java/org/gradle/TestsOnInner.java     |  15 +-
 .../eclipseproject/scala/expectedClasspathFile.txt |   2 +-
 .../projectWithMavenSnapshots.gradle               |  78 -------
 .../shared/producer.gradle                         |  22 ++
 .../shared/projectWithMavenSnapshots.gradle        |  20 ++
 .../src/main/java/org/gradle/Test.java             |   0
 .../src/main/groovy/org/gradle/StartParameter.java |   1 -
 .../gradle/api/artifacts/ResolverContainer.java    |   2 +-
 .../api/artifacts/dsl/RepositoryHandler.java       |  47 +++--
 .../api/internal/DefaultClassPathProvider.java     |   2 +-
 .../artifacts/dsl/DefaultRepositoryHandler.java    |  14 +-
 .../ivyservice/DefaultResolverFactory.java         |  11 +
 .../ivyservice/DefaultSettingsConverter.java       |  13 +-
 .../ivyservice/GradleIBiblioResolver.java          |  47 ++++-
 .../ivyservice/LocalMavenCacheLocator.java         |  94 +++++++++
 .../artifacts/ivyservice/ResolverFactory.java      |   2 +
 .../DefaultTaskArtifactStateRepository.java        |  15 +-
 .../api/internal/file/AbstractFileTreeElement.java |  19 +-
 .../groovy/org/gradle/cache/DefaultSerializer.java |  22 +-
 .../org/gradle/groovy/scripts/UriScriptSource.java |   3 +-
 .../main/groovy/org/gradle/util/GradleVersion.java | 232 +++++++++++++++++----
 .../src/main/groovy/org/gradle/util/HashUtil.java  |   2 +-
 .../dsl/DefaultRepositoryHandlerTest.groovy        |  11 +
 .../ivyservice/DefaultResolverFactoryTest.groovy   |  34 ++-
 .../ivyservice/GradleIBiblioResolverTest.groovy    |  22 +-
 .../ivyservice/LocalMavenCacheLocatorTest.groovy   |  58 ++++++
 .../maven/DefaultMavenPomFactoryTest.groovy        |   2 +-
 .../DefaultTaskArtifactStateRepositoryTest.java    |   7 +-
 .../internal/file/AbstractFileTreeElementTest.java |  39 ++--
 .../SingleProjectTaskReportModelTest.groovy        |  13 +-
 .../org/gradle/cache/DefaultSerializerTest.groovy  |  36 ++++
 .../gradle/groovy/scripts/UriScriptSourceTest.java |  26 ++-
 .../initialization/CommandLineParserTest.groovy    |  64 +++---
 .../org/gradle/util/GradleVersionTest.groovy       | 109 +++++++++-
 .../src/test/groovy/org/gradle/util/JvmTest.groovy |   6 +-
 .../test/groovy/org/gradle/util/PathTest.groovy    |  14 +-
 .../dsl/org.gradle.api.tasks.wrapper.Wrapper.xml   |  16 +-
 .../gradle-docs/src/docs/userguide/depMngmt.xml    |  23 +-
 .../src/docs/userguide/gradleWrapper.xml           |  47 ++---
 .../src/docs/userguide/installation.xml            |   4 +-
 .../src/docs/userguide/javaTutorial.xml            |   7 +-
 .../src/docs/userguide/multiproject.xml            |  66 +++---
 .../src/docs/userguide/writingBuildScripts.xml     | 112 +++++++---
 .../samples/scala/customizedLayout/build.gradle    |   6 +-
 .../samples/scala/mixedJavaAndScala/build.gradle   |   6 +-
 .../src/samples/scala/quickstart/build.gradle      |   6 +-
 .../artifacts/defineRepository/build.gradle        |   6 +
 .../samples/userguide/tutorial/groovy/build.gradle |  54 +++++
 .../userguide/tutorial/projectApi/build.gradle     |   2 +
 .../tutorial/projectCoreProperties/build.gradle    |   9 -
 .../tutorial/projectCoreProperties/settings.gradle |   1 -
 .../src/samples/userguide/wrapper/build.gradle     |   8 -
 .../userguide/wrapper/customized/build.gradle      |   4 +
 .../samples/userguide/wrapper/simple/build.gradle  |   3 +
 .../userguideOutput/projectCoreProperties.out      |  10 -
 ...CrossVersionCompatibilityIntegrationTest.groovy |   5 +-
 .../testing/junit/JUnitTestClassDetecter.java      |   7 +
 .../gradle/api/tasks/compile/AbstractCompile.java  |   2 +-
 .../groovy/org/gradle/api/tasks/testing/Test.java  |  10 +
 .../internal/tasks/scala/AntScalaCompiler.groovy   |   1 +
 .../org/gradle/api/tasks/scala/ScalaDoc.java       |   3 -
 .../org/gradle/api/tasks/scala/ScalaDocTest.java   |   3 +-
 .../java/org/gradle/api/tasks/wrapper/Wrapper.java |  89 ++++----
 .../wrapper/internal/DistributionLocator.java      |  48 +++++
 .../org/gradle/wrapper/BootstrapMainStarter.java   |  13 +-
 .../src/main/java/org/gradle/wrapper/Download.java |   7 +-
 .../main/java/org/gradle/wrapper/IDownload.java    |   3 +-
 .../src/main/java/org/gradle/wrapper/Install.java  |  31 +--
 .../java/org/gradle/wrapper/PathAssembler.java     |  32 ++-
 .../src/main/java/org/gradle/wrapper/Wrapper.java  |  40 ++--
 .../org/gradle/api/tasks/wrapper/WrapperTest.java  |  70 ++++++-
 .../groovy/org/gradle/wrapper/DownloadTest.groovy  |   4 +-
 .../groovy/org/gradle/wrapper/InstallTest.groovy   |  46 ++--
 .../org/gradle/wrapper/PathAssemblerTest.java      |  83 +++++---
 .../groovy/org/gradle/wrapper/WrapperTest.java     |  47 ++---
 .../org/gradle/wrapper/wrapper.properties          |  13 +-
 wrapper/gradle-wrapper.properties                  |   4 +-
 109 files changed, 2107 insertions(+), 836 deletions(-)

diff --git a/build.gradle b/build.gradle
index 7dc94c0..9e5c74d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,7 +29,7 @@ import org.gradle.build.Git
  * setting certain properties. Those properties can be set in the gradle.properties file in the the gradle user home. The
  * following properties can be set:
  *
- * Uploading distributions to Gradle's release and snapshot repository at codehaus: codehausUserName, codehausUserPassword
+ * Uploading distributions to Gradle's release and snapshot repository at codehaus: artifactoryUserName, artifactoryUserPassword
  * Uploading the userguide and the javadoc to Gradle's website: websiteFtpUserName, websiteFtpUserPassword
  * Using the build to create a new distribution and install it on the local machine: gradle_installPath
  */
@@ -400,10 +400,9 @@ uploadDists {
     dependsOn testedDists
     uploadDescriptor = false
     doFirst {
-        it.repositories.add(new WebdavResolver()) {
+        org.apache.ivy.util.url.CredentialsStore.INSTANCE.addCredentials('Artifactory Realm', 'gradle.artifactoryonline.com', artifactoryUserName, artifactoryUserPassword)
+        it.repositories.add(new org.apache.ivy.plugins.resolver.URLResolver()) {
             name = 'gradleReleases'
-            user = codehausUserName
-            userPassword = codehausUserPassword
             addArtifactPattern("${version.distributionUrl}/[artifact]-[revision](-[classifier]).[ext]" as String)
         }
     }
@@ -412,8 +411,8 @@ uploadDists {
 gradle.taskGraph.whenReady {graph ->
     if (graph.hasTask(uploadDists)) {
         // check properties defined and fail early
-        codehausUserName
-        codehausUserPassword
+        artifactoryUserName
+        artifactoryUserPassword
     }
 }
 
@@ -458,11 +457,9 @@ task release {
     dependsOn releaseVersion, tag, releaseArtifacts, testedDists
 }
 
-task wrapper(type: Wrapper, dependsOn: binZip)
-wrapper.doFirst {task ->
-    task.configure {
+task wrapper(type: Wrapper) {
+    doFirst {
         gradleVersion = version
-        jarPath = 'wrapper'
     }
 }
 
diff --git a/buildSrc/src/main/groovy/org/gradle/build/Version.groovy b/buildSrc/src/main/groovy/org/gradle/build/Version.groovy
index e8fa392..ee01df0 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/Version.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/Version.groovy
@@ -71,9 +71,9 @@ class Version {
 
     String getDistributionUrl() {
         if (release) {
-            'https://dav.codehaus.org/dist/gradle'
+            'https://gradle.artifactoryonline.com/gradle/distributions'
         } else {
-            'https://dav.codehaus.org/snapshots.dist/gradle'
+            'https://gradle.artifactoryonline.com/gradle/distributions/gradle-snapshots'
         }
     }
 }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy
index a188a7f..7c43704 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/BuildableDOMCategory.groovy
@@ -19,31 +19,32 @@ import org.w3c.dom.Element
 import org.w3c.dom.Node
 
 class BuildableDOMCategory {
-    public static setText(Element element, String value) {
+    public static void setText(Element element, String value) {
         while (element.hasChildNodes()) {
             element.removeChild(element.getFirstChild())
         }
         element.appendChild(element.ownerDocument.createTextNode(value))
     }
 
-    public static setChildren(Element element, Closure cl) {
+    public static void setChildren(Node element, Closure cl) {
         while (element.hasChildNodes()) {
             element.removeChild(element.getFirstChild())
         }
         leftShift(element, cl)
     }
 
-    public static leftShift(Element parent, Closure cl) {
+    public static def leftShift(Node parent, Closure cl) {
         DomBuilder builder = new DomBuilder(parent)
         cl.delegate = builder
         cl.call()
+        return builder.elements[0]
     }
 
-    public static leftShift(Element parent, Node node) {
+    public static void leftShift(Node parent, Node node) {
         parent.appendChild(parent.ownerDocument.importNode(node, true))
     }
 
-    public static addFirst(Element parent, Closure cl) {
+    public static void addFirst(Node parent, Closure cl) {
         DomBuilder builder = new DomBuilder(parent.ownerDocument, null)
         cl.delegate = builder
         cl.call()
@@ -53,7 +54,7 @@ class BuildableDOMCategory {
         }
     }
 
-    public static addBefore(Element sibling, Closure cl) {
+    public static void addBefore(Node sibling, Closure cl) {
         DomBuilder builder = new DomBuilder(sibling.ownerDocument, null)
         cl.delegate = builder
         cl.call()
@@ -63,12 +64,12 @@ class BuildableDOMCategory {
         }
     }
 
-    public static addBefore(Element sibling, Node n) {
+    public static void addBefore(Element sibling, Node n) {
         def parent = sibling.parentNode
         parent.insertBefore(n, sibling)
     }
 
-    public static addAfter(Element sibling, Closure cl) {
+    public static void addAfter(Element sibling, Closure cl) {
         DomBuilder builder = new DomBuilder(sibling.ownerDocument, null)
         cl.delegate = builder
         cl.call()
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy
index 1f106b6..74b7608 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/DomBuilder.groovy
@@ -29,13 +29,13 @@ class DomBuilder extends BuilderSupport {
         this.document = document
         this.parent = document
     }
-    
-    def DomBuilder(Element parent) {
+
+    def DomBuilder(Node parent) {
         this.document = parent.ownerDocument
         this.parent = parent
     }
 
-    def DomBuilder(Document document, Element parent) {
+    def DomBuilder(Document document, Node parent) {
         this.document = document
         this.parent = parent
     }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy
index 3510e8f..90b03c0 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleElementLocationHandler.groovy
@@ -39,8 +39,7 @@ class SampleElementLocationHandler {
         this.includeLocation = Boolean.valueOf(sampleElement.'@includeLocation')
     }
 
-    public void processSampleLocation(Element child) {
-        
+    public void processSampleLocation(Element parentElement) {
         if (includeLocation && !locationIncluded) {
             Element tipElement = doc.createElement('tip')
             tipElement.setAttribute('role', 'exampleLocation')
@@ -55,7 +54,7 @@ class SampleElementLocationHandler {
             textElement.appendChild(doc.createTextNode(' which is in both the binary and source distributions of Gradle.'))
             filenameElement.appendChild(doc.createTextNode("samples/$srcDir"))
 
-            child.appendChild(tipElement)
+            parentElement.appendChild(tipElement)
 
             locationIncluded = true
         }
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/SampleLayoutHandler.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleLayoutHandler.groovy
new file mode 100644
index 0000000..038b25c
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/SampleLayoutHandler.groovy
@@ -0,0 +1,146 @@
+/*
+ * Copyright 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.gradle.build.docs
+
+import org.w3c.dom.Element
+
+class SampleLayoutHandler {
+    private final String srcDir
+
+    SampleLayoutHandler(String srcDir) {
+        this.srcDir = srcDir
+    }
+
+    void handle(String locationText, Element parentElement, Element sampleManifestElement) {
+        def doc = parentElement.ownerDocument
+        Element outputTitle = doc.createElement("para")
+        outputTitle.appendChild(doc.createTextNode("Build layout"))
+        parentElement.appendChild(outputTitle)
+        Element programListingElement = doc.createElement('programlisting')
+        parentElement.appendChild(programListingElement)
+        StringBuilder content = new StringBuilder()
+
+        TreeNode tree = new TreeNode(srcDir.tokenize('/').last() + '/', '', true)
+        locationText.eachLine { line ->
+            def fileName = line.trim().replace('\\', '/').replaceAll(/^\//, '').replaceAll(/\/+/, '/')
+            if (fileName) {
+                def node = new TreeNode(fileName, fileName, true)
+                def nodeElement = sampleManifestElement.ownerDocument.createElement(node.file ? 'file' : 'dir')
+                nodeElement.setAttribute('path', fileName)
+                sampleManifestElement.appendChild(nodeElement)
+                tree.children << node
+            }
+        }
+        tree.normalise()
+
+        tree.writeTo(content)
+
+        programListingElement.appendChild(doc.createTextNode(content.toString()))
+    }
+}
+
+class TreeNode {
+    String path
+    final List<String> nameParts
+    List<TreeNode> children = []
+    String name
+    final mustInclude
+
+    TreeNode(String name, String path = name, boolean mustInclude = true) {
+        this.name = name
+        this.path = path
+        this.mustInclude = mustInclude
+    }
+
+    @Override
+    String toString() {
+        return path
+    }
+
+    boolean isFile() {
+        return !path.endsWith('/')
+    }
+
+    void normalise() {
+        if (children.isEmpty()) {
+            return
+        }
+
+        TreeNode currentContext = null
+        int pos = 0;
+        while (pos < children.size()) {
+            def child = children.get(pos)
+            if (child.depth == 1) {
+                currentContext = child
+                pos++
+            } else if (currentContext == null || !child.path.startsWith(currentContext.path)) {
+                // Start a new stack
+                def path = child.parentPath
+                currentContext = new TreeNode(path, path, false)
+                children.add(pos, currentContext)
+                pos++
+            } else {
+                // Move this child down one level
+                if (!currentContext.path.endsWith('/')) {
+                    throw new RuntimeException("Parent directory '$currentContext.path' should end with a slash.")
+                }
+                def path = child.path.substring(currentContext.path.length())
+                currentContext.children.add(new TreeNode(path, path, child.mustInclude))
+                children.remove(pos)
+            }
+        }
+        children.each { child ->
+            child.normalise()
+        }
+
+        // Collapse this node if it has a single child which is a directory
+        if (!mustInclude && children.size() == 1 && children[0].path.endsWith('/')) {
+            path = path + children[0].path
+            name = name + children[0].name
+            children = children[0].children
+        }
+    }
+
+    def getDepth() {
+        return path.tokenize('/').size()
+    }
+
+    def getParentPath() {
+        return path.tokenize('/')[0] + '/'
+    }
+
+    def commonPrefix(String a, String b) {
+        def partsA = a.tokenize('/')
+        def partsB = b.tokenize('/')
+        int i = 0
+        for (; i < partsA.size() && i < partsB.size() && partsA[i] == partsB[i]; i++) {
+        }
+        if (i == 0) {
+            return null
+        }
+        return partsA.subList(0, i).join('/')
+    }
+
+    void writeTo(Appendable target, int depth = 0) {
+        depth.times { target.append('  ') }
+        target.append(name)
+        target.append('\n')
+        children.each { child ->
+            child.writeTo(target, depth + 1)
+        }
+    }
+}
+
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy
index a9840f6..2b36e8d 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/UserGuideTransformTask.groovy
@@ -17,7 +17,6 @@
 
 package org.gradle.build.docs
 
-import groovy.xml.MarkupBuilder
 import groovy.xml.dom.DOMCategory
 import org.gradle.api.DefaultTask
 import org.gradle.api.InvalidUserDataException
@@ -76,12 +75,14 @@ public class UserGuideTransformTask extends DefaultTask {
 
     private def transform(Document doc) {
         use(DOMCategory) {
-            addVersionInfo(doc)
-            applyConditionalChunks(doc)
-            transformSamples(doc)
-            transformApiLinks(doc)
-            transformWebsiteLinks(doc)
-            fixProgramListings(doc)
+            use(BuildableDOMCategory) {
+                addVersionInfo(doc)
+                applyConditionalChunks(doc)
+                transformSamples(doc)
+                transformApiLinks(doc)
+                transformWebsiteLinks(doc)
+                fixProgramListings(doc)
+            }
         }
     }
 
@@ -163,120 +164,92 @@ public class UserGuideTransformTask extends DefaultTask {
     }
 
     def transformSamples(Document doc) {
-        File samplesFile = new File(destFile.parentFile, 'samples.xml')
-        samplesFile.withWriter {Writer writer ->
-            MarkupBuilder xml = new MarkupBuilder(writer)
-            xml.samples {
-                doc.documentElement.depthFirst().findAll { it.name() == 'sample' }.each {Element element ->
-                	validator.validate(element)
-                    String sampleId = element.'@id'
-                    String srcDir = element.'@dir'
-
-                    // This class handles the responsibility of adding the location tips to the first child of first
-                    // example defined in the sample.
-                    SampleElementLocationHandler locationHandler = new SampleElementLocationHandler(doc, element, srcDir)
-                   
-                    xml.sample(id: sampleId, dir: srcDir)
-
-                    String title = element.'@title' 
-
-                    Element exampleElement = doc.createElement('example')
-                    exampleElement.setAttribute('id', sampleId)
-                    Element titleElement = doc.createElement('title')
-               	   	titleElement.appendChild(doc.createTextNode(title))
-               	   	exampleElement.appendChild(titleElement);
-                    
-                    element.children().each {Element child ->
-                        if (child.name() == 'sourcefile') {
-                            String file = child.'@file'
-                           
-                            Element sourcefileTitle = doc.createElement("para")
-                    		Element commandElement = doc.createElement('filename')
-                        	commandElement.appendChild(doc.createTextNode(file))
-                        	sourcefileTitle.appendChild(commandElement)
-                        	exampleElement.appendChild(sourcefileTitle);
-
-                            Element programListingElement = doc.createElement('programlisting')
-                            if (file.endsWith('.gradle') || file.endsWith('.groovy')) {
-                                programListingElement.setAttribute('language', 'java')
-                            }
-                            else if (file.endsWith('.xml')) {
-                                programListingElement.setAttribute('language', 'xml')
-                            }
-                            File srcFile
-                            String snippet = child.'@snippet'
-                            if (snippet) {
-                                srcFile = new File(snippetsDir, "$srcDir/$file-$snippet")
-                            } else {
-                                srcFile = new File(snippetsDir, "$srcDir/$file")
-                            }
-                            programListingElement.appendChild(doc.createTextNode(normalise(srcFile.text)))
-                            exampleElement.appendChild(programListingElement)
-                        } else if (child.name() == 'output') {
-                            String args = child.'@args'
-                            String outputFile = child.'@outputFile' ?: "${sampleId}.out"
-                            boolean ignoreExtraLines = child.'@ignoreExtraLines' ?: false
-
-                            xml.sample(id: sampleId, dir: srcDir, args: args, outputFile: outputFile, ignoreExtraLines: ignoreExtraLines)
-
-                            Element outputTitle = doc.createElement("para")
-                            outputTitle.appendChild(doc.createTextNode("Output of "))
-                            Element commandElement = doc.createElement('userinput')
-                            commandElement.appendChild(doc.createTextNode("gradle $args"))
-                            outputTitle.appendChild(commandElement)
-                            exampleElement.appendChild(outputTitle)
-
-                            Element screenElement = doc.createElement('screen')
-                            File srcFile = new File(sourceFile.parentFile, "../../../src/samples/userguideOutput/${outputFile}").canonicalFile
-                            screenElement.appendChild(doc.createTextNode("> gradle $args\n" + normalise(srcFile.text)))
-                            exampleElement.appendChild(screenElement)
-                        } else if (child.name() == 'test') {
-                            String args = child.'@args'
-
-                            xml.sample(id: sampleId, dir: srcDir, args: args)
-                        } else if (child.name() == 'layout') {
-                        	Element outputTitle = doc.createElement("para")
-                    		outputTitle.appendChild(doc.createTextNode("Build layout"))
-                    		exampleElement.appendChild(outputTitle)
-
-                            Element programListingElement = doc.createElement('programlisting')
-                            exampleElement.appendChild(programListingElement)
-                            StringBuilder content = new StringBuilder()
-                            content.append("${srcDir.tokenize('/').last()}/\n")
-                            List stack = []
-                            child.text().eachLine {
-                                def fileName = it.trim()
-                                if (!fileName) {
-                                    return
-                                }
-                                File file = new File(snippetsDir, "$srcDir/$fileName")
-                                if (!file.exists()) {
-                                    throw new RuntimeException("Sample file $file does not exist for sample ${sampleId}.")
-                                }
-                                List context = fileName.tokenize('/')
-
-                                int common = 0;
-                                while (common < stack.size() && common < context.size() && stack[common] == context[common]) {
-                                    common++;
-                                }
-                                stack = stack.subList(0, common)
-
-                                (stack.size() + 1).times { content.append("  ") }
-                                content.append("${context.subList(stack.size(), context.size()).join('/')}${file.directory ? '/' : ''}\n")
-                                if (file.directory) {
-                                    stack = context
-                                }
-                            }
-                            programListingElement.appendChild(doc.createTextNode(content.toString()))
-                        }
-
-                        locationHandler.processSampleLocation(exampleElement)
+        XIncludeAwareXmlProvider samplesXmlProvider = new XIncludeAwareXmlProvider(classpath)
+        samplesXmlProvider.emptyDoc() << {
+            samples()
+        }
+        Element samplesXml = samplesXmlProvider.root.documentElement
+        doc.documentElement.depthFirst().findAll { it.name() == 'sample' }.each { Element element ->
+            validator.validate(element)
+            String sampleId = element.'@id'
+            String srcDir = element.'@dir'
+
+            // This class handles the responsibility of adding the location tips to the first child of first
+            // example defined in the sample.
+            SampleElementLocationHandler locationHandler = new SampleElementLocationHandler(doc, element, srcDir)
+            SampleLayoutHandler layoutHandler = new SampleLayoutHandler(srcDir)
+
+            samplesXml << { sample(id: sampleId, dir: srcDir) }
+
+            String title = element.'@title'
+
+            Element exampleElement = doc.createElement('example')
+            exampleElement.setAttribute('id', sampleId)
+            Element titleElement = doc.createElement('title')
+            titleElement.appendChild(doc.createTextNode(title))
+            exampleElement.appendChild(titleElement);
+
+            element.children().each {Element child ->
+                if (child.name() == 'sourcefile') {
+                    String file = child.'@file'
+
+                    Element sourcefileTitle = doc.createElement("para")
+                    Element commandElement = doc.createElement('filename')
+                    commandElement.appendChild(doc.createTextNode(file))
+                    sourcefileTitle.appendChild(commandElement)
+                    exampleElement.appendChild(sourcefileTitle);
+
+                    Element programListingElement = doc.createElement('programlisting')
+                    if (file.endsWith('.gradle') || file.endsWith('.groovy')) {
+                        programListingElement.setAttribute('language', 'java')
+                    }
+                    else if (file.endsWith('.xml')) {
+                        programListingElement.setAttribute('language', 'xml')
                     }
-                    element.parentNode.insertBefore(exampleElement, element)
-                    element.parentNode.removeChild(element)
+                    File srcFile
+                    String snippet = child.'@snippet'
+                    if (snippet) {
+                        srcFile = new File(snippetsDir, "$srcDir/$file-$snippet")
+                    } else {
+                        srcFile = new File(snippetsDir, "$srcDir/$file")
+                    }
+                    programListingElement.appendChild(doc.createTextNode(normalise(srcFile.text)))
+                    exampleElement.appendChild(programListingElement)
+                } else if (child.name() == 'output') {
+                    String args = child.'@args'
+                    String outputFile = child.'@outputFile' ?: "${sampleId}.out"
+                    boolean ignoreExtraLines = child.'@ignoreExtraLines' ?: false
+
+                    samplesXml << { sample(id: sampleId, dir: srcDir, args: args, outputFile: outputFile, ignoreExtraLines: ignoreExtraLines) }
+
+                    Element outputTitle = doc.createElement("para")
+                    outputTitle.appendChild(doc.createTextNode("Output of "))
+                    Element commandElement = doc.createElement('userinput')
+                    commandElement.appendChild(doc.createTextNode("gradle $args"))
+                    outputTitle.appendChild(commandElement)
+                    exampleElement.appendChild(outputTitle)
+
+                    Element screenElement = doc.createElement('screen')
+                    File srcFile = new File(sourceFile.parentFile, "../../../src/samples/userguideOutput/${outputFile}").canonicalFile
+                    screenElement.appendChild(doc.createTextNode("> gradle $args\n" + normalise(srcFile.text)))
+                    exampleElement.appendChild(screenElement)
+                } else if (child.name() == 'test') {
+                    String args = child.'@args'
+                    samplesXml << { sample(id: sampleId, dir: srcDir, args: args) }
+                } else if (child.name() == 'layout') {
+                    String args = child.'@after'
+                    Element sampleElement = samplesXml << { sample(id: sampleId, dir: srcDir, args: args) }
+                    layoutHandler.handle(child.text(), exampleElement, sampleElement)
                 }
+
+                locationHandler.processSampleLocation(exampleElement)
             }
+            element.parentNode.insertBefore(exampleElement, element)
+            element.parentNode.removeChild(element)
         }
+
+        File samplesFile = new File(destFile.parentFile, 'samples.xml')
+        samplesXmlProvider.write(samplesFile, true)
     }
 
     void applyConditionalChunks(Document doc) {
diff --git a/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy b/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy
index 95db321..e4ae6ee 100644
--- a/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy
+++ b/buildSrc/src/main/groovy/org/gradle/build/docs/XIncludeAwareXmlProvider.groovy
@@ -24,10 +24,11 @@ import javax.xml.transform.dom.DOMSource
 import javax.xml.transform.stream.StreamResult
 import org.w3c.dom.Document
 import org.w3c.dom.Element
+import org.w3c.dom.Node
 
 class XIncludeAwareXmlProvider {
     final Iterable<java.io.File> classpath
-    Element root
+    Document root
 
     XIncludeAwareXmlProvider(Iterable<File> classpath) {
         this.classpath = classpath
@@ -43,18 +44,24 @@ class XIncludeAwareXmlProvider {
         def oldClassloader = Thread.currentThread().getContextClassLoader()
         Thread.currentThread().setContextClassLoader(classloader)
         try {
-            root = parseSourceFile(sourceFile).documentElement
+            root = parseSourceFile(sourceFile)
         } finally {
             Thread.currentThread().setContextClassLoader(oldClassloader)
         }
-        return root
+        return root.documentElement
+    }
+
+    Node emptyDoc() {
+        root = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
     }
 
-    void write(File destFile) {
+    void write(File destFile, boolean indent = false) {
         destFile.withOutputStream {OutputStream stream ->
             TransformerFactory factory = TransformerFactory.newInstance();
             Transformer transformer = factory.newTransformer();
-//                transformer.setOutputProperty(OutputKeys.INDENT, "no");
+            if (indent) {
+                transformer.setOutputProperty(OutputKeys.INDENT, "yes")
+            }
             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
             transformer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml");
             transformer.transform(new DOMSource(root), new StreamResult(stream));
@@ -62,7 +69,7 @@ class XIncludeAwareXmlProvider {
     }
 
     Document getDocument() {
-        return root.ownerDocument
+        return root
     }
     
     private Document parseSourceFile(File sourceFile) {
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/SampleLayoutHandlerTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/SampleLayoutHandlerTest.groovy
new file mode 100644
index 0000000..b935b12
--- /dev/null
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/SampleLayoutHandlerTest.groovy
@@ -0,0 +1,156 @@
+/*
+ * Copyright 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.gradle.build.docs
+
+import org.w3c.dom.Element
+
+class SampleLayoutHandlerTest extends XmlSpecification {
+    final Element samples = document.createElement('samples')
+    final SampleLayoutHandler builder = new SampleLayoutHandler('samples/name')
+    final Element parent = document.createElement("root")
+
+    def buildsLayoutForFileNames() {
+        when:
+        builder.handle('''
+build.gradle
+settings.gradle
+''', parent, samples)
+
+        then:
+        expectLayout('''name/
+  build.gradle
+  settings.gradle
+''')
+    }
+
+    def buildsLayoutForDirNames() {
+        when:
+        builder.handle('''
+src/
+build/
+''', parent, samples)
+
+        then:
+        expectLayout('''name/
+  src/
+  build/
+''')
+    }
+
+    def buildsLayoutForNestedNames() {
+        when:
+        builder.handle('''
+api/build/
+api/build.gradle
+''', parent, samples)
+
+        then:
+        expectLayout('''name/
+  api/
+    build/
+    build.gradle
+''')
+    }
+
+    def addsMetaDataToSamplesManifest() {
+        when:
+        builder.handle('''
+build.gradle
+build/libs/
+''', parent, samples)
+
+        then:
+        formatTree(samples) == '''<samples>
+    <file path="build.gradle"/>
+    <dir path="build/libs/"/>
+</samples>'''
+    }
+
+    def buildsLayoutForMultipleNestingLevels() {
+        when:
+        builder.handle('''
+src/main/java/Source1.java
+src/main/java/org/
+src/test/java/SourceTest.java
+build/libs/test.jar
+''', parent, samples)
+
+        then:
+        expectLayout('''name/
+  src/
+    main/java/
+      Source1.java
+      org/
+    test/java/
+      SourceTest.java
+  build/libs/
+    test.jar
+''')
+    }
+
+    def buildsLayoutForMultipleNestingLevelsWithExplicitDir() {
+        when:
+        builder.handle('''
+src/main/java/
+src/main/java/org/gradle/Source1.java
+src/main/java/org/gradle/Source2.java
+src/test/java/
+src/test/java/org/gradle/SourceTest.java
+''', parent, samples)
+
+        then:
+        expectLayout('''name/
+  src/
+    main/java/
+      org/gradle/
+        Source1.java
+        Source2.java
+    test/java/
+      org/gradle/
+        SourceTest.java
+''')
+    }
+
+    def failsWhenFileHasChildren() {
+        when:
+        builder.handle('''
+src/main/java
+src/main/java/org/gradle/Source1.java
+''', parent, samples)
+
+        then:
+        RuntimeException e = thrown()
+        e.message == 'Parent directory \'java\' should end with a slash.'
+    }
+
+    def removesLeadingSlashAndEmptyElements() {
+        when:
+        builder.handle('''
+/src//java//
+src//java/Source.java
+''', parent, samples)
+
+        then:
+        expectLayout('''name/
+  src/java/
+    Source.java
+''')
+    }
+
+    void expectLayout(String layout) {
+        assert format(parent.childNodes.collect {it}) == """<para>Build layout</para><programlisting>$layout</programlisting>"""
+    }
+}
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/XmlSpecification.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/XmlSpecification.groovy
similarity index 94%
rename from buildSrc/src/test/groovy/org/gradle/build/docs/dsl/XmlSpecification.groovy
rename to buildSrc/src/test/groovy/org/gradle/build/docs/XmlSpecification.groovy
index 38dae26..4279cf5 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/XmlSpecification.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/XmlSpecification.groovy
@@ -13,19 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.gradle.build.docs.dsl
+package org.gradle.build.docs
 
-import spock.lang.Specification
-import org.w3c.dom.Document
-import javax.xml.parsers.DocumentBuilderFactory
-import org.w3c.dom.Node
-import org.w3c.dom.Element
-import org.w3c.dom.Text
-import org.w3c.dom.Attr
+import groovy.xml.dom.DOMCategory
 import javax.xml.parsers.DocumentBuilder
+import javax.xml.parsers.DocumentBuilderFactory
 import org.xml.sax.InputSource
-import org.gradle.build.docs.BuildableDOMCategory
-import groovy.xml.dom.DOMCategory
+import spock.lang.Specification
+import org.w3c.dom.*
 
 class XmlSpecification extends Specification {
     final Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
index b5c98f4..f43d99e 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocRendererTest.groovy
@@ -15,7 +15,7 @@
  */
 package org.gradle.build.docs.dsl.docbook
 
-import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.XmlSpecification
 import org.gradle.build.docs.dsl.model.PropertyMetaData
 import org.gradle.build.docs.dsl.model.TypeMetaData
 import org.gradle.build.docs.dsl.model.MethodMetaData
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy
index 248f9ce..1ff39c4 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/ClassDocTest.groovy
@@ -15,7 +15,7 @@
  */
 package org.gradle.build.docs.dsl.docbook
 
-import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.XmlSpecification
 import org.gradle.build.docs.dsl.model.*
 
 class ClassDocTest extends XmlSpecification {
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy
index 0e770ba..74a359b 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocConverterTest.groovy
@@ -15,7 +15,7 @@
  */
 package org.gradle.build.docs.dsl.docbook
 
-import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.XmlSpecification
 import org.gradle.build.docs.dsl.model.ClassMetaData
 import org.gradle.build.docs.dsl.model.PropertyMetaData
 import org.gradle.build.docs.dsl.model.MethodMetaData
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy
index 0e2c856..59af961 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/JavadocLinkConverterTest.groovy
@@ -16,7 +16,7 @@
 package org.gradle.build.docs.dsl.docbook
 
 import org.gradle.build.docs.dsl.TypeNameResolver
-import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.XmlSpecification
 import org.gradle.build.docs.dsl.model.ClassMetaData
 import org.gradle.build.docs.model.ClassMetaDataRepository
 import org.gradle.build.docs.dsl.model.MethodMetaData
diff --git a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy
index d9a05e8..fe1f2cb 100644
--- a/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy
+++ b/buildSrc/src/test/groovy/org/gradle/build/docs/dsl/docbook/LinkRendererTest.groovy
@@ -15,7 +15,7 @@
  */
 package org.gradle.build.docs.dsl.docbook
 
-import org.gradle.build.docs.dsl.XmlSpecification
+import org.gradle.build.docs.XmlSpecification
 import org.gradle.build.docs.dsl.model.TypeMetaData
 import org.gradle.build.docs.dsl.model.MethodMetaData
 import org.gradle.build.docs.dsl.model.ClassMetaData
diff --git a/gradle.properties b/gradle.properties
index 8bfd5f2..5094e6e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,2 @@
-previousVersion=0.9-rc-3
-nextVersion=0.9
+previousVersion=0.9
+nextVersion=0.9.1
diff --git a/src/toplevel/changelog.txt b/src/toplevel/changelog.txt
index b31a4e1..41ab933 100644
--- a/src/toplevel/changelog.txt
+++ b/src/toplevel/changelog.txt
@@ -1,4 +1,4 @@
 
-Release Notes - Gradle - Version 0.9
+Release Notes - Gradle - Version 0.9.1
 
-See http://docs.codehaus.org/display/GRADLE/Gradle+0.9+Release+Notes
\ No newline at end of file
+See http://docs.codehaus.org/display/GRADLE/Gradle+0.9.1+Release+Notes
\ No newline at end of file
diff --git a/subprojects/gradle-core/core.gradle b/subprojects/gradle-core/core.gradle
index ef8bfe9..bbcc3f4 100644
--- a/subprojects/gradle-core/core.gradle
+++ b/subprojects/gradle-core/core.gradle
@@ -74,7 +74,7 @@ dependencies {
 
     compile libraries.ant_launcher
 
-    integTestCompile libraries.jetty_depends
+    integTestCompile libraries.jetty_depends, project(':wrapper')
 
     testFixtures sourceSets.test.classes, sourceSets.main.classes
     integTestFixtures sourceSets.integTest.classes
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/AbstractIntegrationTest.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/AbstractIntegrationTest.java
index b37251f..417a2e9 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/AbstractIntegrationTest.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/AbstractIntegrationTest.java
@@ -59,9 +59,7 @@ public abstract class AbstractIntegrationTest implements TestFileContext {
     }
 
     protected GradleExecuter usingBuildFile(File file) {
-        StartParameter parameter = startParameter();
-        parameter.setBuildFile(file);
-        return new InProcessGradleExecuter(parameter);
+        return new InProcessGradleExecuter(startParameter()).usingBuildScript(file);
     }
 
     protected GradleExecuter usingBuildScript(String script) {
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy
index 8773115..4632713 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CrossVersionCompatibilityIntegrationTest.groovy
@@ -31,13 +31,14 @@ class CrossVersionCompatibilityIntegrationTest {
     private final BasicGradleDistribution gradle09rc1 = dist.previousVersion('0.9-rc-1')
     private final BasicGradleDistribution gradle09rc2 = dist.previousVersion('0.9-rc-2')
     private final BasicGradleDistribution gradle09rc3 = dist.previousVersion('0.9-rc-3')
+    private final BasicGradleDistribution gradle09 = dist.previousVersion('0.9')
 
     @Test
     public void canBuildJavaProject() {
         dist.testFile('buildSrc/src/main/groovy').assertIsDir()
 
         // Upgrade and downgrade from previous version to current version and back again
-        eachVersion([gradle08, gradle09rc1, gradle09rc2, gradle09rc3]) { version ->
+        eachVersion([gradle08, gradle09rc1, gradle09rc2, gradle09rc3, gradle09]) { version ->
             version.executer().inDirectory(dist.testDir).withTasks('build').run()
             dist.executer().inDirectory(dist.testDir).withTasks('build').run()
             version.executer().inDirectory(dist.testDir).withTasks('build').run()
@@ -46,14 +47,14 @@ class CrossVersionCompatibilityIntegrationTest {
 
     @Test
     public void canUseWrapperFromPreviousVersionToRunCurrentVersion() {
-        eachVersion([gradle09rc1, gradle09rc2, gradle09rc3]) { version ->
+        eachVersion([gradle09rc1, gradle09rc2, gradle09rc3, gradle09]) { version ->
             checkWrapperWorksWith(version, dist)
         }
     }
 
     @Test
     public void canUseWrapperFromCurrentVersionToRunPreviousVersion() {
-        eachVersion([gradle09rc1, gradle09rc2, gradle09rc3]) { version ->
+        eachVersion([gradle09rc1, gradle09rc2, gradle09rc3, gradle09]) { version ->
             checkWrapperWorksWith(dist, version)
         }
     }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalGroovyProjectBuildIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalGroovyProjectBuildIntegrationTest.groovy
new file mode 100644
index 0000000..a6e8121
--- /dev/null
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalGroovyProjectBuildIntegrationTest.groovy
@@ -0,0 +1,55 @@
+/*
+ * Copyright 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.gradle.integtests
+
+import org.gradle.integtests.fixtures.GradleDistribution
+import org.gradle.integtests.fixtures.GradleDistributionExecuter
+import org.gradle.util.TestFile
+import org.junit.Rule
+import org.junit.Test
+
+class IncrementalGroovyProjectBuildIntegrationTest {
+    @Rule public final GradleDistribution distribution = new GradleDistribution()
+    @Rule public final GradleDistributionExecuter executer = new GradleDistributionExecuter()
+
+    @Test
+    public void doesNotRebuildGroovydocIfSourceHasNotChanged() {
+        distribution.testFile("src/main/groovy/BuildClass.java") << 'public class BuildClass { }'
+        distribution.testFile("build.gradle") << '''
+            apply plugin: 'groovy'
+            dependencies { groovy localGroovy() }
+            groovydoc {
+                link('http://java.sun.com/j2se/1.5.0/docs/api', 'java.,org.xml.,javax.,org.xml.')
+            }
+'''
+
+        executer.withTasks("groovydoc").run();
+
+        TestFile indexFile = distribution.testFile("build/docs/groovydoc/index.html");
+        indexFile.assertIsFile();
+        TestFile.Snapshot snapshot = indexFile.snapshot();
+
+        executer.withTasks("groovydoc").run().assertTasksSkipped(':groovydoc');
+
+        indexFile.assertHasNotChangedSince(snapshot);
+
+        distribution.testFile("build.gradle").append("groovydoc.link('http://java.sun.com/j2se/1.5.0/docs/api', 'java.')")
+
+        executer.withTasks("groovydoc").run().assertTasksNotSkipped(':groovydoc');
+
+        executer.withTasks("groovydoc").run().assertTasksSkipped(':groovydoc');
+    }
+}
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalJavaProjectBuildIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalJavaProjectBuildIntegrationTest.groovy
index 245119e..cf63d75 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalJavaProjectBuildIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/IncrementalJavaProjectBuildIntegrationTest.groovy
@@ -64,5 +64,4 @@ class IncrementalJavaProjectBuildIntegrationTest {
         executer.withTasks("jar").run();
         jar.assertHasNotChangedSince(snapshot);
     }
-
 }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy
index e479148..a678bd8 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/JUnitIntegrationTest.groovy
@@ -195,9 +195,10 @@ public class JUnitIntegrationTest {
         executer.withTasks('test').run()
 
         JUnitTestExecutionResult result = new JUnitTestExecutionResult(dist.testDir)
-        result.assertTestClassesExecuted('org.gradle.EmptyRunWithSubclass', 'org.gradle.TestsOnInner$SomeInner')
+        result.assertTestClassesExecuted('org.gradle.EmptyRunWithSubclass', 'org.gradle.TestsOnInner', 'org.gradle.TestsOnInner$SomeInner')
         result.testClass('org.gradle.EmptyRunWithSubclass').assertTestsExecuted('ok')
         result.testClass('org.gradle.EmptyRunWithSubclass').assertTestPassed('ok')
+        result.testClass('org.gradle.TestsOnInner').assertTestPassed('ok')
         result.testClass('org.gradle.TestsOnInner$SomeInner').assertTestPassed('ok')
     }
 
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ProjectLayoutIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ProjectLayoutIntegrationTest.groovy
index 0ea489a..dcc11d2 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ProjectLayoutIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ProjectLayoutIntegrationTest.groovy
@@ -43,10 +43,10 @@ repositories {
 }
 dependencies {
     groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: '1.6.0'
-    scalaTools group: 'org.scala-lang', name: 'scala-compiler', version: '2.7.6'
-    scalaTools group: 'org.scala-lang', name: 'scala-library', version: '2.7.6'
+    scalaTools group: 'org.scala-lang', name: 'scala-compiler', version: '2.8.1'
+    scalaTools group: 'org.scala-lang', name: 'scala-library', version: '2.8.1'
 
-    compile group: 'org.scala-lang', name: 'scala-library', version: '2.7.6'
+    compile group: 'org.scala-lang', name: 'scala-library', version: '2.8.1'
 }
 
 sourceSets.each {
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserGuideSamplesRunner.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserGuideSamplesRunner.groovy
index 5312469..cd1e8d9 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserGuideSamplesRunner.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/UserGuideSamplesRunner.groovy
@@ -27,6 +27,8 @@ import org.junit.runner.Description
 import org.junit.runner.Runner
 import org.junit.runner.notification.Failure
 import org.junit.runner.notification.RunNotifier
+import com.google.common.collect.ListMultimap
+import com.google.common.collect.ArrayListMultimap
 
 class UserGuideSamplesRunner extends Runner {
     static final String NL = System.properties['line.separator']
@@ -101,6 +103,19 @@ class UserGuideSamplesRunner extends Runner {
                     throw e
                 }
             }
+
+            run.files.each { path ->
+                println "  checking file '$path' exists"
+                File file = new File(rootProjectDir, path).canonicalFile
+                Assert.assertTrue("Expected file '$file' does not exist.", file.exists())
+                Assert.assertTrue("Expected file '$file' is not a file.", file.isFile())
+            }
+            run.dirs.each { path ->
+                println "  checking directory '$path' exists"
+                File file = new File(rootProjectDir, path).canonicalFile
+                Assert.assertTrue("Expected directory '$file' does not exist.", file.exists())
+                Assert.assertTrue("Expected directory '$file' is not a directory.", file.isDirectory())
+            }
         } catch (Throwable e) {
             throw new AssertionError("Integration test for sample '$run.id' in dir '$run.subDir' with args $run.args failed:${NL}$e.message").initCause(e)
         }
@@ -170,7 +185,7 @@ class UserGuideSamplesRunner extends Runner {
 
     static Collection<SampleRun> getScriptsForSamples(File userguideInfoDir) {
         Node samples = new XmlParser().parse(new File(userguideInfoDir, 'samples.xml'))
-        Map<String, List<GradleRun>> samplesByDir = new LinkedHashMap<String, List<GradleRun>>()
+        ListMultimap<String, GradleRun> samplesByDir = ArrayListMultimap.create()
 
         samples.children().each {Node sample ->
             String id = sample.'@id'
@@ -178,24 +193,29 @@ class UserGuideSamplesRunner extends Runner {
             String args = sample.'@args'
             String outputFile = sample.'@outputFile'
             boolean ignoreExtraLines = Boolean.valueOf(sample.'@ignoreExtraLines')
-            if (!samplesByDir[dir]) {
-                samplesByDir[dir] = []
-            }
-            GradleRun run = new GradleRun(id: id, subDir: dir, args: args ? args.split('\\s+') as List : null, envs: [:], expectFailure: false, outputFile: outputFile)
+
+            GradleRun run = new GradleRun(id: id)
+            run.subDir = dir
+            run.args = args ? args.split('\\s+') as List : []
+            run.outputFile = outputFile
             run.ignoreExtraLines = ignoreExtraLines as boolean
-            samplesByDir[dir] << run
+
+            sample.file.each { file -> run.files << file.'@path' }
+            sample.dir.each { file -> run.dirs << file.'@path' }
+
+            samplesByDir.put(dir, run)
         }
 
         // Some custom values
-        samplesByDir['userguide/tutorial/properties'].each { it.envs['ORG_GRADLE_PROJECT_envProjectProp'] = 'envPropertyValue' }
-        samplesByDir['userguide/buildlifecycle/taskExecutionEvents']*.expectFailure = true
-        samplesByDir['userguide/buildlifecycle/buildProjectEvaluateEvents']*.expectFailure = true
+        samplesByDir.get('userguide/tutorial/properties').each { it.envs['ORG_GRADLE_PROJECT_envProjectProp'] = 'envPropertyValue' }
+        samplesByDir.get('userguide/buildlifecycle/taskExecutionEvents')*.expectFailure = true
+        samplesByDir.get('userguide/buildlifecycle/buildProjectEvaluateEvents')*.expectFailure = true
 
         Map<String, SampleRun> samplesById = new TreeMap<String, SampleRun>()
 
         // Remove duplicates for a given directory.
-        samplesByDir.values().collect {List<GradleRun> dirSamples ->
-            Collection<GradleRun> runs = dirSamples.findAll {it.args}
+        samplesByDir.asMap().values().collect {List<GradleRun> dirSamples ->
+            Collection<GradleRun> runs = dirSamples.findAll {it.mustRun}
             if (!runs) {
                 // No samples in this dir have any args, so just run gradle tasks in the dir
                 def sample = dirSamples[0]
@@ -232,4 +252,10 @@ class GradleRun {
     String outputFile
     boolean expectFailure
     boolean ignoreExtraLines
+    List files = []
+    List dirs = []
+
+    boolean getMustRun() {
+        return args || files || dirs
+    }
 }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/AbstractGradleExecuter.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/AbstractGradleExecuter.java
index d45fad0..ca5840c 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/AbstractGradleExecuter.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/AbstractGradleExecuter.java
@@ -30,11 +30,13 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
     private Map<String, String> environmentVars = new HashMap<String, String>();
     private String executable;
     private File userHomeDir;
+    private File buildScript;
 
     public GradleExecuter reset() {
         args.clear();
         tasks.clear();
         workingDir = null;
+        buildScript = null;
         quiet = false;
         taskList = false;
         searchUpwards = false;
@@ -61,6 +63,9 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
         if (workingDir != null) {
             executer.inDirectory(workingDir);
         }
+        if (buildScript != null) {
+            executer.usingBuildScript(buildScript);
+        }
         executer.withTasks(tasks);
         executer.withArguments(args);
         executer.withEnvironmentVars(environmentVars);
@@ -74,7 +79,12 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
         executer.withUserHomeDir(userHomeDir);
     }
 
-    public GradleExecuter usingBuildScript(String script) {
+    public GradleExecuter usingBuildScript(File buildScript) {
+        this.buildScript = buildScript;
+        return this;
+    }
+
+    public GradleExecuter usingBuildScript(String scriptText) {
         throw new UnsupportedOperationException();
     }
 
@@ -161,6 +171,10 @@ public abstract class AbstractGradleExecuter implements GradleExecuter {
 
     protected List<String> getAllArgs() {
         List<String> allArgs = new ArrayList<String>();
+        if (buildScript != null) {
+            allArgs.add("--build-file");
+            allArgs.add(buildScript.getAbsolutePath());
+        }
         if (quiet) {
             allArgs.add("--quiet");
         }
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleExecuter.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleExecuter.java
index 4bfe9ac..3ab09c6 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleExecuter.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/GradleExecuter.java
@@ -61,7 +61,17 @@ public interface GradleExecuter {
 
     GradleExecuter usingInitScript(File initScript);
 
-    GradleExecuter usingBuildScript(String script);
+    /**
+     * Uses the given build script
+     */
+    GradleExecuter usingBuildScript(File buildScript);
+
+    /**
+     * Uses the given build script
+     *
+     * @param scriptText The script text.
+     */
+    GradleExecuter usingBuildScript(String scriptText);
 
     /**
      * Sets the user home dir. Set to null to use the default user home dir.
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/InProcessGradleExecuter.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/InProcessGradleExecuter.java
index 22bd733..8e9e9ef 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/InProcessGradleExecuter.java
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/InProcessGradleExecuter.java
@@ -106,8 +106,14 @@ public class InProcessGradleExecuter extends AbstractGradleExecuter {
     }
 
     @Override
-    public GradleExecuter usingBuildScript(String script) {
-        parameter.useEmbeddedBuildFile(script);
+    public GradleExecuter usingBuildScript(File buildScript) {
+        parameter.setBuildFile(buildScript);
+        return this;
+    }
+
+    @Override
+    public GradleExecuter usingBuildScript(String scriptText) {
+        parameter.useEmbeddedBuildFile(scriptText);
         return this;
     }
 
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/PreviousGradleVersionExecuter.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/PreviousGradleVersionExecuter.groovy
index d693a7b..c805fc7 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/PreviousGradleVersionExecuter.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/fixtures/PreviousGradleVersionExecuter.groovy
@@ -17,23 +17,29 @@ package org.gradle.integtests.fixtures
 
 import org.gradle.util.Jvm
 import org.gradle.util.TestFile
+import org.gradle.util.GradleVersion
+import org.gradle.api.tasks.wrapper.internal.DistributionLocator
 
 public class PreviousGradleVersionExecuter extends AbstractGradleExecuter implements BasicGradleDistribution {
     private final GradleDistribution dist
-    def final String version
+    def final GradleVersion version
 
     PreviousGradleVersionExecuter(GradleDistribution dist, String version) {
         this.dist = dist
-        this.version = version
+        this.version = new GradleVersion(version)
     }
 
     def String toString() {
-        "Gradle $version"
+        version.toString()
+    }
+
+    String getVersion() {
+        return version.version
     }
 
     @Override
     boolean worksWith(Jvm jvm) {
-        return version == '0.9-rc-1' ? jvm.isJava6Compatible() : jvm.isJava5Compatible()
+        return version == new GradleVersion('0.9-rc-1') ? jvm.isJava6Compatible() : jvm.isJava5Compatible()
     }
 
     protected ExecutionResult doRun() {
@@ -48,10 +54,10 @@ public class PreviousGradleVersionExecuter extends AbstractGradleExecuter implem
     }
 
     TestFile getBinDistribution() {
-        def zipFile = dist.userHomeDir.parentFile.file("gradle-$version-bin.zip")
+        def zipFile = dist.userHomeDir.parentFile.file("gradle-$version.version-bin.zip")
         if (!zipFile.isFile()) {
             try {
-                URL url = new URL("http://dist.codehaus.org/gradle/${zipFile.name}")
+                URL url = binDistributionUrl
                 System.out.println("downloading $url");
                 zipFile.copyFrom(url)
             } catch (Throwable t) {
@@ -62,6 +68,10 @@ public class PreviousGradleVersionExecuter extends AbstractGradleExecuter implem
         return zipFile
     }
 
+    private URL getBinDistributionUrl() {
+        return new URL(new DistributionLocator().getDistributionFor(version))
+    }
+
     def TestFile getGradleHomeDir() {
         return findGradleHome()
     }
@@ -69,7 +79,7 @@ public class PreviousGradleVersionExecuter extends AbstractGradleExecuter implem
     private TestFile findGradleHome() {
         // maybe download and unzip distribution
         TestFile versionsDir = dist.distributionsDir.parentFile.file('previousVersions')
-        TestFile gradleHome = versionsDir.file("gradle-$version")
+        TestFile gradleHome = versionsDir.file("gradle-$version.version")
         TestFile markerFile = gradleHome.file('ok.txt')
         if (!markerFile.isFile()) {
             TestFile zipFile = binDistribution
diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/maven/MavenSnapshotIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/maven/MavenSnapshotIntegrationTest.groovy
index f802328..6ec925c 100644
--- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/maven/MavenSnapshotIntegrationTest.groovy
+++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/maven/MavenSnapshotIntegrationTest.groovy
@@ -15,21 +15,83 @@
  */
 package org.gradle.integtests.maven
 
-import org.junit.Test
+import org.gradle.integtests.fixtures.GradleDistribution
+import org.gradle.integtests.fixtures.GradleDistributionExecuter
+import org.gradle.integtests.fixtures.HttpServer
 import org.gradle.integtests.fixtures.TestResources
+import org.junit.Before
 import org.junit.Rule
-import org.gradle.integtests.AbstractIntegrationTest
+import org.junit.Test
 
 /**
  * @author Hans Dockter
  */
-class MavenSnapshotIntegrationTest extends AbstractIntegrationTest {
-    @Rule
-    public final TestResources testResources = new TestResources()
+class MavenSnapshotIntegrationTest {
+    @Rule public GradleDistribution distribution = new GradleDistribution()
+    @Rule public GradleDistributionExecuter executer = new GradleDistributionExecuter()
+    @Rule public final TestResources testResources = new TestResources()
+
+    @Before
+    public void setup() {
+        distribution.requireOwnUserHomeDir()
+    }
+
+    @Test
+    public void retrievesAndCacheLocalSnapshot() {
+        def producerProject = distribution.testFile('producer.gradle')
+        def consumerProject = distribution.testFile('projectWithMavenSnapshots.gradle')
+
+        // Publish the first snapshot
+        executer.usingBuildScript(producerProject).withTasks('uploadArchives').run()
+
+        // Retrieve the first snapshot
+        executer.usingBuildScript(consumerProject).withTasks('retrieve').run()
+        def jarFile = distribution.testFile('build/testproject-1.0-SNAPSHOT.jar')
+        def snapshot = jarFile.assertIsFile().snapshot()
+
+        // Retrieve again should use cached snapshot
+        executer.usingBuildScript(consumerProject).withTasks('retrieve').run().assertTasksSkipped(':retrieve')
+        jarFile.assertHasNotChangedSince(snapshot)
+
+        // Publish the second snapshot
+        Thread.sleep(1100)
+        executer.usingBuildScript(producerProject).withTasks('uploadArchives').withArguments("-PemptyJar").run()
+
+        // Retrieve again should use updated snapshot
+        executer.usingBuildScript(consumerProject).withTasks('retrieve').run().assertTasksNotSkipped(':retrieve')
+        jarFile.assertHasChangedSince(snapshot)
+    }
 
     @Test
-    public void retrievesAndCacheSnapshot() {
-        File buildFile = testFile("projectWithMavenSnapshots.gradle");
-        usingBuildFile(buildFile).withTasks('clean', 'retrieveWithTimedOutSnapshotInCache').run();
+    public void retrievesAndCacheSnapshotViaHttp() {
+        HttpServer server = new HttpServer()
+        server.add('/repo', distribution.testFile('repo'))
+        server.start()
+        String repoUrl = "-PrepoUrl=http://localhost:${server.port}/repo"
+
+        def producerProject = distribution.testFile('producer.gradle')
+        def consumerProject = distribution.testFile('projectWithMavenSnapshots.gradle')
+
+        // Publish the first snapshot
+        executer.usingBuildScript(producerProject).withTasks('uploadArchives').run()
+
+        // Retrieve the first snapshot
+        executer.usingBuildScript(consumerProject).withTasks('retrieve').withArguments(repoUrl).run()
+        def jarFile = distribution.testFile('build/testproject-1.0-SNAPSHOT.jar')
+        def snapshot = jarFile.assertIsFile().snapshot()
+
+        // Publish the second snapshot
+        Thread.sleep(1100)
+        executer.usingBuildScript(producerProject).withTasks('uploadArchives').withArguments("-PemptyJar").run()
+
+        // Retrieve again should use cached snapshot
+        executer.usingBuildScript(consumerProject).withTasks('retrieve').withArguments(repoUrl).run().assertTasksSkipped(':retrieve')
+        jarFile.assertHasNotChangedSince(snapshot)
+
+        // Retrieve again with zero timeout should use updated snapshot
+        executer.usingBuildScript(consumerProject).withTasks('retrieve').withArguments("-PnoTimeout", repoUrl).run().assertTasksNotSkipped(':retrieve')
+        jarFile.assertHasChangedSince(snapshot)
+        
+        server.stop()
     }
 }
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesDependentClasses/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesDependentClasses/build.gradle
index 765f414..a375700 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesDependentClasses/build.gradle
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesDependentClasses/build.gradle
@@ -5,7 +5,7 @@ repositories {
 }
 
 dependencies {
-    scalaTools 'org.scala-lang:scala-compiler:2.7.7'
-    scalaTools 'org.scala-lang:scala-library:2.7.7'
-    compile 'org.scala-lang:scala-library:2.7.7'
+    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
+    scalaTools 'org.scala-lang:scala-library:2.8.1'
+    compile 'org.scala-lang:scala-library:2.8.1'
 }
\ No newline at end of file
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesSourceWhenPropertiesChange/build.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesSourceWhenPropertiesChange/build.gradle
index 2ba99a6..58ce9cc 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesSourceWhenPropertiesChange/build.gradle
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/IncrementalScalaCompileIntegrationTest/recompilesSourceWhenPropertiesChange/build.gradle
@@ -5,8 +5,8 @@ repositories {
 }
 
 dependencies {
-    scalaTools 'org.scala-lang:scala-compiler:2.7.7'
-    scalaTools 'org.scala-lang:scala-library:2.7.7'
+    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
+    scalaTools 'org.scala-lang:scala-library:2.8.1'
 
-    compile 'org.scala-lang:scala-library:2.7.7'
+    compile 'org.scala-lang:scala-library:2.8.1'
 }
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/detectsTestClasses/src/test/java/org/gradle/TestsOnInner.java b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/detectsTestClasses/src/test/java/org/gradle/TestsOnInner.java
index 695e2ec..3d7bafa 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/detectsTestClasses/src/test/java/org/gradle/TestsOnInner.java
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/JUnitIntegrationTest/detectsTestClasses/src/test/java/org/gradle/TestsOnInner.java
@@ -1,7 +1,20 @@
 package org.gradle;
 
+import junit.framework.TestCase;
+import org.junit.Test;
+
 public class TestsOnInner {
+    @Test public void ok() { }
+
     public static class SomeInner {
-        @org.junit.Test public void ok() { }
+        @Test public void ok() { }
+    }
+
+    public class NonStaticInner {
+        @Test public void ok() { }
+    }
+
+    public class NonStaticInnerTestCase extends TestCase {
+        public void testOk() { }
     }
 }
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/eclipseproject/scala/expectedClasspathFile.txt b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/eclipseproject/scala/expectedClasspathFile.txt
index 17f5d40..f9f50ff 100644
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/eclipseproject/scala/expectedClasspathFile.txt
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/eclipseproject/scala/expectedClasspathFile.txt
@@ -7,5 +7,5 @@
   <classpathentry kind="src" path="src/test/scala" output="build/classes/test"/>
   <classpathentry kind="lib" path="$cachePath/commons-collections/commons-collections/jars/commons-collections-3.2.jar"/>
   <classpathentry kind="lib" path="$cachePath/junit/junit/jars/junit-4.7.jar"/>
-  <classpathentry kind="lib" path="$cachePath/org.scala-lang/scala-library/jars/scala-library-2.7.7.jar"/>
+  <classpathentry kind="lib" path="$cachePath/org.scala-lang/scala-library/jars/scala-library-2.8.1.jar"/>
 </classpath>
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/retrievesAndCacheSnapshot/projectWithMavenSnapshots.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/retrievesAndCacheSnapshot/projectWithMavenSnapshots.gradle
deleted file mode 100644
index 490cae9..0000000
--- a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/retrievesAndCacheSnapshot/projectWithMavenSnapshots.gradle
+++ /dev/null
@@ -1,78 +0,0 @@
-apply plugin: 'java'
-apply plugin: 'maven'
-
-group = 'org.gradle'
-version = '1.0-SNAPSHOT'
-
-def repoUrl = "file://localhost/$buildDir/pomRepo/"
-
-repositories {
-    project.repo = mavenRepo(urls: repoUrl)
-}
-
-configurations {
-    snapshot1
-    snapshot2
-    snapshot3
-    archives2
-}
-
-jar {
-    baseName = 'testproject'
-}
-
-task jar2(type: Jar) {
-    baseName = 'testproject'
-    from sourceSets.main.allJava
-}
-
-configure([jar, jar2]) {
-    doLast { task ->
-        ant.checksum(file: archivePath, property: "checksum_$task.name")
-        task.checksum = ant.properties."checksum_$task.name"
-    }
-}
-
-artifacts {
-    archives2 jar2
-}
-
-dependencies {
-    snapshot1 "org.gradle:testproject:1.0-SNAPSHOT"
-    snapshot2 "org.gradle:testproject:1.0-SNAPSHOT"
-    snapshot3 "org.gradle:testproject:1.0-SNAPSHOT"
-}
-
-uploadArchives2.doFirst {
-    // Fix for https://issues.apache.org/jira/browse/IVY-1209
-    Thread.sleep 1100
-}
-
-delete {
-    delete "$gradle.gradleUserHomeDir/cache/${group}/testproject"
-}
-
-task retrieveWithEmptyCache(dependsOn: uploadArchives) << {
-    ant.checksum(file: configurations.snapshot1.singleFile, property: 'checksum1')
-    assert jar.checksum == ant.properties.checksum1
-}
-
-task retrieveWithSnapshotInCache(dependsOn: [retrieveWithEmptyCache, uploadArchives2]) << {
-    repo.setSnapshotTimeout(Long.MAX_VALUE)
-    ant.checksum(file: configurations.snapshot2.singleFile, property: 'checksum2')
-    assert jar.checksum == ant.properties.checksum2
-}
-
-task retrieveWithTimedOutSnapshotInCache(dependsOn: retrieveWithSnapshotInCache) << {
-    repo.setSnapshotTimeout(0)
-    ant.checksum(file: configurations.snapshot3.singleFile, property: 'checksum3')
-    assert jar2.checksum == ant.properties.checksum3
-}
-
-configure([uploadArchives, uploadArchives2]) {
-    repositories {
-        mavenDeployer {
-            repository(url: repoUrl)
-        }
-    }
-}
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/producer.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/producer.gradle
new file mode 100644
index 0000000..781de30
--- /dev/null
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/producer.gradle
@@ -0,0 +1,22 @@
+apply plugin: 'java'
+apply plugin: 'maven'
+
+group = 'org.gradle'
+version = '1.0-SNAPSHOT'
+
+def repoUrl = uri('repo')
+
+jar {
+    baseName = 'testproject'
+    if (project.hasProperty('emptyJar')) {
+        exclude '**/*'
+    }
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: repoUrl)
+        }
+    }
+}
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/projectWithMavenSnapshots.gradle b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/projectWithMavenSnapshots.gradle
new file mode 100644
index 0000000..5053600
--- /dev/null
+++ b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/projectWithMavenSnapshots.gradle
@@ -0,0 +1,20 @@
+apply plugin: 'java'
+
+def repoUrl = hasProperty('repoUrl') ? repoUrl : uri('repo')
+
+repositories {
+    mavenRepo(urls: repoUrl) {
+        if (project.hasProperty('noTimeout')) {
+            setSnapshotTimeout(0)
+        }
+    }
+}
+
+dependencies {
+    compile "org.gradle:testproject:1.0-SNAPSHOT"
+}
+
+task retrieve(type: Sync) {
+    into 'build'
+    from configurations.compile
+}
diff --git a/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/retrievesAndCacheSnapshot/src/main/java/org/gradle/Test.java b/subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/src/main/java/org/gradle/Test.java
similarity index 100%
rename from subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/retrievesAndCacheSnapshot/src/main/java/org/gradle/Test.java
rename to subprojects/gradle-core/src/integTest/resources/org/gradle/integtests/maven/MavenSnapshotIntegrationTest/shared/src/main/java/org/gradle/Test.java
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/StartParameter.java b/subprojects/gradle-core/src/main/groovy/org/gradle/StartParameter.java
index 96fd009..80164a9 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/StartParameter.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/StartParameter.java
@@ -520,7 +520,6 @@ public class StartParameter {
 
     /**
      * Returns true if a profile report will be generated.
-     * @return
      */
     public boolean isProfile() {
         return profile;
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/ResolverContainer.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/ResolverContainer.java
index 89d8ae8..2b7bdee 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/ResolverContainer.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/ResolverContainer.java
@@ -54,13 +54,13 @@ import java.util.List;
  */
 public interface ResolverContainer extends NamedDomainObjectContainer<DependencyResolver>, NamedDomainObjectCollection<DependencyResolver> {
     String DEFAULT_MAVEN_CENTRAL_REPO_NAME = "MavenRepo";
+    String DEFAULT_MAVEN_LOCAL_REPO_NAME = "MavenLocal";
     String MAVEN_CENTRAL_URL = "http://repo1.maven.org/maven2/";
     String MAVEN_REPO_PATTERN = "[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]";
     String FLAT_DIR_RESOLVER_PATTERN = "[artifact](-[revision])(-[classifier]).[ext]";
     String DEFAULT_CACHE_ARTIFACT_PATTERN
             = "[organisation]/[module](/[branch])/[type]s/[artifact]-[revision](-[classifier])(.[ext])";
     String DEFAULT_CACHE_IVY_PATTERN = "[organisation]/[module](/[branch])/ivy-[revision].xml";
-    String DEFAULT_CACHE_NAME = "default-gradle-cache";
     String INTERNAL_REPOSITORY_NAME = "internal-repository";
     String DEFAULT_CACHE_DIR_NAME = "cache";
     String RESOLVER_NAME = "name";
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/RepositoryHandler.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/RepositoryHandler.java
index 7570a73..606b505 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/RepositoryHandler.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/RepositoryHandler.java
@@ -67,7 +67,7 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * @throws org.gradle.api.InvalidUserDataException In the case neither rootDir nor rootDirs is specified of if both
      * are specified.
      */
-    FileSystemResolver flatDir(Map args);
+    FileSystemResolver flatDir(Map<String, ?> args);
 
     /**
      * Adds a repository which looks in the Maven central repository for dependencies. The URL used to access this repository is
@@ -80,13 +80,13 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * <tr><th>Key</th>
      *     <th>Description of Associated Value</th></tr>
      * <tr><td><code>name</code></td>
-     *     <td><em>(optional)</em> The name of the repository. The default is {@link #DEFAULT_MAVEN_CENTRAL_REPO_NAME}
+     *     <td><em>(optional)</em> The name of the repository. The default is {@value #DEFAULT_MAVEN_CENTRAL_REPO_NAME}
      * is used as the name. A name must be unique amongst a repository group.
      * </td></tr>
      * <tr><td><code>urls</code></td>
      *     <td>A single jar repository or a collection of jar repositories. Sometimes the artifact
-     * lives in a different repository than the pom. In such a case you can specify further locations to look for an artifact.
-     * But be aware that the pom is only looked up in the root repository</td></tr>
+     * lives in a different repository than the POM. In such a case you can specify further locations to look for an artifact.
+     * But be aware that the POM is only looked up in the root repository</td></tr>
      * </table>
      *
      * <p>Examples:
@@ -102,11 +102,11 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * @return the added resolver
      * @see #mavenRepo(java.util.Map)
      */
-    DependencyResolver mavenCentral(Map args);
+    DependencyResolver mavenCentral(Map<String, ?> args);
 
     /**
      * Adds a repository which looks in the Maven central repository for dependencies. The URL used to access this repository is
-     * {@link #MAVEN_CENTRAL_URL}. The name of the repository is {@link #DEFAULT_MAVEN_CENTRAL_REPO_NAME}.
+     * {@value #MAVEN_CENTRAL_URL}. The name of the repository is {@value #DEFAULT_MAVEN_CENTRAL_REPO_NAME}.
      *
      * <p>Examples:
      * <pre>
@@ -123,7 +123,24 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
     DependencyResolver mavenCentral();
 
     /**
-     * Adds a repository which is Maven compatible. The compatibility is in regard to layout, snapshothandling and
+     * Adds a repository which looks in the local Maven cache for dependencies. The name of the repository is
+     * {@value #DEFAULT_MAVEN_LOCAL_REPO_NAME}.
+     *
+     * <p>Examples:
+     * <pre>
+     * repositories {
+     *     mavenLocal()
+     * }
+     * </pre>
+     * </p>
+     *
+     * @return the added resolver
+     * @see #mavenRepo(java.util.Map)
+     */
+    DependencyResolver mavenLocal();
+
+    /**
+     * Adds a repository which is Maven compatible. The compatibility is in regard to layout, snapshot handling and
      * dealing with the pom.xml. This repository can't be used for publishing in a Maven compatible way. For publishing
      * to a Maven repository, have a look at {@link #mavenDeployer(java.util.Map)} or {@link #mavenInstaller(java.util.Map)}.
      *
@@ -164,7 +181,9 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * @return the added repository
      * @see #mavenCentral(java.util.Map)
      */
-    DependencyResolver mavenRepo(Map args);
+    DependencyResolver mavenRepo(Map<String, ?> args);
+
+    DependencyResolver mavenRepo(Map<String, ?> args, Closure configClosure);
 
     GroovyMavenDeployer mavenDeployer();
 
@@ -185,22 +204,22 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * to point to information related to a particular repository. A name must be unique amongst a repository group.
      * </td></tr>
      * </table>
-     * 
+     *
      * @param args The argument to create the repository
      * @return The added repository
      * @see #mavenDeployer(java.util.Map, groovy.lang.Closure)
      */
-    GroovyMavenDeployer mavenDeployer(Map args);
+    GroovyMavenDeployer mavenDeployer(Map<String, ?> args);
 
     /**
      * Behaves the same way as {@link #mavenDeployer(java.util.Map)}. Additionally a closure can be passed to
      * further configure the added repository.
-     *  
+     *
      * @param args The argument to create the repository
      * @param configureClosure
      * @return The added repository
      */
-    GroovyMavenDeployer mavenDeployer(Map args, Closure configureClosure);
+    GroovyMavenDeployer mavenDeployer(Map<String, ?> args, Closure configureClosure);
 
     MavenResolver mavenInstaller();
 
@@ -225,7 +244,7 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * @return The added repository
      * @see #mavenInstaller(java.util.Map, groovy.lang.Closure) (java.util.Map, groovy.lang.Closure)
      */
-    MavenResolver mavenInstaller(Map args);
+    MavenResolver mavenInstaller(Map<String, ?> args);
 
     /**
      * Behaves the same way as {@link #mavenInstaller(java.util.Map)}. Additionally a closure can be passed to
@@ -235,6 +254,6 @@ public interface RepositoryHandler extends ResolverContainer, ResolverProvider {
      * @param configureClosure
      * @return The added repository
      */
-    MavenResolver mavenInstaller(Map args, Closure configureClosure);
+    MavenResolver mavenInstaller(Map<String, ?> args, Closure configureClosure);
 
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathProvider.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathProvider.java
index 8341960..5ddf321 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathProvider.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathProvider.java
@@ -27,7 +27,7 @@ public class DefaultClassPathProvider extends AbstractClassPathProvider {
         List<Pattern> gradleApiPatterns = toPatterns("gradle-\\w+", "ivy", "slf4j", "ant");
         gradleApiPatterns.addAll(groovyPatterns);
         // Add the test fixture runtime, too
-        gradleApiPatterns.addAll(toPatterns("commons-io", "asm", "commons-lang", "commons-collections"));
+        gradleApiPatterns.addAll(toPatterns("commons-io", "asm", "commons-lang", "commons-collections", "maven-ant-tasks"));
         add("GRADLE_API", gradleApiPatterns);
         add("GRADLE_CORE", toPatterns("gradle-core"));
         add("ANT", toPatterns("ant", "ant-launcher"));
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandler.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandler.java
index e00cb7e..b68e8d3 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandler.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandler.java
@@ -16,6 +16,7 @@
 package org.gradle.api.internal.artifacts.dsl;
 
 import groovy.lang.Closure;
+import org.apache.ivy.plugins.resolver.AbstractResolver;
 import org.apache.ivy.plugins.resolver.DependencyResolver;
 import org.apache.ivy.plugins.resolver.FileSystemResolver;
 import org.gradle.api.InvalidUserDataException;
@@ -99,16 +100,25 @@ public class DefaultRepositoryHandler extends DefaultResolverContainer implement
                 urls == null ? new String[0] : urls.toArray(new String[urls.size()])));
     }
 
+    public DependencyResolver mavenLocal() {
+        return add(getResolverFactory().createMavenLocalResolver(DEFAULT_MAVEN_LOCAL_REPO_NAME));
+    }
+
     public DependencyResolver mavenRepo(Map args) {
+        return mavenRepo(args, null);
+    }
+
+    public DependencyResolver mavenRepo(Map args, Closure configClosure) {
         List<String> urls = createStringifiedListFromMapArg(args, "urls");
         if (urls == null) {
             throw new InvalidUserDataException("You must specify a urls for a Maven repo.");
         }
         List<String> extraUrls = urls.subList(1, urls.size());
-        return add(getResolverFactory().createMavenRepoResolver(
+        AbstractResolver resolver = getResolverFactory().createMavenRepoResolver(
                 getNameFromMap(args, urls.get(0)),
                 urls.get(0),
-                urls.size() == 1 ? new String[0] : extraUrls.toArray(new String[extraUrls.size()])));
+                urls.size() == 1 ? new String[0] : extraUrls.toArray(new String[extraUrls.size()]));
+        return add(resolver, configClosure);
     }
 
     public GroovyMavenDeployer mavenDeployer(Map args) {
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactory.java
index f675538..2eb194d 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactory.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactory.java
@@ -51,9 +51,15 @@ import java.util.Map;
  */
 public class DefaultResolverFactory implements ResolverFactory {
     private final Factory<? extends LoggingManagerInternal> loggingManagerFactory;
+    private final LocalMavenCacheLocator localMavenCacheLocator;
 
     public DefaultResolverFactory(Factory<? extends LoggingManagerInternal> loggingManagerFactory) {
+        this(loggingManagerFactory, new LocalMavenCacheLocator());
+    }
+
+    DefaultResolverFactory(Factory<? extends LoggingManagerInternal> loggingManagerFactory, LocalMavenCacheLocator localMavenCacheLocator) {
         this.loggingManagerFactory = loggingManagerFactory;
+        this.localMavenCacheLocator = localMavenCacheLocator;
     }
 
     public DependencyResolver createResolver(Object userDescription) {
@@ -109,6 +115,11 @@ public class DefaultResolverFactory implements ResolverFactory {
         return tmpFile;
     }
 
+    public AbstractResolver createMavenLocalResolver(String name) {
+        String cacheDir = localMavenCacheLocator.getLocalMavenCache().toURI().toString();
+        return createMavenRepoResolver(name, cacheDir);
+    }
+
     public AbstractResolver createMavenRepoResolver(String name, String root, String... jarRepoUrls) {
         GradleIBiblioResolver iBiblioResolver = createIBiblioResolver(name, root);
         if (jarRepoUrls.length == 0) {
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultSettingsConverter.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultSettingsConverter.java
index 8ca8a69..4af0700 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultSettingsConverter.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultSettingsConverter.java
@@ -16,6 +16,7 @@
 
 package org.gradle.api.internal.artifacts.ivyservice;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.ivy.core.cache.DefaultRepositoryCacheManager;
 import org.apache.ivy.core.cache.RepositoryCacheManager;
 import org.apache.ivy.core.settings.IvySettings;
@@ -188,17 +189,25 @@ public class DefaultSettingsConverter implements SettingsConverter {
             }
             if (evt.getEventType() == TransferEvent.TRANSFER_STARTED) {
                 total = 0;
-                DefaultSettingsConverter.logger.lifecycle("Download " + evt.getResource().getName());
+                DefaultSettingsConverter.logger.lifecycle(String.format("%s %s", StringUtils.capitalize(getRequestType(evt)), evt.getResource().getName()));
                 logger = progressLoggerFactory.start(DefaultSettingsConverter.class.getName());
             }
             if (evt.getEventType() == TransferEvent.TRANSFER_PROGRESS) {
                 total += evt.getLength();
-                logger.progress(String.format("%s/%s downloaded", getLengthText(total), getLengthText(evt)));
+                logger.progress(String.format("%s/%s %sed", getLengthText(total), getLengthText(evt), getRequestType(evt)));
             }
             if (evt.getEventType() == TransferEvent.TRANSFER_COMPLETED
                     || evt.getEventType() == TransferEvent.TRANSFER_ERROR) {
                 logger.completed();
             }
         }
+
+        private String getRequestType(TransferEvent evt) {
+            if (evt.getRequestType() == TransferEvent.REQUEST_PUT) {
+                return "upload";
+            } else {
+                return "download";
+            }
+        }
     }
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolver.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolver.java
index 00d0091..93787bc 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolver.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolver.java
@@ -21,9 +21,11 @@ import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
 import org.apache.ivy.core.resolve.ResolveData;
 import org.apache.ivy.core.resolve.ResolvedModuleRevision;
 import org.apache.ivy.plugins.resolver.IBiblioResolver;
-import org.apache.ivy.util.PropertiesFile;
+import org.gradle.util.UncheckedException;
 
 import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Calendar;
 import java.util.Date;
 
@@ -52,8 +54,8 @@ public class GradleIBiblioResolver extends IBiblioResolver {
 
             Calendar calendarLastResolved = Calendar.getInstance();
             calendarLastResolved.setTime(new Date(lastResolvedTime));
-            if (calendarLastResolved.get(Calendar.YEAR) == year &&
-                    calendarLastResolved.get(Calendar.DAY_OF_YEAR) == dayOfYear) {
+            if (calendarLastResolved.get(Calendar.YEAR) == year && calendarLastResolved.get(Calendar.DAY_OF_YEAR)
+                    == dayOfYear) {
                 return false;
             }
             return true;
@@ -88,6 +90,23 @@ public class GradleIBiblioResolver extends IBiblioResolver {
     }
 
     @Override
+    public void setRoot(String root) {
+        super.setRoot(root);
+
+        URI rootUri;
+        try {
+            rootUri = new URI(root);
+        } catch (URISyntaxException e) {
+            throw UncheckedException.asUncheckedException(e);
+        }
+        if (rootUri.getScheme().equalsIgnoreCase("file")) {
+            setSnapshotTimeout(ALWAYS);
+        } else {
+            setSnapshotTimeout(DAILY);
+        }
+    }
+
+    @Override
     protected ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd, ResolveData data) {
         setChangingPattern(null);
         ResolvedModuleRevision moduleRevision = super.findModuleInCache(dd, data);
@@ -111,17 +130,20 @@ public class GradleIBiblioResolver extends IBiblioResolver {
         cacheProperties.save();
     }
 
-    private Long getLastResolvedTime(PropertiesFile cacheProperties) {
+    private long getLastResolvedTime(PropertiesFile cacheProperties) {
         String lastResolvedProp = cacheProperties.getProperty("resolved.time");
-        Long lastResolvedTime = lastResolvedProp != null ? Long.parseLong(lastResolvedProp) : 0;
-        return lastResolvedTime;
+        if (lastResolvedProp != null) {
+            return Long.parseLong(lastResolvedProp);
+        }
+        // No resolved.time property - assume that the properties file modification time == the resolve time
+        return cacheProperties.file.lastModified();
     }
 
     private PropertiesFile getCacheProperties(DependencyDescriptor dd, ResolvedModuleRevision moduleRevision) {
         DefaultRepositoryCacheManager cacheManager = (DefaultRepositoryCacheManager) getRepositoryCacheManager();
         PropertiesFile props = new PropertiesFile(new File(cacheManager.getRepositoryCacheRoot(),
-                IvyPatternHelper.substitute(
-                        cacheManager.getDataFilePattern(), moduleRevision.getId())), "ivy cached data file for " + dd.getDependencyRevisionId());
+                IvyPatternHelper.substitute(cacheManager.getDataFilePattern(), moduleRevision.getId())),
+                "ivy cached data file for " + dd.getDependencyRevisionId());
         return props;
     }
 
@@ -129,6 +151,15 @@ public class GradleIBiblioResolver extends IBiblioResolver {
         boolean isCacheTimedOut(long lastResolvedTime);
     }
 
+    private static class PropertiesFile extends org.apache.ivy.util.PropertiesFile {
+        private final File file;
+
+        private PropertiesFile(File file, String header) {
+            super(file, header);
+            this.file = file;
+        }
+    }
+
     public static class Interval implements CacheTimeoutStrategy {
         private long interval;
 
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/LocalMavenCacheLocator.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/LocalMavenCacheLocator.java
new file mode 100644
index 0000000..4585172
--- /dev/null
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/LocalMavenCacheLocator.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 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.gradle.api.internal.artifacts.ivyservice;
+
+import org.apache.maven.settings.DefaultMavenSettingsBuilder;
+import org.apache.maven.settings.MavenSettingsBuilder;
+import org.apache.maven.settings.Settings;
+import org.gradle.api.internal.artifacts.publish.maven.pombuilder.PlexusLoggerAdapter;
+import org.gradle.util.UncheckedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.lang.reflect.Field;
+
+/**
+ * @author Steve Ebersole
+ */
+public class LocalMavenCacheLocator {
+    private static final Logger LOGGER = LoggerFactory.getLogger(LocalMavenCacheLocator.class);
+    private static final String USER_HOME_MARKER = "${user.home}/";
+
+    public File getLocalMavenCache() {
+        File userHome = new File(System.getProperty("user.home"));
+        File m2Dir = new File(userHome, ".m2");
+
+        File userSettings = new File(m2Dir, "settings.xml");
+        if (userSettings.exists()) {
+            File overriddenMavenLocal = extractMavenLocal(userSettings, userHome);
+            if (overriddenMavenLocal != null) {
+                return overriddenMavenLocal;
+            }
+        }
+
+        return new File(m2Dir, "repository");
+    }
+
+    private File extractMavenLocal(File userSettings, File userHome) {
+        Settings settings = extractSettings(userSettings);
+        String override = settings.getLocalRepository();
+        if (override != null) {
+            override = override.trim();
+            if (override.length() > 0) {
+                // Nice, it does not even handle the interpolation for us, so we'll handle some common cases...
+                if (override.startsWith(USER_HOME_MARKER)) {
+                    override = userHome.getAbsolutePath() + '/' + override.substring(USER_HOME_MARKER.length());
+                }
+                return new File(override);
+            }
+        }
+        return null;
+    }
+
+    private Settings extractSettings(File userSettings) {
+        try {
+            MavenSettingsBuilder builder = buildSettingsBuilder(userSettings);
+            return builder.buildSettings();
+        } catch (Exception e) {
+            throw UncheckedException.asUncheckedException(e);
+        }
+    }
+
+    private MavenSettingsBuilder buildSettingsBuilder(File userSettings) throws Exception {
+        final String userSettingsPath = userSettings.getAbsolutePath();
+
+        DefaultMavenSettingsBuilder builder = new DefaultMavenSettingsBuilder();
+        builder.enableLogging(new PlexusLoggerAdapter(LOGGER));
+
+        Field userSettingsPathField = DefaultMavenSettingsBuilder.class.getDeclaredField("userSettingsPath");
+        userSettingsPathField.setAccessible(true);
+        userSettingsPathField.set(builder, userSettingsPath);
+
+        Field globalSettingsPathField = DefaultMavenSettingsBuilder.class.getDeclaredField("globalSettingsPath");
+        globalSettingsPathField.setAccessible(true);
+        globalSettingsPathField.set(builder, userSettingsPath);
+
+        builder.initialize();
+
+        return builder;
+    }
+}
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/ResolverFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/ResolverFactory.java
index 44677f5..8c283b6 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/ResolverFactory.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/ivyservice/ResolverFactory.java
@@ -37,6 +37,8 @@ public interface ResolverFactory {
 
     AbstractResolver createMavenRepoResolver(String name, String root, String... jarRepoUrls);
 
+    AbstractResolver createMavenLocalResolver(String name);
+
     GroovyMavenDeployer createMavenDeployer(String name, MavenPomMetaInfoProvider pomMetaInfoProvider, ConfigurationContainer configurationContainer,
                                            Conf2ScopeMappingContainer scopeMapping, FileResolver fileResolver);
 
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepository.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepository.java
index 0f9e745..a50cf8b 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepository.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepository.java
@@ -23,6 +23,7 @@ import org.gradle.api.internal.file.SimpleFileCollection;
 import org.gradle.api.logging.Logger;
 import org.gradle.api.logging.Logging;
 import org.gradle.cache.CacheRepository;
+import org.gradle.cache.DefaultSerializer;
 import org.gradle.cache.PersistentIndexedCache;
 import org.gradle.util.ChangeListener;
 import org.gradle.util.DiffUtil;
@@ -40,6 +41,7 @@ public class DefaultTaskArtifactStateRepository implements TaskArtifactStateRepo
     private final FileSnapshotter inputFilesSnapshotter;
     private final FileSnapshotter outputFilesSnapshotter;
     private PersistentIndexedCache<String, TaskHistory> taskHistoryCache;
+    private DefaultSerializer<TaskHistory> serializer;
 
     public DefaultTaskArtifactStateRepository(CacheRepository repository, FileSnapshotter inputFilesSnapshotter, FileSnapshotter outputFilesSnapshotter) {
         this.repository = repository;
@@ -56,7 +58,8 @@ public class DefaultTaskArtifactStateRepository implements TaskArtifactStateRepo
     }
 
     private void loadTasks(TaskInternal task) {
-        taskHistoryCache = repository.cache("taskArtifacts").forObject(task.getProject().getGradle()).open().openIndexedCache();
+        serializer = new DefaultSerializer<TaskHistory>();
+        taskHistoryCache = repository.cache("taskArtifacts").forObject(task.getProject().getGradle()).open().openIndexedCache(serializer);
     }
 
     private static Set<String> outputFiles(TaskInternal task) {
@@ -311,8 +314,14 @@ public class DefaultTaskArtifactStateRepository implements TaskArtifactStateRepo
         }
 
         private TaskHistory getHistory() {
-            TaskHistory history = taskHistoryCache.get(task.getPath());
-            return history == null ? new TaskHistory() : history;
+            ClassLoader original = serializer.getClassLoader();
+            serializer.setClassLoader(task.getClass().getClassLoader());
+            try {
+                TaskHistory history = taskHistoryCache.get(task.getPath());
+                return history == null ? new TaskHistory() : history;
+            } finally {
+                serializer.setClassLoader(original);
+            }
         }
 
         public TaskExecution getExecution() {
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/file/AbstractFileTreeElement.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/file/AbstractFileTreeElement.java
index d152a53..3da8e6f 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/file/AbstractFileTreeElement.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/file/AbstractFileTreeElement.java
@@ -15,10 +15,10 @@
  */
 package org.gradle.api.internal.file;
 
-import org.gradle.api.file.FileTreeElement;
+import org.apache.commons.io.IOUtils;
 import org.gradle.api.GradleException;
 import org.gradle.api.UncheckedIOException;
-import org.apache.commons.io.IOUtils;
+import org.gradle.api.file.FileTreeElement;
 
 import java.io.*;
 
@@ -53,12 +53,7 @@ public abstract class AbstractFileTreeElement implements FileTreeElement {
 
     public boolean copyTo(File target) {
         try {
-            if (!needsCopy(target)) {
-                return false;
-            }
-
             target.getParentFile().mkdirs();
-
             if (isDirectory()) {
                 target.mkdirs();
             } else {
@@ -79,14 +74,4 @@ public abstract class AbstractFileTreeElement implements FileTreeElement {
             outputStream.close();
         }
     }
-
-    boolean needsCopy(File dest) {
-        if (dest.exists()) {
-            if (getLastModified() == dest.lastModified()) {
-                return false;
-            }
-            // possibly add option to check file size too
-        }
-        return true;
-    }
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/cache/DefaultSerializer.java b/subprojects/gradle-core/src/main/groovy/org/gradle/cache/DefaultSerializer.java
index c866d37..393470b 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/cache/DefaultSerializer.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/cache/DefaultSerializer.java
@@ -15,12 +15,32 @@
  */
 package org.gradle.cache;
 
+import org.gradle.util.ClassLoaderObjectInputStream;
+
 import java.io.*;
 
 public class DefaultSerializer<T> implements Serializer<T> {
+    private ClassLoader classLoader;
+
+    public DefaultSerializer() {
+        classLoader = getClass().getClassLoader();
+    }
+
+    public DefaultSerializer(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    public void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
     public T read(InputStream instr) throws Exception {
         try {
-            return (T) new ObjectInputStream(instr).readObject();
+            return (T) new ClassLoaderObjectInputStream(instr, classLoader).readObject();
         } catch (StreamCorruptedException e) {
             return null;
         }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/UriScriptSource.java b/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/UriScriptSource.java
index d56eb03..d3d92f1 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/UriScriptSource.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/UriScriptSource.java
@@ -45,7 +45,7 @@ public class UriScriptSource implements ScriptSource {
     public String getClassName() {
         if (className == null) {
             URI sourceUri = resource.getURI();
-            String name = StringUtils.substringAfterLast(sourceUri.getPath(), "/");
+            String name = StringUtils.substringBeforeLast(StringUtils.substringAfterLast(sourceUri.getPath(), "/"), ".");
             StringBuilder className = new StringBuilder(name.length());
             for (int i = 0; i < name.length(); i++) {
                 char ch = name.charAt(i);
@@ -58,6 +58,7 @@ public class UriScriptSource implements ScriptSource {
             if (!Character.isJavaIdentifierStart(className.charAt(0))) {
                 className.insert(0, '_');
             }
+            className.setLength(Math.min(className.length(), 30));
             className.append('_');
             String path = sourceUri.toString();
             className.append(HashUtil.createHash(path));
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/util/GradleVersion.java b/subprojects/gradle-core/src/main/groovy/org/gradle/util/GradleVersion.java
index 5ab0787..a31e588 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/util/GradleVersion.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/util/GradleVersion.java
@@ -14,55 +14,207 @@
  * limitations under the License.
  */
 
-package org.gradle.util ;
+package org.gradle.util;
 
 import groovy.lang.GroovySystem;
 import org.apache.ivy.Ivy;
 import org.apache.tools.ant.Main;
+import org.gradle.api.InvalidUserDataException;
 
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * @author Hans Dockter
  * @author Russel Winder
  */
-public class GradleVersion {
-  private final static String BUILD_TIME = "buildTime" ;
-  private final static String VERSION = "version" ;
-  private final static String FILE_NAME = "/org/gradle/version.properties" ;
-  public final static String URL = "http://www.gradle.org" ;
-
-  private final Properties versionProperties ;
-
-  public GradleVersion ( ) {
-    versionProperties = GUtil.loadProperties ( getClass ( ).getResourceAsStream ( FILE_NAME ) ) ;
-  }
-
-  public String getVersion ( ) {
-    return versionProperties.getProperty ( VERSION ) ;
-  }
-  
-  public String getBuildTime ( ) {
-    return versionProperties.getProperty ( BUILD_TIME ) ;
-  }
-  
-  public String prettyPrint ( ) {
-    final StringBuilder sb = new StringBuilder ( ) ;
-    sb.append ( "\n------------------------------------------------------------\nGradle " ) ;
-    sb.append ( getVersion ( ) ) ;
-    sb.append ( "\n------------------------------------------------------------\n\nGradle build time: " ) ;
-    sb.append ( getBuildTime ( ) ) ;
-    sb.append ( "\nGroovy: " ) ;
-    sb.append ( GroovySystem.getVersion ( ) ) ;
-    sb.append ( "\nAnt: " ) ;
-    sb.append ( Main.getAntVersion ( ) ) ;
-    sb.append ( "\nIvy: " ) ;
-    sb.append ( Ivy.getIvyVersion ( ) ) ;
-    sb.append ( "\nJVM: " ) ;
-    sb.append ( Jvm.current() ) ;
-    sb.append ( "\nOS: " ) ;
-    sb.append ( OperatingSystem.current() ) ;
-    sb.append ( "\n" ) ;
-    return sb.toString ( ) ;
-  }
+public class GradleVersion implements Comparable<GradleVersion> {
+    private final static String BUILD_TIME = "buildTime";
+    private final static String VERSION = "version";
+    private final static String FILE_NAME = "/org/gradle/version.properties";
+    public final static String URL = "http://www.gradle.org";
+    private final static Pattern VERSION_PATTERN = Pattern.compile("(\\d+(\\.\\d+)+)(-(\\p{Alpha}+)-(\\d+))?(-(\\d{14}\\+\\d{4}))?");
+
+    private final String version;
+    private final String buildTime;
+    private final Long snapshot;
+    private final String versionPart;
+    private final Stage stage;
+
+    public GradleVersion() {
+        this(GUtil.loadProperties(GradleVersion.class.getResourceAsStream(FILE_NAME)));
+    }
+
+    public GradleVersion(String version) {
+        this(properties(version));
+    }
+
+    private static Properties properties(String version) {
+        Properties properties = new Properties();
+        properties.setProperty(VERSION, version);
+        return properties;
+    }
+
+    private GradleVersion(Properties properties) {
+        version = properties.getProperty(VERSION);
+        buildTime = properties.getProperty(BUILD_TIME);
+        Matcher matcher = VERSION_PATTERN.matcher(version);
+        if (!matcher.matches()) {
+            throw new InvalidUserDataException(String.format("Unexpected Gradle version '%s'.", version));
+        }
+        versionPart = matcher.group(1);
+
+        if (matcher.group(3) != null) {
+            int stageNumber = 0;
+            if (matcher.group(4).equals("milestone")) {
+                stageNumber = 1;
+            } else if (matcher.group(4).equals("preview")) {
+                stageNumber = 2;
+            } else if (matcher.group(4).equals("rc")) {
+                stageNumber = 3;
+            }
+            stage = new Stage(stageNumber, Integer.parseInt(matcher.group(5)));
+        } else {
+            stage = null;
+        }
+
+        if (matcher.group(7) != null) {
+            try {
+                snapshot = new SimpleDateFormat("yyyyMMddHHmmssZ").parse(matcher.group(7)).getTime();
+            } catch (ParseException e) {
+                throw UncheckedException.asUncheckedException(e);
+            }
+        } else {
+            snapshot = null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return String.format("Gradle %s", version);
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public String getBuildTime() {
+        return buildTime;
+    }
+
+    public boolean isSnapshot() {
+        return snapshot != null;
+    }
+
+    public int compareTo(GradleVersion gradleVersion) {
+        String[] majorVersionParts = versionPart.split("\\.");
+        String[] otherMajorVersionParts = gradleVersion.versionPart.split("\\.");
+        for (int i = 0; i < majorVersionParts.length && i < otherMajorVersionParts.length; i++) {
+            int part = Integer.parseInt(majorVersionParts[i]);
+            int otherPart = Integer.parseInt(otherMajorVersionParts[i]);
+            if (part > otherPart) {
+                return 1;
+            }
+            if (otherPart > part) {
+                return -1;
+            }
+        }
+        if (majorVersionParts.length > otherMajorVersionParts.length) {
+            return 1;
+        }
+        if (majorVersionParts.length < otherMajorVersionParts.length) {
+            return -1;
+        }
+
+        if (stage != null && gradleVersion.stage != null) {
+            int diff = stage.compareTo(gradleVersion.stage);
+            if (diff != 0) {
+                return diff;
+            }
+        }
+        if (stage == null && gradleVersion.stage != null) {
+            return 1;
+        }
+        if (stage != null && gradleVersion.stage == null) {
+            return -1;
+        }
+
+        if (snapshot != null && gradleVersion.snapshot != null) {
+            return snapshot.compareTo(gradleVersion.snapshot);
+        }
+        if (snapshot == null && gradleVersion.snapshot != null) {
+            return 1;
+        }
+        if (snapshot != null && gradleVersion.snapshot == null) {
+            return -1;
+        }
+
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o == null || o.getClass() != getClass()) {
+            return false;
+        }
+        GradleVersion other = (GradleVersion) o;
+        return version.equals(other.version);
+    }
+
+    @Override
+    public int hashCode() {
+        return version.hashCode();
+    }
+
+    public String prettyPrint() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("\n------------------------------------------------------------\nGradle ");
+        sb.append(getVersion());
+        sb.append("\n------------------------------------------------------------\n\nGradle build time: ");
+        sb.append(getBuildTime());
+        sb.append("\nGroovy: ");
+        sb.append(GroovySystem.getVersion());
+        sb.append("\nAnt: ");
+        sb.append(Main.getAntVersion());
+        sb.append("\nIvy: ");
+        sb.append(Ivy.getIvyVersion());
+        sb.append("\nJVM: ");
+        sb.append(Jvm.current());
+        sb.append("\nOS: ");
+        sb.append(OperatingSystem.current());
+        sb.append("\n");
+        return sb.toString();
+    }
+
+    private static final class Stage implements Comparable<Stage> {
+        final int stage;
+        final int number;
+
+        private Stage(int stage, int number) {
+            this.stage = stage;
+            this.number = number;
+        }
+
+        public int compareTo(Stage other) {
+            if (stage > other.stage) {
+                return 1;
+            }
+            if (stage < other.stage) {
+                return -1;
+            }
+            if (number > other.number) {
+                return 1;
+            }
+            if (number < other.number) {
+                return -1;
+            }
+            return 0;
+        }
+    }
 }
diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/util/HashUtil.java b/subprojects/gradle-core/src/main/groovy/org/gradle/util/HashUtil.java
index b3feba9..e596238 100644
--- a/subprojects/gradle-core/src/main/groovy/org/gradle/util/HashUtil.java
+++ b/subprojects/gradle-core/src/main/groovy/org/gradle/util/HashUtil.java
@@ -37,7 +37,7 @@ public class HashUtil {
             throw UncheckedException.asUncheckedException(e);
         }
         messageDigest.update(scriptText.getBytes());
-        return new BigInteger(1, messageDigest.digest()).toString(16);
+        return new BigInteger(1, messageDigest.digest()).toString(32);
     }
 
     public static byte[] createHash(File file) {
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandlerTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandlerTest.groovy
index b0a8b0d..74e8b3e 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandlerTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/DefaultRepositoryHandlerTest.groovy
@@ -101,6 +101,17 @@ class DefaultRepositoryHandlerTest extends DefaultResolverContainerTest {
         assertEquals([expectedResolver], repositoryHandler.resolvers)
     }
 
+    @Test
+    public void testMavenLocalWithNoArgs() {
+        context.checking {
+            one(resolverFactoryMock).createMavenLocalResolver(ResolverContainer.DEFAULT_MAVEN_LOCAL_REPO_NAME)
+            will(returnValue(expectedResolver))
+        }
+        prepareResolverFactoryToTakeAndReturnExpectedResolver()
+        assert repositoryHandler.mavenLocal().is(expectedResolver)
+        assertEquals([expectedResolver], repositoryHandler.resolvers)
+    }
+
     @Test(expected = InvalidUserDataException)
     public void testMavenRepoWithMissingUrls() {
         repositoryHandler.mavenRepo([name: 'someName'])
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactoryTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactoryTest.groovy
index af3b866..5891900 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactoryTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/DefaultResolverFactoryTest.groovy
@@ -19,15 +19,19 @@ package org.gradle.api.internal.artifacts.ivyservice
 import org.apache.ivy.core.cache.DefaultRepositoryCacheManager
 import org.gradle.api.InvalidUserDataException
 import org.gradle.api.artifacts.ResolverContainer
-import org.junit.Before
+import org.gradle.util.JUnit4GroovyMockery
+import org.jmock.integration.junit4.JMock
 import org.junit.Test
+import org.junit.runner.RunWith
 import org.apache.ivy.plugins.resolver.*
-import static org.junit.Assert.assertEquals
-import static org.junit.Assert.assertTrue
+import static org.junit.Assert.*
+import static org.hamcrest.Matchers.*
+import org.gradle.api.internal.Factory
 
 /**
  * @author Hans Dockter
  */
+ at RunWith(JMock.class)
 class DefaultResolverFactoryTest {
     static final String RESOLVER_URL = 'http://a.b.c/'
     static final Map RESOLVER_MAP = [name: 'mapresolver', url: 'http://x.y.z/']
@@ -40,13 +44,11 @@ class DefaultResolverFactoryTest {
     static final String TEST_REPO_URL = 'http://www.gradle.org'
     static final File TEST_CACHE_DIR = 'somepath' as File
 
-    DefaultResolverFactory factory
+    final JUnit4GroovyMockery context = new JUnit4GroovyMockery()
+    final LocalMavenCacheLocator localMavenCacheLocator = context.mock(LocalMavenCacheLocator.class)
+    final DefaultResolverFactory factory = new DefaultResolverFactory(context.mock(Factory.class), localMavenCacheLocator)
 
-    @Before public void setUp() {
-        factory = new DefaultResolverFactory()
-    }
-
-    @Test (expected = InvalidUserDataException) public void testCreateResolver() {
+    @Test(expected = InvalidUserDataException) public void testCreateResolver() {
         checkMavenResolver(factory.createResolver(RESOLVER_URL), RESOLVER_URL, RESOLVER_URL)
         checkMavenResolver(factory.createResolver(RESOLVER_MAP), RESOLVER_MAP.name, RESOLVER_MAP.url)
         DependencyResolver resolver = factory.createResolver(TEST_RESOLVER)
@@ -100,6 +102,19 @@ class DefaultResolverFactoryTest {
 
     }
 
+    @Test public void testCreateLocalMavenRepo() {
+        File repoDir = new File(".m2/repository")
+
+        context.checking {
+            one(localMavenCacheLocator).getLocalMavenCache()
+            will(returnValue(repoDir))
+        }
+
+        def repo = factory.createMavenLocalResolver('name')
+        assertThat(repo, instanceOf(GradleIBiblioResolver))
+        assertThat(repo.root, equalTo(repoDir.toURI().toString() + '/'))
+    }
+
     private void checkNoModuleRepository(RepositoryResolver resolver, String expectedName, List expectedArtifactPatterns,
                                          List expectedIvyPatterns) {
         assertEquals(expectedName, resolver.name)
@@ -107,5 +122,4 @@ class DefaultResolverFactoryTest {
         assert expectedArtifactPatterns == resolver.artifactPatterns
         assertTrue(resolver.allownomd)
     }
-
 }
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolverTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolverTest.groovy
index b91c082..3822360 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolverTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/GradleIBiblioResolverTest.groovy
@@ -20,14 +20,30 @@ import spock.lang.Specification
 /**
  * @author Hans Dockter
  */
-class GradleIBiblioResolverTest extends Specification{
+class GradleIBiblioResolverTest extends Specification {
     GradleIBiblioResolver gradleIBiblioResolver = new GradleIBiblioResolver()
 
-    def testInit() {
+    def defaults() {
         expect:
         gradleIBiblioResolver.getSnapshotTimeout().is(GradleIBiblioResolver.DAILY)
     }
-    
+
+    def usesDailyExpiryForRemoteUrls() {
+        when:
+        gradleIBiblioResolver.setRoot("http://server/repo")
+
+        then:
+        gradleIBiblioResolver.getSnapshotTimeout().is(GradleIBiblioResolver.DAILY)
+    }
+
+    def usesAlwaysExpiryForLocalUrls() {
+        when:
+        gradleIBiblioResolver.setRoot(new File(".").toURI().toString())
+
+        then:
+        gradleIBiblioResolver.getSnapshotTimeout().is(GradleIBiblioResolver.ALWAYS)
+    }
+
     def timeoutStrategyNever_shouldReturnAlwaysFalse() {
         expect:
         !GradleIBiblioResolver.NEVER.isCacheTimedOut(0)
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/LocalMavenCacheLocatorTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/LocalMavenCacheLocatorTest.groovy
new file mode 100644
index 0000000..fbc536e
--- /dev/null
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/ivyservice/LocalMavenCacheLocatorTest.groovy
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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.gradle.api.internal.artifacts.ivyservice
+
+import spock.lang.Specification
+import org.junit.Rule
+import org.gradle.util.SetSystemProperties
+import org.gradle.util.TemporaryFolder
+
+class LocalMavenCacheLocatorTest extends Specification {
+    @Rule public final SetSystemProperties systemProperties = new SetSystemProperties()
+    @Rule public final TemporaryFolder tmpDir = new TemporaryFolder()
+    final LocalMavenCacheLocator locator = new LocalMavenCacheLocator()
+
+    def setup() {
+        System.setProperty('user.home', tmpDir.dir.absolutePath)
+    }
+
+    def usesDefaultWhenNoSettingsXmlFile() {
+        expect:
+        locator.localMavenCache == new File(tmpDir.dir, '.m2/repository')
+    }
+
+    def usesValueFromSettingsXmlFile() {
+        tmpDir.file('.m2/settings.xml') << """
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <localRepository>${tmpDir.file('.m2/custom').absolutePath}</localRepository>
+</settings>"""
+
+        expect:
+        locator.localMavenCache == new File(tmpDir.dir, '.m2/custom')
+    }
+
+    def usesValueWithPlaceholderFromSettingsXmlFile() {
+        tmpDir.file('.m2/settings.xml') << '''
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <localRepository>${user.home}/.m2/custom</localRepository>
+</settings>'''
+
+        expect:
+        locator.localMavenCache == new File(tmpDir.dir, '.m2/custom')
+    }
+}
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/publish/maven/DefaultMavenPomFactoryTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/publish/maven/DefaultMavenPomFactoryTest.groovy
index d0188b5..d8a4b0a 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/publish/maven/DefaultMavenPomFactoryTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/publish/maven/DefaultMavenPomFactoryTest.groovy
@@ -41,6 +41,6 @@ public class DefaultMavenPomFactoryTest extends Specification {
         mavenPom.mavenProject != null
         mavenPom.pomDependenciesConverter.is(pomDependenciesConverter)
         mavenPom.configurations.is(configurationContainer)
-        mavenPom.fileResolver = fileResolver
+        mavenPom.fileResolver == fileResolver
     }
 }
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepositoryTest.java b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepositoryTest.java
index 9ccb703..e195ef2 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepositoryTest.java
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/changedetection/DefaultTaskArtifactStateRepositoryTest.java
@@ -20,10 +20,7 @@ import org.gradle.api.DefaultTask;
 import org.gradle.api.internal.TaskInternal;
 import org.gradle.api.internal.project.ProjectInternal;
 import org.gradle.api.invocation.Gradle;
-import org.gradle.cache.CacheBuilder;
-import org.gradle.cache.CacheRepository;
-import org.gradle.cache.PersistentCache;
-import org.gradle.cache.PersistentIndexedCache;
+import org.gradle.cache.*;
 import org.gradle.util.*;
 import org.hamcrest.Matcher;
 import org.jmock.Expectations;
@@ -581,7 +578,7 @@ public class DefaultTaskArtifactStateRepositoryTest {
             one(builder).open();
             will(returnValue(persistentCache));
             
-            one(persistentCache).openIndexedCache();
+            one(persistentCache).openIndexedCache(with(notNullValue(Serializer.class)));
             will(returnValue(new TestIndexedCache()));
         }});
     }
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/file/AbstractFileTreeElementTest.java b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/file/AbstractFileTreeElementTest.java
index dc788fc..e0fc255 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/file/AbstractFileTreeElementTest.java
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/file/AbstractFileTreeElementTest.java
@@ -16,41 +16,46 @@
 package org.gradle.api.internal.file;
 
 import org.gradle.api.file.RelativePath;
-import org.gradle.util.TestFile;
-import org.gradle.util.TemporaryFolder;
 import org.gradle.util.GFileUtils;
-
-import static org.junit.Assert.*;
-
+import org.gradle.util.TemporaryFolder;
+import org.gradle.util.TestFile;
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 
+import static org.hamcrest.Matchers.*;
+import static org.junit.Assert.*;
+
 public class AbstractFileTreeElementTest {
     @Rule
     public final TemporaryFolder tmpDir = new TemporaryFolder();
 
     @Test
-    public void testNeedsCopy() throws IOException {
-        TestFile source = tmpDir.createFile("src");
-        TestFile dest = tmpDir.getDir().file("dest");
-        dest.assertDoesNotExist();
+    public void canCopyToOutputStream() {
+        TestFile src = tmpDir.file("src");
+        src.write("content");
 
-        TestFileTreeElement element = new TestFileTreeElement(source);
+        ByteArrayOutputStream outstr = new ByteArrayOutputStream();
+        new TestFileTreeElement(src).copyTo(outstr);
 
-        assertTrue(element.needsCopy(dest));
+        assertThat(new String(outstr.toByteArray()), equalTo("content"));
+    }
 
-        element.copyTo(dest);
+    @Test
+    public void canCopyToFile() {
+        TestFile src = tmpDir.file("src");
+        src.write("content");
+        TestFile dest = tmpDir.file("dir/dest");
 
-        assertFalse(element.needsCopy(dest));
+        new TestFileTreeElement(src).copyTo(dest);
 
-        dest.setLastModified(source.lastModified() - 1000);
-        assertTrue(element.needsCopy(dest));
+        dest.assertIsFile();
+        assertThat(dest.getText(), equalTo("content"));
     }
-
+    
     private class TestFileTreeElement extends AbstractFileTreeElement {
         private final TestFile file;
 
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/internal/SingleProjectTaskReportModelTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/internal/SingleProjectTaskReportModelTest.groovy
index ef8ad90..024b9cb 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/internal/SingleProjectTaskReportModelTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/tasks/diagnostics/internal/SingleProjectTaskReportModelTest.groovy
@@ -69,12 +69,13 @@ class SingleProjectTaskReportModelTest extends TaskModelSpecification {
         model.build([task1, task2, task3, task4, task5])
 
         then:
-        TaskDetails t = (model.getTasksForGroup('group1') as List).first()
-        t.task == task3
-        t.children*.task == [task1, task2]
-        t = (model.getTasksForGroup('group2') as List).first()
-        t.task == task5
-        t.children*.task == [task4]
+        TaskDetails task3Details = (model.getTasksForGroup('group1') as List).first()
+        task3Details.task == task3
+        task3Details.children*.task == [task1, task2]
+
+        TaskDetails task5Details = (model.getTasksForGroup('group2') as List).first()
+        task5Details.task == task5
+        task5Details.children*.task == [task4]
     }
 
     def theDependenciesOfATopLevelTaskAreTheUnionOfTheDependenciesOfItsChildren() {
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/cache/DefaultSerializerTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/cache/DefaultSerializerTest.groovy
new file mode 100644
index 0000000..70f30ca
--- /dev/null
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/cache/DefaultSerializerTest.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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.gradle.cache
+
+import spock.lang.Specification
+
+class DefaultSerializerTest extends Specification {
+    def canSerializeAndDeserializeObject() {
+        GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader)
+        DefaultSerializer serializer = new DefaultSerializer(classLoader)
+
+        Class cl = classLoader.parseClass('package org.gradle.cache; class TestObj implements Serializable { }')
+        Object o = cl.newInstance()
+
+        when:
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
+        serializer.write(outputStream, o)
+        Object r = serializer.read(new ByteArrayInputStream(outputStream.toByteArray()))
+
+        then:
+        cl.isInstance(r)
+    }
+}
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/groovy/scripts/UriScriptSourceTest.java b/subprojects/gradle-core/src/test/groovy/org/gradle/groovy/scripts/UriScriptSourceTest.java
index 29b200e..634b5cd 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/groovy/scripts/UriScriptSourceTest.java
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/groovy/scripts/UriScriptSourceTest.java
@@ -112,18 +112,30 @@ public class UriScriptSourceTest {
     }
     
     @Test
-    public void encodesScriptFileBaseNameToClassName() {
+    public void generatesClassNameFromFileNameByRemovingExtensionAndAddingHashOfURL() {
         UriScriptSource source = new UriScriptSource("<file-type>", scriptFile);
-        assertThat(source.getClassName(), matchesRegexp("build_script_[0-9a-z]+"));
+        assertThat(source.getClassName(), matchesRegexp("build_[0-9a-z]{25,26}"));
+    }
 
-        source = new UriScriptSource("<file-type>", new File(testDir, "name with-some + invalid.chars"));
-        assertThat(source.getClassName(), matchesRegexp("name_with_some___invalid_chars_[0-9a-z]+"));
+    @Test
+    public void truncatesClassNameAt30Characters() {
+        UriScriptSource source = new UriScriptSource("<file-type>", new File(testDir, "a-long-file-name-12345678901234567890.gradle"));
+        assertThat(source.getClassName(), matchesRegexp("a_long_file_name_1234567890123_[0-9a-z]{25,26}"));
+    }
 
-        source = new UriScriptSource("<file-type>", new File(testDir, "123"));
-        assertThat(source.getClassName(), matchesRegexp("_123_[0-9a-z]+"));
+    @Test
+    public void encodesReservedCharactersInClassName() {
+        UriScriptSource source = new UriScriptSource("<file-type>", new File(testDir, "name-+.chars.gradle"));
+        assertThat(source.getClassName(), matchesRegexp("name___chars_[0-9a-z]{25,26}"));
+    }
+
+    @Test
+    public void prefixesClassNameWhenFirstCharacterIsNotValidIdentifierStartChar() {
+        UriScriptSource source = new UriScriptSource("<file-type>", new File(testDir, "123"));
+        assertThat(source.getClassName(), matchesRegexp("_123_[0-9a-z]{25,26}"));
 
         source = new UriScriptSource("<file-type>", new File(testDir, "-"));
-        assertThat(source.getClassName(), matchesRegexp("__[0-9a-z]+"));
+        assertThat(source.getClassName(), matchesRegexp("__[0-9a-z]{25,26}"));
     }
 
     @Test
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/CommandLineParserTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/CommandLineParserTest.groovy
index de4b733..dc0666b 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/CommandLineParserTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/CommandLineParserTest.groovy
@@ -178,17 +178,17 @@ class CommandLineParserTest extends Specification {
         parser.option('a', 'b', 'long-option-a')
 
         expect:
-        def result = parser.parse(['--long-option-a'])
-        result.hasOption('a')
-        result.hasOption('b')
-        result.hasOption('long-option-a')
-        result.option('a') == result.option('long-option-a')
-        result.option('a') == result.option('b')
+        def longOptionResult = parser.parse(['--long-option-a'])
+        longOptionResult.hasOption('a')
+        longOptionResult.hasOption('b')
+        longOptionResult.hasOption('long-option-a')
+        longOptionResult.option('a') == longOptionResult.option('long-option-a')
+        longOptionResult.option('a') == longOptionResult.option('b')
 
-        result = parser.parse(['-a'])
-        result.hasOption('a')
-        result.hasOption('b')
-        result.hasOption('long-option-a')
+        def shortOptionResult = parser.parse(['-a'])
+        shortOptionResult.hasOption('a')
+        shortOptionResult.hasOption('b')
+        shortOptionResult.hasOption('long-option-a')
     }
 
     def parsesCommandLineWhenOptionAppearsMultipleTimes() {
@@ -215,26 +215,26 @@ class CommandLineParserTest extends Specification {
         parser.option('a')
 
         expect:
-        def result = parser.parse(['a'])
-        result.extraArguments == ['a']
-        !result.hasOption('a')
+        def singleArgResult = parser.parse(['a'])
+        singleArgResult.extraArguments == ['a']
+        !singleArgResult.hasOption('a')
 
-        result = parser.parse(['a', 'b'])
-        result.extraArguments == ['a', 'b']
-        !result.hasOption('a')
+        def multipleArgsResult = parser.parse(['a', 'b'])
+        multipleArgsResult.extraArguments == ['a', 'b']
+        !multipleArgsResult.hasOption('a')
     }
 
     def parsesCommandLineWithOptionsAndSubcommand() {
         parser.option('a')
 
         expect:
-        def result = parser.parse(['-a', 'a'])
-        result.extraArguments == ['a']
-        result.hasOption('a')
+        def optionBeforeSubcommandResult = parser.parse(['-a', 'a'])
+        optionBeforeSubcommandResult.extraArguments == ['a']
+        optionBeforeSubcommandResult.hasOption('a')
 
-        result = parser.parse(['a', '-a'])
-        result.extraArguments == ['a', '-a']
-        !result.hasOption('a')
+        def optionAfterSubcommandResult = parser.parse(['a', '-a'])
+        optionAfterSubcommandResult.extraArguments == ['a', '-a']
+        !optionAfterSubcommandResult.hasOption('a')
     }
 
     def parsesCommandLineWithOptionsAndSubcommandWhenMixedOptionsAllowed() {
@@ -242,23 +242,27 @@ class CommandLineParserTest extends Specification {
         parser.allowMixedSubcommandsAndOptions()
 
         expect:
-        def result = parser.parse(['-a', 'a'])
-        result.extraArguments == ['a']
-        result.hasOption('a')
+        def optionBeforeSubcommandResult = parser.parse(['-a', 'a'])
+        optionBeforeSubcommandResult.extraArguments == ['a']
+        optionBeforeSubcommandResult.hasOption('a')
 
-        result = parser.parse(['a', '-a'])
-        result.extraArguments == ['a']
-        result.hasOption('a')
+        def optionAfterSubcommandResult = parser.parse(['a', '-a'])
+        optionAfterSubcommandResult.extraArguments == ['a']
+        optionAfterSubcommandResult.hasOption('a')
     }
 
     def parsesCommandLineWithSubcommandThatHasOptions() {
-        expect:
+        when:
         def result = parser.parse(['a', '--option', 'b'])
+
+        then:
         result.extraArguments == ['a', '--option', 'b']
 
+        when:
         parser.allowMixedSubcommandsAndOptions()
-
         result = parser.parse(['a', '--option', 'b'])
+
+        then:
         result.extraArguments == ['a', '--option', 'b']
     }
 
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/util/GradleVersionTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/util/GradleVersionTest.groovy
index 0d691c7..5bc9e1a 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/util/GradleVersionTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/util/GradleVersionTest.groovy
@@ -13,27 +13,113 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
- 
+
 package org.gradle.util
 
 import org.codehaus.groovy.runtime.InvokerHelper
 import static org.junit.Assert.*
-import org.junit.Test
+
 import org.apache.tools.ant.Main
-import org.apache.ivy.Ivy;
+import org.apache.ivy.Ivy
+import spock.lang.Specification;
 
 /**
  * @author Hans Dockter
  */
-class GradleVersionTest {
-    @Test public void testGradleVersion() {
-        GradleVersion gradleVersion = new GradleVersion()
-        assertNotNull(gradleVersion.version)
-        assertNotNull(gradleVersion.buildTime)
+class GradleVersionTest extends Specification {
+    final GradleVersion version = new GradleVersion()
+
+    def equalsAndHashCode() {
+        expect:
+        Matchers.strictlyEquals(new GradleVersion('0.9'), new GradleVersion('0.9'))
+        new GradleVersion('0.9') != new GradleVersion('1.0')
+    }
+
+    def canConstructSnapshotVersion() {
+        expect:
+        new GradleVersion('0.9-20101220110000+1100').snapshot
+        !new GradleVersion('0.9-rc-1').snapshot
+    }
+
+    def canCompareMajorVersions() {
+        expect:
+        new GradleVersion(a) > new GradleVersion(b)
+        new GradleVersion(b) < new GradleVersion(a)
+        new GradleVersion(a) == new GradleVersion(a)
+        new GradleVersion(b) == new GradleVersion(b)
+
+        where:
+        a | b
+        '0.9' | '0.8'
+        '1.0' | '0.10'
+        '10.0' | '2.1'
+        '2.5' | '2.4'
+    }
+
+    def canComparePointVersions() {
+        expect:
+        new GradleVersion(a) > new GradleVersion(b)
+        new GradleVersion(b) < new GradleVersion(a)
+        new GradleVersion(a) == new GradleVersion(a)
+        new GradleVersion(b) == new GradleVersion(b)
+
+        where:
+        a | b
+        '0.9.2' | '0.9.1'
+        '0.10.1' | '0.9.2'
+    }
+
+    def canComparePointVersionAndMajorVersions() {
+        expect:
+        new GradleVersion(a) > new GradleVersion(b)
+        new GradleVersion(b) < new GradleVersion(a)
+        new GradleVersion(a) == new GradleVersion(a)
+        new GradleVersion(b) == new GradleVersion(b)
+
+        where:
+        a | b
+        '0.9.1' | '0.9'
+        '0.10' | '0.9.1'
+    }
+
+    def canComparePreviewsMilestonesAndRCVersions() {
+        expect:
+        new GradleVersion(a) > new GradleVersion(b)
+        new GradleVersion(b) < new GradleVersion(a)
+        new GradleVersion(a) == new GradleVersion(a)
+        new GradleVersion(b) == new GradleVersion(b)
+
+        where:
+        a | b
+        '1.0-milestone-2' | '1.0-milestone-1'
+        '1.0-preview-2' | '1.0-preview-1'
+        '1.0-rc-2' | '1.0-rc-1'
+        '1.0-preview-1' | '1.0-milestone-7'
+        '1.0-rc-7' | '1.0-rc-1'
+        '1.0' | '1.0-rc-7'
+    }
+
+    def canCompareSnapshotVersions() {
+        expect:
+        new GradleVersion(a) > new GradleVersion(b)
+        new GradleVersion(b) < new GradleVersion(a)
+        new GradleVersion(a) == new GradleVersion(a)
+        new GradleVersion(b) == new GradleVersion(b)
+
+        where:
+        a | b
+        '0.9-20101220110000+1100' | '0.9-20101220100000+1100'
+        '0.9-20101220110000+1000' | '0.9-20101220100000+1100'
+        '0.9' | '0.9-20101220100000+1000'
+    }
+
+    def defaultValuesForGradleVersion() {
+        expect:
+        version.version != null
+        version.buildTime != null
     }
 
-    @Test public void testPrettyPrint() {
-        GradleVersion version = new GradleVersion()
+    def prettyPrint() {
         String expectedText = """
 ------------------------------------------------------------
 Gradle $version.version
@@ -46,6 +132,7 @@ Ivy: ${Ivy.ivyVersion}
 JVM: ${Jvm.current()}
 OS: ${OperatingSystem.current()}
 """
-        assertEquals(expectedText, version.prettyPrint())
+        expect:
+        version.prettyPrint() == expectedText
     }
 }
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/util/JvmTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/util/JvmTest.groovy
index 597f2e2..589c78c 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/util/JvmTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/util/JvmTest.groovy
@@ -24,20 +24,18 @@ class JvmTest extends Specification {
     @Rule public final SetSystemProperties sysProp = new SetSystemProperties()
 
     def usesSystemPropertyToDetermineIfCompatibleWithJava5() {
-        println System.properties['java.version']
+        System.properties['java.version'] = '1.5'
 
         expect:
-        System.properties['java.version'] = '1.5'
         def jvm = new Jvm()
         jvm.java5Compatible
         !jvm.java6Compatible
     }
 
     def usesSystemPropertyToDetermineIfCompatibleWithJava6() {
-        println System.properties['java.version']
+        System.properties['java.version'] = '1.6'
 
         expect:
-        System.properties['java.version'] = '1.6'
         def jvm = new Jvm()
         jvm.java5Compatible
         jvm.java6Compatible
diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/util/PathTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/util/PathTest.groovy
index 14f71e3..23c5052 100644
--- a/subprojects/gradle-core/src/test/groovy/org/gradle/util/PathTest.groovy
+++ b/subprojects/gradle-core/src/test/groovy/org/gradle/util/PathTest.groovy
@@ -59,12 +59,17 @@ class PathTest extends Specification {
     }
 
     def convertsRelativePathToAbsolutePath() {
-        expect:
+        when:
         def Path path = Path.path(':')
+
+        then:
         path.absolutePath('path') == ':path'
         path.resolve('path') == Path.path(':path')
 
+        when:
         path = Path.path(':sub')
+
+        then:
         path.absolutePath('path') == ':sub:path'
         path.resolve('path') == Path.path(':sub:path')
     }
@@ -80,12 +85,17 @@ class PathTest extends Specification {
     }
 
     def convertsAbsolutePathToRelativePath() {
-        expect:
+        when:
         def path = Path.path(':')
+
+        then:
         path.relativePath(':') == ':'
         path.relativePath(':path') == 'path'
 
+        when:
         path = Path.path(':sub')
+
+        then:
         path.relativePath(':') == ':'
         path.relativePath(':sub') == ':sub'
         path.relativePath(':sub:path') == 'path'
diff --git a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml
index 4071dc2..7e6a24b 100644
--- a/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml
+++ b/subprojects/gradle-docs/src/docs/dsl/org.gradle.api.tasks.wrapper.Wrapper.xml
@@ -37,16 +37,12 @@
                 <td><literal>PathBase.GRADLE_USER_HOME</literal></td>
             </tr>
             <tr>
-                <td>archiveName</td>
-                <td><literal>'gradle'</literal></td>
-            </tr>
-            <tr>
-                <td>archiveClassifier</td>
-                <td><literal>'bin'</literal></td>
-            </tr>
-            <tr>
-                <td>urlRoot</td>
-                <td><literal>'http://dist.codehaus.org/gradle'</literal></td>
+                <td>distributionUrl</td>
+                <td><literal>'http://gradle.artifactoryonline.com/gradle/distributions/gradle-${gradleVersion}-bin.zip'</literal>
+                    (or
+                    <literal>'http://gradle.artifactoryonline.com/gradle/distributions/gradle-snapshots/gradle-${gradleVersion}-bin.zip'</literal>
+                    for snapshot versions).
+                </td>
             </tr>
             <tr>
                 <td>gradleVersion</td>
diff --git a/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml b/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml
index d5b37c7..1153b3c 100644
--- a/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml
@@ -410,13 +410,10 @@
     </section>
     <section id='sec:repositories'>
         <title>Repositories</title>
-        <section id='sub:introduction'>
-            <title>Introduction</title>
-            <para>The Gradle repository management, based on Apache Ivy, gives you have a lot of freedom
-                regarding the repository layout and the retrieval policies. Additionally Gradle provides a couple of convenience
-                method to add preconfigured repositories.
-            </para>
-        </section>
+        <para>Gradle repository management, based on Apache Ivy, gives you a lot of freedom
+            regarding repository layout and retrieval policies. Additionally Gradle provides various convenience
+            method to add preconfigured repositories.
+        </para>
         <section id='sub:maven_repo'>
             <title>Maven repositories</title>
             <para>To add the central Maven2 repository (<ulink url='http://repo1.maven.org/maven2'/>) simply
@@ -425,16 +422,16 @@
             <sample id="mavenCentral" dir="userguide/artifacts/defineRepository" title="Adding central Maven repository">
                 <sourcefile file="build.gradle" snippet="maven-central"/>
             </sample>
-            <para>Now Gradle looks for your dependencies in this repository.
+            <para>Now Gradle will look for your dependencies in this repository.
             </para>
             <para>Quite often certain jars are not in the official Maven repository for licensing reasons (e.g. JTA),
                 but its POMs are.
             </para>
-            <sample id="mavenCentralJarRepo" dir="userguide/artifacts/defineRepository" title="Adding many Maven repositories">
+            <sample id="mavenCentralJarRepo" dir="userguide/artifacts/defineRepository" title="Adding several Maven repositories">
                 <sourcefile file="build.gradle" snippet="maven-central-jar-repo"/>
             </sample>
-            <para>Gradle looks first in the central Maven repository for the POM and the JAR. If the JAR can't be
-                found there, its looks for it in the other repositories.
+            <para>Gradle will look first in the central Maven repository for the POM and the JAR. If the JAR can't be
+                found there, it will look for it in the other repositories.
             </para>
             <para>For adding a custom Maven repository you can say:
             </para>
@@ -449,6 +446,10 @@
             </sample>
             <para>The first URL is used to look for POMs and JARs. The subsequent URLs are used to look for JARs.
             </para>
+            <para>To use the local Maven cache as a repository you can say:</para>
+            <sample id="mavenLocalRepo" dir="userguide/artifacts/defineRepository" title="Adding the local Maven cache as a repository">
+                <sourcefile file="build.gradle" snippet="maven-local"/>
+            </sample>
             <section>
             	<title>Accessing password protected Maven repositories</title>
             	<para>To access a password protected Maven repository (basic authentication) you need to use one of Ivy features:</para>
diff --git a/subprojects/gradle-docs/src/docs/userguide/gradleWrapper.xml b/subprojects/gradle-docs/src/docs/userguide/gradleWrapper.xml
index debcc8f..4212665 100644
--- a/subprojects/gradle-docs/src/docs/userguide/gradleWrapper.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/gradleWrapper.xml
@@ -13,42 +13,37 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<chapter id='gradle_wrapper' xmlns:xi="http://www.w3.org/2001/XInclude">
+<chapter id='gradle_wrapper'>
     <title>The Gradle Wrapper</title>
     <para>Gradle is a new tool. You can't expect it to be installed on machines beyond your sphere of influence. An
         example are continuous integration server where Gradle is not installed and where you have no admin rights for
         the machine. Or what if you provide an open source project and you want to make it as easy as possible for your
         users to build it?
     </para>
-    <para>There is a simple and good news. Gradle provides a solution for this. It ships with a
-        <emphasis>Wrapper</emphasis>
-        task.
+    <para>There is a simple and good <apilink class="org.gradle.api.tasks.wrapper.Wrapper"/> task.
         <footnote>
             <para>If you download the Gradle source distribution or check out Gradle from SVN, you can build Gradle via
-                the Gradle wrapper.
-            </para>
-        </footnote>
-        <footnote>
-            <para>Gradle itself is continuously built by Bamboo and Teamcity via this wrapper. See
+                the Gradle wrapper. Gradle itself is continuously built by Bamboo and Teamcity via this wrapper. See
                 <ulink url='website:ci-server.html'/>
             </para>
         </footnote>
         You can create such a task in your build script.
     </para>
-    <sample id="wrapperSimple" dir="userguide/wrapper" title="Wrapper task">
-        <sourcefile file="build.gradle" snippet="wrapper-simple"/>
+    <sample id="wrapperSimple" dir="userguide/wrapper/simple" title="Wrapper task">
+        <sourcefile file="build.gradle"/>
     </sample>
     <para>The build master usually explicitly executes this task. After such
         an execution you find the following new or updated files in your project directory (in case the default configuration of the wrapper task is
         used).
     </para>
-    <screen><![CDATA[
-project-root/
-  gradlew
-  gradlew.bat
-  gradle-wrapper.jar
-  gradle-wrapper.properties
-]]></screen>
+    <sample id="wrapperSimple" dir="userguide/wrapper/simple" title="Wrapper generated files">
+        <layout after="wrapper">
+            gradlew
+            gradlew.bat
+            gradle/wrapper/gradle-wrapper.jar
+            gradle/wrapper/gradle-wrapper.properties
+        </layout>
+    </sample>
     <para>All these files must be submitted to your version control system. The <command>gradlew</command> command
         can be used <emphasis>exactly</emphasis> the same way as the <command>gradle</command> command.
     </para>
@@ -64,17 +59,15 @@ project-root/
             command.
         </para>
         <para>You can specify where the wrapper files should be stored (within your project directory):</para>
-        <sample id="wrapperCustomized" dir="userguide/wrapper" title="Configuration of wrapper task">
+        <sample id="wrapperCustomized" dir="userguide/wrapper/customized" title="Configuration of wrapper task">
             <sourcefile file="build.gradle"/>
+            <layout after="wrapper">
+                gradlew
+                gradlew.bat
+                wrapper/wrapper.jar
+                wrapper/wrapper.properties
+            </layout>
         </sample>
-        <screen><![CDATA[
-project-root/
-  gradlew
-  gradlew.bat
-  wrapper/
-    gradle-wrapper.jar
-    gradle-wrapper.properties
-]]></screen>
         <para>
             You can specify the download URL of the wrapper distribution. You can also specify where the wrapper distribution
             should be stored and unpacked (either within the project or within the gradle user home dir). If the wrapper
diff --git a/subprojects/gradle-docs/src/docs/userguide/installation.xml b/subprojects/gradle-docs/src/docs/userguide/installation.xml
index ffe8bea..1fe93f5 100644
--- a/subprojects/gradle-docs/src/docs/userguide/installation.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/installation.xml
@@ -84,10 +84,10 @@ some zip front ends for Mac OS X don't restore the file permissions properly.
 
 <screen>
 ------------------------------------------------------------
-Gradle 0.9
+Gradle 0.9.1
 ------------------------------------------------------------
 
-Gradle build time: Sunday, 19 December 2010 12:50:06 PM EST
+Gradle build time: Sunday, 2 January 2011 09:52:16 AM EST
 Groovy: 1.7.6
 Ant: Apache Ant version 1.8.1 compiled on April 30 2010
 Ivy: 2.2.0
diff --git a/subprojects/gradle-docs/src/docs/userguide/javaTutorial.xml b/subprojects/gradle-docs/src/docs/userguide/javaTutorial.xml
index 9527983..8c6d383 100644
--- a/subprojects/gradle-docs/src/docs/userguide/javaTutorial.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/javaTutorial.xml
@@ -193,10 +193,9 @@
         </para>
         <sample id="javaMultiProject" dir="java/multiproject" includeLocation="true" title="Multi-project build - hierarchical layout">
             <layout>
-                api
-                services
-                services/webservice
-                shared
+                api/
+                services/webservice/
+                shared/
             </layout>
         </sample>
         <para>Here we have three projects. Project <literal>api</literal> produces a JAR file which is shipped to the
diff --git a/subprojects/gradle-docs/src/docs/userguide/multiproject.xml b/subprojects/gradle-docs/src/docs/userguide/multiproject.xml
index bf7e2ff..4661460 100644
--- a/subprojects/gradle-docs/src/docs/userguide/multiproject.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/multiproject.xml
@@ -32,7 +32,7 @@
                 <layout>
                     build.gradle
                     settings.gradle
-                    bluewhale
+                    bluewhale/
                 </layout>
                 <sourcefile file="settings.gradle"/>
             </sample>
@@ -59,8 +59,8 @@
                 <layout>
                     build.gradle
                     settings.gradle
-                    bluewhale
-                    krill
+                    bluewhale/
+                    krill/
                 </layout>
                 <sourcefile file="settings.gradle"/>
             </sample>
@@ -114,9 +114,7 @@
                 <layout>
                     build.gradle
                     settings.gradle
-                    bluewhale
                     bluewhale/build.gradle
-                    krill
                     krill/build.gradle
                 </layout>
                 <sourcefile file="settings.gradle"/>
@@ -138,11 +136,9 @@
                     <layout>
                         build.gradle
                         settings.gradle
-                        bluewhale
                         bluewhale/build.gradle
-                        krill
                         krill/build.gradle
-                        tropicalFish
+                        tropicalFish/
                     </layout>
                     <sourcefile file="settings.gradle"/>
                     <sourcefile file="build.gradle"/>
@@ -160,11 +156,8 @@
                     <layout>
                         build.gradle
                         settings.gradle
-                        bluewhale
                         bluewhale/build.gradle
-                        krill
                         krill/build.gradle
-                        tropicalFish
                         tropicalFish/build.gradle
                     </layout>
                     <sourcefile file="settings.gradle"/>
@@ -241,7 +234,7 @@
             The root project is the only project in a path that is not specified by its name. The path
             <literal>:bluewhale</literal>
             corresponds to the file system path
-            <literal>water/project</literal>
+            <literal>water/bluewhale</literal>
             in the case of the example above.
         </para>
         <para>The path of a task is simply its project path plus the task name. For example <literal>
@@ -270,9 +263,7 @@
                 <sample id="multiprojectFirstMessages" dir="userguide/multiproject/dependencies/firstMessages/messages" includeLocation="true" title="Dependencies and execution order">
                     <layout>
                         settings.gradle
-                        consumer
                         consumer/build.gradle
-                        producer
                         producer/build.gradle
                     </layout>
                     <sourcefile file="settings.gradle"/>
@@ -289,9 +280,7 @@
                 <sample id="multiprojectMessagesHack" dir="userguide/multiproject/dependencies/messagesHack/messages" title="Dependencies and execution order">
                     <layout>
                         settings.gradle
-                        aProducer
                         aProducer/build.gradle
-                        consumer
                         consumer/build.gradle
                     </layout>
                     <sourcefile file="settings.gradle"/>
@@ -321,9 +310,7 @@
                 <sample id="multiprojectMessagesDependencies" dir="userguide/multiproject/dependencies/messagesWithDependencies/messages" includeLocation="true" title="Declaring dependencies">
                     <layout>
                         settings.gradle
-                        consumer
                         consumer/build.gradle
-                        producer
                         producer/build.gradle
                     </layout>
                     <sourcefile file="settings.gradle"/>
@@ -456,9 +443,11 @@
                 <layout>
                     settings.gradle
                     build.gradle
-                    date
+                    date/
+                    date/src/main/java/
                     date/src/main/java/org/gradle/sample/DateServlet.java
-                    hello
+                    hello/
+                    hello/src/main/java/
                     hello/src/main/java/org/gradle/sample/HelloServlet.java
                 </layout>
                 <sourcefile file="settings.gradle"/>
@@ -468,7 +457,7 @@
                 <literal>date</literal>
                 and
                 <literal>hello</literal>
-                task have a
+                projects have a
                 <emphasis>configuration</emphasis>
                 dependency on <literal>webDist</literal>, as all the build logic for the webapp projects is injected by
                 <literal>webDist</literal>. The
@@ -525,23 +514,22 @@
             <layout>
                 settings.gradle
                 build.gradle
-                api
+                api/
+                api/src/main/java/
                 api/src/main/java/org/gradle/sample/api/Person.java
                 api/src/main/java/org/gradle/sample/apiImpl/PersonImpl.java
-                services
-                services/personService
+                services/personService/
+                services/personService/src/main/java/
                 services/personService/src/main/java/org/gradle/sample/services/PersonService.java
+                services/personService/src/test/java/
                 services/personService/src/test/java/org/gradle/sample/services/PersonServiceTest.java
-                shared
+                shared/
+                shared/src/main/java/
                 shared/src/main/java/org/gradle/sample/shared/Helper.java
             </layout>
         </sample>
-        <para>We have the projects <literal>shared</literal>,
-            <literal>api</literal>
-            and <literal>personService</literal>.
-            <literal>personService</literal>
-            has a lib dependency on the other two projects.
-            <literal>api</literal>
+        <para>We have the projects <literal>shared</literal>, <literal>api</literal> and<literal>personService</literal>.
+            <literal>personService</literal> has a lib dependency on the other two projects. <literal>api</literal>
             has a lib dependency on <literal>shared</literal>.
             <footnote>
                 <para>
@@ -559,12 +547,12 @@
             <literal>build.gradle</literal> of the root project.
             <footnote>
                 <para>We do this here, as it makes the layout a bit easier. We usually put the project specific stuff
-                    into the buildscript of the respective projects.
+                    into the build script of the respective projects.
                 </para>
             </footnote>
             A <emphasis>lib</emphasis>
-            dependency is a special form of an execution dependency. It causes the other project to be build first and
-            adds the jar with the classes of the other project to the classpath. It also add the dependencies of the
+            dependency is a special form of an execution dependency. It causes the other project to be built first and
+            adds the jar with the classes of the other project to the classpath. It also adds the dependencies of the
             other project to the classpath. So you can enter the
             <literal>api</literal>
             directory and trigger a <userinput>gradle compile</userinput>. First
@@ -590,7 +578,7 @@
             interfaces but tested with all classes from <literal>api</literal>.
         </para>
         <section id="disable_dependency_projects">
-            <title>Disable the build of dependency projects.</title>
+            <title>Disabling the build of dependency projects</title>
             <para>Sometimes you don't want depended on projects to be built when doing a partial build.
                 To disable the build of the depended on projects you can run gradle with the <code>-a</code> option.
             </para>
@@ -616,7 +604,7 @@
             <output args=":api:build"/>
         </sample>
 
-        <para>While you are working in a typical development cycle repeatedly building and testing changes to a
+        <para>While you are working in a typical development cycle repeatedly building and testing changes to
             the :api project (knowing that you are only changing files in this one project), you may not want to
             even suffer the expense of :shared:compile checking to see what has changed in the :shared project.
             Adding the <literal>-a</literal> option will cause gradle to use cached jars to resolve any project lib
@@ -637,7 +625,7 @@
         </sample>
 
         <para>You also might want to refactor some part of the :api project that is used in other projects.
-            If you make these types of changes, it is not sufficient to test just the :api,
+            If you make these types of changes, it is not sufficient to test just the :api
             project, you also need to test all projects that depend on the :api project.
             The <literal>buildDependents</literal> task also tests all the projects that have a project lib dependency
             (in the testRuntime configuration) on the specified project.
@@ -659,7 +647,7 @@
         </para>
         <para>Method inheritance might be interesting to use as Gradle's
             <emphasis>Configuration Injection</emphasis>
-            does not support methods yet (but will in a future release.).
+            does not support methods yet (but will in a future release).
         </para>
         <para>You might be wondering why we have implemented a feature we obviously don't like that much. One reason is
             that it is offered by other tools and we want to have the check mark in a feature comparison :). And we like
@@ -671,7 +659,7 @@
         <para>Writing this chapter was pretty exhausting and reading it might have a similar effect. Our final message
             for this chapter is that multi-project builds with Gradle are usually
             <emphasis>not</emphasis>
-            difficult. There are six elements you need to remember: <literal>allproject</literal>, <literal>
+            difficult. There are six elements you need to remember: <literal>allprojects</literal>, <literal>
             subprojects</literal>, <literal>dependsOn</literal>, <literal>childrenDependOnMe</literal>,
             <literal>dependsOnChildren</literal>
             and project lib dependencies.
diff --git a/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml b/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml
index fbb45e4..f968633 100644
--- a/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml
+++ b/subprojects/gradle-docs/src/docs/userguide/writingBuildScripts.xml
@@ -1,5 +1,5 @@
 <!--
-  ~ Copyright 2009 the original author or authors.
+  ~ Copyright 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.
@@ -13,12 +13,18 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<chapter id='writing_build_scripts' xmlns:xi="http://www.w3.org/2001/XInclude">
+<chapter id='writing_build_scripts'>
     <title>Writing Build Scripts</title>
     <para>This chapter looks at some of the details of writing a build script.</para>
 
+    <section>
+        <title>The Gradle build language</title>
+        <para>Gradle provides a <firstterm>domain specific language</firstterm>, or DSL, for describing builds.
+            This build language is based on Groovy, with some additions to make it easier to describe a build.
+        </para>
+    </section>
     <section id='sec:project_api'>
-        <title>Project API</title>
+        <title>The Project API</title>
         <para>In the tutorial in <xref linkend='tutorial_java_projects'/> we used, for example, the
             <literal>apply()</literal> method. Where does this method come from? We said earlier that the build script
             defines a project in Gradle. For each project in the build creates an instance of type
@@ -49,7 +55,7 @@
             <classname>Project</classname> object.
         </para>
         <sample id="projectApi" dir="userguide/tutorial/projectApi" title="Accessing property of the Project object">
-            <sourcefile file="build.gradle"/>
+            <sourcefile file="build.gradle" snippet="project-name"/>
             <output args="-q check"/>
         </sample>
         <para>Both <literal>println</literal> statements print out the same property. The first uses auto-delegation to
@@ -81,7 +87,7 @@
                 <tr>
                     <td><literal>name</literal></td>
                     <td><classname>String</classname></td>
-                    <td>The name of the directory containing the build script.</td>
+                    <td>The name of the project directory.</td>
                 </tr>
                 <tr>
                     <td><literal>path</literal></td>
@@ -94,21 +100,11 @@
                     <td>A description for the project.</td>
                 </tr>
                 <tr>
-                    <td><literal>buildFile</literal></td>
-                    <td><classname>File</classname></td>
-                    <td>The build script.</td>
-                </tr>
-                <tr>
                     <td><literal>projectDir</literal></td>
                     <td><classname>File</classname></td>
                     <td>The directory containing the build script.</td>
                 </tr>
                 <tr>
-                    <td><literal>buildDirName</literal></td>
-                    <td><classname>String</classname></td>
-                    <td><filename>build</filename></td>
-                </tr>
-                <tr>
                     <td><literal>buildDir</literal></td>
                     <td><classname>File</classname></td>
                     <td><filename><replaceable>projectDir</replaceable>/build</filename></td>
@@ -129,22 +125,80 @@
                     <td>An <classname>AntBuilder</classname> instance</td>
                 </tr>
             </table>
-
-            <para>Below is a sample build which demonstrates some of these properties.</para>
-            <sample id="projectCoreProperties" dir="userguide/tutorial/projectCoreProperties" title="Project properties">
-                <layout>
-                    build.gradle
-                    subProject
-                    subProject/build.gradle
-                </layout>
-                <sourcefile file="build.gradle"/>
-                <output args="-q check"/>
-            </sample>
         </section>
     </section>
     <section>
-        <title>Script API</title>
-        <para>When Gradle executes a script, it compiles the script into a class which implements <apilink class="org.gradle.api.Script"/>.</para>
+        <title>The Script API</title>
+        <para>When Gradle executes a script, it compiles the script into a class which implements <apilink class="org.gradle.api.Script"/>.
+            This means that all of the properties and methods declared by the <classname>Script</classname> interface
+            are available in your script.
+        </para>
+    </section>
+    <section>
+        <title>Some Groovy basics</title>
+        <para>Groovy provides plenty of features for creating DSLs, and the Gradle build language takes advantage of these.
+            Understanding how the build language works will help you when you write your build script, and in particular,
+            when you start to write customs plugins and tasks.
+        </para>
+        <section>
+            <title>Groovy JDK</title>
+            <para>
+                Groovy adds lots of useful methods to JVM classes. For example, <classname>Iterable</classname> gets
+                an <literal>each</literal> method, which iterates over the elements of the <classname>Iterable</classname>:
+            </para>
+            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Groovy JDK methods">
+                <sourcefile file="build.gradle" snippet="groovyJdk"/>
+            </sample>
+            <para>Have a look at <ulink url="http://groovy.codehaus.org/groovy-jdk/"/> for more details.</para>
+        </section>
+        <section>
+            <title>Property accessors</title>
+            <para>
+               Groovy automatically converts a property reference into a call to the appropriate getter or setter method.
+            </para>
+            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Property accessors">
+                <sourcefile file="build.gradle" snippet="propertyAccessors"/>
+            </sample>
+        </section>
+        <section>
+            <title>Optional parentheses on method calls</title>
+            <para>
+                Parentheses are optional for method calls.
+            </para>
+            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Method call without parentheses">
+                <sourcefile file="build.gradle" snippet="methodCallWithoutParentheses"/>
+            </sample>
+        </section>
+        <section>
+            <title>List and map literals</title>
+            <para>
+                Groovy provides some shortcuts for defining <classname>List</classname> and <classname>Map</classname>
+                instances.
+            </para>
+            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="List and map literals">
+                <sourcefile file="build.gradle" snippet="listAndMapLiterals"/>
+            </sample>
+        </section>
+        <section>
+            <title>Closures as the last parameter in a method</title>
+            <para>The Gradle DSL uses closures in many places. You can find out more about closures <ulink url="http://groovy.codehaus.org/Closures">here</ulink>.
+                When the last parameter of a method is a closure, you can place the closure after the method call:
+            </para>
+            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Closure as method parameter">
+                <sourcefile file="build.gradle" snippet="closureAsLastParam"/>
+            </sample>
+        </section>
+        <section>
+            <title>Closure delegate</title>
+            <para>
+                Each closure has a <literal>delegate</literal> object, which Groovy uses to look up variable and method
+                references which are not local variables or parameters of the closure. Gradle uses this for
+                <firstterm>configuration closures</firstterm>, where the <literal>delegate</literal> object is set to
+                the object to be configured.
+            </para>
+            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Closure delegates">
+                <sourcefile file="build.gradle" snippet="closureDelegates"/>
+            </sample>
+        </section>
     </section>
-
 </chapter>
diff --git a/subprojects/gradle-docs/src/samples/scala/customizedLayout/build.gradle b/subprojects/gradle-docs/src/samples/scala/customizedLayout/build.gradle
index f644cfa..1126ddd 100644
--- a/subprojects/gradle-docs/src/samples/scala/customizedLayout/build.gradle
+++ b/subprojects/gradle-docs/src/samples/scala/customizedLayout/build.gradle
@@ -5,10 +5,10 @@ repositories {
 }
 
 dependencies {
-    scalaTools 'org.scala-lang:scala-compiler:2.7.7'
-    scalaTools 'org.scala-lang:scala-library:2.7.7'
+    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
+    scalaTools 'org.scala-lang:scala-library:2.8.1'
 
-    compile 'org.scala-lang:scala-library:2.7.7'
+    compile 'org.scala-lang:scala-library:2.8.1'
     testCompile group: 'junit', name: 'junit', version: '4.7'
 }
 
diff --git a/subprojects/gradle-docs/src/samples/scala/mixedJavaAndScala/build.gradle b/subprojects/gradle-docs/src/samples/scala/mixedJavaAndScala/build.gradle
index e6afb98..7de1015 100644
--- a/subprojects/gradle-docs/src/samples/scala/mixedJavaAndScala/build.gradle
+++ b/subprojects/gradle-docs/src/samples/scala/mixedJavaAndScala/build.gradle
@@ -7,9 +7,9 @@ repositories {
 }
 
 dependencies {
-    scalaTools 'org.scala-lang:scala-compiler:2.7.7'
-    scalaTools 'org.scala-lang:scala-library:2.7.7'
+    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
+    scalaTools 'org.scala-lang:scala-library:2.8.1'
 
-    compile 'org.scala-lang:scala-library:2.7.7'
+    compile 'org.scala-lang:scala-library:2.8.1'
     testCompile group: 'junit', name: 'junit', version: '4.7'
 }
diff --git a/subprojects/gradle-docs/src/samples/scala/quickstart/build.gradle b/subprojects/gradle-docs/src/samples/scala/quickstart/build.gradle
index a18fb25..4822853 100644
--- a/subprojects/gradle-docs/src/samples/scala/quickstart/build.gradle
+++ b/subprojects/gradle-docs/src/samples/scala/quickstart/build.gradle
@@ -10,11 +10,11 @@ repositories {
 
 dependencies {
     // Libraries needed to run the scala tools
-    scalaTools 'org.scala-lang:scala-compiler:2.7.7'
-    scalaTools 'org.scala-lang:scala-library:2.7.7'
+    scalaTools 'org.scala-lang:scala-compiler:2.8.1'
+    scalaTools 'org.scala-lang:scala-library:2.8.1'
 
     // Libraries needed for scala api
-    compile 'org.scala-lang:scala-library:2.7.7'
+    compile 'org.scala-lang:scala-library:2.8.1'
 }
 // END SNIPPET declare-scala-version
 
diff --git a/subprojects/gradle-docs/src/samples/userguide/artifacts/defineRepository/build.gradle b/subprojects/gradle-docs/src/samples/userguide/artifacts/defineRepository/build.gradle
index 8c3666d..9fc01af 100644
--- a/subprojects/gradle-docs/src/samples/userguide/artifacts/defineRepository/build.gradle
+++ b/subprojects/gradle-docs/src/samples/userguide/artifacts/defineRepository/build.gradle
@@ -15,6 +15,12 @@ repositories {
 }
 //END SNIPPET maven-central-jar-repo
 
+//START SNIPPET maven-local
+repositories {
+    mavenLocal()
+}
+//END SNIPPET maven-local
+
 //START SNIPPET maven-like-repo
 repositories {
     mavenRepo urls: "http://repo.mycompany.com/maven2"
diff --git a/subprojects/gradle-docs/src/samples/userguide/tutorial/groovy/build.gradle b/subprojects/gradle-docs/src/samples/userguide/tutorial/groovy/build.gradle
new file mode 100644
index 0000000..257ede7
--- /dev/null
+++ b/subprojects/gradle-docs/src/samples/userguide/tutorial/groovy/build.gradle
@@ -0,0 +1,54 @@
+apply plugin: 'java'
+
+// START SNIPPET groovyJdk
+// Iterable gets an each() method
+configurations.runtime.each { File f -> println f }
+// END SNIPPET groovyJdk
+
+// START SNIPPET propertyAccessors
+// Using a getter method
+println project.buildDir
+println getProject().getBuildDir()
+
+// Using a setter method
+project.buildDir = 'target'
+getProject().setBuildDir('target')
+// END SNIPPET propertyAccessors
+
+// START SNIPPET methodCallWithoutParentheses
+test.systemProperty 'some.prop', 'value'
+test.systemProperty('some.prop', 'value')
+// END SNIPPET methodCallWithoutParentheses
+
+// START SNIPPET listAndMapLiterals
+// List literal
+test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']
+
+List<String> list = new ArrayList<String>()
+list.add('org/gradle/api/**')
+list.add('org/gradle/internal/**')
+test.includes = list
+
+// Map literal
+apply plugin: 'java'
+
+Map<String, String> map = new HashMap<String, String>()
+map.put('plugin', 'java')
+apply(map)
+// END SNIPPET listAndMapLiterals
+
+// START SNIPPET closureAsLastParam
+repositories {
+    println "in a closure"
+}
+repositories() { println "in a closure" }
+repositories({ println "in a closure" })
+// END SNIPPET closureAsLastParam
+
+// START SNIPPET closureDelegates
+dependencies {
+    assert delegate == project.dependencies
+    compile('junit:junit:4.8.1')
+    delegate.compile('junit:junit:4.8.1')
+}
+// END SNIPPET closureDelegates
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectApi/build.gradle b/subprojects/gradle-docs/src/samples/userguide/tutorial/projectApi/build.gradle
index d598d2f..ba0dcb8 100644
--- a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectApi/build.gradle
+++ b/subprojects/gradle-docs/src/samples/userguide/tutorial/projectApi/build.gradle
@@ -1,5 +1,7 @@
+// START SNIPPET project-name
 println name
 println project.name
+// END SNIPPET project-name
 
 task check << {
 }
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectCoreProperties/build.gradle b/subprojects/gradle-docs/src/samples/userguide/tutorial/projectCoreProperties/build.gradle
deleted file mode 100644
index de24787..0000000
--- a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectCoreProperties/build.gradle
+++ /dev/null
@@ -1,9 +0,0 @@
-task check << {
-    allprojects {
-        println "project path $path"
-        println "  project name = $name"
-        println "  project dir = '${rootProject.relativePath(projectDir)}'"
-        println "  build file = '${rootProject.relativePath(buildFile)}'"
-        println "  build dir = '${rootProject.relativePath(buildDir)}'"
-    }
-}
diff --git a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectCoreProperties/settings.gradle b/subprojects/gradle-docs/src/samples/userguide/tutorial/projectCoreProperties/settings.gradle
deleted file mode 100644
index 79dcf99..0000000
--- a/subprojects/gradle-docs/src/samples/userguide/tutorial/projectCoreProperties/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include 'subProject'
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/userguide/wrapper/build.gradle b/subprojects/gradle-docs/src/samples/userguide/wrapper/build.gradle
deleted file mode 100644
index 517f82e..0000000
--- a/subprojects/gradle-docs/src/samples/userguide/wrapper/build.gradle
+++ /dev/null
@@ -1,8 +0,0 @@
-//START SNIPPET wrapper-simple
-task wrapper(type: Wrapper) {
-    gradleVersion = '0.8'
-//END SNIPPET wrapper-simple
-    jarPath = 'wrapper'
-//START SNIPPET wrapper-simple
-}
-//END SNIPPET wrapper-simple
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/userguide/wrapper/customized/build.gradle b/subprojects/gradle-docs/src/samples/userguide/wrapper/customized/build.gradle
new file mode 100644
index 0000000..eed403b
--- /dev/null
+++ b/subprojects/gradle-docs/src/samples/userguide/wrapper/customized/build.gradle
@@ -0,0 +1,4 @@
+task wrapper(type: Wrapper) {
+    gradleVersion = '0.9'
+    jarFile = 'wrapper/wrapper.jar'
+}
diff --git a/subprojects/gradle-docs/src/samples/userguide/wrapper/simple/build.gradle b/subprojects/gradle-docs/src/samples/userguide/wrapper/simple/build.gradle
new file mode 100644
index 0000000..ad082e6
--- /dev/null
+++ b/subprojects/gradle-docs/src/samples/userguide/wrapper/simple/build.gradle
@@ -0,0 +1,3 @@
+task wrapper(type: Wrapper) {
+    gradleVersion = '0.9'
+}
\ No newline at end of file
diff --git a/subprojects/gradle-docs/src/samples/userguideOutput/projectCoreProperties.out b/subprojects/gradle-docs/src/samples/userguideOutput/projectCoreProperties.out
deleted file mode 100644
index aee5606..0000000
--- a/subprojects/gradle-docs/src/samples/userguideOutput/projectCoreProperties.out
+++ /dev/null
@@ -1,10 +0,0 @@
-project path :
-  project name = projectCoreProperties
-  project dir = '.'
-  build file = 'build.gradle'
-  build dir = 'build'
-project path :subProject
-  project name = subProject
-  project dir = 'subProject'
-  build file = 'subProject/build.gradle'
-  build dir = 'subProject/build'
diff --git a/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy b/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy
index 794b0a8..cc31bfe 100644
--- a/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy
+++ b/subprojects/gradle-open-api/src/integTest/groovy/org/gradle/integtests/openapi/CrossVersionCompatibilityIntegrationTest.groovy
@@ -37,17 +37,18 @@ class CrossVersionCompatibilityIntegrationTest {
     private final BasicGradleDistribution gradle09rc1 = dist.previousVersion('0.9-rc-1')
     private final BasicGradleDistribution gradle09rc2 = dist.previousVersion('0.9-rc-2')
     private final BasicGradleDistribution gradle09rc3 = dist.previousVersion('0.9-rc-3')
+    private final BasicGradleDistribution gradle09 = dist.previousVersion('0.9')
 
     @Test
     public void canUseOpenApiFromCurrentVersionToBuildUsingAnOlderVersion() {
-        [gradle09rc1, gradle09rc2, gradle09rc3].each {
+        [gradle09rc1, gradle09rc2, gradle09rc3, gradle09].each {
             checkCanBuildUsing(dist, it)
         }
     }
 
     @Test
     public void canUseOpenApiFromOlderVersionToBuildUsingCurrentVersion() {
-        [gradle09rc1, gradle09rc2, gradle09rc3].each {
+        [gradle09rc1, gradle09rc2, gradle09rc3, gradle09].each {
             checkCanBuildUsing(it, dist)
         }
     }
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassDetecter.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassDetecter.java
index 9aabfc5..b1e9625 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassDetecter.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/internal/tasks/testing/junit/JUnitTestClassDetecter.java
@@ -58,6 +58,13 @@ class JUnitTestClassDetecter extends TestClassVisitor {
         this.superClassName = superName;
     }
 
+    @Override
+    public void visitInnerClass(String name, String outerName, String innerName, int access) {
+        if (name.equals(className) && (access & Opcodes.ACC_STATIC) == 0) {
+            isAbstract = true;
+        }
+    }
+
     /**
      * Visits an annotation of the class.
      *
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java
index e67dbdd..d1c5847 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AbstractCompile.java
@@ -83,7 +83,7 @@ public abstract class AbstractCompile extends SourceTask {
     /**
      * Sets the Java language level to use to compile the source files.
      *
-     * @return The source language level. Must not be null.
+     * @param sourceCompatibility The source language level. Must not be null.
      */
     public void setSourceCompatibility(String sourceCompatibility) {
         this.sourceCompatibility = sourceCompatibility;
diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
index 3425643..ec8f934 100644
--- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
+++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/Test.java
@@ -91,6 +91,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public File getWorkingDir() {
         return options.getWorkingDir();
     }
@@ -113,6 +114,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public String getExecutable() {
         return options.getExecutable();
     }
@@ -135,6 +137,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public Map<String, Object> getSystemProperties() {
         return options.getSystemProperties();
     }
@@ -165,6 +168,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public FileCollection getBootstrapClasspath() {
         return options.getBootstrapClasspath();
     }
@@ -201,6 +205,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public List<String> getJvmArgs() {
         return options.getJvmArgs();
     }
@@ -231,6 +236,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public boolean getEnableAssertions() {
         return options.getEnableAssertions();
     }
@@ -273,6 +279,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public Map<String, Object> getEnvironment() {
         return options.getEnvironment();
     }
@@ -567,6 +574,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * {@inheritDoc}
      */
+    @Input
     public boolean isIgnoreFailures() {
         return ignoreFailures;
     }
@@ -676,6 +684,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
     /**
      * Specifies whether the test report should be generated.
      */
+    @Input
     public boolean isTestReport() {
         return testReport;
     }
@@ -709,6 +718,7 @@ public class Test extends ConventionTask implements JavaForkOptions, PatternFilt
      * exclude patterns are scanned for test classes, and any found are executed. When {@code false} the classes which
      * match the include and exclude patterns are executed.
      */
+    @Input
     public boolean isScanForTestClasses() {
         return scanForTestClasses;
     }
diff --git a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/internal/tasks/scala/AntScalaCompiler.groovy b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/internal/tasks/scala/AntScalaCompiler.groovy
index 50e3045..623f3dd 100644
--- a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/internal/tasks/scala/AntScalaCompiler.groovy
+++ b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/internal/tasks/scala/AntScalaCompiler.groovy
@@ -61,6 +61,7 @@ class AntScalaCompiler implements ScalaCompiler {
                 extensionDirs.each {dir ->
                     extdirs(location: dir)
                 }
+                classpath(location: destinationDir)
                 classpath.each {file ->
                     classpath(location: file)
                 }
diff --git a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java
index 7008439..8538684 100644
--- a/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java
+++ b/subprojects/gradle-scala/src/main/groovy/org/gradle/api/tasks/scala/ScalaDoc.java
@@ -111,9 +111,6 @@ public class ScalaDoc extends SourceTask {
         if (!GUtil.isTrue(options.getDocTitle())) {
             options.setDocTitle(getTitle());
         }
-        if (!GUtil.isTrue(options.getWindowTitle())) {
-            options.setWindowTitle(getTitle());
-        }
         getAntScalaDoc().execute(getSource(), getDestinationDir(), getClasspath(), getScalaClasspath(), options);
     }
 
diff --git a/subprojects/gradle-scala/src/test/groovy/org/gradle/api/tasks/scala/ScalaDocTest.java b/subprojects/gradle-scala/src/test/groovy/org/gradle/api/tasks/scala/ScalaDocTest.java
index 386204a..1d63e79 100644
--- a/subprojects/gradle-scala/src/test/groovy/org/gradle/api/tasks/scala/ScalaDocTest.java
+++ b/subprojects/gradle-scala/src/test/groovy/org/gradle/api/tasks/scala/ScalaDocTest.java
@@ -85,14 +85,13 @@ public class ScalaDocTest extends AbstractTaskTest {
     }
 
     @Test
-    public void testSetsDocTitleAndWindowTitleIfNotSet() {
+    public void testSetsDocTitleIfNotSet() {
         setUpMocksAndAttributes(scalaDoc);
         scalaDoc.setTitle("title");
 
         scalaDoc.generate();
 
         assertThat(scalaDoc.getScalaDocOptions().getDocTitle(), equalTo("title"));
-        assertThat(scalaDoc.getScalaDocOptions().getWindowTitle(), equalTo("title"));
     }
 
     private void setUpMocksAndAttributes(final ScalaDoc docTask) {
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java
index 0de9662..8bb1e63 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java
@@ -22,6 +22,7 @@ import org.gradle.api.internal.file.FileResolver;
 import org.gradle.api.tasks.Input;
 import org.gradle.api.tasks.OutputFile;
 import org.gradle.api.tasks.TaskAction;
+import org.gradle.api.tasks.wrapper.internal.DistributionLocator;
 import org.gradle.api.tasks.wrapper.internal.WrapperScriptGenerator;
 import org.gradle.util.DeprecationLogger;
 import org.gradle.util.GFileUtils;
@@ -48,24 +49,18 @@ import java.util.Properties;
  */
 public class Wrapper extends DefaultTask {
     // Properties used by the gradle-wrapper
-    static final String URL_ROOT_PROPERTY = "urlRoot";
+    static final String DISTRIBUTION_URL_PROPERTY = "distributionUrl";
     static final String DISTRIBUTION_BASE_PROPERTY = "distributionBase";
     static final String ZIP_STORE_BASE_PROPERTY = "zipStoreBase";
     static final String DISTRIBUTION_PATH_PROPERTY = "distributionPath";
-    static final String DISTRIBUTION_VERSION_PROPERTY = "distributionVersion";
     static final String ZIP_STORE_PATH_PROPERTY = "zipStorePath";
-    static final String DISTRIBUTION_NAME_PROPERTY = "distributionName";
-    static final String DISTRIBUTION_CLASSIFIER_PROPERTY = "distributionClassifier";
-    static final String WRAPPER_DIR = "gradle-wrapper";
-    static final String WRAPPER_JAR = WRAPPER_DIR + ".jar";
-    static final String WRAPPER_PROPERTIES = WRAPPER_DIR + ".properties";
-
-    public static final String DEFAULT_URL_ROOT = "http://dist.codehaus.org/gradle";
-    public static final String WRAPPER_JAR_BASE_NAME = "gradle-wrapper";
+
     public static final String DEFAULT_DISTRIBUTION_PARENT_NAME = "wrapper/dists";
     public static final String DEFAULT_ARCHIVE_NAME = "gradle";
     public static final String DEFAULT_ARCHIVE_CLASSIFIER = "bin";
 
+    private String distributionUrl;
+
     /**
      * Specifies how the wrapper path should be interpreted.
      */
@@ -80,27 +75,24 @@ public class Wrapper extends DefaultTask {
     private String distributionPath;
 
     @Input
+    private PathBase distributionBase = PathBase.GRADLE_USER_HOME;
+
     private String archiveName;
 
-    @Input
     private String archiveClassifier;
 
-    //    @Input
-    private PathBase distributionBase = PathBase.GRADLE_USER_HOME;
-
-    @Input
-    private String gradleVersion;
+    private GradleVersion gradleVersion;
 
-    @Input
     private String urlRoot;
 
     @Input
     private String archivePath;
 
-    //    @Input
+    @Input
     private PathBase archiveBase = PathBase.GRADLE_USER_HOME;
 
     private WrapperScriptGenerator wrapperScriptGenerator = new WrapperScriptGenerator();
+    private final DistributionLocator locator = new DistributionLocator();
 
     public Wrapper() {
         scriptFile = "gradlew";
@@ -109,8 +101,7 @@ public class Wrapper extends DefaultTask {
         archiveName = DEFAULT_ARCHIVE_NAME;
         archiveClassifier = DEFAULT_ARCHIVE_CLASSIFIER;
         archivePath = DEFAULT_DISTRIBUTION_PARENT_NAME;
-        urlRoot = DEFAULT_URL_ROOT;
-        gradleVersion = new GradleVersion().getVersion();
+        gradleVersion = new GradleVersion();
     }
 
     @TaskAction
@@ -129,7 +120,7 @@ public class Wrapper extends DefaultTask {
 
         writeProperties(propertiesFileDestination);
 
-        URL jarFileSource = getClass().getResource("/" + WRAPPER_JAR_BASE_NAME + ".jar");
+        URL jarFileSource = getClass().getResource("/gradle-wrapper.jar");
         if (jarFileSource == null) {
             throw new GradleException("Cannot locate wrapper JAR resource.");
         }
@@ -140,12 +131,9 @@ public class Wrapper extends DefaultTask {
 
     private void writeProperties(File propertiesFileDestination) {
         Properties wrapperProperties = new Properties();
-        wrapperProperties.put(URL_ROOT_PROPERTY, urlRoot);
+        wrapperProperties.put(DISTRIBUTION_URL_PROPERTY, getDistributionUrl());
         wrapperProperties.put(DISTRIBUTION_BASE_PROPERTY, distributionBase.toString());
         wrapperProperties.put(DISTRIBUTION_PATH_PROPERTY, distributionPath);
-        wrapperProperties.put(DISTRIBUTION_NAME_PROPERTY, archiveName);
-        wrapperProperties.put(DISTRIBUTION_CLASSIFIER_PROPERTY, archiveClassifier);
-        wrapperProperties.put(DISTRIBUTION_VERSION_PROPERTY, gradleVersion);
         wrapperProperties.put(ZIP_STORE_BASE_PROPERTY, archiveBase.toString());
         wrapperProperties.put(ZIP_STORE_PATH_PROPERTY, archivePath);
         GUtil.saveProperties(wrapperProperties, propertiesFileDestination);
@@ -170,7 +158,7 @@ public class Wrapper extends DefaultTask {
      */
     @Deprecated
     public String getScriptDestinationPath() {
-        DeprecationLogger.nagUser("getScriptDestinationPath()", "getScriptFile()");
+        DeprecationLogger.nagUser("Wrapper.getScriptDestinationPath()", "getScriptFile()");
         return getProject().relativePath(getScriptFile().getParentFile());
     }
 
@@ -184,7 +172,7 @@ public class Wrapper extends DefaultTask {
      */
     @Deprecated
     public void setScriptDestinationPath(String scriptDestinationPath) {
-        DeprecationLogger.nagUser("setScriptDestinationPath()", "setScriptFile()");
+        DeprecationLogger.nagUser("Wrapper.setScriptDestinationPath()", "setScriptFile()");
         setScriptFile(scriptDestinationPath + "/gradlew");
     }
 
@@ -217,7 +205,7 @@ public class Wrapper extends DefaultTask {
      */
     @Deprecated
     public String getJarPath() {
-        DeprecationLogger.nagUser("getJarPath()", "getJarFile()");
+        DeprecationLogger.nagUser("Wrapper.getJarPath()", "getJarFile()");
         return getProject().relativePath(getJarFile().getParentFile());
     }
 
@@ -228,7 +216,7 @@ public class Wrapper extends DefaultTask {
      */
     @Deprecated
     public void setJarPath(String jarPath) {
-        DeprecationLogger.nagUser("setJarPath()", "setJarFile()");
+        DeprecationLogger.nagUser("Wrapper.setJarPath()", "setJarFile()");
         setJarFile(jarPath + "/gradle-wrapper.jar");
     }
 
@@ -258,7 +246,7 @@ public class Wrapper extends DefaultTask {
      * @see #setGradleVersion(String)
      */
     public String getGradleVersion() {
-        return gradleVersion;
+        return gradleVersion.getVersion();
     }
 
     /**
@@ -266,27 +254,50 @@ public class Wrapper extends DefaultTask {
      * use for building your project.
      */
     public void setGradleVersion(String gradleVersion) {
-        this.gradleVersion = gradleVersion;
+        this.gradleVersion = new GradleVersion(gradleVersion);
     }
 
     /**
-     * The base URL to download the gradle distribution from.
+     * The URL to download the gradle distribution from.
      *
-     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[archiveClassifier]-[gradleVersion].zip</code>
+     * <p>If not set, the download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[gradleVersion]-[archiveClassifier].zip</code>
      *
      * <p>The wrapper downloads a certain distribution only once and caches it. If your distribution base is the
      * project, you might submit the distribution to your version control system. That way no download is necessary at
      * all. This might be in particular interesting, if you provide a custom gradle snapshot to the wrapper, because you
      * don't need to provide a download server then.
      */
+    @Input
+    public String getDistributionUrl() {
+        if (distributionUrl != null) {
+            return distributionUrl;
+        }
+        return locator.getDistribution(getUrlRoot(), gradleVersion, archiveName, archiveClassifier);
+    }
+
+    public void setDistributionUrl(String url) {
+        this.distributionUrl = url;
+    }
+
+    /**
+     * The base URL to download the gradle distribution from.
+     *
+     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[gradleVersion]-[archiveClassifier].zip</code>
+     */
+    @Deprecated
     public String getUrlRoot() {
-        return urlRoot;
+        if (urlRoot != null) {
+            return urlRoot;
+        }
+        return locator.getDistributionRepository(gradleVersion);
     }
 
     /**
      * Sets the base URL to download the gradle distribution from.
      */
+    @Deprecated
     public void setUrlRoot(String urlRoot) {
+        DeprecationLogger.nagUser("Wrapper.setUrlRoot()", "setDistributionUrl()");
         this.urlRoot = urlRoot;
     }
 
@@ -341,30 +352,36 @@ public class Wrapper extends DefaultTask {
     /**
      * The name of the archive as part of the download URL.
      *
-     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[archiveClassifier]-[gradleVersion].zip</code>
+     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[gradleVersion]-[archiveClassifier].zip</code>
      *
      * <p>The default for the archive name is {@value #DEFAULT_ARCHIVE_NAME}.
      */
+    @Deprecated
     public String getArchiveName() {
         return archiveName;
     }
 
+    @Deprecated
     public void setArchiveName(String archiveName) {
+        DeprecationLogger.nagUser("Wrapper.setArchiveName()", "setDistributionUrl()");
         this.archiveName = archiveName;
     }
 
     /**
      * The classifier of the archive as part of the download URL.
      *
-     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[archiveClassifier]-[gradleVersion].zip</code>
+     * <p>The download URL is assembled by the pattern: <code>[urlRoot]/[archiveName]-[gradleVersion]-[archiveClassifier].zip</code>
      *
      * <p>The default for the archive classifier is {@value #DEFAULT_ARCHIVE_CLASSIFIER}.
      */
+    @Deprecated
     public String getArchiveClassifier() {
         return archiveClassifier;
     }
 
+    @Deprecated
     public void setArchiveClassifier(String archiveClassifier) {
+        DeprecationLogger.nagUser("Wrapper.setArchiveClassifier()", "setDistributionUrl()");
         this.archiveClassifier = archiveClassifier;
     }
 
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/DistributionLocator.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/DistributionLocator.java
new file mode 100644
index 0000000..75fb740
--- /dev/null
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/internal/DistributionLocator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 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.gradle.api.tasks.wrapper.internal;
+
+import org.gradle.util.GradleVersion;
+
+public class DistributionLocator {
+    private static final String ARTIFACTORY_RELEASE_REPOSITORY = "http://gradle.artifactoryonline.com/gradle/distributions";
+    private static final String ARTIFACTORY_SNAPSHOT_REPOSITORY = "http://gradle.artifactoryonline.com/gradle/distributions/gradle-snapshots";
+    private static final String CODEHAUS_RELEASE_REPOSITORY = "http://dist.codehaus.org/gradle";
+    private static final String CODEHAUS_SNAPSHOT_REPOSITORY = "http://snapshots.dist.codehaus.org/gradle";
+
+    public String getDistributionFor(GradleVersion version) {
+        return getDistribution(getDistributionRepository(version), version, "gradle", "bin");
+    }
+
+    public String getDistributionRepository(GradleVersion version) {
+        if (version.compareTo(new GradleVersion("0.9")) >= 0) {
+            if (version.isSnapshot()) {
+                return ARTIFACTORY_SNAPSHOT_REPOSITORY;
+            }
+            return ARTIFACTORY_RELEASE_REPOSITORY;
+        } else {
+            if (version.isSnapshot()) {
+                return CODEHAUS_SNAPSHOT_REPOSITORY;
+            }
+            return CODEHAUS_RELEASE_REPOSITORY;
+        }
+    }
+
+    public String getDistribution(String repositoryUrl, GradleVersion version, String archiveName,
+                                  String archiveClassifier) {
+        return String.format("%s/%s-%s-%s.zip", repositoryUrl, archiveName, version.getVersion(), archiveClassifier);
+    }
+}
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/BootstrapMainStarter.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/BootstrapMainStarter.java
index 6d4a68c..0026397 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/BootstrapMainStarter.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/BootstrapMainStarter.java
@@ -24,9 +24,9 @@ import java.net.URLClassLoader;
  * @author Hans Dockter
  */
 public class BootstrapMainStarter {
-    public void start(String[] args, String gradleHome, String version) throws Exception {
+    public void start(String[] args, File gradleHome) throws Exception {
         boolean debug = GradleWrapperMain.isDebug();
-        File gradleJar = new File(gradleHome, "lib/gradle-launcher-" + version + ".jar");
+        File gradleJar = findLauncherJar(gradleHome);
         if (debug) {
             System.out.println("gradleJar = " + gradleJar.getAbsolutePath());
         }
@@ -36,4 +36,13 @@ public class BootstrapMainStarter {
         Method mainMethod = mainClass.getMethod("main", String[].class);
         mainMethod.invoke(null, new Object[] {args});
     }
+
+    private File findLauncherJar(File gradleHome) {
+        for (File file : new File(gradleHome, "lib").listFiles()) {
+            if (file.getName().matches("gradle-launcher-.*\\.jar")) {
+                return file;
+            }
+        }
+        throw new RuntimeException(String.format("Could not locate the Gradle launcher JAR in Gradle distribution '%s'.", gradleHome));
+    }
 }
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Download.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Download.java
index 00125af..831e850 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Download.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Download.java
@@ -17,6 +17,7 @@
 package org.gradle.wrapper;
 
 import java.io.*;
+import java.net.URI;
 import java.net.URL;
 import java.net.URLConnection;
 
@@ -27,7 +28,7 @@ class Download implements IDownload {
     private static final int PROGRESS_CHUNK = 20000;
     private static final int BUFFER_SIZE = 10000;
 
-    public void download(String address, File destination) throws Exception {
+    public void download(URI address, File destination) throws Exception {
         if (destination.exists()) {
             return;
         }
@@ -36,12 +37,12 @@ class Download implements IDownload {
         downloadInternal(address, destination);
     }
 
-    private void downloadInternal(String address, File destination) throws Exception {
+    private void downloadInternal(URI address, File destination) throws Exception {
         OutputStream out = null;
         URLConnection conn;
         InputStream in = null;
         try {
-            URL url = new URL(address);
+            URL url = address.toURL();
             out = new BufferedOutputStream(
                     new FileOutputStream(destination));
             conn = url.openConnection();
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/IDownload.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/IDownload.java
index 1280079..fbab4df 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/IDownload.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/IDownload.java
@@ -16,10 +16,11 @@
 package org.gradle.wrapper;
 
 import java.io.File;
+import java.net.URI;
 
 /**
  * @author Hans Dockter
  */
 public interface IDownload {
-    void download(String address, File destination) throws Exception;
+    void download(URI address, File destination) throws Exception;
 }
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Install.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Install.java
index 9caae3d..900dd7d 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Install.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Install.java
@@ -17,6 +17,7 @@
 package org.gradle.wrapper;
 
 import java.io.*;
+import java.net.URI;
 import java.util.Enumeration;
 import java.util.Locale;
 import java.util.zip.ZipEntry;
@@ -39,34 +40,36 @@ public class Install {
         this.pathAssembler = pathAssembler;
     }
 
-    public String createDist(String urlRoot, String distBase, String distPath, String distName, String distVersion,
-                             String distClassifier, String zipBase, String zipPath) throws Exception {
-        String gradleHome = pathAssembler.gradleHome(distBase, distPath, distName, distVersion);
-        File gradleHomeFile = new File(gradleHome);
-        if (!alwaysDownload && !alwaysUnpack && gradleHomeFile.isDirectory()) {
+    public File createDist(URI distributionUrl, String distBase, String distPath, String zipBase, String zipPath) throws Exception {
+        File gradleHome = pathAssembler.gradleHome(distBase, distPath, distributionUrl);
+        if (!alwaysDownload && !alwaysUnpack && gradleHome.isDirectory()) {
             return gradleHome;
         }
-        File localZipFile = new File(pathAssembler.distZip(zipBase, zipPath, distName, distVersion, distClassifier));
+        File localZipFile = pathAssembler.distZip(zipBase, zipPath, distributionUrl);
         if (alwaysDownload || !localZipFile.exists()) {
             File tmpZipFile = new File(localZipFile.getParentFile(), localZipFile.getName() + ".part");
             tmpZipFile.delete();
-            String downloadUrl = urlRoot + "/" + distName + "-" + distVersion + "-" + distClassifier + ".zip";
-            System.out.println("Downloading " + downloadUrl);
-            download.download(downloadUrl, tmpZipFile);
+            System.out.println("Downloading " + distributionUrl);
+            download.download(distributionUrl, tmpZipFile);
             tmpZipFile.renameTo(localZipFile);
         }
-        if (gradleHomeFile.isDirectory()) {
-            System.out.println("Deleting directory " + gradleHomeFile.getAbsolutePath());
-            deleteDir(gradleHomeFile);
+        if (gradleHome.isDirectory()) {
+            System.out.println("Deleting directory " + gradleHome.getAbsolutePath());
+            deleteDir(gradleHome);
         }
-        File distDest = gradleHomeFile.getParentFile();
+        File distDest = gradleHome.getParentFile();
         System.out.println("Unzipping " + localZipFile.getAbsolutePath() + " to " + distDest.getAbsolutePath());
         unzip(localZipFile, distDest);
+        if (!gradleHome.isDirectory()) {
+            throw new RuntimeException(String.format(
+                    "Gradle distribution '%s' does not contain expected directory '%s'.", distributionUrl,
+                    gradleHome.getName()));
+        }
         setExecutablePermissions(gradleHome);
         return gradleHome;
     }
 
-    private void setExecutablePermissions(String gradleHome) {
+    private void setExecutablePermissions(File gradleHome) {
         if (isWindows()) {
             return;
         }
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/PathAssembler.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/PathAssembler.java
index 2d082f8..f3b4bec 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/PathAssembler.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/PathAssembler.java
@@ -15,6 +15,11 @@
  */
 package org.gradle.wrapper;
 
+import java.io.File;
+import java.net.URI;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * @author Hans Dockter
  */
@@ -31,12 +36,31 @@ public class PathAssembler {
         this.gradleUserHome = gradleUserHome;
     }
 
-    public String gradleHome(String distBase, String distPath, String distName, String distVersion) {
-        return getBaseDir(distBase) + "/" + distPath + "/" + distName + "-" + distVersion ;
+    public File gradleHome(String distBase, String distPath, URI distUrl) {
+        return new File(getBaseDir(distBase), distPath + "/" + getDistHome(distUrl));
+    }
+
+    public File distZip(String zipBase, String zipPath, URI distUrl) {
+        return new File(getBaseDir(zipBase), zipPath + "/" + getDistName(distUrl));
     }
 
-    public String distZip(String zipBase, String zipPath, String distName, String distVersion, String distClassifier) {
-        return getBaseDir(zipBase) + "/" + zipPath + "/" + distName + "-" + distVersion + "-" + distClassifier + ".zip";
+    private String getDistHome(URI distUrl) {
+        String name = getDistName(distUrl);
+        Matcher matcher = Pattern.compile("(\\p{Alpha}+-\\d+\\.\\d+.*?)(-\\p{Alpha}+)?\\.zip").matcher(name);
+        if (!matcher.matches()) {
+            throw new RuntimeException(String.format("Cannot determine Gradle version from distribution URL '%s'.",
+                    distUrl));
+        }
+        return matcher.group(1);
+    }
+
+    private String getDistName(URI distUrl) {
+        String path = distUrl.getPath();
+        int p = path.lastIndexOf("/");
+        if (p < 0) {
+            return path;
+        }
+        return path.substring(p + 1);
     }
 
     private String getBaseDir(String base) {
diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Wrapper.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Wrapper.java
index c416198..f9d0eef 100644
--- a/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Wrapper.java
+++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/wrapper/Wrapper.java
@@ -18,6 +18,7 @@ package org.gradle.wrapper;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
+import java.net.URI;
 import java.util.Arrays;
 import java.util.Properties;
 
@@ -27,18 +28,15 @@ import java.util.Properties;
 public class Wrapper {
     public static final String WRAPPER_PROPERTIES_PROPERTY = "org.gradle.wrapper.properties";
     
-    public static final String URL_ROOT_PROPERTY = "urlRoot";
+    public static final String DISTRIBUTION_URL_PROPERTY = "distributionUrl";
     public static final String DISTRIBUTION_BASE_PROPERTY = "distributionBase";
     public static final String ZIP_STORE_BASE_PROPERTY = "zipStoreBase";
     public static final String DISTRIBUTION_PATH_PROPERTY = "distributionPath";
-    public static final String DISTRIBUTION_VERSION_PROPERTY = "distributionVersion";
     public static final String ZIP_STORE_PATH_PROPERTY = "zipStorePath";
-    public static final String DISTRIBUTION_NAME_PROPERTY = "distributionName";
-    public static final String DISTRIBUTION_CLASSIFIER_PROPERTY = "distributionClassifier";
 
     public void execute(String[] args, Install install, BootstrapMainStarter bootstrapMainStarter) throws Exception {
         Properties wrapperProperties = new Properties();
-        InputStream inStream = new FileInputStream(new File(System.getProperty(WRAPPER_PROPERTIES_PROPERTY)));
+        InputStream inStream = new FileInputStream(getWrapperPropertiesFile());
         try {
             wrapperProperties.load(inStream);
         } finally {
@@ -47,20 +45,30 @@ public class Wrapper {
         if (GradleWrapperMain.isDebug()) {
             System.out.println("wrapperProperties = " + wrapperProperties);
         }
-        String version = (String) wrapperProperties.get(DISTRIBUTION_VERSION_PROPERTY);
-        String gradleHome = install.createDist(
-                (String) wrapperProperties.get(URL_ROOT_PROPERTY),
-                (String) wrapperProperties.get(DISTRIBUTION_BASE_PROPERTY),
-                (String) wrapperProperties.get(DISTRIBUTION_PATH_PROPERTY),
-                (String) wrapperProperties.get(DISTRIBUTION_NAME_PROPERTY),
-                version,
-                (String) wrapperProperties.get(DISTRIBUTION_CLASSIFIER_PROPERTY),
-                (String) wrapperProperties.get(ZIP_STORE_BASE_PROPERTY),
-                (String) wrapperProperties.get(ZIP_STORE_PATH_PROPERTY)
+        File gradleHome = install.createDist(
+                new URI(getProperty(wrapperProperties, DISTRIBUTION_URL_PROPERTY)),
+                getProperty(wrapperProperties, DISTRIBUTION_BASE_PROPERTY),
+                getProperty(wrapperProperties, DISTRIBUTION_PATH_PROPERTY),
+                getProperty(wrapperProperties, ZIP_STORE_BASE_PROPERTY),
+                getProperty(wrapperProperties, ZIP_STORE_PATH_PROPERTY)
         );
         if (GradleWrapperMain.isDebug()) {
             System.out.println("args = " + Arrays.asList(args));
         }
-        bootstrapMainStarter.start(args, gradleHome, version);
+        bootstrapMainStarter.start(args, gradleHome);
+    }
+
+    private File getWrapperPropertiesFile() {
+        return new File(System.getProperty(WRAPPER_PROPERTIES_PROPERTY));
+    }
+
+    private String getProperty(Properties wrapperProperties, String propertyName) {
+        String value = wrapperProperties.getProperty(propertyName);
+        if (value == null) {
+            throw new RuntimeException(String.format(
+                    "No value with key '%s' specified in wrapper properties file '%s'.", propertyName,
+                    getWrapperPropertiesFile()));
+        }
+        return value;
     }
 }
diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java
index 7b201e2..d9c392f 100644
--- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java
+++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java
@@ -61,9 +61,9 @@ public class WrapperTest extends AbstractTaskTest {
         wrapper.setGradleVersion("1.0");
         targetWrapperJarPath = "jarPath";
         expectedTargetWrapperJar = new TestFile(getProject().getProjectDir(),
-                targetWrapperJarPath + "/" + Wrapper.WRAPPER_JAR);
+                targetWrapperJarPath + "/gradle-wrapper.jar");
         expectedTargetWrapperProperties = new File(getProject().getProjectDir(),
-                targetWrapperJarPath + "/" + Wrapper.WRAPPER_PROPERTIES);
+                targetWrapperJarPath + "/gradle-wrapper.properties");
         new File(getProject().getProjectDir(), targetWrapperJarPath).mkdirs();
         wrapper.setJarPath(targetWrapperJarPath);
         wrapper.setDistributionPath("somepath");
@@ -86,9 +86,62 @@ public class WrapperTest extends AbstractTaskTest {
         assertEquals(Wrapper.DEFAULT_ARCHIVE_NAME, wrapper.getArchiveName());
         assertEquals(Wrapper.DEFAULT_ARCHIVE_CLASSIFIER, wrapper.getArchiveClassifier());
         assertEquals(Wrapper.DEFAULT_DISTRIBUTION_PARENT_NAME, wrapper.getArchivePath());
-        assertEquals(Wrapper.DEFAULT_URL_ROOT, wrapper.getUrlRoot());
         assertEquals(Wrapper.PathBase.GRADLE_USER_HOME, wrapper.getDistributionBase());
         assertEquals(Wrapper.PathBase.GRADLE_USER_HOME, wrapper.getArchiveBase());
+        assertNotNull(wrapper.getUrlRoot());
+        assertNotNull(wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testDownloadsFromReleaseRepositoryForReleaseVersions() {
+        wrapper.setGradleVersion("0.9.1");
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions", wrapper.getUrlRoot());
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions/gradle-0.9.1-bin.zip", wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testDownloadsFromReleaseRepositoryForPreviewReleaseVersions() {
+        wrapper.setGradleVersion("1.0-milestone-1");
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions", wrapper.getUrlRoot());
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions/gradle-1.0-milestone-1-bin.zip", wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testDownloadsFromOldReleaseRepositoryForPre09ReleaseVersions() {
+        wrapper.setGradleVersion("0.9-rc-3");
+        assertEquals("http://dist.codehaus.org/gradle", wrapper.getUrlRoot());
+        assertEquals("http://dist.codehaus.org/gradle/gradle-0.9-rc-3-bin.zip", wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testDownloadsFromSnapshotRepositoryForSnapshotVersions() {
+        wrapper.setGradleVersion("0.9.1-20101224110000+1100");
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions/gradle-snapshots", wrapper.getUrlRoot());
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions/gradle-snapshots/gradle-0.9.1-20101224110000+1100-bin.zip", wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testDownloadsFromOldSnapshotRepositoryForPre09SnapshotVersions() {
+        wrapper.setGradleVersion("0.9-20101224110000+1100");
+        assertEquals("http://snapshots.dist.codehaus.org/gradle", wrapper.getUrlRoot());
+        assertEquals("http://snapshots.dist.codehaus.org/gradle/gradle-0.9-20101224110000+1100-bin.zip", wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testUsesExplicitlyDefinedDistributionUrl() {
+        wrapper.setGradleVersion("0.9");
+        wrapper.setDistributionUrl("http://some-url");
+        assertEquals("http://gradle.artifactoryonline.com/gradle/distributions", wrapper.getUrlRoot());
+        assertEquals("http://some-url", wrapper.getDistributionUrl());
+    }
+
+    @Test
+    public void testAssemblesDistributionUrlFromPartsIfNotSpecified() {
+        wrapper.setGradleVersion("0.9");
+        wrapper.setUrlRoot("http://some-url");
+        wrapper.setArchiveName("archive");
+        wrapper.setArchiveClassifier("all");
+        assertEquals("http://some-url/archive-0.9-all.zip", wrapper.getDistributionUrl());
     }
 
     @Test
@@ -99,7 +152,7 @@ public class WrapperTest extends AbstractTaskTest {
     @Test
     public void testCheckInputs() throws IOException {
         assertThat(wrapper.getInputs().getProperties().keySet(),
-                equalTo(WrapUtil.toSet("archiveClassifier", "distributionPath", "archiveName", "urlRoot", "gradleVersion", "archivePath")));
+                equalTo(WrapUtil.toSet("distributionBase", "distributionPath", "distributionUrl", "archiveBase", "archivePath")));
     }
 
     @Test
@@ -121,8 +174,8 @@ public class WrapperTest extends AbstractTaskTest {
         context.checking(new Expectations() {
             {
                 one(wrapperScriptGeneratorMock).generate(
-                        toNative("../" + targetWrapperJarPath + "/" + Wrapper.WRAPPER_JAR),
-                        toNative("../" + targetWrapperJarPath + "/" + Wrapper.WRAPPER_PROPERTIES),
+                        toNative("../" + targetWrapperJarPath + "/gradle-wrapper.jar"),
+                        toNative("../" + targetWrapperJarPath + "/gradle-wrapper.properties"),
                         wrapper.getScriptFile());
             }
         });
@@ -131,12 +184,9 @@ public class WrapperTest extends AbstractTaskTest {
         expectedTargetWrapperJar.unzipTo(unjarDir);
         unjarDir.file(GradleWrapperMain.class.getName().replace(".", "/") + ".class").assertIsFile();
         Properties properties = GUtil.loadProperties(expectedTargetWrapperProperties);
-        assertEquals(properties.getProperty(Wrapper.URL_ROOT_PROPERTY), wrapper.getUrlRoot());
+        assertEquals(properties.getProperty(Wrapper.DISTRIBUTION_URL_PROPERTY), wrapper.getDistributionUrl());
         assertEquals(properties.getProperty(Wrapper.DISTRIBUTION_BASE_PROPERTY), wrapper.getDistributionBase().toString());
         assertEquals(properties.getProperty(Wrapper.DISTRIBUTION_PATH_PROPERTY), wrapper.getDistributionPath());
-        assertEquals(properties.getProperty(Wrapper.DISTRIBUTION_NAME_PROPERTY), wrapper.getArchiveName());
-        assertEquals(properties.getProperty(Wrapper.DISTRIBUTION_CLASSIFIER_PROPERTY), wrapper.getArchiveClassifier());
-        assertEquals(properties.getProperty(Wrapper.DISTRIBUTION_VERSION_PROPERTY), wrapper.getGradleVersion());
         assertEquals(properties.getProperty(Wrapper.ZIP_STORE_BASE_PROPERTY), wrapper.getArchiveBase().toString());
         assertEquals(properties.getProperty(Wrapper.ZIP_STORE_PATH_PROPERTY), wrapper.getArchivePath());
     }
diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/DownloadTest.groovy b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/DownloadTest.groovy
index 019f112..70fd784 100644
--- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/DownloadTest.groovy
+++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/DownloadTest.groovy
@@ -30,7 +30,7 @@ class DownloadTest {
     File testDir
     File downloadFile
     File rootDir
-    String sourceRoot
+    URI sourceRoot
     File remoteFile
     @Rule
     public TemporaryFolder tmpDir = new TemporaryFolder();
@@ -41,7 +41,7 @@ class DownloadTest {
         rootDir = new File(testDir, 'root')
         downloadFile = new File(rootDir, 'file')
         (remoteFile = new File(testDir, 'remoteFile')).write('sometext')
-        sourceRoot = "file:///$remoteFile.canonicalPath"
+        sourceRoot = remoteFile.toURI()
     }
 
     @Test public void testDownload() {
diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy
index c31aff7..ac1aa97 100644
--- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy
+++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/InstallTest.groovy
@@ -33,11 +33,7 @@ class InstallTest {
     String testZipPath
     String testDistBase
     String testDistPath
-    String testDistName
-    String testDistVersion
-    String testDistClassifier
-
-    String urlRoot
+    URI testDistUrl
     IDownload downloadMock
     PathAssembler pathAssemblerMock;
     boolean downloadCalled
@@ -57,20 +53,17 @@ class InstallTest {
         testZipPath = 'someZipPath'
         testDistBase = PathBase.GRADLE_USER_HOME.toString()
         testDistPath = 'someDistPath'
-        testDistName = 'gradle'
-        testDistVersion = '1.0'
-        testDistClassifier = 'clf'
+        testDistUrl = new URI('http://server/gradle-0.9.zip')
         distributionDir = new File(testDir, testDistPath)
-        gradleHomeDir = new File(distributionDir, "$testDistName-$testDistVersion")
+        gradleHomeDir = new File(distributionDir, 'gradle-0.9')
         zipStore = new File(testDir, 'zips');
-        zipDestination = new File(zipStore, "$testDistName-$testDistVersion-$testDistClassifier" + ".zip")
-        urlRoot = 'file://./tmpTest'
+        zipDestination = new File(zipStore, 'gradle-0.9.zip')
         install = new Install(false, false, createDownloadMock(), createPathAssemblerMock())
     }
 
     IDownload createDownloadMock() {
-        [download: {String url, File destination ->
-            assertEquals("$urlRoot/$testDistName-${testDistVersion}-${testDistClassifier}.zip" as String, url)
+        [download: {URI url, File destination ->
+            assertEquals(testDistUrl, url)
             assertEquals(zipDestination.getAbsolutePath() + '.part', destination.getAbsolutePath())
             zip = createTestZip()
             downloadCalled = true
@@ -78,19 +71,16 @@ class InstallTest {
     }
 
     PathAssembler createPathAssemblerMock() {
-        [gradleHome: {String distBase, String distPath, String distName, String distVersion ->
+        [gradleHome: {String distBase, String distPath, URI distUrl ->
             assertEquals(testDistBase, distBase)
             assertEquals(testDistPath, distPath)
-            assertEquals(testDistName, distName)
-            assertEquals(testDistVersion, distVersion)
-            gradleHomeDir.getAbsolutePath()},
-         distZip: { String zipBase, String zipPath, String distName, String distVersion, String distClassifier ->
+            assertEquals(testDistUrl, distUrl)
+            gradleHomeDir},
+         distZip: { String zipBase, String zipPath, URI distUrl ->
             assertEquals(testZipBase, zipBase)
             assertEquals(testZipPath, zipPath)
-            assertEquals(testDistName, distName)
-            assertEquals(testDistVersion, distVersion)
-            assertEquals(testDistClassifier, distClassifier)
-            zipDestination.getAbsolutePath()
+             assertEquals(testDistUrl, distUrl)
+            zipDestination
         }] as PathAssembler
     }
 
@@ -108,13 +98,13 @@ class InstallTest {
         zipStore.mkdirs()
         AntBuilder antBuilder = new AntBuilder()
         antBuilder.zip(destfile: zipDestination.absolutePath + '.part') {
-            zipfileset(dir: explodedZipDir, prefix: "$testDistName-$testDistVersion")
+            zipfileset(dir: explodedZipDir, prefix: 'gradle-0.9')
         }
         (zipDestination.absolutePath + '.part') as File
     }
 
     @Test public void testCreateDist() {
-        assertEquals(gradleHomeDir.absolutePath, install.createDist(urlRoot, testDistBase, testDistPath, testDistName, testDistVersion, testDistClassifier, testZipBase, testZipPath))
+        assertEquals(gradleHomeDir, install.createDist(testDistUrl, testDistBase, testDistPath, testZipBase, testZipPath))
         assert downloadCalled
         assert distributionDir.isDirectory()
         assert zipDestination.exists()
@@ -124,7 +114,7 @@ class InstallTest {
 
     @Test public void testCreateDistWithExistingRoot() {
         distributionDir.mkdirs()
-        install.createDist(urlRoot, testDistBase, testDistPath, testDistName, testDistVersion, testDistClassifier, testZipBase, testZipPath)
+        install.createDist(testDistUrl, testDistBase, testDistPath, testZipBase, testZipPath)
         assert downloadCalled
         assert gradleHomeDir.isDirectory()
         assert gradleScript.exists()
@@ -133,7 +123,7 @@ class InstallTest {
     @Test public void testCreateDistWithExistingDist() {
         gradleHomeDir.mkdirs()
         long lastModified = gradleHomeDir.lastModified()
-        install.createDist(urlRoot, testDistBase, testDistPath, testDistName, testDistVersion, testDistClassifier, testZipBase, testZipPath)
+        install.createDist(testDistUrl, testDistBase, testDistPath, testZipBase, testZipPath)
         assert !downloadCalled
         assert lastModified == gradleHomeDir.lastModified()
     }
@@ -143,7 +133,7 @@ class InstallTest {
         createTestZip().renameTo(zipDestination)
         gradleHomeDir.mkdirs()
         File testFile = new File(gradleHomeDir, 'testfile')
-        install.createDist(urlRoot, testDistBase, testDistPath, testDistName, testDistVersion, testDistClassifier, testZipBase, testZipPath)
+        install.createDist(testDistUrl, testDistBase, testDistPath, testZipBase, testZipPath)
         assert distributionDir.isDirectory()
         assert gradleScript.exists()
         assert !testFile.exists()
@@ -155,7 +145,7 @@ class InstallTest {
         createTestZip().renameTo(zipDestination)
         distributionDir.mkdirs()
         File testFile = new File(gradleHomeDir, 'testfile')
-        install.createDist(urlRoot, testDistBase, testDistPath, testDistName, testDistVersion, testDistClassifier, testZipBase, testZipPath)
+        install.createDist(testDistUrl, testDistBase, testDistPath, testZipBase, testZipPath)
         assert gradleHomeDir.isDirectory()
         assert gradleScript.exists()
         assert !testFile.exists()
diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/PathAssemblerTest.java b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/PathAssemblerTest.java
index 0b8cfee..8b0cd66 100644
--- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/PathAssemblerTest.java
+++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/PathAssemblerTest.java
@@ -15,65 +15,86 @@
  */
 package org.gradle.wrapper;
 
-import org.junit.Before;
 import org.junit.Test;
-import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.net.URI;
+
+import static org.junit.Assert.*;
 
 /**
  * @author Hans Dockter
  */
 public class PathAssemblerTest {
     public static final String TEST_GRADLE_USER_HOME = "someUserHome";
-    private PathAssembler pathAssembler;
-    private String testPath;
-    private String testName;
-    private String testVersion;
-    private String testClassifier;
+    private PathAssembler pathAssembler = new PathAssembler(TEST_GRADLE_USER_HOME);
 
-    @Before
-    public void setUp() {
-        pathAssembler = new PathAssembler(TEST_GRADLE_USER_HOME);
-        testPath = "somepath";
-        testName = "somename";
-        testVersion = "someversion";
-        testClassifier = "someclassifier";
+    @Test
+    public void gradleHomeWithGradleUserHomeBase() throws Exception {
+        File gradleHome = pathAssembler.gradleHome(PathAssembler.GRADLE_USER_HOME_STRING, "somePath", new URI("http://server/dist/gradle-0.9-bin.zip"));
+        assertEquals(file(TEST_GRADLE_USER_HOME + "/somePath/gradle-0.9"), gradleHome);
     }
 
     @Test
-    public void gradleHomeWithGradleUserHomeBase() {
-        String gradleHome = pathAssembler.gradleHome(PathAssembler.GRADLE_USER_HOME_STRING, testPath, testName,
-                testVersion);
-        assertEquals(TEST_GRADLE_USER_HOME + "/" + testPath + "/" + testName + "-" + testVersion, gradleHome);
+    public void gradleHomeWithProjectBase() throws Exception {
+        File gradleHome = pathAssembler.gradleHome(PathAssembler.PROJECT_STRING, "somePath", new URI("http://server/dist/gradle-0.9-bin.zip"));
+        assertEquals(file(currentDirPath() + "/somePath/gradle-0.9"), gradleHome);
     }
 
     @Test
-    public void gradleHomeWithProjectBase() {
-        String gradleHome = pathAssembler.gradleHome(PathAssembler.PROJECT_STRING, testPath, testName, testVersion);
-        assertEquals(currentDirPath() + "/" + testPath + "/" + testName + "-" + testVersion, gradleHome);
+    public void gradleHomeForUriWithNoPath() throws Exception {
+        File gradleHome = pathAssembler.gradleHome(PathAssembler.GRADLE_USER_HOME_STRING, "somePath", new URI("http://server/gradle-0.9-bin.zip"));
+        assertEquals(file(TEST_GRADLE_USER_HOME + "/somePath/gradle-0.9"), gradleHome);
+    }
+
+    @Test
+    public void gradleHomeForSnapshotVersion() throws Exception {
+        File gradleHome = pathAssembler.gradleHome(PathAssembler.GRADLE_USER_HOME_STRING, "somePath", new URI("http://server/gradle-0.9-some-branch-2010+1100-bin.zip"));
+        assertEquals(file(TEST_GRADLE_USER_HOME + "/somePath/gradle-0.9-some-branch-2010+1100"), gradleHome);
+    }
+
+    @Test
+    public void gradleHomeForUrlWithNoClassifier() throws Exception {
+        File gradleHome = pathAssembler.gradleHome(PathAssembler.GRADLE_USER_HOME_STRING, "somePath", new URI("http://server/gradle-0.9.zip"));
+        assertEquals(file(TEST_GRADLE_USER_HOME + "/somePath/gradle-0.9"), gradleHome);
+    }
+
+    @Test
+    public void gradleHomeForUrlWithNoVersion() throws Exception {
+        try {
+            pathAssembler.gradleHome(PathAssembler.GRADLE_USER_HOME_STRING, "somePath", new URI("http://server/gradle-bin.zip"));
+            fail();
+        } catch (RuntimeException e) {
+            assertEquals("Cannot determine Gradle version from distribution URL 'http://server/gradle-bin.zip'.", e.getMessage());
+        }
     }
 
     @Test(expected = RuntimeException.class)
-    public void gradleHomeWithUnknownBase() {
-        pathAssembler.gradleHome("unknownBase", testPath, testName, testVersion);
+    public void gradleHomeWithUnknownBase() throws Exception {
+        pathAssembler.gradleHome("unknownBase", "somePath", new URI("http://server/gradle.zip"));
     }
 
     @Test
-    public void distZipWithGradleUserHomeBase() {
-        String gradleHome = pathAssembler.distZip(PathAssembler.GRADLE_USER_HOME_STRING, testPath, testName, testVersion, testClassifier);
-        assertEquals(TEST_GRADLE_USER_HOME + "/" + testPath + "/" + testName + "-" + testVersion + "-" + testClassifier + ".zip", gradleHome);
+    public void distZipWithGradleUserHomeBase() throws Exception {
+        File dist = pathAssembler.distZip(PathAssembler.GRADLE_USER_HOME_STRING, "somePath", new URI("http://server/dist/gradle.zip"));
+        assertEquals(file(TEST_GRADLE_USER_HOME + "/somePath/gradle.zip"), dist);
     }
 
     @Test
-    public void distZipWithProjectBase() {
-        String gradleHome = pathAssembler.distZip(PathAssembler.PROJECT_STRING, testPath, testName, testVersion, testClassifier);
-        assertEquals(currentDirPath() + "/" + testPath + "/" + testName + "-" + testVersion + "-" + testClassifier + ".zip", gradleHome);
+    public void distZipWithProjectBase() throws Exception {
+        File dist = pathAssembler.distZip(PathAssembler.PROJECT_STRING, "somePath", new URI("http://server/dist/gradle.zip"));
+        assertEquals(file(currentDirPath() + "/somePath/gradle.zip"), dist);
     }
 
     @Test(expected = RuntimeException.class)
-    public void distZipWithUnknownBase() {
-        pathAssembler.distZip("unknownBase", testPath, testName, testVersion, testClassifier);
+    public void distZipWithUnknownBase() throws Exception {
+        pathAssembler.distZip("unknownBase", "somePath", new URI("http://server/dist/gradle.zip"));
     }
 
+    private File file(String path) {
+        return new File(path);
+    }
+    
     private String currentDirPath() {
         return System.getProperty("user.dir");
     }
diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/WrapperTest.java b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/WrapperTest.java
index 2543666..0d17aea 100644
--- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/WrapperTest.java
+++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/wrapper/WrapperTest.java
@@ -15,17 +15,20 @@
  */
 package org.gradle.wrapper;
 
+import org.gradle.util.JUnit4GroovyMockery;
+import org.gradle.util.SetSystemProperties;
+import org.gradle.util.TemporaryFolder;
 import org.jmock.Expectations;
 import org.jmock.integration.junit4.JUnit4Mockery;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.net.URI;
 import java.util.Properties;
 
 /**
@@ -36,50 +39,38 @@ public class WrapperTest {
     Wrapper wrapper;
     BootstrapMainStarter bootstrapMainStarterMock;
     Install installMock;
-
-    JUnit4Mockery context = new JUnit4Mockery();
-
-    private File propertiesDir = new File("propertiesDir");
-    private File propertiesFile;
+    final JUnit4Mockery context = new JUnit4GroovyMockery();
+    @Rule
+    public final SetSystemProperties systemProperties = new SetSystemProperties();
+    @Rule
+    public final TemporaryFolder tmpDir = new TemporaryFolder();
+    private File propertiesDir = tmpDir.getDir();
+    private File propertiesFile = new File(propertiesDir, "wrapper.properties");
 
     @Before
     public void setUp() throws IOException {
-        context.setImposteriser(ClassImposteriser.INSTANCE);
         wrapper = new Wrapper();
         bootstrapMainStarterMock = context.mock(BootstrapMainStarter.class);
         installMock = context.mock(Install.class);
-        propertiesDir.mkdirs();
-        propertiesFile = new File(propertiesDir, "wrapper.properties");
         Properties testProperties = new Properties();
         testProperties.load(WrapperTest.class.getResourceAsStream("/org/gradle/wrapper/wrapper.properties"));
         testProperties.store(new FileOutputStream(propertiesFile), null);
         System.setProperty(Wrapper.WRAPPER_PROPERTIES_PROPERTY, propertiesFile.getCanonicalPath());
     }
 
-    @After
-    public void tearDown() {
-        propertiesFile.delete();
-        propertiesDir.delete();
-        System.getProperties().remove(Wrapper.WRAPPER_PROPERTIES_PROPERTY);
-    }
-
     @Test
     public void execute() throws Exception {
         final String[] expectedArgs = { "arg1", "arg2" };
-        final int expectedExitValue = 5;
-        final String expectedGradleHome = "somepath";
+        final File expectedGradleHome = new File("somepath");
         context.checking(new Expectations() {{
           one(installMock).createDist(
-                  "test" + Wrapper.URL_ROOT_PROPERTY,
-                  "test" + Wrapper.DISTRIBUTION_BASE_PROPERTY,
-                  "test" + Wrapper.DISTRIBUTION_PATH_PROPERTY,
-                  "test" + Wrapper.DISTRIBUTION_NAME_PROPERTY,
-                  "test" + Wrapper.DISTRIBUTION_VERSION_PROPERTY,
-                  "test" + Wrapper.DISTRIBUTION_CLASSIFIER_PROPERTY,
-                  "test" + Wrapper.ZIP_STORE_BASE_PROPERTY,
-                  "test" + Wrapper.ZIP_STORE_PATH_PROPERTY
+                  new URI("http://server/test/gradle.zip"),
+                  "testDistBase",
+                  "testDistPath",
+                  "testZipBase",
+                  "testZipPath"
           ); will(returnValue(expectedGradleHome));
-          one(bootstrapMainStarterMock).start(expectedArgs, expectedGradleHome, "test" + Wrapper.DISTRIBUTION_VERSION_PROPERTY);
+          one(bootstrapMainStarterMock).start(expectedArgs, expectedGradleHome);
         }});
         wrapper.execute(expectedArgs, installMock, bootstrapMainStarterMock);
     }
diff --git a/subprojects/gradle-wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties b/subprojects/gradle-wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties
index 2abba00..74fdc73 100644
--- a/subprojects/gradle-wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties
+++ b/subprojects/gradle-wrapper/src/test/resources/org/gradle/wrapper/wrapper.properties
@@ -1,8 +1,5 @@
-urlRoot=testurlRoot
-distributionBase=testdistributionBase
-zipStoreBase=testzipStoreBase
-distributionPath=testdistributionPath
-zipStorePath=testzipStorePath
-distributionName=testdistributionName
-distributionClassifier=testdistributionClassifier
-distributionVersion=testdistributionVersion
+distributionUrl=http://server/test/gradle.zip
+distributionBase=testDistBase
+zipStoreBase=testZipBase
+distributionPath=testDistPath
+zipStorePath=testZipPath
diff --git a/wrapper/gradle-wrapper.properties b/wrapper/gradle-wrapper.properties
index 6ebe28f..59555db 100644
--- a/wrapper/gradle-wrapper.properties
+++ b/wrapper/gradle-wrapper.properties
@@ -18,8 +18,8 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
-distributionVersion=0.9-rc-3
+distributionVersion=0.9
 zipStorePath=wrapper/dists
-urlRoot=http\://dist.codehaus.org/gradle
+urlRoot=http\://gradle.artifactoryonline.com/gradle/distributions
 distributionName=gradle
 distributionClassifier=bin

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/gradle-1.12.git



More information about the pkg-java-commits mailing list