Index: build.gradle
===================================================================
--- build.gradle	(revision 1596)
+++ build.gradle	(working copy)
@@ -1,701 +1,704 @@
-import java.text.DateFormat
-import java.text.SimpleDateFormat
-import java.util.jar.Attributes
-import org.apache.tools.ant.taskdefs.condition.Os
-import org.gradle.api.Task
-import org.gradle.api.artifacts.repositories.WebdavResolver
-import org.gradle.api.tasks.testing.ForkMode
-import org.gradle.api.tasks.wrapper.Wrapper
-import org.gradle.build.release.Svn
-import org.gradle.build.release.Version
-import org.gradle.build.samples.WrapperProjectCreator
-import org.gradle.build.startscripts.StartScriptsGenerator
-import org.gradle.util.GradleVersion
-import org.apache.ivy.plugins.resolver.*
-import org.gradle.build.docs.UserGuideTransformTask
-import org.gradle.build.docs.ExtractSnippetsTask
-import org.gradle.build.docs.SampleElementValidator
-
-/**
- * For building Gradle you usually don't need to specify any properties. Only certain functionality of the Gradle requires
- * 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 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
- * Creating a JDK-1.4 compatible distribtution with retro-translator: gradle_retroLibsDir (This dir shoud contain rt.jar, jce.jar and jsse.jar from
- * a JDK 1.4).
- */
-
-defaultTasks "clean", "dists"
-
-usePlugin('groovy')
-
-archivesBaseName = 'gradle'
-
-sourceCompatibility = 1.5
-targetCompatibility = 1.5
-
-svn = new Svn(project)
-
-type = 'jar'
-version = new Version(svn, project, false)
-group = 'org.gradle'
-buildTime = new Date()
-versionModifier = null
-
-repositories {
-    mavenCentral()
-    add(new URLResolver()) {
-        name = 'sf_gradleRepo'
-        addArtifactPattern('http://gradle.sourceforge.net/gradleRepo/[organisation]/[module](/[branch])/[type]s/[artifact]-[revision](-[classifier])(.[ext])')
-    }
-}
-
-configurations {
-    distLib {
-        visible = false
-        extendsFrom getByName('default')
-    }
-    ftpAntTask
-    retrotranslatorAntTask
-    userGuideStyleSheets
-    userGuideTask
-}
-
-dependencies {
-
-    // todo: Improve dependency handling for xUnit jars
-    ftpAntTask module("org.apache.ant:ant-commons-net:1.7.0") {
-        module("commons-net:commons-net:1.4.1") {
-            dependencies("oro:oro:2.0.8@jar")
-        }
-    }
-
-    retrotranslatorAntTask 'net.sf.retrotranslator:retrotranslator-runtime:1.2.7@jar', 'net.sf.retrotranslator:retrotranslator-transformer:1.2.7@jar',
-            'backport-util-concurrent:backport-util-concurrent:3.1@jar'
-
-    userGuideTask 'xalan:xalan:2.7.1', 'xerces:xercesImpl:2.9.1'
-    userGuideTask module('xhtmlrenderer:xhtmlrenderer:R8rc1') {
-        dependency 'itext:itext:2.0.8@jar'
-    }
-
-    userGuideStyleSheets 'docbook:docbook-xsl:1.74.3@zip'
-
-    groovy module("org.codehaus.groovy:groovy-all:1.6.3") {
-        module("org.apache.ant:ant:1.7.0") {
-            dependencies("org.apache.ant:ant-junit:1.7.0@jar", "org.apache.ant:ant-launcher:1.7.0@jar")
-        }
-    }
-
-    compile module("commons-httpclient:commons-httpclient:3.0") {
-        dependencies("commons-codec:commons-codec:1.2@jar", "org.slf4j:jcl-over-slf4j:1.5.3@jar")
-    }
-
-    // Needed by the eclipse plugin
-    compile module("dom4j:dom4j:1.6.1") {
-        dependencies("jaxen:jaxen:1.1@jar")
-    }
-
-    compile "org.mortbay.jetty:jetty-plus:6.1.14@jar",
-            "org.mortbay.jetty:jetty-util:6.1.14@jar",
-            "javax.servlet:servlet-api:2.5@jar"
-
-    compile module("org.mortbay.jetty:jetty:6.1.14") {
-        // todo - these should be runtime dependencies
-        dependencies("javax.servlet:servlet-api:2.5@jar",
-                "org.apache.ant:ant:1.7.0@jar",
-                // todo jsp stuff should be a module
-                "org.mortbay.jetty:jsp-api-2.1:6.1.14@jar",
-                "org.mortbay.jetty:jsp-2.1:6.1.14@jar",
-                "org.eclipse.jdt:core:3.1.1@jar",
-                "org.mortbay.jetty:jetty-util:6.1.14@jar",
-                "org.mortbay.jetty:jetty-naming:6.1.14@jar",
-                "org.mortbay.jetty:jetty-annotations:6.1.14@jar")
-    }
-
-    compile module("org.apache.ivy:ivy:2.1.0-rc1") {
-        dependencies("jsch:jsch:0.1.31")
-    }
-
-    compile "net.sf.jopt-simple:jopt-simple:2.4.1@jar",
-            "org.apache.ant:ant:1.7.0@jar",
-            "ch.qos.logback:logback-classic:0.9.9@jar",
-            "org.slf4j:slf4j-api:1.5.3@jar",
-            "ch.qos.logback:logback-core:0.9.9@jar",
-            "commons-io:commons-io:1.4@jar",
-            "commons-lang:commons-lang:2.3@jar",
-            "commons-codec:commons-codec:1.2@jar",
-            "slide:webdavlib:2.0@jar",
-            "biz.aQute:bndlib:0.0.255@jar",
-            "org.apache.maven:maven-ant-tasks:2.0.9@jar",
-            "asm:asm-all:2.2.3@jar"
-
-    runtime "org.apache.ant:ant-junit:1.7.0@jar",
-            "org.apache.ant:ant-launcher:1.7.0@jar",
-            "org.apache.ant:ant-nodeps:1.7.0@jar",
-            "org.apache.ant:ant-trax:1.7.0@jar",
-            "junit:junit:4.5"
-
-    def FIRST_LEVEL_JMOCK = ['org.hamcrest:hamcrest-core:1.1@jar', 'org.hamcrest:hamcrest-library:1.1@jar', 'org.jmock:jmock-junit4:2.4.0@jar']
-    testCompile "junit:junit:4.5", "xmlunit:xmlunit:1.2", FIRST_LEVEL_JMOCK
-    testCompile module("org.jmock:jmock:2.4.0") {
-        dependencies('org.jmock:jmock-legacy:2.4.0@jar', 'org.objenesis:objenesis:1.0', 'cglib:cglib-nodep:2.1_3')
-        dependencies(FIRST_LEVEL_JMOCK as Object[])
-    }
-    // todo - these should not be here
-    testCompile 'org.jmock:jmock-legacy:2.4.0@jar', 'org.objenesis:objenesis:1.0', 'cglib:cglib-nodep:2.1_3'
-    distLib "junit:junit:4.5"
-}
-
-distributionUploadUrl = null
-docsRemoteDir = ''
-javadocRemoteDir = ''
-groovydocRemoteDir = ''
-build.taskGraph.whenReady {graph ->
-    String prefix = ''
-    if (graph.hasTask(':release')) {
-        versionModifier = ''
-        distributionUploadUrl = 'https://dav.codehaus.org/dist/gradle'
-        prefix = version as String
-    } else {
-        versionModifier = new SimpleDateFormat('yyyyMMddHHmmssZ').format(buildTime)
-        distributionUploadUrl = 'https://dav.codehaus.org/snapshots.dist/gradle'
-        prefix = 'latest'
-    }
-    docsRemoteDir = prefix + '/docs'
-    javadocRemoteDir = docsRemoteDir + '/javadoc'
-    groovydocRemoteDir = docsRemoteDir + '/groovydoc'
-    manifest.mainAttributes([
-            (Attributes.Name.IMPLEMENTATION_TITLE.toString()): 'Gradle',
-            (Attributes.Name.IMPLEMENTATION_VERSION.toString()): version.toString(),
-    ])
-}
-
-processResources.doLast {
-    File versionPropertiesDestination = new File(classesDir, GradleVersion.FILE_NAME)
-    logger.info('Write version properties to: {}', versionPropertiesDestination.absoluteFile)
-    Properties versionProperties = new Properties()
-    versionProperties.putAll([
-            (GradleVersion.VERSION): version.toString(),
-            (GradleVersion.BUILD_TIME): DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(buildTime)
-    ])
-    versionProperties.store(new FileOutputStream(versionPropertiesDestination), '')
-}
-
-[compile, compileTests]*.groovyOptions*.fork(memoryInitialSize: '128M', memoryMaximumSize: '1G')
-
-test {
-    // We set forkmode to ONCE as our tests are written in Groovy and the startup time of Groovy is significant.
-    options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea", '-Xms128m', '-Xmx1g', '-XX:MaxPermSize=128m', '-XX:+HeapDumpOnOutOfMemoryError'])
-
-    exclude 'org/gradle/integtests/**/*IntegrationTest.*'
-}
-
-task wrapperJar(type: Jar) {
-    appendix = 'wrapper'
-    fileSet(dir: classesDir) {
-        include 'org/gradle/wrapper/'
-    }
-    manifest.mainAttributes("Main-Class": 'org.gradle.wrapper.WrapperMain')
-}
-
-jar.manifest.mainAttributes("Main-Class": "org.gradle.BootstrapMain")
-
-explodedDistDir = new File(distsDir, 'exploded')
-explodedDistDocsDir = new File(explodedDistDir, 'docs')
-explodedDistJavadocsDir = new File(explodedDistDocsDir, 'javadoc')
-explodedDistGroovydocsDir = new File(explodedDistDocsDir, 'groovydoc')
-explodedDistSamplesDir = new File(explodedDistDir, 'samples')
-explodedDistLibDir = new File(explodedDistDir, 'lib')
-samplesSrcDir = new File(srcRoot, 'samples')
-userguideOutputDir = new File(samplesSrcDir, 'userguideOutput')
-
-task explodedDistBase(dependsOn: [libs, javadoc, groovydoc]) << {
-    [explodedDistDir, explodedDistSamplesDir, explodedDistLibDir]*.mkdirs()
-    File explodedDistBinDir = mkdir(explodedDistDir, 'bin')
-    File explodedDistSrcDir = mkdir(explodedDistDir, 'src')
-
-    ant {
-        logger.info('Generate lib dir')
-        configurations.distLib.each {File file ->
-            copy(file: file, todir: explodedDistLibDir)
-        }
-        // todo: find out why Ivy does not include the jar in the resolve
-        delete { fileset(dir:explodedDistLibDir, includes:"$archivesBaseName-*.jar") }
-        copy(file: jar.archivePath, toDir: explodedDistLibDir)
-        copy(file: wrapperJar.archivePath, toDir: explodedDistLibDir)
-        logger.info('Generate start scripts')
-        StartScriptsGenerator.generate("$archivesBaseName-${version}.jar", explodedDistBinDir, archivesBaseName)
-        logger.info('Generate and copy samples.')
-        WrapperProjectCreator.createProject(explodedDistSamplesDir, binZip.archivePath.parentFile,
-                version.toString())
-        logger.info('Copy binary sources.')
-        copy(toDir: explodedDistSrcDir) {
-            (srcDirs + resourceDirs + groovySrcDirs).findAll {it.isDirectory()}.each {dir -> fileset(dir: dir)}
-        }
-        logger.info('Copy and generate top level files.')
-        copy(toDir: explodedDistDir) {fileset(dir: new File(srcRoot, 'toplevel'))}
-        // Set permissions (important for running integration tests against the exploded dist)
-        chmod(dir: "$explodedDistDir/bin", perm: "ugo+rx", includes: "**/*")
-    }
-}
-
-task explodedDist(dependsOn: [explodedDistBase, 'userguide', 'distDocs'])
-
-zipRootFolder = "$archivesBaseName-${-> version}"
-
-distsRetroLibsFolder = new File(distsDir, 'retroLibs')
-
-task retroTranslateLibs(dependsOn: explodedDist) << {
-    distsRetroLibsFolder.mkdirs()
-    ant {
-        taskdef(name: "retrotranslator", classname: "net.sf.retrotranslator.transformer.RetrotranslatorTask",
-                classpath: configurations.retrotranslatorAntTask.asPath)
-        List libFiles = explodedDistLibDir.listFiles()
-        File logbackCore = libFiles.find { it.name.startsWith('logback-core') }
-        File logbackClassic = libFiles.find { it.name.startsWith('logback-classic') }
-        File gradle = libFiles.find { it.name.startsWith('gradle-') && !it.name.startsWith('gradle-wrapper') }
-        File gradleWrapper = libFiles.find { it.name.startsWith('gradle-wrapper')}
-        List retroFiles = [logbackCore, logbackClassic, gradle, gradleWrapper]
-        String libExcludes = retroFiles.join(',')
-        retroFiles.each {File file ->
-            retroExe(file) {
-                fileset(dir: distsRetroLibsFolder)
-                fileset(dir: explodedDistLibDir, excludes: libExcludes)
-                fileset(dir: gradle_retroLibsDir)
-            }
-        }
-    }
-}
-retroTranslateLibs {
-    enabled = project.hasProperty('gradle_retroLibsDir')
-    skipProperties << 'skip.archive_all-jdk14_zip'
-}
-
-void retroExe(File file, Closure fileSet) {
-    ant {
-        retrotranslator(target: "1.4", destjar: new File(distsRetroLibsFolder, file.name), smart: true, verify: false, failonwarning: false) {
-            jarfileset(dir: explodedDistLibDir, includes: file.name)
-            classpath() {
-                fileset(dir: gradle_retroLibsDir)
-                fileSet.delegate = delegate
-                fileSet()
-            }
-        }
-    }
-}
-
-Closure binFileSets = {task ->
-    delegate = task
-    zipFileSet(dir: explodedDistDir, prefix: zipRootFolder, fileMode: '775') {
-        include 'bin/*'
-        exclude 'bin/*.*'
-    }
-    zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
-        include 'bin/*.*'
-    }
-}
-
-task allZip(type: Zip) {
-    dependsOn explodedDist
-    classifier = 'all'
-}
-allZip.doFirst {task ->
-    task.configure {
-        zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
-            exclude 'bin/*'
-        }
-        binFileSets(delegate)
-    }
-}
-
-task binZip(type: Zip) {
-    dependsOn explodedDist
-    classifier = 'bin'
-}
-binZip.doFirst {task ->
-    task.configure {
-        zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
-            exclude 'bin/*'
-            exclude 'src/'
-            exclude 'samples/'
-        }
-        binFileSets(delegate)
-    }
-}
-
-task srcZip(type: Zip) {
-    dependsOn explodedDist
-    classifier = 'src'
-}
-srcZip.doFirst {task ->
-    task.configure {
-        zipFileSet(dir: projectDir, prefix: zipRootFolder, fileMode: '775') {
-            include 'gradlew'
-        }
-        zipFileSet(dir: projectDir, prefix: zipRootFolder) {
-            include 'buildSrc/', 'wrapper/', 'lib/', 'src/', 'gradle.properties', 'build.gradle', 'gradlew.bat'
-        }
-    }
-}
-
-task jdk14AllZip(type: Zip) {
-    dependsOn retroTranslateLibs, explodedDist
-    classifier = 'all-jdk14'
-    enabled = project.hasProperty('gradle_retroLibsDir')
-}
-jdk14AllZip.doFirst {Task task ->
-    task.configure {
-        zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
-            exclude 'bin/*'
-            exclude 'lib/gradle*.jar'
-            exclude 'lib/logback*.jar'
-        }
-        zipFileSet(dir: distsRetroLibsFolder, prefix: "$zipRootFolder/lib")
-        configurations.retrotranslatorAntTask.each {File file ->
-            zipFileSet(dir: file.parentFile, prefix: "$zipRootFolder/lib") {
-                include file.name
-            }
-        }
-        binFileSets(delegate)
-    }
-}
-
-artifacts {
-    tasks.findAll {task -> task.name.matches('.*Zip') }.each {
-        dists it
-    }
-}
-
-groovydoc.destinationDir = explodedDistGroovydocsDir
-
-javadoc {
-    dependsOn compile
-    destinationDir = explodedDistJavadocsDir
-    // todo: include only the public packages
-    options.subPackages 'org.gradle'
-    exclude 'org.gradle.api.internal'
-    // todo: make this true
-    failOnError = false
-}
-javadoc.doFirst {
-    javadoc.title = "Gradle API $version"
-    javadoc.options.docTitle = javadoc.title
-}
-
-srcDocsDir = file('src/docs')
-userguideDir = new File(buildDir, "$docsDir.name/userguide")
-userguideSrcDir = new File(srcDocsDir, 'userguide')
-userguideHtmlDir = new File(explodedDistDocsDir, 'userguide')
-userguidePdfFile = new File(userguideHtmlDir, 'userguide.pdf')
-userguideSingleHtmlFile = new File(userguideHtmlDir, 'userguide_single.html')
-docbookSrc = new File(project.buildDir, 'docbook/src')
-docbookDir = new File(project.buildDir, 'docbook/stylesheets')
-snippetsDir = new File(project.buildDir, 'docbook/snippets')
-
-task userguide(dependsOn: ['userguideHtml', 'userguideSingleHtml', 'userguidePdf'], description: 'Generates the userguide')
-
-task samples(type: ExtractSnippetsTask) {
-    sourceFiles = ant.fileset(dir: samplesSrcDir) {
-        exclude(name: 'userguideOutput/**')
-        exclude(name: 'userguide/tutorial/antChecksumFiles/**')
-    }
-    destDir = explodedDistSamplesDir
-    snippetsDir = project.snippetsDir
-}
-samples << {
-    ant.copy(todir: explodedDistSamplesDir) {
-        fileset(dir: samplesSrcDir) {
-            include(name: 'userguide/tutorial/antChecksumFiles/**')
-        }
-    }
-}
-
-task userguideSrc(type: UserGuideTransformTask, dependsOn: samples) {
-    sourceFile = new File(userguideSrcDir, 'userguide.xml')
-    destFile = new File(docbookSrc, 'userguide.xml')
-    snippetsDir = project.snippetsDir
-    classpath = configurations.userGuideTask
-    validator = new SampleElementValidator()
-}
-userguideSrc.doFirst {
-    userguideSrc.javadocUrl = "http://www.gradle.org/${javadocRemoteDir}"
-    userguideSrc.groovydocUrl = "http://www.gradle.org/${groovydocRemoteDir}"
-}
-userguideSrc.skipProperties << 'skip.userguide'
-
-task userguideStyleSheets << {
-    ant.unzip(src: configurations.userGuideStyleSheets.singleFile, dest: docbookDir) {
-        globmapper(from: 'docbook-xsl-1.74.3/*', to: '*')
-    }
-    ant.copy(todir: docbookDir) {
-        fileset(dir: new File(srcDocsDir, 'stylesheets'), includes: '*.xsl')
-    }
-}
-userguideStyleSheets.skipProperties << 'skip.userguide'
-
-task userguideHtml(dependsOn: [userguideSrc, userguideStyleSheets]) << {
-    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
-        arg(value: '-in')
-        arg(value: new File(docbookSrc, 'userguide.xml'))
-        arg(value: '-xsl')
-        arg(value: new File(docbookDir, 'userGuideHtml.xsl'))
-        arg(line: "-param base.dir ${userguideHtmlDir}/")
-        classpath {
-            path(path: configurations.userGuideTask.asPath)
-            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
-        }
-    }
-    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: userguideHtmlDir)
-}
-userguideHtml.skipProperties << 'skip.userguide'
-
-task userguideSingleHtml(dependsOn: [userguideSrc, userguideStyleSheets]) << {
-    userguideSingleHtmlFile.parentFile.mkdirs()
-    
-    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
-        arg(value: '-in')
-        arg(value: new File(docbookSrc, 'userguide.xml'))
-        arg(value: '-out')
-        arg(value: userguideSingleHtmlFile)
-        arg(value: '-xsl')
-        arg(value: new File(docbookDir, 'userGuideSingleHtml.xsl'))
-        classpath {
-            path(path: configurations.userGuideTask.asPath)
-            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
-        }
-    }
-    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: userguideSingleHtmlFile.parentFile)
-    ant.copy(file: new File(userguideSrcDir, 'print.css'), todir: userguideSingleHtmlFile.parentFile)
-}
-userguideSingleHtml.skipProperties << 'skip.userguide'
-
-task userguidePdf(dependsOn: [userguideSrc, userguideStyleSheets]) << {
-    File pdfSourceHtml = new File(docbookSrc, 'userguidePdf.html')
-
-    pdfSourceHtml.parentFile.mkdirs()
-    userguidePdfFile.parentFile.mkdirs()
-
-    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
-        arg(value: '-in')
-        arg(value: new File(docbookSrc, 'userguide.xml'))
-        arg(value: '-out')
-        arg(value: pdfSourceHtml)
-        arg(value: '-xsl')
-        arg(value: new File(docbookDir, 'userGuidePdf.xsl'))
-        classpath {
-            path(path: configurations.userGuideTask.asPath)
-            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
-        }
-    }
-    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: pdfSourceHtml.parentFile)
-    ant.copy(file: new File(userguideSrcDir, 'print.css'), todir: pdfSourceHtml.parentFile)
-
-    def uris = configurations.userGuideTask.files.collect {it.toURI().toURL()}
-    def classloader = new URLClassLoader(uris as URL[], getClass().classLoader)
-    def renderer = classloader.loadClass('org.xhtmlrenderer.pdf.ITextRenderer').newInstance()
-    renderer.setDocument(pdfSourceHtml)
-    renderer.layout()
-
-    userguidePdfFile.withOutputStream {
-        renderer.createPDF(it)
-    }
-}
-userguidePdf.skipProperties << 'skip.userguide'
-
-task uploadDocs(dependsOn: [userguide, javadoc, groovydoc]) << {
-    ftp(action: 'mkdir', remotedir: docsRemoteDir)
-    ftp(action: 'delete', remotedir: docsRemoteDir) {
-        fileset() {
-            include(name: '**/*')
-        }
-    }
-    ftp(action: 'send', remotedir: docsRemoteDir) {
-        fileset(dir: explodedDistDocsDir)
-    }
-}
-
-task distDocs(type: UserGuideTransformTask, dependsOn: userguideStyleSheets) {
-    standalone = true
-    sourceFile = new File(userguideSrcDir, 'gettingStarted.xml')
-    destFile = new File(docbookSrc, 'gettingStarted.xml')
-    snippetsDir = project.snippetsDir
-    classpath = configurations.userGuideTask
-}
-distDocs.doFirst {
-    distDocs.javadocUrl = "http://www.gradle.org/${javadocRemoteDir}"
-    distDocs.groovydocUrl = "http://www.gradle.org/${groovydocRemoteDir}"
-}
-distDocs << {
-    explodedDistDir.mkdirs()
-
-    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: docbookDir)
-    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
-        arg(value: '-in')
-        arg(value: new File(docbookSrc , 'gettingStarted.xml'))
-        arg(value: '-out')
-        arg(value: new File(explodedDistDir, 'getting-started.html'))
-        arg(value: '-xsl')
-        arg(value: new File(docbookDir, 'standaloneHtml.xsl'))
-        classpath {
-            path(path: configurations.userGuideTask.asPath)
-            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
-        }
-    }
-}
-
-task websiteDocs(type: UserGuideTransformTask, dependsOn: userguideStyleSheets) {
-    standalone = true
-    sourceFile = new File(userguideSrcDir, 'gettingStarted.xml')
-    destFile = new File(docbookSrc, 'gettingStarted.xml')
-    snippetsDir = project.snippetsDir
-    classpath = configurations.userGuideTask
-}
-websiteDocs.doFirst {
-    websiteDocs.javadocUrl = "http://www.gradle.org/${javadocRemoteDir}"
-    websiteDocs.groovydocUrl = "http://www.gradle.org/${groovydocRemoteDir}"
-}
-websiteDocs << {
-    File websiteDocs = new File(buildDir, 'docs')
-    websiteDocs.mkdirs()
-
-    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
-        arg(value: '-in')
-        arg(value: new File(docbookSrc , 'gettingStarted.xml'))
-        arg(value: '-out')
-        arg(value: new File(websiteDocs, 'getting-started.html'))
-        arg(value: '-xsl')
-        arg(value: new File(docbookDir, 'docFragment.xsl'))
-        classpath {
-            path(path: configurations.userGuideTask.asPath)
-            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
-        }
-    }
-}
-
-// The integtests depend on dists because of the wrapper test, and userguideSrc because of the int test generated from
-// the userguide source
-integTestDistDir = new File(buildDir, 'integtest')
-task integTest(type: Test, dependsOn: [explodedDist, binZip, userguideSrc]) {
-    options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea"])
-    options.systemProperties['integTest.gradleHomeDir'] = integTestDistDir.absolutePath
-    options.systemProperties['integTest.srcDir'] = file('src').absolutePath
-    options.systemProperties['integTest.userGuideInfoDir'] = docbookSrc.absolutePath
-
-    include 'org/gradle/integtests/**/*IntegrationTest.*'
-    exclude '**/Abstract*'
-}
-integTest.doFirst {
-    ant {
-        copy(todir: integTestDistDir) {
-            fileset(dir: explodedDistDir )
-        }
-        chmod(dir: "$integTestDistDir/bin", perm: "ugo+rx", includes: "**/*")
-    }
-}
-
-task nightlyBuild(dependsOn: [integTest, uploadDocs])
-
-task install(dependsOn: integTest, description: 'Installs the distribution into directory $gradle_installPath') << {
-    ant.delete(dir: installDir)
-    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
-        windowsInstall()
-    } else {
-        asternixInstall()
-    }
-    ant.move(file: "${installDir.parentFile}/$zipRootFolder", tofile: installDir)
-}
-
-build.taskGraph.whenReady { graph ->
-    if (graph.hasTask(install)) {
-        // Do this early to ensure that the properties we need have been set, and fail early
-        installDir = file("$gradle_installPath")
-        if (installDir.file) {
-            throw new RuntimeException("Install directory $installDir does not look like a Gradle installation. Cannot delete it to install.")
-        }
-        if (installDir.directory) {
-            File libDir = new File(installDir, "lib")
-            if (!libDir.directory || !libDir.list().findAll { it.matches('gradle.*\\.jar')}) {
-                throw new RuntimeException("Install directory $installDir does not look like a Gradle installation. Cannot delete it to install.")
-            }
-        }
-    }
-}
-
-void windowsInstall() {
-    ant.unzip(src: binZip.archivePath, dest: installDir.parentFile)
-}
-
-/**
- * We can't use the Ant unzip task, as this task does not preserve the *nix file system permissions of the Gradle zip.
- */
-void asternixInstall() {
-    ant.exec(executable: "unzip") {
-        arg(value: '-q')
-        arg(value: '-d')
-        arg(value: installDir.parentFile)
-        arg(value: "${binZip.archivePath}")
-    }
-}
-
-uploadDists {
-    dependsOn 'integTest'
-}.doFirst {
-    it.repositories.add(new WebdavResolver()) {
-        name = 'gradleReleases'
-        user = codehausUserName
-        userPassword = codehausUserPassword
-        addArtifactPattern("$distributionUploadUrl/[artifact]-[revision](-[classifier]).[ext]" as String)
-    }
-}
-build.taskGraph.whenReady {graph ->
-    if (graph.hasTask(uploadDists)) {
-        // check properties defined and fail early
-        codehausUserName
-        codehausUserPassword
-    }
-}
-
-task developerBuild(dependsOn: [clean, integTest])
-
-task ide << {
-    def libDir = file('lib')
-    ant.delete(dir: libDir)
-    [configurations.runtime, configurations.testRuntime].each {config ->
-        config.files.each {file ->
-            ant.copy(file: file, todir: libDir)
-        }
-    }
-}
-
-task release(dependsOn: [uploadDists, uploadDocs]) << {
-    svn.release()
-}
-
-task wrapper(type: Wrapper, dependsOn: binZip) << {task ->
-    task.configure {
-        gradleVersion = customWrapperVersion ?: version
-        jarPath = 'wrapper'
-    }
-}
-
-task rebuildWrapper(dependsOn: [clean, wrapper])
-
-void ftp(Map args, Closure antFileset = {}) {
-    ant {
-        taskdef(name: 'ftp',
-                classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
-                classpath: configurations.ftpAntTask.asPath)
-        Map ftpArgs = args + [
-                server: 'ftp.gradle.org',
-                userid: websiteFtpUserName,
-                password: websiteFtpUserPassword
-        ]
-        delegate.ftp(ftpArgs) {
-            antFileset.delegate = delegate
-            antFileset()
-        }
-    }
-}
+import java.text.DateFormat
+import java.text.SimpleDateFormat
+import java.util.jar.Attributes
+import org.apache.tools.ant.taskdefs.condition.Os
+import org.gradle.api.Task
+import org.gradle.api.artifacts.repositories.WebdavResolver
+import org.gradle.api.tasks.testing.ForkMode
+import org.gradle.api.tasks.wrapper.Wrapper
+import org.gradle.build.release.Svn
+import org.gradle.build.release.Version
+import org.gradle.build.samples.WrapperProjectCreator
+import org.gradle.build.startscripts.StartScriptsGenerator
+import org.gradle.util.GradleVersion
+import org.apache.ivy.plugins.resolver.*
+import org.gradle.build.docs.UserGuideTransformTask
+import org.gradle.build.docs.ExtractSnippetsTask
+import org.gradle.build.docs.SampleElementValidator
+
+/**
+ * For building Gradle you usually don't need to specify any properties. Only certain functionality of the Gradle requires
+ * 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 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
+ * Creating a JDK-1.4 compatible distribtution with retro-translator: gradle_retroLibsDir (This dir shoud contain rt.jar, jce.jar and jsse.jar from
+ * a JDK 1.4).
+ */
+
+defaultTasks "clean", "dists"
+
+usePlugin('groovy')
+
+archivesBaseName = 'gradle'
+
+sourceCompatibility = 1.5
+targetCompatibility = 1.5
+
+svn = new Svn(project)
+
+type = 'jar'
+version = new Version(svn, project, false)
+group = 'org.gradle'
+buildTime = new Date()
+versionModifier = null
+
+repositories {
+    mavenCentral()
+    add(new URLResolver()) {
+        name = 'sf_gradleRepo'
+        addArtifactPattern('http://gradle.sourceforge.net/gradleRepo/[organisation]/[module](/[branch])/[type]s/[artifact]-[revision](-[classifier])(.[ext])')
+    }
+}
+
+configurations {
+    distLib {
+        visible = false
+        extendsFrom getByName('default')
+    }
+    ftpAntTask
+    retrotranslatorAntTask
+    userGuideStyleSheets
+    userGuideTask
+}
+
+dependencies {
+
+    // todo: Improve dependency handling for xUnit jars
+    ftpAntTask module("org.apache.ant:ant-commons-net:1.7.0") {
+        module("commons-net:commons-net:1.4.1") {
+            dependencies("oro:oro:2.0.8@jar")
+        }
+    }
+
+    retrotranslatorAntTask 'net.sf.retrotranslator:retrotranslator-runtime:1.2.7@jar', 'net.sf.retrotranslator:retrotranslator-transformer:1.2.7@jar',
+            'backport-util-concurrent:backport-util-concurrent:3.1@jar'
+
+    userGuideTask 'xalan:xalan:2.7.1', 'xerces:xercesImpl:2.9.1'
+    userGuideTask module('xhtmlrenderer:xhtmlrenderer:R8rc1') {
+        dependency 'itext:itext:2.0.8@jar'
+    }
+
+    userGuideStyleSheets 'docbook:docbook-xsl:1.74.3@zip'
+
+    groovy module("org.codehaus.groovy:groovy-all:1.6.3") {
+        module("org.apache.ant:ant:1.7.0") {
+            dependencies("org.apache.ant:ant-junit:1.7.0@jar", "org.apache.ant:ant-launcher:1.7.0@jar")
+        }
+    }
+
+    compile module("commons-httpclient:commons-httpclient:3.0") {
+        dependencies("commons-codec:commons-codec:1.2@jar", "org.slf4j:jcl-over-slf4j:1.5.3@jar")
+    }
+
+    // Needed by the eclipse plugin
+    compile module("dom4j:dom4j:1.6.1") {
+        dependencies("jaxen:jaxen:1.1@jar")
+    }
+
+    compile "org.mortbay.jetty:jetty-plus:6.1.14@jar",
+            "org.mortbay.jetty:jetty-util:6.1.14@jar",
+            "javax.servlet:servlet-api:2.5@jar"
+
+    compile module("org.mortbay.jetty:jetty:6.1.14") {
+        // todo - these should be runtime dependencies
+        dependencies("javax.servlet:servlet-api:2.5@jar",
+                "org.apache.ant:ant:1.7.0@jar",
+                // todo jsp stuff should be a module
+                "org.mortbay.jetty:jsp-api-2.1:6.1.14@jar",
+                "org.mortbay.jetty:jsp-2.1:6.1.14@jar",
+                "org.eclipse.jdt:core:3.1.1@jar",
+                "org.mortbay.jetty:jetty-util:6.1.14@jar",
+                "org.mortbay.jetty:jetty-naming:6.1.14@jar",
+                "org.mortbay.jetty:jetty-annotations:6.1.14@jar")
+    }
+
+    compile module("org.apache.ivy:ivy:2.1.0-rc1") {
+        dependencies("jsch:jsch:0.1.31")
+    }
+
+    // add tools.jar to the compile time classpath.  Needed by DebugHelper.java.
+    compile files(System.getProperty('tools.jar'))
+  
+    compile "net.sf.jopt-simple:jopt-simple:2.4.1@jar",
+            "org.apache.ant:ant:1.7.0@jar",
+            "ch.qos.logback:logback-classic:0.9.9@jar",
+            "org.slf4j:slf4j-api:1.5.3@jar",
+            "ch.qos.logback:logback-core:0.9.9@jar",
+            "commons-io:commons-io:1.4@jar",
+            "commons-lang:commons-lang:2.3@jar",
+            "commons-codec:commons-codec:1.2@jar",
+            "slide:webdavlib:2.0@jar",
+            "biz.aQute:bndlib:0.0.255@jar",
+            "org.apache.maven:maven-ant-tasks:2.0.9@jar",
+            "asm:asm-all:2.2.3@jar"
+
+    runtime "org.apache.ant:ant-junit:1.7.0@jar",
+            "org.apache.ant:ant-launcher:1.7.0@jar",
+            "org.apache.ant:ant-nodeps:1.7.0@jar",
+            "org.apache.ant:ant-trax:1.7.0@jar",
+            "junit:junit:4.5"
+
+    def FIRST_LEVEL_JMOCK = ['org.hamcrest:hamcrest-core:1.1@jar', 'org.hamcrest:hamcrest-library:1.1@jar', 'org.jmock:jmock-junit4:2.4.0@jar']
+    testCompile "junit:junit:4.5", "xmlunit:xmlunit:1.2", FIRST_LEVEL_JMOCK
+    testCompile module("org.jmock:jmock:2.4.0") {
+        dependencies('org.jmock:jmock-legacy:2.4.0@jar', 'org.objenesis:objenesis:1.0', 'cglib:cglib-nodep:2.1_3')
+        dependencies(FIRST_LEVEL_JMOCK as Object[])
+    }
+    // todo - these should not be here
+    testCompile 'org.jmock:jmock-legacy:2.4.0@jar', 'org.objenesis:objenesis:1.0', 'cglib:cglib-nodep:2.1_3'
+    distLib "junit:junit:4.5"
+}
+
+distributionUploadUrl = null
+docsRemoteDir = ''
+javadocRemoteDir = ''
+groovydocRemoteDir = ''
+build.taskGraph.whenReady {graph ->
+    String prefix = ''
+    if (graph.hasTask(':release')) {
+        versionModifier = ''
+        distributionUploadUrl = 'https://dav.codehaus.org/dist/gradle'
+        prefix = version as String
+    } else {
+        versionModifier = new SimpleDateFormat('yyyyMMddHHmmssZ').format(buildTime)
+        distributionUploadUrl = 'https://dav.codehaus.org/snapshots.dist/gradle'
+        prefix = 'latest'
+    }
+    docsRemoteDir = prefix + '/docs'
+    javadocRemoteDir = docsRemoteDir + '/javadoc'
+    groovydocRemoteDir = docsRemoteDir + '/groovydoc'
+    manifest.mainAttributes([
+            (Attributes.Name.IMPLEMENTATION_TITLE.toString()): 'Gradle',
+            (Attributes.Name.IMPLEMENTATION_VERSION.toString()): version.toString(),
+    ])
+}
+
+processResources.doLast {
+    File versionPropertiesDestination = new File(classesDir, GradleVersion.FILE_NAME)
+    logger.info('Write version properties to: {}', versionPropertiesDestination.absoluteFile)
+    Properties versionProperties = new Properties()
+    versionProperties.putAll([
+            (GradleVersion.VERSION): version.toString(),
+            (GradleVersion.BUILD_TIME): DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(buildTime)
+    ])
+    versionProperties.store(new FileOutputStream(versionPropertiesDestination), '')
+}
+
+[compile, compileTests]*.groovyOptions*.fork(memoryInitialSize: '128M', memoryMaximumSize: '1G')
+
+test {
+    // We set forkmode to ONCE as our tests are written in Groovy and the startup time of Groovy is significant.
+    options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea", '-Xms128m', '-Xmx1g', '-XX:MaxPermSize=128m', '-XX:+HeapDumpOnOutOfMemoryError'])
+
+    exclude 'org/gradle/integtests/**/*IntegrationTest.*'
+}
+
+task wrapperJar(type: Jar) {
+    appendix = 'wrapper'
+    fileSet(dir: classesDir) {
+        include 'org/gradle/wrapper/'
+    }
+    manifest.mainAttributes("Main-Class": 'org.gradle.wrapper.WrapperMain')
+}
+
+jar.manifest.mainAttributes("Main-Class": "org.gradle.BootstrapMain")
+
+explodedDistDir = new File(distsDir, 'exploded')
+explodedDistDocsDir = new File(explodedDistDir, 'docs')
+explodedDistJavadocsDir = new File(explodedDistDocsDir, 'javadoc')
+explodedDistGroovydocsDir = new File(explodedDistDocsDir, 'groovydoc')
+explodedDistSamplesDir = new File(explodedDistDir, 'samples')
+explodedDistLibDir = new File(explodedDistDir, 'lib')
+samplesSrcDir = new File(srcRoot, 'samples')
+userguideOutputDir = new File(samplesSrcDir, 'userguideOutput')
+
+task explodedDistBase(dependsOn: [libs, javadoc, groovydoc]) << {
+    [explodedDistDir, explodedDistSamplesDir, explodedDistLibDir]*.mkdirs()
+    File explodedDistBinDir = mkdir(explodedDistDir, 'bin')
+    File explodedDistSrcDir = mkdir(explodedDistDir, 'src')
+
+    ant {
+        logger.info('Generate lib dir')
+        configurations.distLib.each {File file ->
+            copy(file: file, todir: explodedDistLibDir)
+        }
+        // todo: find out why Ivy does not include the jar in the resolve
+        delete { fileset(dir:explodedDistLibDir, includes:"$archivesBaseName-*.jar") }
+        copy(file: jar.archivePath, toDir: explodedDistLibDir)
+        copy(file: wrapperJar.archivePath, toDir: explodedDistLibDir)
+        logger.info('Generate start scripts')
+        StartScriptsGenerator.generate("$archivesBaseName-${version}.jar", explodedDistBinDir, archivesBaseName)
+        logger.info('Generate and copy samples.')
+        WrapperProjectCreator.createProject(explodedDistSamplesDir, binZip.archivePath.parentFile,
+                version.toString())
+        logger.info('Copy binary sources.')
+        copy(toDir: explodedDistSrcDir) {
+            (srcDirs + resourceDirs + groovySrcDirs).findAll {it.isDirectory()}.each {dir -> fileset(dir: dir)}
+        }
+        logger.info('Copy and generate top level files.')
+        copy(toDir: explodedDistDir) {fileset(dir: new File(srcRoot, 'toplevel'))}
+        // Set permissions (important for running integration tests against the exploded dist)
+        chmod(dir: "$explodedDistDir/bin", perm: "ugo+rx", includes: "**/*")
+    }
+}
+
+task explodedDist(dependsOn: [explodedDistBase, 'userguide', 'distDocs'])
+
+zipRootFolder = "$archivesBaseName-${-> version}"
+
+distsRetroLibsFolder = new File(distsDir, 'retroLibs')
+
+task retroTranslateLibs(dependsOn: explodedDist) << {
+    distsRetroLibsFolder.mkdirs()
+    ant {
+        taskdef(name: "retrotranslator", classname: "net.sf.retrotranslator.transformer.RetrotranslatorTask",
+                classpath: configurations.retrotranslatorAntTask.asPath)
+        List libFiles = explodedDistLibDir.listFiles()
+        File logbackCore = libFiles.find { it.name.startsWith('logback-core') }
+        File logbackClassic = libFiles.find { it.name.startsWith('logback-classic') }
+        File gradle = libFiles.find { it.name.startsWith('gradle-') && !it.name.startsWith('gradle-wrapper') }
+        File gradleWrapper = libFiles.find { it.name.startsWith('gradle-wrapper')}
+        List retroFiles = [logbackCore, logbackClassic, gradle, gradleWrapper]
+        String libExcludes = retroFiles.join(',')
+        retroFiles.each {File file ->
+            retroExe(file) {
+                fileset(dir: distsRetroLibsFolder)
+                fileset(dir: explodedDistLibDir, excludes: libExcludes)
+                fileset(dir: gradle_retroLibsDir)
+            }
+        }
+    }
+}
+retroTranslateLibs {
+    enabled = project.hasProperty('gradle_retroLibsDir')
+    skipProperties << 'skip.archive_all-jdk14_zip'
+}
+
+void retroExe(File file, Closure fileSet) {
+    ant {
+        retrotranslator(target: "1.4", destjar: new File(distsRetroLibsFolder, file.name), smart: true, verify: false, failonwarning: false) {
+            jarfileset(dir: explodedDistLibDir, includes: file.name)
+            classpath() {
+                fileset(dir: gradle_retroLibsDir)
+                fileSet.delegate = delegate
+                fileSet()
+            }
+        }
+    }
+}
+
+Closure binFileSets = {task ->
+    delegate = task
+    zipFileSet(dir: explodedDistDir, prefix: zipRootFolder, fileMode: '775') {
+        include 'bin/*'
+        exclude 'bin/*.*'
+    }
+    zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
+        include 'bin/*.*'
+    }
+}
+
+task allZip(type: Zip) {
+    dependsOn explodedDist
+    classifier = 'all'
+}
+allZip.doFirst {task ->
+    task.configure {
+        zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
+            exclude 'bin/*'
+        }
+        binFileSets(delegate)
+    }
+}
+
+task binZip(type: Zip) {
+    dependsOn explodedDist
+    classifier = 'bin'
+}
+binZip.doFirst {task ->
+    task.configure {
+        zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
+            exclude 'bin/*'
+            exclude 'src/'
+            exclude 'samples/'
+        }
+        binFileSets(delegate)
+    }
+}
+
+task srcZip(type: Zip) {
+    dependsOn explodedDist
+    classifier = 'src'
+}
+srcZip.doFirst {task ->
+    task.configure {
+        zipFileSet(dir: projectDir, prefix: zipRootFolder, fileMode: '775') {
+            include 'gradlew'
+        }
+        zipFileSet(dir: projectDir, prefix: zipRootFolder) {
+            include 'buildSrc/', 'wrapper/', 'lib/', 'src/', 'gradle.properties', 'build.gradle', 'gradlew.bat'
+        }
+    }
+}
+
+task jdk14AllZip(type: Zip) {
+    dependsOn retroTranslateLibs, explodedDist
+    classifier = 'all-jdk14'
+    enabled = project.hasProperty('gradle_retroLibsDir')
+}
+jdk14AllZip.doFirst {Task task ->
+    task.configure {
+        zipFileSet(dir: explodedDistDir, prefix: zipRootFolder) {
+            exclude 'bin/*'
+            exclude 'lib/gradle*.jar'
+            exclude 'lib/logback*.jar'
+        }
+        zipFileSet(dir: distsRetroLibsFolder, prefix: "$zipRootFolder/lib")
+        configurations.retrotranslatorAntTask.each {File file ->
+            zipFileSet(dir: file.parentFile, prefix: "$zipRootFolder/lib") {
+                include file.name
+            }
+        }
+        binFileSets(delegate)
+    }
+}
+
+artifacts {
+    tasks.findAll {task -> task.name.matches('.*Zip') }.each {
+        dists it
+    }
+}
+
+groovydoc.destinationDir = explodedDistGroovydocsDir
+
+javadoc {
+    dependsOn compile
+    destinationDir = explodedDistJavadocsDir
+    // todo: include only the public packages
+    options.subPackages 'org.gradle'
+    exclude 'org.gradle.api.internal'
+    // todo: make this true
+    failOnError = false
+}
+javadoc.doFirst {
+    javadoc.title = "Gradle API $version"
+    javadoc.options.docTitle = javadoc.title
+}
+
+srcDocsDir = file('src/docs')
+userguideDir = new File(buildDir, "$docsDir.name/userguide")
+userguideSrcDir = new File(srcDocsDir, 'userguide')
+userguideHtmlDir = new File(explodedDistDocsDir, 'userguide')
+userguidePdfFile = new File(userguideHtmlDir, 'userguide.pdf')
+userguideSingleHtmlFile = new File(userguideHtmlDir, 'userguide_single.html')
+docbookSrc = new File(project.buildDir, 'docbook/src')
+docbookDir = new File(project.buildDir, 'docbook/stylesheets')
+snippetsDir = new File(project.buildDir, 'docbook/snippets')
+
+task userguide(dependsOn: ['userguideHtml', 'userguideSingleHtml', 'userguidePdf'], description: 'Generates the userguide')
+
+task samples(type: ExtractSnippetsTask) {
+    sourceFiles = ant.fileset(dir: samplesSrcDir) {
+        exclude(name: 'userguideOutput/**')
+        exclude(name: 'userguide/tutorial/antChecksumFiles/**')
+    }
+    destDir = explodedDistSamplesDir
+    snippetsDir = project.snippetsDir
+}
+samples << {
+    ant.copy(todir: explodedDistSamplesDir) {
+        fileset(dir: samplesSrcDir) {
+            include(name: 'userguide/tutorial/antChecksumFiles/**')
+        }
+    }
+}
+
+task userguideSrc(type: UserGuideTransformTask, dependsOn: samples) {
+    sourceFile = new File(userguideSrcDir, 'userguide.xml')
+    destFile = new File(docbookSrc, 'userguide.xml')
+    snippetsDir = project.snippetsDir
+    classpath = configurations.userGuideTask
+    validator = new SampleElementValidator()
+}
+userguideSrc.doFirst {
+    userguideSrc.javadocUrl = "http://www.gradle.org/${javadocRemoteDir}"
+    userguideSrc.groovydocUrl = "http://www.gradle.org/${groovydocRemoteDir}"
+}
+userguideSrc.skipProperties << 'skip.userguide'
+
+task userguideStyleSheets << {
+    ant.unzip(src: configurations.userGuideStyleSheets.singleFile, dest: docbookDir) {
+        globmapper(from: 'docbook-xsl-1.74.3/*', to: '*')
+    }
+    ant.copy(todir: docbookDir) {
+        fileset(dir: new File(srcDocsDir, 'stylesheets'), includes: '*.xsl')
+    }
+}
+userguideStyleSheets.skipProperties << 'skip.userguide'
+
+task userguideHtml(dependsOn: [userguideSrc, userguideStyleSheets]) << {
+    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
+        arg(value: '-in')
+        arg(value: new File(docbookSrc, 'userguide.xml'))
+        arg(value: '-xsl')
+        arg(value: new File(docbookDir, 'userGuideHtml.xsl'))
+        arg(line: "-param base.dir ${userguideHtmlDir}/")
+        classpath {
+            path(path: configurations.userGuideTask.asPath)
+            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
+        }
+    }
+    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: userguideHtmlDir)
+}
+userguideHtml.skipProperties << 'skip.userguide'
+
+task userguideSingleHtml(dependsOn: [userguideSrc, userguideStyleSheets]) << {
+    userguideSingleHtmlFile.parentFile.mkdirs()
+    
+    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
+        arg(value: '-in')
+        arg(value: new File(docbookSrc, 'userguide.xml'))
+        arg(value: '-out')
+        arg(value: userguideSingleHtmlFile)
+        arg(value: '-xsl')
+        arg(value: new File(docbookDir, 'userGuideSingleHtml.xsl'))
+        classpath {
+            path(path: configurations.userGuideTask.asPath)
+            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
+        }
+    }
+    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: userguideSingleHtmlFile.parentFile)
+    ant.copy(file: new File(userguideSrcDir, 'print.css'), todir: userguideSingleHtmlFile.parentFile)
+}
+userguideSingleHtml.skipProperties << 'skip.userguide'
+
+task userguidePdf(dependsOn: [userguideSrc, userguideStyleSheets]) << {
+    File pdfSourceHtml = new File(docbookSrc, 'userguidePdf.html')
+
+    pdfSourceHtml.parentFile.mkdirs()
+    userguidePdfFile.parentFile.mkdirs()
+
+    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
+        arg(value: '-in')
+        arg(value: new File(docbookSrc, 'userguide.xml'))
+        arg(value: '-out')
+        arg(value: pdfSourceHtml)
+        arg(value: '-xsl')
+        arg(value: new File(docbookDir, 'userGuidePdf.xsl'))
+        classpath {
+            path(path: configurations.userGuideTask.asPath)
+            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
+        }
+    }
+    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: pdfSourceHtml.parentFile)
+    ant.copy(file: new File(userguideSrcDir, 'print.css'), todir: pdfSourceHtml.parentFile)
+
+    def uris = configurations.userGuideTask.files.collect {it.toURI().toURL()}
+    def classloader = new URLClassLoader(uris as URL[], getClass().classLoader)
+    def renderer = classloader.loadClass('org.xhtmlrenderer.pdf.ITextRenderer').newInstance()
+    renderer.setDocument(pdfSourceHtml)
+    renderer.layout()
+
+    userguidePdfFile.withOutputStream {
+        renderer.createPDF(it)
+    }
+}
+userguidePdf.skipProperties << 'skip.userguide'
+
+task uploadDocs(dependsOn: [userguide, javadoc, groovydoc]) << {
+    ftp(action: 'mkdir', remotedir: docsRemoteDir)
+    ftp(action: 'delete', remotedir: docsRemoteDir) {
+        fileset() {
+            include(name: '**/*')
+        }
+    }
+    ftp(action: 'send', remotedir: docsRemoteDir) {
+        fileset(dir: explodedDistDocsDir)
+    }
+}
+
+task distDocs(type: UserGuideTransformTask, dependsOn: userguideStyleSheets) {
+    standalone = true
+    sourceFile = new File(userguideSrcDir, 'gettingStarted.xml')
+    destFile = new File(docbookSrc, 'gettingStarted.xml')
+    snippetsDir = project.snippetsDir
+    classpath = configurations.userGuideTask
+}
+distDocs.doFirst {
+    distDocs.javadocUrl = "http://www.gradle.org/${javadocRemoteDir}"
+    distDocs.groovydocUrl = "http://www.gradle.org/${groovydocRemoteDir}"
+}
+distDocs << {
+    explodedDistDir.mkdirs()
+
+    ant.copy(file: new File(userguideSrcDir, 'style.css'), todir: docbookDir)
+    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
+        arg(value: '-in')
+        arg(value: new File(docbookSrc , 'gettingStarted.xml'))
+        arg(value: '-out')
+        arg(value: new File(explodedDistDir, 'getting-started.html'))
+        arg(value: '-xsl')
+        arg(value: new File(docbookDir, 'standaloneHtml.xsl'))
+        classpath {
+            path(path: configurations.userGuideTask.asPath)
+            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
+        }
+    }
+}
+
+task websiteDocs(type: UserGuideTransformTask, dependsOn: userguideStyleSheets) {
+    standalone = true
+    sourceFile = new File(userguideSrcDir, 'gettingStarted.xml')
+    destFile = new File(docbookSrc, 'gettingStarted.xml')
+    snippetsDir = project.snippetsDir
+    classpath = configurations.userGuideTask
+}
+websiteDocs.doFirst {
+    websiteDocs.javadocUrl = "http://www.gradle.org/${javadocRemoteDir}"
+    websiteDocs.groovydocUrl = "http://www.gradle.org/${groovydocRemoteDir}"
+}
+websiteDocs << {
+    File websiteDocs = new File(buildDir, 'docs')
+    websiteDocs.mkdirs()
+
+    ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true) {
+        arg(value: '-in')
+        arg(value: new File(docbookSrc , 'gettingStarted.xml'))
+        arg(value: '-out')
+        arg(value: new File(websiteDocs, 'getting-started.html'))
+        arg(value: '-xsl')
+        arg(value: new File(docbookDir, 'docFragment.xsl'))
+        classpath {
+            path(path: configurations.userGuideTask.asPath)
+            path(location: new File(docbookDir, 'extensions/xalan27.jar'))
+        }
+    }
+}
+
+// The integtests depend on dists because of the wrapper test, and userguideSrc because of the int test generated from
+// the userguide source
+integTestDistDir = new File(buildDir, 'integtest')
+task integTest(type: Test, dependsOn: [explodedDist, binZip, userguideSrc]) {
+    options.fork(forkMode: ForkMode.ONCE, jvmArgs: ["-ea"])
+    options.systemProperties['integTest.gradleHomeDir'] = integTestDistDir.absolutePath
+    options.systemProperties['integTest.srcDir'] = file('src').absolutePath
+    options.systemProperties['integTest.userGuideInfoDir'] = docbookSrc.absolutePath
+
+    include 'org/gradle/integtests/**/*IntegrationTest.*'
+    exclude '**/Abstract*'
+}
+integTest.doFirst {
+    ant {
+        copy(todir: integTestDistDir) {
+            fileset(dir: explodedDistDir )
+        }
+        chmod(dir: "$integTestDistDir/bin", perm: "ugo+rx", includes: "**/*")
+    }
+}
+
+task nightlyBuild(dependsOn: [integTest, uploadDocs])
+
+task install(dependsOn: integTest, description: 'Installs the distribution into directory $gradle_installPath') << {
+    ant.delete(dir: installDir)
+    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
+        windowsInstall()
+    } else {
+        asternixInstall()
+    }
+    ant.move(file: "${installDir.parentFile}/$zipRootFolder", tofile: installDir)
+}
+
+build.taskGraph.whenReady { graph ->
+    if (graph.hasTask(install)) {
+        // Do this early to ensure that the properties we need have been set, and fail early
+        installDir = file("$gradle_installPath")
+        if (installDir.file) {
+            throw new RuntimeException("Install directory $installDir does not look like a Gradle installation. Cannot delete it to install.")
+        }
+        if (installDir.directory) {
+            File libDir = new File(installDir, "lib")
+            if (!libDir.directory || !libDir.list().findAll { it.matches('gradle.*\\.jar')}) {
+                throw new RuntimeException("Install directory $installDir does not look like a Gradle installation. Cannot delete it to install.")
+            }
+        }
+    }
+}
+
+void windowsInstall() {
+    ant.unzip(src: binZip.archivePath, dest: installDir.parentFile)
+}
+
+/**
+ * We can't use the Ant unzip task, as this task does not preserve the *nix file system permissions of the Gradle zip.
+ */
+void asternixInstall() {
+    ant.exec(executable: "unzip") {
+        arg(value: '-q')
+        arg(value: '-d')
+        arg(value: installDir.parentFile)
+        arg(value: "${binZip.archivePath}")
+    }
+}
+
+uploadDists {
+    dependsOn 'integTest'
+}.doFirst {
+    it.repositories.add(new WebdavResolver()) {
+        name = 'gradleReleases'
+        user = codehausUserName
+        userPassword = codehausUserPassword
+        addArtifactPattern("$distributionUploadUrl/[artifact]-[revision](-[classifier]).[ext]" as String)
+    }
+}
+build.taskGraph.whenReady {graph ->
+    if (graph.hasTask(uploadDists)) {
+        // check properties defined and fail early
+        codehausUserName
+        codehausUserPassword
+    }
+}
+
+task developerBuild(dependsOn: [clean, integTest])
+
+task ide << {
+    def libDir = file('lib')
+    ant.delete(dir: libDir)
+    [configurations.runtime, configurations.testRuntime].each {config ->
+        config.files.each {file ->
+            ant.copy(file: file, todir: libDir)
+        }
+    }
+}
+
+task release(dependsOn: [uploadDists, uploadDocs]) << {
+    svn.release()
+}
+
+task wrapper(type: Wrapper, dependsOn: binZip) << {task ->
+    task.configure {
+        gradleVersion = customWrapperVersion ?: version
+        jarPath = 'wrapper'
+    }
+}
+
+task rebuildWrapper(dependsOn: [clean, wrapper])
+
+void ftp(Map args, Closure antFileset = {}) {
+    ant {
+        taskdef(name: 'ftp',
+                classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
+                classpath: configurations.ftpAntTask.asPath)
+        Map ftpArgs = args + [
+                server: 'ftp.gradle.org',
+                userid: websiteFtpUserName,
+                password: websiteFtpUserPassword
+        ]
+        delegate.ftp(ftpArgs) {
+            antFileset.delegate = delegate
+            antFileset()
+        }
+    }
+}
Index: src/main/groovy/org/gradle/api/DebugHelper.java
===================================================================
--- src/main/groovy/org/gradle/api/DebugHelper.java	(revision 0)
+++ src/main/groovy/org/gradle/api/DebugHelper.java	(revision 0)
@@ -0,0 +1,81 @@
+/*=============================================================================
+                    AUTOMATED LOGIC CORPORATION
+            Copyright (c) 1999 - 2009 All Rights Reserved
+     This document contains confidential/proprietary information.
+===============================================================================
+
+   @(#)DebugHelper
+
+   Author(s) jmurph
+   $Log: $    
+=============================================================================*/
+package org.gradle;
+
+import org.gradle.api.internal.artifacts.dsl.AddSourceFileFieldForDebug;
+import org.gradle.groovy.scripts.FileScriptSource;
+
+import java.io.File;
+
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.Field;
+import com.sun.jdi.Value;
+import com.sun.jdi.StringReference;
+
+/**
+ * This class exists for use by external tools (IDEs) to support debugging
+ * of Gradle scripts.  Do not move or rename it as this will break such tools.
+ * Because such tools are expected to use reflection to access this class,
+ * changing the names or signatures of methods may also break such tools.
+ *
+ * By using this class, external tools can avoid making assumptions about the
+ * operation of Gradle, which means that Gradle can be modified without breaking
+ * the debugging support of such tools. 
+ */
+public class DebugHelper
+{
+    private DebugHelper() {}
+
+    /**
+     * Gradle compiles scripts into classes for execution within the Java VM.  A
+     * debugger needs to know what class name will be generated for a given script
+     * so that break points can be registered with the VM.
+     *
+     * @param scriptFile the script file for which the class name is desired.  Cannot
+     *        be null.
+     * @return the fully qualified class name of the generated script.  Currently
+     *         Gradle always generates scripts into the default package, but that
+     *         should not be assumed.  If the given scriptFile cannot be turned into
+     *         a class (because it does not exist, for example) then null is returned.
+     */
+    public static String getClassNameForScript(File scriptFile) {
+        assert scriptFile != null;
+
+        FileScriptSource source = new FileScriptSource("debug helper", scriptFile);
+        return source.getClassName();
+    }
+
+    /**
+     * For a class in the remote VM (using the Java Debugging APIs), determine the
+     * Gradle source script.  This allows a debugger to show the source file for
+     * the given reference type.
+     *
+     * @param refType The class in the remote VM.  Cannot be null.
+     * @return the script file for this class.  It is possible that the returned
+     *         file object does not represent a actual file (i.e. exists() might
+     *         return false).  If the script file cannot be determined, null is
+     *         returned.
+     */
+    public static File getScriptFromClass(ReferenceType refType) {
+        assert refType != null;
+
+        String sourceFileFieldName = AddSourceFileFieldForDebug.FIELD_NAME;
+        Field sourceFileField = refType.fieldByName(sourceFileFieldName);
+        if (sourceFileField == null)
+            return null;
+
+        Value sourceFileValue = refType.getValue(sourceFileField);
+        String sourceFilePath = ((StringReference)sourceFileValue).value();
+        return new File(sourceFilePath);
+    }
+}
+
Index: src/main/groovy/org/gradle/api/internal/artifacts/dsl/AddSourceFileFieldForDebug.java
===================================================================
--- src/main/groovy/org/gradle/api/internal/artifacts/dsl/AddSourceFileFieldForDebug.java	(revision 0)
+++ src/main/groovy/org/gradle/api/internal/artifacts/dsl/AddSourceFileFieldForDebug.java	(revision 0)
@@ -0,0 +1,35 @@
+/*=============================================================================
+                    AUTOMATED LOGIC CORPORATION
+            Copyright (c) 1999 - 2009 All Rights Reserved
+     This document contains confidential/proprietary information.
+===============================================================================
+
+   @(#)AddFieldForDebug
+
+   Author(s) jmurph
+   $Log: $    
+=============================================================================*/
+package org.gradle.api.internal.artifacts.dsl;
+
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+
+public class AddSourceFileFieldForDebug extends CompilationUnit.PrimaryClassNodeOperation
+{
+    public static final String FIELD_NAME = "__SOURCE_FILE";
+    private final String path;
+
+    public AddSourceFileFieldForDebug(String path) {
+        this.path = path;
+    }
+
+    public void call(SourceUnit sourceUnit, GeneratorContext generatorContext, ClassNode classNode) throws CompilationFailedException {
+        classNode.addField(FIELD_NAME, groovyjarjarasm.asm.Opcodes.ACC_PRIVATE | groovyjarjarasm.asm.Opcodes.ACC_STATIC | groovyjarjarasm.asm.Opcodes.ACC_FINAL | groovyjarjarasm.asm.Opcodes.ACC_TRANSIENT, ClassHelper.STRING_TYPE, new ConstantExpression(path));
+    }
+}
+
Index: src/main/groovy/org/gradle/configuration/BuildScriptCompiler.java
===================================================================
--- src/main/groovy/org/gradle/configuration/BuildScriptCompiler.java	(revision 1596)
+++ src/main/groovy/org/gradle/configuration/BuildScriptCompiler.java	(working copy)
@@ -1,54 +1,59 @@
-/*
- * Copyright 2009 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.configuration;
-
-import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.internal.project.ProjectScript;
-import org.gradle.api.internal.project.ImportsReader;
-import org.gradle.api.internal.artifacts.dsl.TaskDefinitionScriptTransformer;
-import org.gradle.api.internal.artifacts.dsl.BuildScriptClasspathScriptTransformer;
-import org.gradle.groovy.scripts.*;
-import groovy.lang.Script;
-
-public class BuildScriptCompiler implements ProjectEvaluator {
-    private final ImportsReader importsReader;
-    private final ScriptProcessorFactory scriptProcessorFactory;
-    private final IProjectScriptMetaData projectScriptMetaData;
-
-    public BuildScriptCompiler(ImportsReader importsReader, ScriptProcessorFactory scriptProcessorFactory,
-                               IProjectScriptMetaData projectScriptMetaData) {
-        this.importsReader = importsReader;
-        this.scriptProcessorFactory = scriptProcessorFactory;
-        this.projectScriptMetaData = projectScriptMetaData;
-    }
-
-    public void evaluate(ProjectInternal project) {
-        ScriptSource source = new ImportsScriptSource(project.getBuildScriptSource(), importsReader,
-                project.getRootDir());
-        ScriptProcessor processor = scriptProcessorFactory.createProcessor(source);
-        processor.setClassloader(project.getBuildScriptClassLoader());
-
-        processor.setTransformer(new BuildScriptClasspathScriptTransformer());
-        Script classPathScript = processor.process(ProjectScript.class);
-        projectScriptMetaData.applyMetaData(classPathScript, project);
-        classPathScript.run();
-
-        processor.setTransformer(new TaskDefinitionScriptTransformer());
-        Script buildScript = processor.process(ProjectScript.class);
-        projectScriptMetaData.applyMetaData(buildScript, project);
-        project.setBuildScript(buildScript);
-    }
-}
+/*
+ * Copyright 2009 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.configuration;
+
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.project.ProjectScript;
+import org.gradle.api.internal.project.ImportsReader;
+import org.gradle.api.internal.artifacts.dsl.TaskDefinitionScriptTransformer;
+import org.gradle.api.internal.artifacts.dsl.BuildScriptClasspathScriptTransformer;
+import org.gradle.groovy.scripts.*;
+import org.gradle.api.internal.artifacts.dsl.AddSourceFileFieldForDebug;
+import groovy.lang.Script;
+
+public class BuildScriptCompiler implements ProjectEvaluator {
+    private final ImportsReader importsReader;
+    private final ScriptProcessorFactory scriptProcessorFactory;
+    private final IProjectScriptMetaData projectScriptMetaData;
+
+    public BuildScriptCompiler(ImportsReader importsReader, ScriptProcessorFactory scriptProcessorFactory,
+                               IProjectScriptMetaData projectScriptMetaData) {
+        this.importsReader = importsReader;
+        this.scriptProcessorFactory = scriptProcessorFactory;
+        this.projectScriptMetaData = projectScriptMetaData;
+    }
+
+    public void evaluate(ProjectInternal project) {
+        ScriptSource source = new ImportsScriptSource(project.getBuildScriptSource(), importsReader,
+                project.getRootDir());
+        ScriptProcessor processor = scriptProcessorFactory.createProcessor(source);
+        processor.setClassloader(project.getBuildScriptClassLoader());
+
+        processor.addTransformer(new BuildScriptClasspathScriptTransformer());
+        Script classPathScript = processor.process(ProjectScript.class);
+        projectScriptMetaData.applyMetaData(classPathScript, project);
+        classPathScript.run();
+
+        processor.clearTransformers();
+        processor.addTransformer(new TaskDefinitionScriptTransformer());
+        String path = source.getSourceFileCanonicalPath();
+        if (path != null)
+            processor.addTransformer(new AddSourceFileFieldForDebug(path));
+        Script buildScript = processor.process(ProjectScript.class);
+        projectScriptMetaData.applyMetaData(buildScript, project);
+        project.setBuildScript(buildScript);
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/CachePropertiesHandler.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/CachePropertiesHandler.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/CachePropertiesHandler.java	(working copy)
@@ -1,33 +1,34 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import java.io.File;
-
-/**
- * @author Hans Dockter
- */
-public interface CachePropertiesHandler {
-    String HASH_KEY = "hash";
-    String PROPERTY_FILE_NAME = "cache.properties";
-    String VERSION_KEY = "version";
-
-    enum CacheState { VALID, INVALID }
-
-    void writeProperties(String scriptText, File scriptCacheDir);
-
-    CacheState getCacheState(String testScript, File scriptCacheDir);
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import java.io.File;
+
+/**
+ * @author Hans Dockter
+ */
+public interface CachePropertiesHandler {
+    String HASH_KEY = "hash";
+    String PROPERTY_FILE_NAME = "cache.properties";
+    String VERSION_KEY = "version";
+    String SOURCEFILE_KEY = "sourcefile";
+
+    enum CacheState { VALID, INVALID }
+
+    void writeProperties(ScriptSource script, File scriptCacheDir);
+
+    CacheState getCacheState(ScriptSource script, File scriptCacheDir);
+}
Index: src/main/groovy/org/gradle/groovy/scripts/DefaultCachePropertiesHandler.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/DefaultCachePropertiesHandler.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/DefaultCachePropertiesHandler.java	(working copy)
@@ -1,54 +1,67 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import org.gradle.util.GUtil;
-import org.gradle.util.GradleVersion;
-import org.gradle.util.HashUtil;
-
-import java.io.File;
-import java.util.Properties;
-
-/**
- * @author Hans Dockter
- */
-public class DefaultCachePropertiesHandler implements CachePropertiesHandler {
-    public void writeProperties(String scriptText, File scriptCacheDir) {
-        assert scriptText != null;
-
-        Properties properties = new Properties();
-        properties.put(CachePropertiesHandler.HASH_KEY, HashUtil.createHash(scriptText));
-        properties.put(CachePropertiesHandler.VERSION_KEY, new GradleVersion().getVersion());
-        
-        GUtil.saveProperties(properties, new File(scriptCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME));
-    }
-
-    public CacheState getCacheState(String scriptText, File scriptCacheDir) {
-        assert scriptText != null;
-        
-        File propertiesFile = new File(scriptCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME);
-        if (!propertiesFile.isFile()) {
-            return CacheState.INVALID;
-        }
-        Properties properties = GUtil.loadProperties(new File(scriptCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME));
-
-        if (!properties.get(CachePropertiesHandler.VERSION_KEY).equals(new GradleVersion().getVersion())) {
-            return CacheState.INVALID;
-        }
-        return HashUtil.createHash(scriptText).equals(properties.get(CachePropertiesHandler.HASH_KEY)) ?
-                CacheState.VALID : CacheState.INVALID;
-    }
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import org.gradle.util.GUtil;
+import org.gradle.util.GradleVersion;
+import org.gradle.util.HashUtil;
+
+import java.io.File;
+import java.util.Properties;
+
+/**
+ * @author Hans Dockter
+ */
+public class DefaultCachePropertiesHandler implements CachePropertiesHandler {
+    public void writeProperties(ScriptSource script, File scriptCacheDir) {
+        assert script != null && script.getText() != null;
+
+        Properties properties = new Properties();
+        properties.put(CachePropertiesHandler.HASH_KEY, HashUtil.createHash(script.getText()));
+        properties.put(CachePropertiesHandler.VERSION_KEY, new GradleVersion().getVersion());
+
+        String path = script.getSourceFileCanonicalPath();
+        if (path != null) {
+            properties.put(CachePropertiesHandler.SOURCEFILE_KEY, path);
+        }
+
+        GUtil.saveProperties(properties, new File(scriptCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME));
+    }
+
+    public CacheState getCacheState(ScriptSource script, File scriptCacheDir) {
+        assert script != null && script.getText() != null;
+
+        File propertiesFile = new File(scriptCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME);
+        if (!propertiesFile.isFile()) {
+            return CacheState.INVALID;
+        }
+
+        Properties properties = GUtil.loadProperties(propertiesFile);
+
+        if (!properties.get(CachePropertiesHandler.VERSION_KEY).equals(new GradleVersion().getVersion())) {
+            return CacheState.INVALID;
+        }
+
+        String path = script.getSourceFileCanonicalPath();
+        String cachedPath = properties.getProperty(CachePropertiesHandler.SOURCEFILE_KEY);
+        if ((path == null && cachedPath != null) || (path != null && !path.equals(cachedPath))) {
+            return CacheState.INVALID;
+        }
+
+        return HashUtil.createHash(script.getText()).equals(properties.get(CachePropertiesHandler.HASH_KEY)) ?
+            CacheState.VALID : CacheState.INVALID;
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java	(working copy)
@@ -1,143 +1,146 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import groovy.lang.Binding;
-import groovy.lang.GroovyClassLoader;
-import groovy.lang.Script;
-import org.codehaus.groovy.control.*;
-import org.codehaus.groovy.runtime.InvokerHelper;
-import org.gradle.api.GradleException;
-import org.gradle.api.GradleScriptException;
-import org.gradle.util.Clock;
-import org.gradle.util.GFileUtils;
-import org.gradle.util.WrapUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.net.URLClassLoader;
-import java.security.CodeSource;
-
-/**
- * @author Hans Dockter
- */
-public class DefaultScriptCompilationHandler implements ScriptCompilationHandler {
-    private Logger logger = LoggerFactory.getLogger(DefaultScriptCompilationHandler.class);
-
-    private final CachePropertiesHandler cachePropertiesHandler;
-
-    public DefaultScriptCompilationHandler(CachePropertiesHandler cachePropertiesHandler) {
-        this.cachePropertiesHandler = cachePropertiesHandler;
-    }
-
-    public <T extends Script> T createScriptOnTheFly(ScriptSource source, ClassLoader classLoader,
-                                                     CompilationUnit.SourceUnitOperation transformer,
-                                                     Class<T> scriptBaseClass) {
-        Clock clock = new Clock();
-        logger.debug("Compiling script using {} with {}.", source.getDisplayName(), transformer);
-        CompilerConfiguration configuration = createBaseCompilerConfiguration(scriptBaseClass);
-        Class scriptClass = compileScript(source, classLoader, configuration, transformer);
-        T script = scriptBaseClass.cast(InvokerHelper.createScript(scriptClass, new Binding()));
-
-        logger.debug("Timing: Creating script took: {}", clock.getTime());
-        return script;
-    }
-
-    public void writeToCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
-                             CompilationUnit.SourceUnitOperation transformer, Class<? extends Script> scriptBaseClass) {
-        Clock clock = new Clock();
-        logger.debug("Compiling script using {} with {}.", source.getDisplayName(), transformer);
-        GFileUtils.deleteDirectory(scriptCacheDir);
-        scriptCacheDir.mkdirs();
-        CompilerConfiguration configuration = createBaseCompilerConfiguration(scriptBaseClass);
-        configuration.setTargetDirectory(scriptCacheDir);
-        compileScript(source, classLoader, configuration, transformer);
-
-        cachePropertiesHandler.writeProperties(source.getText(), scriptCacheDir);
-        logger.debug("Timing: Writing script to cache at {} took: {}", scriptCacheDir.getAbsolutePath(),
-                clock.getTime());
-    }
-
-    private Class compileScript(ScriptSource source, ClassLoader classLoader, CompilerConfiguration configuration,
-                              final CompilationUnit.SourceUnitOperation transformer) {
-        GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader, configuration, false) {
-            @Override
-            protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
-                CompilationUnit compilationUnit = super.createCompilationUnit(config, source);
-                if (transformer != null) {
-                    compilationUnit.addPhaseOperation(transformer, Phases.CANONICALIZATION);
-                }
-                return compilationUnit;
-            }
-        };
-        String scriptText = source.getText();
-        String scriptName = source.getClassName();
-        Class scriptClass;
-        try {
-            scriptClass = groovyClassLoader.parseClass(scriptText == null ? "" : scriptText, scriptName);
-        } catch (MultipleCompilationErrorsException e) {
-            throw new GradleScriptException(String.format("Could not compile %s.", source.getDisplayName()), e, source,
-                    e.getErrorCollector().getSyntaxError(0).getLine());
-        } catch (CompilationFailedException e) {
-            throw new GradleException(String.format("Could not compile %s.", source.getDisplayName()), e);
-        }
-        if (scriptClass == null) {
-            // Assume an empty script
-            String emptySource = String.format("class %s extends %s { public Object run() { return null } }",
-                    source.getClassName(), configuration.getScriptBaseClass().replaceAll("\\$", "."));
-            scriptClass = groovyClassLoader.parseClass(emptySource, scriptName);
-        }
-        return scriptClass;
-    }
-
-    private CompilerConfiguration createBaseCompilerConfiguration(Class<? extends Script> scriptBaseClass) {
-        CompilerConfiguration configuration = new CompilerConfiguration();
-        configuration.setScriptBaseClass(scriptBaseClass.getName());
-        return configuration;
-    }
-
-    public <T extends Script> T loadFromCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
-                                              Class<T> scriptBaseClass) {
-        String scriptText = source.getText();
-        String scriptName = source.getClassName();
-        CachePropertiesHandler.CacheState cacheState = cachePropertiesHandler.getCacheState(scriptText, scriptCacheDir);
-        if (cacheState == CachePropertiesHandler.CacheState.INVALID) {
-            return null;
-        }
-        Clock clock = new Clock();
-        Script script;
-        try {
-            URLClassLoader urlClassLoader = new URLClassLoader(WrapUtil.toArray(scriptCacheDir.toURI().toURL()),
-                    classLoader);
-            script = (Script) urlClassLoader.loadClass(scriptName).newInstance();
-        } catch (ClassNotFoundException e) {
-            logger.debug("Class not in cache: ", e);
-            return null;
-        } catch (Exception e) {
-            throw new GradleException(e);
-        }
-        if (!scriptBaseClass.isInstance(script)) {
-            return null;
-        }
-        logger.debug("Timing: Loading script from cache took: {}", clock.getTime());
-        return scriptBaseClass.cast(script);
-    }
-
-    public CachePropertiesHandler getCachePropertyHandler() {
-        return cachePropertiesHandler;
-    }
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import groovy.lang.Binding;
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.Script;
+import org.codehaus.groovy.control.*;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.gradle.api.GradleException;
+import org.gradle.api.GradleScriptException;
+import org.gradle.util.Clock;
+import org.gradle.util.GFileUtils;
+import org.gradle.util.WrapUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.util.List;
+
+/**
+ * @author Hans Dockter
+ */
+public class DefaultScriptCompilationHandler implements ScriptCompilationHandler {
+    private Logger logger = LoggerFactory.getLogger(DefaultScriptCompilationHandler.class);
+
+    private final CachePropertiesHandler cachePropertiesHandler;
+
+    public DefaultScriptCompilationHandler(CachePropertiesHandler cachePropertiesHandler) {
+        this.cachePropertiesHandler = cachePropertiesHandler;
+    }
+
+    public <T extends Script> T createScriptOnTheFly(ScriptSource source, ClassLoader classLoader,
+                                                     List transformers,
+                                                     Class<T> scriptBaseClass) {
+        Clock clock = new Clock();
+        logger.debug("Compiling script on the fly using {} with {}.", source.getDisplayName(), transformers);
+        CompilerConfiguration configuration = createBaseCompilerConfiguration(scriptBaseClass);
+        Class scriptClass = compileScript(source, classLoader, configuration, transformers);
+        T script = scriptBaseClass.cast(InvokerHelper.createScript(scriptClass, new Binding()));
+
+        logger.debug("Timing: Creating script took: {}", clock.getTime());
+        return script;
+    }
+
+    public void writeToCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
+                             List transformers, Class<? extends Script> scriptBaseClass) {
+        Clock clock = new Clock();
+        logger.debug("Compiling script to cache using {} with {}.", source.getDisplayName(), transformers);
+        GFileUtils.deleteDirectory(scriptCacheDir);
+        scriptCacheDir.mkdirs();
+        CompilerConfiguration configuration = createBaseCompilerConfiguration(scriptBaseClass);
+        configuration.setTargetDirectory(scriptCacheDir);
+        compileScript(source, classLoader, configuration, transformers);
+
+        cachePropertiesHandler.writeProperties(source, scriptCacheDir);
+        logger.debug("Timing: Writing script to cache at {} took: {}", scriptCacheDir.getAbsolutePath(),
+                clock.getTime());
+    }
+
+    private Class compileScript(ScriptSource source, ClassLoader classLoader, CompilerConfiguration configuration,
+                              final List transformers) {
+        GroovyClassLoader groovyClassLoader = new GroovyClassLoader(classLoader, configuration, false) {
+            @Override
+            protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource source) {
+                CompilationUnit compilationUnit = super.createCompilationUnit(config, source);
+                for (Object transformer : transformers) {
+                    if (transformer instanceof CompilationUnit.SourceUnitOperation)
+                        compilationUnit.addPhaseOperation((CompilationUnit.SourceUnitOperation)transformer, Phases.CANONICALIZATION);
+                    else if (transformer instanceof CompilationUnit.PrimaryClassNodeOperation)
+                        compilationUnit.addPhaseOperation((CompilationUnit.PrimaryClassNodeOperation)transformer, Phases.CANONICALIZATION);
+                }
+                return compilationUnit;
+            }
+        };
+        String scriptText = source.getText();
+        String scriptName = source.getClassName();
+        Class scriptClass;
+        try {
+            scriptClass = groovyClassLoader.parseClass(scriptText == null ? "" : scriptText, scriptName);
+        } catch (MultipleCompilationErrorsException e) {
+            throw new GradleScriptException(String.format("Could not compile %s.", source.getDisplayName()), e, source,
+                    e.getErrorCollector().getSyntaxError(0).getLine());
+        } catch (CompilationFailedException e) {
+            throw new GradleException(String.format("Could not compile %s.", source.getDisplayName()), e);
+        }
+        if (scriptClass == null) {
+            // Assume an empty script
+            String emptySource = String.format("class %s extends %s { public Object run() { return null } }",
+                    source.getClassName(), configuration.getScriptBaseClass().replaceAll("\\$", "."));
+            scriptClass = groovyClassLoader.parseClass(emptySource, scriptName);
+        }
+        return scriptClass;
+    }
+
+    private CompilerConfiguration createBaseCompilerConfiguration(Class<? extends Script> scriptBaseClass) {
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setScriptBaseClass(scriptBaseClass.getName());
+        return configuration;
+    }
+
+    public <T extends Script> T loadFromCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
+                                              Class<T> scriptBaseClass) {
+        CachePropertiesHandler.CacheState cacheState = cachePropertiesHandler.getCacheState(source, scriptCacheDir);
+        if (cacheState == CachePropertiesHandler.CacheState.INVALID) {
+            return null;
+        }
+        Clock clock = new Clock();
+        Script script;
+        try {
+            URLClassLoader urlClassLoader = new URLClassLoader(WrapUtil.toArray(scriptCacheDir.toURI().toURL()),
+                    classLoader);
+            String scriptName = source.getClassName();
+            script = (Script) urlClassLoader.loadClass(scriptName).newInstance();
+        } catch (ClassNotFoundException e) {
+            logger.debug("Class not in cache: ", e);
+            return null;
+        } catch (Exception e) {
+            throw new GradleException(e);
+        }
+        if (!scriptBaseClass.isInstance(script)) {
+            return null;
+        }
+        logger.debug("Timing: Loading script from cache took: {}", clock.getTime());
+        return scriptBaseClass.cast(script);
+    }
+
+    public CachePropertiesHandler getCachePropertyHandler() {
+        return cachePropertiesHandler;
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/DefaultScriptProcessorFactory.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/DefaultScriptProcessorFactory.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/DefaultScriptProcessorFactory.java	(working copy)
@@ -1,112 +1,133 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import org.codehaus.groovy.control.CompilationUnit;
-import org.gradle.CacheUsage;
-import org.gradle.api.Project;
-
-import java.io.File;
-
-/**
- * @author Hans Dockter
- */
-public class DefaultScriptProcessorFactory implements ScriptProcessorFactory {
-    private ScriptCompilationHandler scriptCompilationHandler;
-    private final CacheUsage cacheUsage;
-
-    public DefaultScriptProcessorFactory(ScriptCompilationHandler scriptCompilationHandler, CacheUsage cacheUsage) {
-        this.scriptCompilationHandler = scriptCompilationHandler;
-        this.cacheUsage = cacheUsage;
-    }
-
-    public ScriptProcessor createProcessor(ScriptSource source) {
-        return new ScriptProcessorImpl(source);
-    }
-
-
-    private boolean isCacheable(File sourceFile) {
-        return cacheUsage != CacheUsage.OFF && sourceFile != null && sourceFile.isFile();
-    }
-
-    public ScriptCompilationHandler getScriptCacheHandler() {
-        return scriptCompilationHandler;
-    }
-
-    public CacheUsage getCacheUsage() {
-        return cacheUsage;
-    }
-
-    private class ScriptProcessorImpl implements ScriptProcessor {
-        private final ScriptSource source;
-        private ClassLoader classloader;
-        private CompilationUnit.SourceUnitOperation transformer;
-
-        public ScriptProcessorImpl(ScriptSource source) {
-            this.source = source;
-        }
-
-        public ScriptProcessor setClassloader(ClassLoader classloader) {
-            this.classloader = classloader;
-            return this;
-        }
-
-        public ScriptProcessor setTransformer(CompilationUnit.SourceUnitOperation transformer) {
-            this.transformer = transformer;
-            return this;
-        }
-
-        public <T extends ScriptWithSource> T process(Class<T> scriptType) {
-            ClassLoader classloader = this.classloader != null ? this.classloader : Thread.currentThread().getContextClassLoader();
-
-            File sourceFile = source.getSourceFile();
-            T script;
-            if (isCacheable(sourceFile)) {
-                script = loadViaCache(classloader, scriptType);
-            }
-            else {
-                script = loadWithoutCache(classloader, scriptType);
-            }
-            script.setScriptSource(source);
-            return script;
-        }
-
-        private <T extends ScriptWithSource> T loadWithoutCache(ClassLoader classLoader, Class<T> scriptBaseClass) {
-            return scriptCompilationHandler.createScriptOnTheFly(source, classLoader, transformer, scriptBaseClass);
-        }
-
-        private <T extends ScriptWithSource> T loadViaCache(ClassLoader classLoader, Class<T> scriptBaseClass) {
-            File sourceFile = source.getSourceFile();
-            File cacheDir = new File(sourceFile.getParentFile(), Project.CACHE_DIR_NAME);
-            File scriptCacheDir = new File(cacheDir, sourceFile.getName());
-            if (transformer != null) {
-                scriptCacheDir = new File(scriptCacheDir, transformer.getClass().getSimpleName());
-            }
-            else {
-                scriptCacheDir = new File(scriptCacheDir, "NoTransformer");
-            }
-            
-            if (cacheUsage == CacheUsage.ON) {
-                T cachedScript = scriptCompilationHandler.loadFromCache(source, classLoader, scriptCacheDir, scriptBaseClass);
-                if (cachedScript != null) {
-                    return cachedScript;
-                }
-            }
-            scriptCompilationHandler.writeToCache(source, classLoader, scriptCacheDir, transformer, scriptBaseClass);
-            return scriptCompilationHandler.loadFromCache(source, classLoader, scriptCacheDir, scriptBaseClass);
-        }
-    }
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import org.codehaus.groovy.control.CompilationUnit;
+import org.gradle.CacheUsage;
+import org.gradle.api.Project;
+
+import java.io.File;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * @author Hans Dockter
+ */
+public class DefaultScriptProcessorFactory implements ScriptProcessorFactory {
+    private ScriptCompilationHandler scriptCompilationHandler;
+    private final CacheUsage cacheUsage;
+
+    public DefaultScriptProcessorFactory(ScriptCompilationHandler scriptCompilationHandler, CacheUsage cacheUsage) {
+        this.scriptCompilationHandler = scriptCompilationHandler;
+        this.cacheUsage = cacheUsage;
+    }
+
+    public ScriptProcessor createProcessor(ScriptSource source) {
+        return new ScriptProcessorImpl(source);
+    }
+
+
+    private boolean isCacheable(File sourceFile) {
+        return cacheUsage != CacheUsage.OFF && sourceFile != null && sourceFile.isFile();
+    }
+
+    public ScriptCompilationHandler getScriptCacheHandler() {
+        return scriptCompilationHandler;
+    }
+
+    public CacheUsage getCacheUsage() {
+        return cacheUsage;
+    }
+
+    private class ScriptProcessorImpl implements ScriptProcessor {
+        private final ScriptSource source;
+        private ClassLoader classloader;
+        private final List transformers = new ArrayList();
+
+        public ScriptProcessorImpl(ScriptSource source) {
+            this.source = source;
+        }
+
+        public ScriptProcessor setClassloader(ClassLoader classloader) {
+            this.classloader = classloader;
+            return this;
+        }
+
+        public ScriptProcessor clearTransformers() {
+            transformers.clear();
+            return this;
+        }
+
+        public ScriptProcessor addTransformer(CompilationUnit.SourceUnitOperation transformer) {
+            assert transformer != null;
+            transformers.add(transformer);
+            return this;
+        }
+
+        public ScriptProcessor addTransformer(CompilationUnit.PrimaryClassNodeOperation transformer) {
+            assert transformer != null;
+            transformers.add(transformer);
+            return this;
+        }
+
+        public <T extends ScriptWithSource> T process(Class<T> scriptType) {
+            ClassLoader classloader = this.classloader != null ? this.classloader : Thread.currentThread().getContextClassLoader();
+
+            File sourceFile = source.getSourceFile();
+            T script;
+            if (isCacheable(sourceFile)) {
+                script = loadViaCache(classloader, scriptType);
+            }
+            else {
+                script = loadWithoutCache(classloader, scriptType);
+            }
+            script.setScriptSource(source);
+            return script;
+        }
+
+        private <T extends ScriptWithSource> T loadWithoutCache(ClassLoader classLoader, Class<T> scriptBaseClass) {
+            return scriptCompilationHandler.createScriptOnTheFly(source, classLoader, transformers, scriptBaseClass);
+        }
+
+        private <T extends ScriptWithSource> T loadViaCache(ClassLoader classLoader, Class<T> scriptBaseClass) {
+            File sourceFile = source.getSourceFile();
+            File cacheDir = new File(sourceFile.getParentFile(), Project.CACHE_DIR_NAME);
+            File scriptCacheDir = new File(cacheDir, sourceFile.getName());
+            if (!transformers.isEmpty()) {
+                StringBuilder transformerNameBuilder = new StringBuilder();
+                for (Iterator it = transformers.iterator(); it.hasNext();) {
+                    transformerNameBuilder.append(it.next().getClass().getSimpleName());
+                    if (it.hasNext())
+                        transformerNameBuilder.append('-');
+                }
+                scriptCacheDir = new File(scriptCacheDir, transformerNameBuilder.toString());
+            }
+            else {
+                scriptCacheDir = new File(scriptCacheDir, "NoTransformer");
+            }
+            
+            if (cacheUsage == CacheUsage.ON) {
+                T cachedScript = scriptCompilationHandler.loadFromCache(source, classLoader, scriptCacheDir, scriptBaseClass);
+                if (cachedScript != null) {
+                    return cachedScript;
+                }
+            }
+            scriptCompilationHandler.writeToCache(source, classLoader, scriptCacheDir, transformers, scriptBaseClass);
+            return scriptCompilationHandler.loadFromCache(source, classLoader, scriptCacheDir, scriptBaseClass);
+        }
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/FileScriptSource.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/FileScriptSource.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/FileScriptSource.java	(working copy)
@@ -1,66 +1,83 @@
-/*
- * Copyright 2008 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.groovy.scripts;
-
-import org.gradle.util.GFileUtils;
-
-import java.io.File;
-
-/**
- * A {@link ScriptSource} which loads the script from a file.
- */
-public class FileScriptSource implements ScriptSource {
-    private final String description;
-    private final File sourceFile;
-
-    public FileScriptSource(String description, File sourceFile) {
-        this.description = description;
-        this.sourceFile = sourceFile;
-    }
-
-    public String getText() {
-        if (!sourceFile.exists()) {
-            return "";
-        }
-        return GFileUtils.readFileToString(sourceFile);
-    }
-
-    public String getClassName() {
-        String name = sourceFile.getName();
-        StringBuilder className = new StringBuilder();
-        for (int i = 0; i < name.length(); i++) {
-            char ch = name.charAt(i);
-            if (Character.isJavaIdentifierPart(ch)) {
-                className.append(ch);
-            }
-            else {
-                className.append('_');
-            }
-        }
-        if (!Character.isJavaIdentifierStart(className.charAt(0))) {
-            className.insert(0, '_');
-        }
-        return className.toString();
-    }
-
-    public File getSourceFile() {
-        return sourceFile;
-    }
-
-    public String getDisplayName() {
-        return String.format("%s '%s'", description, sourceFile.getAbsolutePath());
-    }
-}
+/*
+ * Copyright 2008 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.groovy.scripts;
+
+import org.gradle.util.GFileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A {@link ScriptSource} which loads the script from a file.
+ */
+public class FileScriptSource implements ScriptSource {
+    private final String description;
+    private final File sourceFile;
+
+    public FileScriptSource(String description, File sourceFile) {
+        this.description = description;
+        this.sourceFile = sourceFile;
+    }
+
+    public String getText() {
+        if (!sourceFile.exists()) {
+            return "";
+        }
+        return GFileUtils.readFileToString(sourceFile);
+    }
+
+    public String getClassName() {
+        String name = sourceFile.getName();
+        StringBuilder className = new StringBuilder();
+        for (int i = 0; i < name.length(); i++) {
+            char ch = name.charAt(i);
+            if (Character.isJavaIdentifierPart(ch)) {
+                className.append(ch);
+            }
+            else {
+                className.append('_');
+            }
+        }
+        if (!Character.isJavaIdentifierStart(className.charAt(0))) {
+            className.insert(0, '_');
+        }
+        return className.toString();
+    }
+
+    public File getSourceFile() {
+        return sourceFile;
+    }
+
+    public String getSourceFileCanonicalPath()
+    {
+        String path = null;
+        if (sourceFile != null)
+        {
+            try {
+                path = sourceFile.getCanonicalPath();
+            } catch (IOException ignored) {
+                // can't get the canonical path, use the absolute path as a fallback
+                path = sourceFile.getAbsolutePath();
+            }
+        }
+
+        return path;
+    }
+    
+    public String getDisplayName() {
+        return String.format("%s '%s'", description, sourceFile.getAbsolutePath());
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/ImportsScriptSource.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/ImportsScriptSource.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/ImportsScriptSource.java	(working copy)
@@ -1,63 +1,67 @@
-/*
- * Copyright 2008 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.groovy.scripts;
-
-import org.gradle.api.internal.project.ImportsReader;
-import org.gradle.util.GUtil;
-
-import java.io.File;
-
-public class ImportsScriptSource implements ScriptSource {
-    private final ScriptSource source;
-    private final ImportsReader importsReader;
-    private final File rootDir;
-
-    public ImportsScriptSource(ScriptSource source, ImportsReader importsReader, File rootDir) {
-        this.source = source;
-        this.importsReader = importsReader;
-        this.rootDir = rootDir;
-    }
-
-    public ScriptSource getSource() {
-        return source;
-    }
-
-    public String getText() {
-        String text = source.getText();
-        assert text != null;
-
-        String imports;
-        if (text.length() > 0) {
-            imports = '\n' + importsReader.getImports(rootDir);
-        } else {
-            imports = "";
-        }
-
-        return text + imports;
-    }
-
-    public String getClassName() {
-        return source.getClassName();
-    }
-
-    public File getSourceFile() {
-        return source.getSourceFile();
-    }
-
-    public String getDisplayName() {
-        return source.getDisplayName();
-    }
-}
+/*
+ * Copyright 2008 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.groovy.scripts;
+
+import org.gradle.api.internal.project.ImportsReader;
+import org.gradle.util.GUtil;
+
+import java.io.File;
+
+public class ImportsScriptSource implements ScriptSource {
+    private final ScriptSource source;
+    private final ImportsReader importsReader;
+    private final File rootDir;
+
+    public ImportsScriptSource(ScriptSource source, ImportsReader importsReader, File rootDir) {
+        this.source = source;
+        this.importsReader = importsReader;
+        this.rootDir = rootDir;
+    }
+
+    public ScriptSource getSource() {
+        return source;
+    }
+
+    public String getText() {
+        String text = source.getText();
+        assert text != null;
+
+        String imports;
+        if (text.length() > 0) {
+            imports = '\n' + importsReader.getImports(rootDir);
+        } else {
+            imports = "";
+        }
+
+        return text + imports;
+    }
+
+    public String getClassName() {
+        return source.getClassName();
+    }
+
+    public File getSourceFile() {
+        return source.getSourceFile();
+    }
+
+    public String getSourceFileCanonicalPath() {
+        return source.getSourceFileCanonicalPath();
+    }
+
+    public String getDisplayName() {
+        return source.getDisplayName();
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/ScriptCompilationHandler.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/ScriptCompilationHandler.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/ScriptCompilationHandler.java	(working copy)
@@ -1,37 +1,38 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import groovy.lang.Script;
-
-import java.io.File;
-
-import org.codehaus.groovy.control.CompilationUnit;
-
-/**
- * @author Hans Dockter
- */
-public interface ScriptCompilationHandler {
-    <T extends Script> T createScriptOnTheFly(ScriptSource source, ClassLoader classLoader,
-                                              CompilationUnit.SourceUnitOperation transformer,
-                                              Class<T> scriptBaseClass);
-
-    void writeToCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
-                      CompilationUnit.SourceUnitOperation transformer, Class<? extends Script> scriptBaseClass);
-
-    <T extends Script> T loadFromCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
-                                       Class<T> scriptBaseClass);
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import groovy.lang.Script;
+
+import java.io.File;
+import java.util.List;
+
+import org.codehaus.groovy.control.CompilationUnit;
+
+/**
+ * @author Hans Dockter
+ */
+public interface ScriptCompilationHandler {
+    <T extends Script> T createScriptOnTheFly(ScriptSource source, ClassLoader classLoader,
+                                              List transformers,
+                                              Class<T> scriptBaseClass);
+
+    void writeToCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
+                      List transformers, Class<? extends Script> scriptBaseClass);
+
+    <T extends Script> T loadFromCache(ScriptSource source, ClassLoader classLoader, File scriptCacheDir,
+                                       Class<T> scriptBaseClass);
+}
Index: src/main/groovy/org/gradle/groovy/scripts/ScriptProcessor.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/ScriptProcessor.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/ScriptProcessor.java	(working copy)
@@ -1,38 +1,48 @@
-/*
- * Copyright 2009 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.groovy.scripts;
-
-import org.codehaus.groovy.control.CompilationUnit;
-
-/**
- * Compiles a script into an executable {@code Script} object.
- */
-public interface ScriptProcessor {
-    /**
-     * Sets the parent classloader for the script. Can be null.
-     */
-    ScriptProcessor setClassloader(ClassLoader classloader);
-
-    /**
-     * Sets the transformer to use to compile the script. Can be null.
-     */
-    ScriptProcessor setTransformer(CompilationUnit.SourceUnitOperation transformer);
-
-    /**
-     * Compiles the script into a {@code Script} object of the given type.
-     */
-    <T extends ScriptWithSource> T process(Class<T> scriptType);
-}
+/*
+ * Copyright 2009 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.groovy.scripts;
+
+import org.codehaus.groovy.control.CompilationUnit;
+
+/**
+ * Compiles a script into an executable {@code Script} object.
+ */
+public interface ScriptProcessor {
+    /**
+     * Sets the parent classloader for the script. Can be null.
+     */
+    ScriptProcessor setClassloader(ClassLoader classloader);
+
+    /**
+     * Removes all transformers to use to compile the script.
+     */
+    ScriptProcessor clearTransformers();
+
+    /**
+     * Adds the transformer to use to compile the script. Cannot be null.
+     */
+    ScriptProcessor addTransformer(CompilationUnit.SourceUnitOperation transformer);
+
+    /**
+     * Adds the transformer to use to compile the script. Cannot be null.
+     */
+    ScriptProcessor addTransformer(CompilationUnit.PrimaryClassNodeOperation transformer);
+
+    /**
+     * Compiles the script into a {@code Script} object of the given type.
+     */
+    <T extends ScriptWithSource> T process(Class<T> scriptType);
+}
Index: src/main/groovy/org/gradle/groovy/scripts/ScriptSource.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/ScriptSource.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/ScriptSource.java	(working copy)
@@ -1,43 +1,48 @@
-/*
- * Copyright 2008 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.groovy.scripts;
-
-import java.io.File;
-
-/**
- * The source for the text of a script.
- */
-public interface ScriptSource {
-    /**
-     * Returns the text of this script. Returns an empty String if this script has no text. Never returns null.
-     */
-    String getText();
-
-    /**
-     * Returns the name to use for the compiled class for this script. Never returns null.
-     */
-    String getClassName();
-
-    /**
-     * Returns the source file for this script, if any. Returns null if there is no source file for this script.
-     */
-    File getSourceFile();
-
-    /**
-     * Returns the description for this script. Never returns null.
-     */
-    String getDisplayName();
-}
+/*
+ * Copyright 2008 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.groovy.scripts;
+
+import java.io.File;
+
+/**
+ * The source for the text of a script.
+ */
+public interface ScriptSource {
+    /**
+     * Returns the text of this script. Returns an empty String if this script has no text. Never returns null.
+     */
+    String getText();
+
+    /**
+     * Returns the name to use for the compiled class for this script. Never returns null.
+     */
+    String getClassName();
+
+    /**
+     * Returns the source file for this script, if any. Returns null if there is no source file for this script.
+     */
+    File getSourceFile();
+
+    /**
+     * Returns the canonical path of the source file for this script, if any. Returns null if there is no source file for this script.
+     */
+    String getSourceFileCanonicalPath();
+
+    /**
+     * Returns the description for this script. Never returns null.
+     */
+    String getDisplayName();
+}
Index: src/main/groovy/org/gradle/groovy/scripts/StrictScriptSource.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/StrictScriptSource.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/StrictScriptSource.java	(working copy)
@@ -1,55 +1,59 @@
-/*
- * Copyright 2009 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.groovy.scripts;
-
-import org.gradle.api.GradleException;
-
-import java.io.File;
-
-public class StrictScriptSource implements ScriptSource {
-    private final ScriptSource source;
-
-    public StrictScriptSource(ScriptSource source) {
-        this.source = source;
-    }
-
-    public ScriptSource getSource() {
-        return source;
-    }
-
-    public String getText() {
-        File sourceFile = source.getSourceFile();
-        if (!sourceFile.exists()) {
-            throw new GradleException(String.format("Cannot read %s as it does not exist.", source.getDisplayName()));
-        }
-        if (!sourceFile.isFile()) {
-            throw new GradleException(String.format("Cannot read %s as it is not a file.", source.getDisplayName()));
-        }
-        return source.getText();
-    }
-
-    public String getClassName() {
-        return source.getClassName();
-    }
-
-    public File getSourceFile() {
-        return source.getSourceFile();
-    }
-
-    public String getDisplayName() {
-        return source.getDisplayName();
-    }
-}
+/*
+ * Copyright 2009 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.groovy.scripts;
+
+import org.gradle.api.GradleException;
+
+import java.io.File;
+
+public class StrictScriptSource implements ScriptSource {
+    private final ScriptSource source;
+
+    public StrictScriptSource(ScriptSource source) {
+        this.source = source;
+    }
+
+    public ScriptSource getSource() {
+        return source;
+    }
+
+    public String getText() {
+        File sourceFile = source.getSourceFile();
+        if (!sourceFile.exists()) {
+            throw new GradleException(String.format("Cannot read %s as it does not exist.", source.getDisplayName()));
+        }
+        if (!sourceFile.isFile()) {
+            throw new GradleException(String.format("Cannot read %s as it is not a file.", source.getDisplayName()));
+        }
+        return source.getText();
+    }
+
+    public String getClassName() {
+        return source.getClassName();
+    }
+
+    public File getSourceFile() {
+        return source.getSourceFile();
+    }
+
+    public String getSourceFileCanonicalPath() {
+        return source.getSourceFileCanonicalPath();
+    }
+
+    public String getDisplayName() {
+        return source.getDisplayName();
+    }
+}
Index: src/main/groovy/org/gradle/groovy/scripts/StringScriptSource.java
===================================================================
--- src/main/groovy/org/gradle/groovy/scripts/StringScriptSource.java	(revision 1596)
+++ src/main/groovy/org/gradle/groovy/scripts/StringScriptSource.java	(working copy)
@@ -1,60 +1,64 @@
-/*
- * Copyright 2008 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.groovy.scripts;
-
-import org.gradle.api.Project;
-import org.gradle.util.GUtil;
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
-
-import java.io.File;
-
-public class StringScriptSource implements ScriptSource {
-    private final String description;
-    private final String content;
-
-    public StringScriptSource(String description, String content) {
-        this.description = description;
-        this.content = content;
-    }
-
-    public String getText() {
-        if (content == null) {
-            return "";
-        }
-        return content;
-    }
-
-    public String getClassName() {
-        return Project.EMBEDDED_SCRIPT_ID;
-    }
-
-    public File getSourceFile() {
-        return null;
-    }
-
-    public String getDisplayName() {
-        return description;
-    }
-
-    public boolean equals(Object obj) {
-        return EqualsBuilder.reflectionEquals(this, obj);
-    }
-
-    public int hashCode() {
-        return HashCodeBuilder.reflectionHashCode(this);
-    }
-}
+/*
+ * Copyright 2008 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.groovy.scripts;
+
+import org.gradle.api.Project;
+import org.gradle.util.GUtil;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+import java.io.File;
+
+public class StringScriptSource implements ScriptSource {
+    private final String description;
+    private final String content;
+
+    public StringScriptSource(String description, String content) {
+        this.description = description;
+        this.content = content;
+    }
+
+    public String getText() {
+        if (content == null) {
+            return "";
+        }
+        return content;
+    }
+
+    public String getClassName() {
+        return Project.EMBEDDED_SCRIPT_ID;
+    }
+
+    public File getSourceFile() {
+        return null;
+    }
+
+    public String getSourceFileCanonicalPath() {
+        return null;
+    }
+
+    public String getDisplayName() {
+        return description;
+    }
+
+    public boolean equals(Object obj) {
+        return EqualsBuilder.reflectionEquals(this, obj);
+    }
+
+    public int hashCode() {
+        return HashCodeBuilder.reflectionHashCode(this);
+    }
+}
Index: src/test/groovy/org/gradle/configuration/BuildScriptCompilerTest.java
===================================================================
--- src/test/groovy/org/gradle/configuration/BuildScriptCompilerTest.java	(revision 1596)
+++ src/test/groovy/org/gradle/configuration/BuildScriptCompilerTest.java	(working copy)
@@ -1,99 +1,103 @@
-/*
- * Copyright 2009 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.configuration;
-
-import org.gradle.api.internal.artifacts.dsl.TaskDefinitionScriptTransformer;
-import org.gradle.api.internal.artifacts.dsl.BuildScriptClasspathScriptTransformer;
-import org.gradle.api.internal.project.ImportsReader;
-import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.internal.project.ProjectScript;
-import org.gradle.groovy.scripts.*;
-import static org.gradle.util.Matchers.*;
-import static org.hamcrest.Matchers.*;
-import org.jmock.Expectations;
-import org.jmock.integration.junit4.JMock;
-import org.jmock.integration.junit4.JUnit4Mockery;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-
-@RunWith(JMock.class)
-public class BuildScriptCompilerTest {
-    private final JUnit4Mockery context = new JUnit4Mockery() {{
-        setImposteriser(ClassImposteriser.INSTANCE);
-    }};
-    private final ProjectInternal project = context.mock(ProjectInternal.class);
-    private final ScriptSource scriptSource = context.mock(ScriptSource.class);
-    private final ScriptProcessorFactory scriptProcessorFactory = context.mock(ScriptProcessorFactory.class);
-    private final ScriptProcessor processor = context.mock(ScriptProcessor.class);
-    private final IProjectScriptMetaData projectScriptMetaData = context.mock(IProjectScriptMetaData.class);
-    private final ImportsReader importsReader = context.mock(ImportsReader.class);
-    private final ClassLoader classLoader = context.mock(ClassLoader.class);
-    private final ProjectScript classpathScript = context.mock(ProjectScript.class, "classpath");
-    private final ProjectScript buildScript = context.mock(ProjectScript.class, "build");
-    private final File rootDir = new File("root dir");
-    private final BuildScriptCompiler evaluator = new BuildScriptCompiler(importsReader, scriptProcessorFactory,
-            projectScriptMetaData);
-
-    @Before
-    public void setUp() {
-        context.checking(new Expectations() {{
-            allowing(project).getBuildScriptSource();
-            will(returnValue(scriptSource));
-
-            allowing(project).getRootDir();
-            will(returnValue(rootDir));
-
-            allowing(project).getBuildScriptClassLoader();
-            will(returnValue(classLoader));
-        }});
-    }
-
-    @Test
-    public void createsAndExecutesScriptAndNotifiesListener() {
-        final ScriptSource expectedScriptSource = new ImportsScriptSource(scriptSource, importsReader, rootDir);
-
-        context.checking(new Expectations() {{
-            one(scriptProcessorFactory).createProcessor(with(reflectionEquals(expectedScriptSource)));
-            will(returnValue(processor));
-
-            one(processor).setClassloader(classLoader);
-
-            one(processor).setTransformer(with(notNullValue(BuildScriptClasspathScriptTransformer.class)));
-
-            one(processor).process(ProjectScript.class);
-            will(returnValue(classpathScript));
-
-            one(projectScriptMetaData).applyMetaData(classpathScript, project);
-
-            one(classpathScript).run();
-
-            one(processor).setTransformer(with(notNullValue(TaskDefinitionScriptTransformer.class)));
-
-            one(processor).process(ProjectScript.class);
-            will(returnValue(buildScript));
-
-            one(projectScriptMetaData).applyMetaData(buildScript, project);
-
-            one(project).setBuildScript(buildScript);
-        }});
-
-        evaluator.evaluate(project);
-    }
+/*
+ * Copyright 2009 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.configuration;
+
+import org.gradle.api.internal.artifacts.dsl.TaskDefinitionScriptTransformer;
+import org.gradle.api.internal.artifacts.dsl.BuildScriptClasspathScriptTransformer;
+import org.gradle.api.internal.project.ImportsReader;
+import org.gradle.api.internal.project.ProjectInternal;
+import org.gradle.api.internal.project.ProjectScript;
+import org.gradle.groovy.scripts.*;
+import static org.gradle.util.Matchers.*;
+import static org.hamcrest.Matchers.*;
+import org.jmock.Expectations;
+import org.jmock.integration.junit4.JMock;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.jmock.lib.legacy.ClassImposteriser;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(JMock.class)
+public class BuildScriptCompilerTest {
+    private final JUnit4Mockery context = new JUnit4Mockery() {{
+        setImposteriser(ClassImposteriser.INSTANCE);
+    }};
+    private final ProjectInternal project = context.mock(ProjectInternal.class);
+    private final ScriptSource scriptSource = context.mock(ScriptSource.class);
+    private final ScriptProcessorFactory scriptProcessorFactory = context.mock(ScriptProcessorFactory.class);
+    private final ScriptProcessor processor = context.mock(ScriptProcessor.class);
+    private final IProjectScriptMetaData projectScriptMetaData = context.mock(IProjectScriptMetaData.class);
+    private final ImportsReader importsReader = context.mock(ImportsReader.class);
+    private final ClassLoader classLoader = context.mock(ClassLoader.class);
+    private final ProjectScript classpathScript = context.mock(ProjectScript.class, "classpath");
+    private final ProjectScript buildScript = context.mock(ProjectScript.class, "build");
+    private final File rootDir = new File("root dir");
+    private final BuildScriptCompiler evaluator = new BuildScriptCompiler(importsReader, scriptProcessorFactory,
+            projectScriptMetaData);
+
+    @Before
+    public void setUp() {
+        context.checking(new Expectations() {{
+            allowing(project).getBuildScriptSource();
+            will(returnValue(scriptSource));
+
+            allowing(project).getRootDir();
+            will(returnValue(rootDir));
+
+            allowing(project).getBuildScriptClassLoader();
+            will(returnValue(classLoader));
+
+            allowing(scriptSource).getSourceFileCanonicalPath();
+            will(returnValue(null));
+        }});
+    }
+
+    @Test
+    public void createsAndExecutesScriptAndNotifiesListener() {
+        final ScriptSource expectedScriptSource = new ImportsScriptSource(scriptSource, importsReader, rootDir);
+
+        context.checking(new Expectations() {{
+            one(scriptProcessorFactory).createProcessor(with(reflectionEquals(expectedScriptSource)));
+            will(returnValue(processor));
+
+            one(processor).setClassloader(classLoader);
+
+            one(processor).addTransformer(with(notNullValue(BuildScriptClasspathScriptTransformer.class)));
+
+            one(processor).process(ProjectScript.class);
+            will(returnValue(classpathScript));
+
+            one(projectScriptMetaData).applyMetaData(classpathScript, project);
+
+            one(classpathScript).run();
+
+            one(processor).clearTransformers();
+            one(processor).addTransformer(with(notNullValue(TaskDefinitionScriptTransformer.class)));
+
+            one(processor).process(ProjectScript.class);
+            will(returnValue(buildScript));
+
+            one(projectScriptMetaData).applyMetaData(buildScript, project);
+
+            one(project).setBuildScript(buildScript);
+        }});
+
+        evaluator.evaluate(project);
+    }
 }
\ No newline at end of file
Index: src/test/groovy/org/gradle/groovy/scripts/DefaultCachePropertiesHandlerTest.java
===================================================================
--- src/test/groovy/org/gradle/groovy/scripts/DefaultCachePropertiesHandlerTest.java	(revision 1596)
+++ src/test/groovy/org/gradle/groovy/scripts/DefaultCachePropertiesHandlerTest.java	(working copy)
@@ -1,112 +1,134 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.After;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertEquals;
-import org.gradle.util.HelperUtil;
-import org.gradle.util.WrapUtil;
-import org.gradle.util.GradleVersion;
-import org.gradle.util.GUtil;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.FileInputStream;
-import java.util.Properties;
-import java.util.Map;
-import java.util.HashMap;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.math.BigInteger;
-
-/**
- * @author Hans Dockter
- */
-public class DefaultCachePropertiesHandlerTest {
-    public static final String TEST_SCRIPT_TEXT = "someScript";
-
-    private DefaultCachePropertiesHandler cachePropertyHandler;
-
-    private File testCacheDir;
-
-    @Before
-    public void setUp() {
-        testCacheDir = HelperUtil.makeNewTestDir();
-        cachePropertyHandler = new DefaultCachePropertiesHandler();
-    }
-
-    @After
-    public void tearDown() {
-        HelperUtil.deleteTestDir();
-    }
-
-    @Test
-    public void getCacheStateWithNoCachePropertiesFile() {
-        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(TEST_SCRIPT_TEXT, testCacheDir));
-    }
-
-    @Test
-    public void getCacheStateWithDifferentHashes() throws NoSuchAlgorithmException, IOException {
-        createPropertiesFile(TEST_SCRIPT_TEXT + "delta", new GradleVersion().getVersion());
-        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(TEST_SCRIPT_TEXT, testCacheDir));
-    }
-
-    private String createHash(String scriptText) throws NoSuchAlgorithmException {
-        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
-        messageDigest.update(scriptText.getBytes());
-        return new BigInteger(1, messageDigest.digest()).toString(16);
-    }
-
-    @Test
-    public void getCacheStateWithSameHashes() throws NoSuchAlgorithmException, IOException {
-        createPropertiesFile(TEST_SCRIPT_TEXT, new GradleVersion().getVersion());
-        assertEquals(CachePropertiesHandler.CacheState.VALID, cachePropertyHandler.getCacheState(TEST_SCRIPT_TEXT, testCacheDir));
-    }
-
-    @Test
-    public void getCacheStateWithDifferentVersions() throws NoSuchAlgorithmException, IOException {
-        createPropertiesFile(TEST_SCRIPT_TEXT, new GradleVersion().getVersion() + "delta");
-        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(TEST_SCRIPT_TEXT, testCacheDir));
-    }
-
-    private void createPropertiesFile(String scriptText, String version) throws NoSuchAlgorithmException, IOException {
-        Properties properties = new Properties();
-        properties.put(CachePropertiesHandler.HASH_KEY, createHash(scriptText));
-        properties.put(CachePropertiesHandler.VERSION_KEY, version);
-        GUtil.saveProperties(properties, new File(testCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME));
-    }
-
-    @Test
-    public void writeProperties() throws IOException, NoSuchAlgorithmException {
-        cachePropertyHandler.writeProperties(TEST_SCRIPT_TEXT, testCacheDir);
-        checkWriteProperties(new HashMap());
-    }
-
-    private void checkWriteProperties(Map additionalExpectedProperties) throws IOException, NoSuchAlgorithmException {
-        File propertiesFile = new File(testCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME);
-        Properties actualProperties = GUtil.loadProperties(propertiesFile);
-        Properties expectedProperties = new Properties();
-        expectedProperties.put(CachePropertiesHandler.HASH_KEY, createHash(TEST_SCRIPT_TEXT));
-        expectedProperties.put(CachePropertiesHandler.VERSION_KEY, new GradleVersion().getVersion());
-        expectedProperties.putAll(additionalExpectedProperties);
-        assertEquals(expectedProperties, actualProperties);
-    }
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.After;
+import static org.junit.Assert.assertEquals;
+import org.gradle.util.HelperUtil;
+import org.gradle.util.GradleVersion;
+import org.gradle.util.GUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Map;
+import java.util.HashMap;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.math.BigInteger;
+
+/**
+ * @author Hans Dockter
+ */
+public class DefaultCachePropertiesHandlerTest {
+    private static final String TEST_SCRIPT_TEXT = "someScript";
+    private static final File TEST_SCRIPT_FILE  = new File("someLocation").getAbsoluteFile();
+    private static final String TEST_SCRIPT_LOC  = TEST_SCRIPT_FILE.getPath();
+    private static final ScriptSource testScriptSource = new FileScriptSource("test script", TEST_SCRIPT_FILE)
+    {
+        @Override public String getText() {
+            return TEST_SCRIPT_TEXT;
+        }
+    };
+    
+    private DefaultCachePropertiesHandler cachePropertyHandler;
+    private File testCacheDir;
+
+    @Before
+    public void setUp() {
+        testCacheDir = HelperUtil.makeNewTestDir();
+        cachePropertyHandler = new DefaultCachePropertiesHandler();
+    }
+
+    @After
+    public void tearDown() {
+        HelperUtil.deleteTestDir();
+    }
+
+    @Test
+    public void getCacheStateWithNoCachePropertiesFile() {
+        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    @Test
+    public void getCacheStateWithDifferentHashes() throws NoSuchAlgorithmException, IOException {
+        createPropertiesFile(TEST_SCRIPT_TEXT + "delta", TEST_SCRIPT_LOC, new GradleVersion().getVersion());
+        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    private String createHash(String scriptText) throws NoSuchAlgorithmException {
+        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+        messageDigest.update(scriptText.getBytes());
+        return new BigInteger(1, messageDigest.digest()).toString(16);
+    }
+
+    @Test
+    public void getCacheStateWithSameHashes() throws NoSuchAlgorithmException, IOException {
+        createPropertiesFile(TEST_SCRIPT_TEXT, TEST_SCRIPT_LOC, new GradleVersion().getVersion());
+        assertEquals(CachePropertiesHandler.CacheState.VALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    @Test
+    public void getCacheStateWithDifferentLocations() throws NoSuchAlgorithmException, IOException {
+        createPropertiesFile(TEST_SCRIPT_TEXT, TEST_SCRIPT_LOC + "delta", new GradleVersion().getVersion());
+        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    @Test
+    public void getCacheStateWithSameLocations() throws NoSuchAlgorithmException, IOException {
+        createPropertiesFile(TEST_SCRIPT_TEXT, TEST_SCRIPT_LOC, new GradleVersion().getVersion());
+        assertEquals(CachePropertiesHandler.CacheState.VALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    @Test
+    public void getCacheStateWithDifferentVersions() throws NoSuchAlgorithmException, IOException {
+        createPropertiesFile(TEST_SCRIPT_TEXT, TEST_SCRIPT_LOC, new GradleVersion().getVersion() + "delta");
+        assertEquals(CachePropertiesHandler.CacheState.INVALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    @Test
+    public void getCacheStateWithSameVersions() throws NoSuchAlgorithmException, IOException {
+        createPropertiesFile(TEST_SCRIPT_TEXT, TEST_SCRIPT_LOC, new GradleVersion().getVersion());
+        assertEquals(CachePropertiesHandler.CacheState.VALID, cachePropertyHandler.getCacheState(testScriptSource, testCacheDir));
+    }
+
+    private void createPropertiesFile(String scriptText, String scriptLoc, String version) throws NoSuchAlgorithmException, IOException {
+        Properties properties = new Properties();
+        properties.put(CachePropertiesHandler.HASH_KEY, createHash(scriptText));
+        properties.put(CachePropertiesHandler.VERSION_KEY, version);
+        properties.put(CachePropertiesHandler.SOURCEFILE_KEY, scriptLoc);
+        GUtil.saveProperties(properties, new File(testCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME));
+    }
+
+    @Test
+    public void writeProperties() throws IOException, NoSuchAlgorithmException {
+        cachePropertyHandler.writeProperties(testScriptSource, testCacheDir);
+        checkWriteProperties(new HashMap());
+    }
+
+    private void checkWriteProperties(Map additionalExpectedProperties) throws IOException, NoSuchAlgorithmException {
+        File propertiesFile = new File(testCacheDir, CachePropertiesHandler.PROPERTY_FILE_NAME);
+        Properties actualProperties = GUtil.loadProperties(propertiesFile);
+        Properties expectedProperties = new Properties();
+        expectedProperties.put(CachePropertiesHandler.HASH_KEY, createHash(TEST_SCRIPT_TEXT));
+        expectedProperties.put(CachePropertiesHandler.VERSION_KEY, new GradleVersion().getVersion());
+        expectedProperties.put(CachePropertiesHandler.SOURCEFILE_KEY, TEST_SCRIPT_LOC);
+        expectedProperties.putAll(additionalExpectedProperties);
+        assertEquals(expectedProperties, actualProperties);
+    }
+}
Index: src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandlerTest.java
===================================================================
--- src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandlerTest.java	(revision 1596)
+++ src/test/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandlerTest.java	(working copy)
@@ -1,250 +1,270 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import groovy.lang.Script;
-import org.codehaus.groovy.control.CompilationFailedException;
-import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.ast.CodeVisitorSupport;
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.gradle.api.GradleScriptException;
-import org.gradle.api.InputStreamClassLoader;
-import org.gradle.api.Project;
-import org.gradle.util.HelperUtil;
-import static org.hamcrest.Matchers.*;
-import org.jmock.Expectations;
-import org.jmock.integration.junit4.JMock;
-import org.jmock.integration.junit4.JUnit4Mockery;
-import org.junit.After;
-import static org.junit.Assert.*;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * @author Hans Dockter
- */
-@RunWith(JMock.class)
-public class DefaultScriptCompilationHandlerTest {
-
-    static final String TEST_SCRIPT_NAME = "somename_craidle";
-    static final String TEST_EXPECTED_SYSTEMPROP_VALUE = "somevalue";
-    static final String TEST_EXPECTED_SYSTEMPROP_KEY = "somekey";
-
-    private DefaultScriptCompilationHandler scriptCompilationHandler;
-
-    private File testProjectDir;
-
-    private File scriptCacheDir;
-    private File cachedFile;
-
-    private String testScript;
-    private ScriptSource scriptSource;
-
-    private InputStreamClassLoader classLoader;
-
-    private Class<? extends Script> expectedScriptClass;
-
-    private CachePropertiesHandler cachePropertiesHandlerMock;
-
-    private JUnit4Mockery context = new JUnit4Mockery();
-
-    @Before
-    public void setUp() throws IOException, ClassNotFoundException {
-        cachePropertiesHandlerMock = context.mock(CachePropertiesHandler.class);
-        testProjectDir = HelperUtil.makeNewTestDir("projectdir");
-        classLoader = new InputStreamClassLoader();
-        InputStream inputStream = this.getClass().getResourceAsStream("/org/gradle/api/ClasspathTester.dat");
-        classLoader.loadClass("org.gradle.api.ClasspathTester", inputStream);
-        scriptCompilationHandler = new DefaultScriptCompilationHandler(cachePropertiesHandlerMock);
-        scriptCacheDir = new File(testProjectDir, "cache");
-        testScript = "System.setProperty('" + TEST_EXPECTED_SYSTEMPROP_KEY + "', '" + TEST_EXPECTED_SYSTEMPROP_VALUE + "')";
-        scriptSource = new StringScriptSource("script", testScript);
-        cachedFile = new File(scriptCacheDir, scriptSource.getClassName() + ".class");
-        expectedScriptClass = TestBaseScript.class;
-    }
-
-    @After
-    public void tearDown() {
-        HelperUtil.deleteTestDir();
-        System.getProperties().remove(TEST_EXPECTED_SYSTEMPROP_KEY);
-    }
-
-    @Test
-    public void init() {
-        assertSame(cachePropertiesHandlerMock, scriptCompilationHandler.getCachePropertyHandler());
-    }
-    
-    @Test
-    public void testWriteToCache() {
-        context.checking(new Expectations() {{
-            one(cachePropertiesHandlerMock).writeProperties(testScript, scriptCacheDir);
-            one(cachePropertiesHandlerMock).getCacheState(testScript, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
-        }});
-        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, null, expectedScriptClass);
-
-        checkScriptClassesInCache();
-
-        Script script = scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass);
-        evaluateScript(script);
-    }
-
-    @Test
-    public void testWriteToCacheAndLoadFromCacheWithWhitespaceOnly() {
-        final String emptyScript = "// ignore me\n";
-        StringScriptSource scriptSource = new StringScriptSource("script", emptyScript);
-        context.checking(new Expectations() {{
-            one(cachePropertiesHandlerMock).getCacheState(emptyScript, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
-            one(cachePropertiesHandlerMock).writeProperties(emptyScript, scriptCacheDir);
-        }});
-
-        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, null, expectedScriptClass);
-
-        checkScriptClassesInCache();
-
-        Script script = scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass);
-        assertThat(script, is(expectedScriptClass));
-    }
-
-    @Test
-    public void testWriteToCacheAndLoadFromCacheWithEmptyScript() {
-        final String emptyScript = "";
-        StringScriptSource scriptSource = new StringScriptSource("script", emptyScript);
-        context.checking(new Expectations() {{
-            one(cachePropertiesHandlerMock).getCacheState(emptyScript, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
-            one(cachePropertiesHandlerMock).writeProperties(emptyScript, scriptCacheDir);
-        }});
-
-        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, null, expectedScriptClass);
-
-        checkScriptClassesInCache();
-
-        Script script = scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass);
-        assertThat(script, is(expectedScriptClass));
-    }
-
-    @Test public void testCreateScriptOnTheFly() {
-        Script script = scriptCompilationHandler.createScriptOnTheFly(scriptSource, classLoader, null, expectedScriptClass);
-
-        checkScriptClassesNotInCache();
-
-        evaluateScript(script);
-    }
-
-    @Test public void testCreateScriptOnTheFlyWithWhitespaceOnlyScript() {
-        Script script = scriptCompilationHandler.createScriptOnTheFly(new StringScriptSource("script", "// ignore me\n"), classLoader, null, expectedScriptClass);
-
-        checkScriptClassesNotInCache();
-
-        assertThat(script, is(expectedScriptClass));
-    }
-
-    @Test public void testCreateScriptOnTheFlyWithEmptyScript() {
-        Script script = scriptCompilationHandler.createScriptOnTheFly(new StringScriptSource("script", ""), classLoader, null, expectedScriptClass);
-
-        checkScriptClassesNotInCache();
-
-        assertThat(script, is(expectedScriptClass));
-    }
-
-    @Test public void testLoadFromCacheWithInvalidCache() {
-        context.checking(new Expectations() {{
-            allowing(cachePropertiesHandlerMock).getCacheState(testScript, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.INVALID));
-        }});
-        assertNull(scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass));
-    }
-
-    @Test public void testLoadFromCacheWhenNotAssignableToBaseClass() {
-        context.checking(new Expectations() {{
-            one(cachePropertiesHandlerMock).writeProperties(testScript, scriptCacheDir);
-            allowing(cachePropertiesHandlerMock).getCacheState(testScript, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
-        }});
-        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, null, Script.class);
-        assertNull(scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass));
-    }
-
-    @Test public void testWriteToCacheWithException() {
-        ScriptSource source = new StringScriptSource("script", "\n\nnew HHHHJSJSJ jsj");
-        try {
-            scriptCompilationHandler.writeToCache(source, classLoader, scriptCacheDir, null, expectedScriptClass);
-            fail();
-        } catch (GradleScriptException e) {
-            assertThat(e.getScriptSource(), sameInstance(source));
-            assertThat(e.getLineNumber(), equalTo(3));
-        }
-    }
-
-    @Test public void testCreateScriptWithException() {
-        ScriptSource source = new StringScriptSource("script", "\n\nnew HHHHJSJSJ jsj");
-        try {
-            scriptCompilationHandler.createScriptOnTheFly(source, classLoader, null, expectedScriptClass);
-            fail();
-        } catch (GradleScriptException e) {
-            assertThat(e.getScriptSource(), sameInstance(source));
-            assertThat(e.getLineNumber(), equalTo(3));
-        }
-    }
-
-    @Test public void testCanVisitAndTransformScriptClass() {
-        CompilationUnit.SourceUnitOperation visitor = new CompilationUnit.SourceUnitOperation() {
-            @Override
-            public void call(SourceUnit source) throws CompilationFailedException {
-                source.getAST().getStatementBlock().visit(new CodeVisitorSupport() {
-                    @Override
-                    public void visitMethodCallExpression(MethodCallExpression call) {
-                        call.setObjectExpression(new ClassExpression(ClassHelper.make(System.class)));
-                        call.setMethod(new ConstantExpression("setProperty"));
-                        ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments();
-                        arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_KEY));
-                        arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_VALUE));
-                    }
-                });
-            }
-        };
-
-        Script script = scriptCompilationHandler.createScriptOnTheFly(new StringScriptSource("source", "transformMe()"), classLoader, visitor, expectedScriptClass);
-        evaluateScript(script);
-    }
-
-    private void checkScriptClassesInCache() {
-        assertTrue(scriptCacheDir.isDirectory());
-        assertTrue(cachedFile.isFile());
-    }
-
-    private void checkScriptClassesNotInCache() {
-        assertTrue(!scriptCacheDir.exists() || (scriptCacheDir.isDirectory() && scriptCacheDir.list().length == 0));
-    }
-
-    private void evaluateScript(Script script) {
-        assertThat(script, instanceOf(expectedScriptClass));
-        assertEquals(script.getClass().getSimpleName(), Project.EMBEDDED_SCRIPT_ID);
-        System.setProperty(TEST_EXPECTED_SYSTEMPROP_KEY, "not the expected value");
-        script.run();
-        assertEquals(TEST_EXPECTED_SYSTEMPROP_VALUE, System.getProperty(TEST_EXPECTED_SYSTEMPROP_KEY));
-    }
-
-    public abstract static class TestBaseScript extends Script {
-    }
-}
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import groovy.lang.Script;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.gradle.api.GradleScriptException;
+import org.gradle.api.InputStreamClassLoader;
+import org.gradle.api.Project;
+import org.gradle.api.internal.artifacts.dsl.AddSourceFileFieldForDebug;
+import org.gradle.api.internal.artifacts.dsl.TaskDefinitionScriptTransformer;
+import org.gradle.util.HelperUtil;
+import static org.hamcrest.Matchers.*;
+import org.jmock.Expectations;
+import org.jmock.integration.junit4.JMock;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.junit.After;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Arrays;
+import java.lang.reflect.Field;
+
+/**
+ * @author Hans Dockter
+ */
+@RunWith(JMock.class)
+public class DefaultScriptCompilationHandlerTest {
+
+    static final String TEST_SCRIPT_NAME = "somename_craidle";
+    static final String TEST_EXPECTED_SYSTEMPROP_VALUE = "somevalue";
+    static final String TEST_EXPECTED_SYSTEMPROP_KEY = "somekey";
+
+    private DefaultScriptCompilationHandler scriptCompilationHandler;
+
+    private File testProjectDir;
+
+    private File scriptCacheDir;
+    private File cachedFile;
+
+    private String testScript;
+    private ScriptSource scriptSource;
+
+    private InputStreamClassLoader classLoader;
+
+    private Class<? extends Script> expectedScriptClass;
+
+    private CachePropertiesHandler cachePropertiesHandlerMock;
+
+    private JUnit4Mockery context = new JUnit4Mockery();
+
+    @Before
+    public void setUp() throws IOException, ClassNotFoundException {
+        cachePropertiesHandlerMock = context.mock(CachePropertiesHandler.class);
+        testProjectDir = HelperUtil.makeNewTestDir("projectdir");
+        classLoader = new InputStreamClassLoader();
+        InputStream inputStream = this.getClass().getResourceAsStream("/org/gradle/api/ClasspathTester.dat");
+        classLoader.loadClass("org.gradle.api.ClasspathTester", inputStream);
+        scriptCompilationHandler = new DefaultScriptCompilationHandler(cachePropertiesHandlerMock);
+        scriptCacheDir = new File(testProjectDir, "cache");
+        testScript = "System.setProperty('" + TEST_EXPECTED_SYSTEMPROP_KEY + "', '" + TEST_EXPECTED_SYSTEMPROP_VALUE + "')";
+        scriptSource = new StringScriptSource("script", testScript);
+        cachedFile = new File(scriptCacheDir, scriptSource.getClassName() + ".class");
+        expectedScriptClass = TestBaseScript.class;
+    }
+
+    @After
+    public void tearDown() {
+        HelperUtil.deleteTestDir();
+        System.getProperties().remove(TEST_EXPECTED_SYSTEMPROP_KEY);
+    }
+
+    @Test
+    public void init() {
+        assertSame(cachePropertiesHandlerMock, scriptCompilationHandler.getCachePropertyHandler());
+    }
+    
+    @Test
+    public void testWriteToCache() {
+        context.checking(new Expectations() {{
+            one(cachePropertiesHandlerMock).writeProperties(scriptSource, scriptCacheDir);
+            one(cachePropertiesHandlerMock).getCacheState(scriptSource, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
+        }});
+        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, Collections.emptyList(), expectedScriptClass);
+
+        checkScriptClassesInCache();
+
+        Script script = scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass);
+        evaluateScript(script);
+    }
+
+    @Test
+    public void testWriteToCacheAndLoadFromCacheWithWhitespaceOnly() {
+        final String emptyScript = "// ignore me\n";
+        final StringScriptSource scriptSource = new StringScriptSource("script", emptyScript);
+        context.checking(new Expectations() {{
+            one(cachePropertiesHandlerMock).getCacheState(scriptSource, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
+            one(cachePropertiesHandlerMock).writeProperties(scriptSource, scriptCacheDir);
+        }});
+
+        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, Collections.emptyList(), expectedScriptClass);
+
+        checkScriptClassesInCache();
+
+        Script script = scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass);
+        assertThat(script, is(expectedScriptClass));
+    }
+
+    @Test
+    public void testWriteToCacheAndLoadFromCacheWithEmptyScript() {
+        final String emptyScript = "";
+        final StringScriptSource scriptSource = new StringScriptSource("script", emptyScript);
+        context.checking(new Expectations() {{
+            one(cachePropertiesHandlerMock).getCacheState(scriptSource, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
+            one(cachePropertiesHandlerMock).writeProperties(scriptSource, scriptCacheDir);
+        }});
+
+        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, Collections.emptyList(), expectedScriptClass);
+
+        checkScriptClassesInCache();
+
+        Script script = scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass);
+        assertThat(script, is(expectedScriptClass));
+    }
+
+    @Test public void testCreateScriptOnTheFly() {
+        Script script = scriptCompilationHandler.createScriptOnTheFly(scriptSource, classLoader, Collections.emptyList(), expectedScriptClass);
+
+        checkScriptClassesNotInCache();
+
+        evaluateScript(script);
+    }
+
+    @Test public void testCreateScriptOnTheFlyWithWhitespaceOnlyScript() {
+        Script script = scriptCompilationHandler.createScriptOnTheFly(new StringScriptSource("script", "// ignore me\n"), classLoader, Collections.emptyList(), expectedScriptClass);
+
+        checkScriptClassesNotInCache();
+
+        assertThat(script, is(expectedScriptClass));
+    }
+
+    @Test public void testCreateScriptOnTheFlyWithEmptyScript() {
+        Script script = scriptCompilationHandler.createScriptOnTheFly(new StringScriptSource("script", ""), classLoader, Collections.emptyList(), expectedScriptClass);
+
+        checkScriptClassesNotInCache();
+
+        assertThat(script, is(expectedScriptClass));
+    }
+
+    @Test public void testLoadFromCacheWithInvalidCache() {
+        context.checking(new Expectations() {{
+            allowing(cachePropertiesHandlerMock).getCacheState(scriptSource, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.INVALID));
+        }});
+        assertNull(scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass));
+    }
+
+    @Test public void testLoadFromCacheWhenNotAssignableToBaseClass() {
+        context.checking(new Expectations() {{
+            one(cachePropertiesHandlerMock).writeProperties(scriptSource, scriptCacheDir);
+            allowing(cachePropertiesHandlerMock).getCacheState(scriptSource, scriptCacheDir); will(returnValue(CachePropertiesHandler.CacheState.VALID));
+        }});
+        scriptCompilationHandler.writeToCache(scriptSource, classLoader, scriptCacheDir, Collections.emptyList(), Script.class);
+        assertNull(scriptCompilationHandler.loadFromCache(scriptSource, classLoader, scriptCacheDir, expectedScriptClass));
+    }
+
+    @Test public void testWriteToCacheWithException() {
+        ScriptSource source = new StringScriptSource("script", "\n\nnew HHHHJSJSJ jsj");
+        try {
+            scriptCompilationHandler.writeToCache(source, classLoader, scriptCacheDir, Collections.emptyList(), expectedScriptClass);
+            fail();
+        } catch (GradleScriptException e) {
+            assertThat(e.getScriptSource(), sameInstance(source));
+            assertThat(e.getLineNumber(), equalTo(3));
+        }
+    }
+
+    @Test public void testCreateScriptWithException() {
+        ScriptSource source = new StringScriptSource("script", "\n\nnew HHHHJSJSJ jsj");
+        try {
+            scriptCompilationHandler.createScriptOnTheFly(source, classLoader, Collections.emptyList(), expectedScriptClass);
+            fail();
+        } catch (GradleScriptException e) {
+            assertThat(e.getScriptSource(), sameInstance(source));
+            assertThat(e.getLineNumber(), equalTo(3));
+        }
+    }
+
+    @Test public void testCanVisitAndTransformScriptClass() {
+        CompilationUnit.SourceUnitOperation visitor = new CompilationUnit.SourceUnitOperation() {
+            @Override
+            public void call(SourceUnit source) throws CompilationFailedException {
+                source.getAST().getStatementBlock().visit(new CodeVisitorSupport() {
+                    @Override
+                    public void visitMethodCallExpression(MethodCallExpression call) {
+                        call.setObjectExpression(new ClassExpression(ClassHelper.make(System.class)));
+                        call.setMethod(new ConstantExpression("setProperty"));
+                        ArgumentListExpression arguments = (ArgumentListExpression) call.getArguments();
+                        arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_KEY));
+                        arguments.addExpression(new ConstantExpression(TEST_EXPECTED_SYSTEMPROP_VALUE));
+                    }
+                });
+            }
+        };
+
+        Script script = scriptCompilationHandler.createScriptOnTheFly(new StringScriptSource("source", "transformMe()"), 
+                                                  classLoader, Collections.singletonList(visitor), expectedScriptClass);
+        evaluateScript(script);
+    }
+
+    private void checkScriptClassesInCache() {
+        assertTrue(scriptCacheDir.isDirectory());
+        assertTrue(cachedFile.isFile());
+    }
+
+    private void checkScriptClassesNotInCache() {
+        assertTrue(!scriptCacheDir.exists() || (scriptCacheDir.isDirectory() && scriptCacheDir.list().length == 0));
+    }
+
+    private void evaluateScript(Script script) {
+        assertThat(script, instanceOf(expectedScriptClass));
+        assertEquals(script.getClass().getSimpleName(), Project.EMBEDDED_SCRIPT_ID);
+        System.setProperty(TEST_EXPECTED_SYSTEMPROP_KEY, "not the expected value");
+        script.run();
+        assertEquals(TEST_EXPECTED_SYSTEMPROP_VALUE, System.getProperty(TEST_EXPECTED_SYSTEMPROP_KEY));
+    }
+
+    public abstract static class TestBaseScript extends Script {
+    }
+
+    @Test public void testSourceFileFieldAdded() throws NoSuchFieldException, IllegalAccessException {
+        final String TEST_LOC = "testLocation";
+
+        final DefaultScriptCompilationHandler handler = new DefaultScriptCompilationHandler(cachePropertiesHandlerMock);
+
+        Object[] transformers = new Object[] { new TaskDefinitionScriptTransformer(), new AddSourceFileFieldForDebug(TEST_LOC)};
+        final Script script = handler.createScriptOnTheFly(scriptSource, classLoader, Arrays.asList(transformers), expectedScriptClass);
+        final Field field = script.getClass().getDeclaredField(AddSourceFileFieldForDebug.FIELD_NAME);
+        field.setAccessible(true);
+        final String value = (String) field.get(null);
+
+        assertEquals("Field "+AddSourceFileFieldForDebug.FIELD_NAME+" on the compiled class does not have the correct value", TEST_LOC, value);
+    }    
+}
Index: src/test/groovy/org/gradle/groovy/scripts/DefaultScriptProcessorFactoryTest.java
===================================================================
--- src/test/groovy/org/gradle/groovy/scripts/DefaultScriptProcessorFactoryTest.java	(revision 1596)
+++ src/test/groovy/org/gradle/groovy/scripts/DefaultScriptProcessorFactoryTest.java	(working copy)
@@ -1,303 +1,304 @@
-/*
- * Copyright 2007-2008 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.groovy.scripts;
-
-import groovy.lang.Script;
-import org.apache.commons.io.FileUtils;
-import org.gradle.CacheUsage;
-import org.gradle.api.Project;
-import org.gradle.util.HelperUtil;
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.jmock.integration.junit4.JUnit4Mockery;
-import org.jmock.integration.junit4.JMock;
-import org.junit.After;
-import static org.junit.Assert.*;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.CompilationFailedException;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
-
-/**
- * @author Hans Dockter
- */
-@RunWith(JMock.class)
-public class DefaultScriptProcessorFactoryTest {
-    static final String TEST_BUILD_FILE_NAME = "mybuild.craidle";
-    static final String TEST_SCRIPT_TEXT = "sometext";
-
-    DefaultScriptProcessorFactory scriptProcessor;
-
-    File testCacheDir;
-    File testScriptFileDir;
-    File testScriptFile;
-
-    ClassLoader testClassLoader;
-    ClassLoader originalClassLoader;
-
-    ScriptCompilationHandler scriptCompilationHandlerMock;
-
-    ScriptWithSource expectedScript;
-
-    Mockery context = new JUnit4Mockery();
-
-    Class expectedScriptBaseClass = Script.class;
-
-    ScriptSource source;
-
-    @Before
-    public void setUp() {
-        context.setImposteriser(ClassImposteriser.INSTANCE);
-        scriptCompilationHandlerMock = context.mock(ScriptCompilationHandler.class);
-        testClassLoader = new URLClassLoader(new URL[0]);
-        testScriptFileDir = HelperUtil.makeNewTestDir("projectdir");
-        testScriptFile = new File(testScriptFileDir, TEST_BUILD_FILE_NAME);
-        testCacheDir = new File(new File(new File(testScriptFileDir, Project.CACHE_DIR_NAME), TEST_BUILD_FILE_NAME), "NoTransformer");
-        expectedScript = context.mock(ScriptWithSource.class);
-        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.ON);
-        source = context.mock(ScriptSource.class);
-
-        context.checking(new Expectations() {{
-            allowing(source).getDisplayName();
-            will(returnValue("[script source]"));
-
-            allowing(expectedScript).setScriptSource(source);
-        }});
-
-        originalClassLoader = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader(testClassLoader);
-    }
-
-    @After
-    public void tearDown() {
-        Thread.currentThread().setContextClassLoader(originalClassLoader);
-
-        HelperUtil.deleteTestDir();
-    }
-
-    @Test
-    public void testInit() {
-        assertSame(scriptCompilationHandlerMock, scriptProcessor.getScriptCacheHandler());
-        assertEquals(CacheUsage.ON, scriptProcessor.getCacheUsage());
-    }
-
-    @Test
-    public void testWithNonExistingSourceFile() {
-        context.checking(new Expectations(){{
-            allowing(source).getSourceFile();
-            will(returnValue(testScriptFile));
-
-            one(scriptCompilationHandlerMock).createScriptOnTheFly(
-                    source,
-                    testClassLoader,
-                    null,
-                    expectedScriptBaseClass);
-            will(returnValue(expectedScript));
-        }});
-
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testWithNoSouceFile() {
-        context.checking(new Expectations() {
-            {
-                allowing(source).getSourceFile();
-                will(returnValue(null));
-
-                one(scriptCompilationHandlerMock).createScriptOnTheFly(
-                        source,
-                        testClassLoader,
-                        null,
-                        expectedScriptBaseClass);
-                will(returnValue(expectedScript));
-            }
-        });
-
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testWithNonCachedExistingSourceFile() {
-        createBuildScriptFile();
-        context.checking(new Expectations() {
-            {
-                allowing(source).getSourceFile();
-                will(returnValue(testScriptFile));
-
-                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
-                will(returnValue(null));
-
-                one(scriptCompilationHandlerMock).writeToCache(
-                        source,
-                        testClassLoader,
-                        testCacheDir,
-                        null,
-                        expectedScriptBaseClass);
-
-                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
-                will(returnValue(expectedScript));
-
-            }
-        });
-
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testWithExistingCachedSourceFile() {
-        createBuildScriptFile();
-        context.checking(new Expectations() {
-            {
-                allowing(source).getSourceFile();
-                will(returnValue(testScriptFile));
-
-                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
-                will(returnValue(expectedScript));
-            }
-        });
-
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testWithExistingBuildFileAndRebuildCache() {
-        createBuildScriptFile();
-        context.checking(new Expectations() {
-            {
-                allowing(source).getSourceFile();
-                will(returnValue(testScriptFile));
-
-                one(scriptCompilationHandlerMock).writeToCache(
-                        source,
-                        testClassLoader,
-                        testCacheDir,
-                        null,
-                        expectedScriptBaseClass);
-
-                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
-                will(returnValue(expectedScript));
-            }
-        });
-
-        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.REBUILD);
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testWithExistingSourceFileAndCacheOff() {
-        createBuildScriptFile();
-        context.checking(new Expectations() {
-            {
-                allowing(source).getSourceFile();
-                will(returnValue(testScriptFile));
-
-                one(scriptCompilationHandlerMock).createScriptOnTheFly(
-                        source,
-                        testClassLoader,
-                        null,
-                        expectedScriptBaseClass);
-                will(returnValue(expectedScript));
-            }
-        });
-
-        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.OFF);
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testWithNonExistingSourceFileAndCacheOff() {
-        context.checking(new Expectations() {
-            {
-                allowing(source).getSourceFile();
-                will(returnValue(testScriptFile));
-
-                one(scriptCompilationHandlerMock).createScriptOnTheFly(
-                        source,
-                        testClassLoader,
-                        null,
-                        expectedScriptBaseClass);
-                will(returnValue(expectedScript));
-            }
-        });
-
-        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.OFF);
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testUsesSuppliedClassLoader() {
-        final ClassLoader classLoader = new ClassLoader() {
-        };
-
-        context.checking(new Expectations(){{
-            allowing(source).getSourceFile();
-            will(returnValue(testScriptFile));
-
-            one(scriptCompilationHandlerMock).createScriptOnTheFly(
-                    source,
-                    classLoader,
-                    null,
-                    expectedScriptBaseClass);
-            will(returnValue(expectedScript));
-        }});
-
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).setClassloader(classLoader).process(expectedScriptBaseClass));
-    }
-
-    @Test
-    public void testUsesSuppliedTransformerToGenerateCacheDir() {
-        createBuildScriptFile();
-
-        final CompilationUnit.SourceUnitOperation transformer = new CompilationUnit.SourceUnitOperation() {
-            public void call(SourceUnit source) throws CompilationFailedException {
-            }
-        };
-        final File expectedCacheDir = new File(testCacheDir.getParentFile(), transformer.getClass().getSimpleName());
-
-        context.checking(new Expectations(){{
-            allowing(source).getSourceFile();
-            will(returnValue(testScriptFile));
-
-            one(scriptCompilationHandlerMock).loadFromCache(
-                    source,
-                    testClassLoader,
-                    expectedCacheDir,
-                    expectedScriptBaseClass);
-            will(returnValue(expectedScript));
-        }});
-
-        assertSame(expectedScript, scriptProcessor.createProcessor(source).setTransformer(transformer).process(expectedScriptBaseClass));
-    }
-    
-    private void createBuildScriptFile() {
-        try {
-            FileUtils.writeStringToFile(testScriptFile, TEST_SCRIPT_TEXT);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
+/*
+ * Copyright 2007-2008 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.groovy.scripts;
+
+import groovy.lang.Script;
+import org.apache.commons.io.FileUtils;
+import org.gradle.CacheUsage;
+import org.gradle.api.Project;
+import org.gradle.util.HelperUtil;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.lib.legacy.ClassImposteriser;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import org.jmock.integration.junit4.JMock;
+import org.junit.After;
+import static org.junit.Assert.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.CompilationFailedException;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+
+/**
+ * @author Hans Dockter
+ */
+@RunWith(JMock.class)
+public class DefaultScriptProcessorFactoryTest {
+    static final String TEST_BUILD_FILE_NAME = "mybuild.craidle";
+    static final String TEST_SCRIPT_TEXT = "sometext";
+
+    DefaultScriptProcessorFactory scriptProcessor;
+
+    File testCacheDir;
+    File testScriptFileDir;
+    File testScriptFile;
+
+    ClassLoader testClassLoader;
+    ClassLoader originalClassLoader;
+
+    ScriptCompilationHandler scriptCompilationHandlerMock;
+
+    ScriptWithSource expectedScript;
+
+    Mockery context = new JUnit4Mockery();
+
+    Class expectedScriptBaseClass = Script.class;
+
+    ScriptSource source;
+
+    @Before
+    public void setUp() {
+        context.setImposteriser(ClassImposteriser.INSTANCE);
+        scriptCompilationHandlerMock = context.mock(ScriptCompilationHandler.class);
+        testClassLoader = new URLClassLoader(new URL[0]);
+        testScriptFileDir = HelperUtil.makeNewTestDir("projectdir");
+        testScriptFile = new File(testScriptFileDir, TEST_BUILD_FILE_NAME);
+        testCacheDir = new File(new File(new File(testScriptFileDir, Project.CACHE_DIR_NAME), TEST_BUILD_FILE_NAME), "NoTransformer");
+        expectedScript = context.mock(ScriptWithSource.class);
+        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.ON);
+        source = context.mock(ScriptSource.class);
+
+        context.checking(new Expectations() {{
+            allowing(source).getDisplayName();
+            will(returnValue("[script source]"));
+
+            allowing(expectedScript).setScriptSource(source);
+        }});
+
+        originalClassLoader = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(testClassLoader);
+    }
+
+    @After
+    public void tearDown() {
+        Thread.currentThread().setContextClassLoader(originalClassLoader);
+
+        HelperUtil.deleteTestDir();
+    }
+
+    @Test
+    public void testInit() {
+        assertSame(scriptCompilationHandlerMock, scriptProcessor.getScriptCacheHandler());
+        assertEquals(CacheUsage.ON, scriptProcessor.getCacheUsage());
+    }
+
+    @Test
+    public void testWithNonExistingSourceFile() {
+        context.checking(new Expectations(){{
+            allowing(source).getSourceFile();
+            will(returnValue(testScriptFile));
+
+            one(scriptCompilationHandlerMock).createScriptOnTheFly(
+                    source,
+                    testClassLoader,
+                    Collections.emptyList(),
+                    expectedScriptBaseClass);
+            will(returnValue(expectedScript));
+        }});
+
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testWithNoSouceFile() {
+        context.checking(new Expectations() {
+            {
+                allowing(source).getSourceFile();
+                will(returnValue(null));
+
+                one(scriptCompilationHandlerMock).createScriptOnTheFly(
+                        source,
+                        testClassLoader,
+                        Collections.emptyList(),
+                        expectedScriptBaseClass);
+                will(returnValue(expectedScript));
+            }
+        });
+
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testWithNonCachedExistingSourceFile() {
+        createBuildScriptFile();
+        context.checking(new Expectations() {
+            {
+                allowing(source).getSourceFile();
+                will(returnValue(testScriptFile));
+
+                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
+                will(returnValue(null));
+
+                one(scriptCompilationHandlerMock).writeToCache(
+                        source,
+                        testClassLoader,
+                        testCacheDir,
+                        Collections.emptyList(),
+                        expectedScriptBaseClass);
+
+                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
+                will(returnValue(expectedScript));
+
+            }
+        });
+
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testWithExistingCachedSourceFile() {
+        createBuildScriptFile();
+        context.checking(new Expectations() {
+            {
+                allowing(source).getSourceFile();
+                will(returnValue(testScriptFile));
+
+                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
+                will(returnValue(expectedScript));
+            }
+        });
+
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testWithExistingBuildFileAndRebuildCache() {
+        createBuildScriptFile();
+        context.checking(new Expectations() {
+            {
+                allowing(source).getSourceFile();
+                will(returnValue(testScriptFile));
+
+                one(scriptCompilationHandlerMock).writeToCache(
+                        source,
+                        testClassLoader,
+                        testCacheDir,
+                        Collections.emptyList(),
+                        expectedScriptBaseClass);
+
+                one(scriptCompilationHandlerMock).loadFromCache(source, testClassLoader, testCacheDir, expectedScriptBaseClass);
+                will(returnValue(expectedScript));
+            }
+        });
+
+        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.REBUILD);
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testWithExistingSourceFileAndCacheOff() {
+        createBuildScriptFile();
+        context.checking(new Expectations() {
+            {
+                allowing(source).getSourceFile();
+                will(returnValue(testScriptFile));
+
+                one(scriptCompilationHandlerMock).createScriptOnTheFly(
+                        source,
+                        testClassLoader,
+                        Collections.emptyList(),
+                        expectedScriptBaseClass);
+                will(returnValue(expectedScript));
+            }
+        });
+
+        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.OFF);
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testWithNonExistingSourceFileAndCacheOff() {
+        context.checking(new Expectations() {
+            {
+                allowing(source).getSourceFile();
+                will(returnValue(testScriptFile));
+
+                one(scriptCompilationHandlerMock).createScriptOnTheFly(
+                        source,
+                        testClassLoader,
+                        Collections.emptyList(),
+                        expectedScriptBaseClass);
+                will(returnValue(expectedScript));
+            }
+        });
+
+        scriptProcessor = new DefaultScriptProcessorFactory(scriptCompilationHandlerMock, CacheUsage.OFF);
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testUsesSuppliedClassLoader() {
+        final ClassLoader classLoader = new ClassLoader() {
+        };
+
+        context.checking(new Expectations(){{
+            allowing(source).getSourceFile();
+            will(returnValue(testScriptFile));
+
+            one(scriptCompilationHandlerMock).createScriptOnTheFly(
+                    source,
+                    classLoader,
+                    Collections.emptyList(),
+                    expectedScriptBaseClass);
+            will(returnValue(expectedScript));
+        }});
+
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).setClassloader(classLoader).process(expectedScriptBaseClass));
+    }
+
+    @Test
+    public void testUsesSuppliedTransformerToGenerateCacheDir() {
+        createBuildScriptFile();
+
+        final CompilationUnit.SourceUnitOperation transformer = new CompilationUnit.SourceUnitOperation() {
+            public void call(SourceUnit source) throws CompilationFailedException {
+            }
+        };
+        final File expectedCacheDir = new File(testCacheDir.getParentFile(), transformer.getClass().getSimpleName());
+
+        context.checking(new Expectations(){{
+            allowing(source).getSourceFile();
+            will(returnValue(testScriptFile));
+
+            one(scriptCompilationHandlerMock).loadFromCache(
+                    source,
+                    testClassLoader,
+                    expectedCacheDir,
+                    expectedScriptBaseClass);
+            will(returnValue(expectedScript));
+        }});
+
+        assertSame(expectedScript, scriptProcessor.createProcessor(source).addTransformer(transformer).process(expectedScriptBaseClass));
+    }
+    
+    private void createBuildScriptFile() {
+        try {
+            FileUtils.writeStringToFile(testScriptFile, TEST_SCRIPT_TEXT);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
 }
\ No newline at end of file
