diff --git a/build.gradle b/build.gradle index 7be46cbb4568..32a84faa9f26 100644 --- a/build.gradle +++ b/build.gradle @@ -50,7 +50,7 @@ libraries = [ commons_io : 'commons-io:commons-io:1.4@jar', commons_lang : 'commons-lang:commons-lang:2.4@jar', dom4j : 'dom4j:dom4j:1.6.1@jar', - groovy : 'org.codehaus.groovy:groovy:1.7.0@jar', + groovy : 'org.codehaus.groovy:groovy-all:1.7.0@jar', ivy : 'org.apache.ivy:ivy:2.1.0@jar', jaxen : 'jaxen:jaxen:1.1@jar', jopt_simple : 'net.sf.jopt-simple:jopt-simple:3.2@jar', @@ -63,8 +63,8 @@ libraries = [ junit : 'junit:junit:4.7' ] -libraries.groovy_depends = [libraries.groovy, libraries.ant, libraries.ant_launcher, libraries.asm_all, - libraries.antlr, libraries.commons_cli, libraries.ant_junit, libraries.junit] +libraries.groovy_depends = [libraries.groovy, libraries.ant, libraries.ant_launcher, libraries.commons_cli, + libraries.ant_junit, libraries.junit] libraries.jetty_depends = ["org.mortbay.jetty:jetty:6.1.22@jar", "org.mortbay.jetty:jetty-util:6.1.22@jar", "javax.servlet:servlet-api:2.5@jar"] @@ -137,15 +137,22 @@ configurations { runtime { visible = false } + plugins { + visible = false + } testRuntime { extendsFrom runtime + extendsFrom plugins } } dependencies { - groovyProjects().each { + runtimeProjects().each { runtime project(path: it.path) } + pluginProjects().each { + plugins project(path: it.path) + } } evaluationDependsOn(':docs') @@ -176,6 +183,9 @@ binDistImage = copySpec { } into('lib') { from configurations.runtime + into('plugins') { + from configurations.plugins - configurations.runtime + } } } @@ -353,6 +363,14 @@ def groovyProjects() { subprojects.findAll { project -> project.name != 'docs' } } +def runtimeProjects() { + groovyProjects() - pluginProjects() +} + +def pluginProjects() { + ['plugins', 'codeQuality', 'jetty', 'wrapper'].collect { project(it) } +} + class Version { String versionNumber Date buildTime diff --git a/subprojects/gradle-core/core.gradle b/subprojects/gradle-core/core.gradle index 77553f748a34..be6fc585fa6c 100644 --- a/subprojects/gradle-core/core.gradle +++ b/subprojects/gradle-core/core.gradle @@ -103,7 +103,7 @@ def writeVersionProperties(File destination) { test { xmsSize = '128m' - xmxSize = '1100m' + xmxSize = '512m' maxPermSize = '128m' // there must be a nicer way of doing this... diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/BuildAggregationIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/BuildAggregationIntegrationTest.groovy index 6e26f81e3cc3..47c29ec3f8db 100644 --- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/BuildAggregationIntegrationTest.groovy +++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/BuildAggregationIntegrationTest.groovy @@ -18,59 +18,67 @@ package org.gradle.integtests import org.junit.Test import static org.hamcrest.Matchers.* import org.gradle.util.TestFile +import org.junit.runner.RunWith + +@RunWith(DistributionIntegrationTestRunner.class) +class BuildAggregationIntegrationTest { + // Injected by test runner + private GradleDistribution dist; + private GradleExecuter executer; -class BuildAggregationIntegrationTest extends AbstractIntegrationTest { @Test public void canExecuteAnotherBuildFromBuild() { - testFile('build.gradle') << ''' - assertThat(gradle.parent, nullValue()) + dist.testFile('build.gradle') << ''' + assert gradle.parent == null task build(type: GradleBuild) { dir = 'other' tasks = ['dostuff'] + startParameter.searchUpwards = false } ''' - testFile('other/build.gradle') << ''' - assertThat(gradle.parent, notNullValue()) + dist.testFile('other/build.gradle') << ''' + assert gradle.parent != null task dostuff << { - assertThat(gradle.parent, notNullValue()) + assert gradle.parent != null } ''' - inTestDirectory().withTasks('build').run() + executer.withTasks('build').run() } @Test public void treatsBuildSrcProjectAsANestedBuild() { - testFile('build.gradle') << ''' - assertThat(gradle.parent, nullValue()) + dist.testFile('build.gradle') << ''' + assert gradle.parent == null task build ''' - testFile('buildSrc/build.gradle') << ''' + dist.testFile('buildSrc/build.gradle') << ''' apply id: 'java' - assertThat(gradle.parent, notNullValue()) + assert gradle.parent != null classes << { - assertThat(gradle.parent, notNullValue()) + assert gradle.parent != null } ''' - inTestDirectory().withTasks('build').run() + executer.withTasks('build').run() } @Test public void reportsNestedBuildFailure() { - TestFile other = testFile('other.gradle') << ''' + TestFile other = dist.testFile('other.gradle') << ''' 1/0 ''' - testFile('build.gradle') << ''' + dist.testFile('build.gradle') << ''' task build(type: GradleBuild) { buildFile = 'other.gradle' + startParameter.searchUpwards = false } ''' - ExecutionFailure failure = inTestDirectory().withTasks('build').runWithFailure() + ExecutionFailure failure = executer.withTasks('build').runWithFailure() failure.assertHasFileName("Build file '${other}'") failure.assertHasLineNumber(2) failure.assertHasDescription('A problem occurred evaluating root project') @@ -79,11 +87,9 @@ class BuildAggregationIntegrationTest extends AbstractIntegrationTest { @Test public void reportsBuildSrcFailure() { - testFile('buildSrc/src/main/java/Broken.java') << 'broken!' - ExecutionFailure failure = inTestDirectory().runWithFailure() + dist.testFile('buildSrc/src/main/java/Broken.java') << 'broken!' + ExecutionFailure failure = executer.runWithFailure() failure.assertHasFileName('Default buildSrc build script') failure.assertHasDescription('Execution failed for task \':compileJava\'') } } - - diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CodeQualityIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CodeQualityIntegrationTest.groovy index dd7ac4905ed4..bbf9990c6f96 100644 --- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CodeQualityIntegrationTest.groovy +++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/CodeQualityIntegrationTest.groovy @@ -53,7 +53,7 @@ apply id: 'code-quality' testFile('build.gradle') << ''' apply id: 'groovy' apply id: 'code-quality' -dependencies { groovy files(org.gradle.util.BootstrapUtil.gradleClasspath) } +dependencies { groovy localGroovy() } ''' writeCheckstyleConfig() @@ -111,7 +111,7 @@ apply id: 'code-quality' testFile('build.gradle') << ''' apply id: 'groovy' apply id: 'code-quality' -dependencies { groovy files(org.gradle.util.BootstrapUtil.gradleClasspath) } +dependencies { groovy localGroovy() } ''' writeCodeNarcConfigFile() @@ -146,7 +146,7 @@ apply id: 'code-quality' testFile('build.gradle') << ''' apply id: 'groovy' apply id: 'code-quality' -dependencies { groovy files(org.gradle.util.BootstrapUtil.gradleClasspath) } +dependencies { groovy localGroovy() } ''' writeCodeNarcConfigFile() diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/DistributionIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/DistributionIntegrationTest.groovy index 693df03a311d..30833788cf9c 100644 --- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/DistributionIntegrationTest.groovy +++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/DistributionIntegrationTest.groovy @@ -86,8 +86,11 @@ class DistributionIntegrationTest { contentsDir.file("lib/gradle-core-${version}.jar").assertIsFile() contentsDir.file("lib/gradle-ui-${version}.jar").assertIsFile() contentsDir.file("lib/gradle-launcher-${version}.jar").assertIsFile() - contentsDir.file("lib/gradle-jetty-${version}.jar").assertIsFile() - contentsDir.file("lib/gradle-wrapper-${version}.jar").assertIsFile() + contentsDir.file("lib/plugins/gradle-code-quality-${version}.jar").assertIsFile() + contentsDir.file("lib/plugins/gradle-plugins-${version}.jar").assertIsFile() + contentsDir.file("lib/plugins/gradle-jetty-${version}.jar").assertIsFile() + contentsDir.file("lib/plugins/gradle-wrapper-${version}.jar").assertIsFile() + contentsDir.file("lib/plugins/gradle-wrapper-tasks-${version}.jar").assertIsFile() // Docs contentsDir.file('getting-started.html').assertIsFile() diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ForkingGradleExecuter.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ForkingGradleExecuter.java index 590c30cc1281..2d9f606d4353 100644 --- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ForkingGradleExecuter.java +++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/ForkingGradleExecuter.java @@ -106,6 +106,7 @@ Map executeInternal(String windowsCommandSnippet, String unixCommandSnippet, boo builder.errorOutput(errStream); builder.environment("GRADLE_HOME", ""); builder.environment("JAVA_HOME", System.getProperty("java.home")); + builder.environment("GRADLE_OPTS", "-ea"); builder.environment(environmentVars); builder.execDirectory(getWorkingDir()); @@ -177,7 +178,7 @@ public ForkedExecutionFailure(Map result) { } public void assertHasLineNumber(int lineNumber) { - throw new UnsupportedOperationException(); + assertThat(getError(), containsString(String.format(" line: %d", lineNumber))); } public void assertHasFileName(String filename) { @@ -185,7 +186,7 @@ public void assertHasFileName(String filename) { } public void assertHasCause(String description) { - assertThatCause(equalTo(description)); + assertThatCause(startsWith(description)); } public void assertThatCause(final Matcher matcher) { @@ -203,7 +204,7 @@ public void describeTo(Description description) { } public void assertHasDescription(String context) { - assertThatDescription(equalTo(context)); + assertThatDescription(startsWith(context)); } public void assertThatDescription(Matcher matcher) { diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/InitScriptExecutionIntegrationTest.groovy b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/InitScriptExecutionIntegrationTest.groovy index 62664ff3bb05..e3e61d06014b 100644 --- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/InitScriptExecutionIntegrationTest.groovy +++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/InitScriptExecutionIntegrationTest.groovy @@ -38,7 +38,7 @@ assertNotNull(gradle) assertSame(initscript.classLoader, getClass().classLoader.parent) assertSame(initscript.classLoader, Thread.currentThread().contextClassLoader) assertSame(scriptClassLoader, initscript.classLoader.parent) -assertSame(Gradle.class.classLoader, scriptClassLoader.parent) +assertSame(Gradle.class.classLoader, scriptClassLoader.parent.parent) ''' testFile('build.gradle') << 'task doStuff' diff --git a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/RemoteListenerIntegrationTest.java b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/RemoteListenerIntegrationTest.java index 9c120afe7f4e..bca9a3c6d6a2 100644 --- a/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/RemoteListenerIntegrationTest.java +++ b/subprojects/gradle-core/src/integTest/groovy/org/gradle/integtests/RemoteListenerIntegrationTest.java @@ -48,7 +48,7 @@ public void tryRemoteSenderAndReceiver() throws Throwable { ListenerBroadcast broadcast = new ListenerBroadcast(TestListenerInterface.class); broadcast.add(listenerMock); RemoteExceptionListener exceptionListener = new RemoteExceptionListener(); - RemoteReceiver receiver = new RemoteReceiver(broadcast, exceptionListener); + RemoteReceiver receiver = new RemoteReceiver(broadcast, exceptionListener, getClass().getClassLoader()); executeJava(RemoteProcess.class.getName(), receiver.getBoundPort()); if (exceptionListener.ex != null) { diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java index 4eb1918ce2ee..dc83479ca8b1 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/artifacts/dsl/DependencyHandler.java @@ -95,7 +95,7 @@ public interface DependencyHandler { * Adds a dependency to the given configuration. * * @param configurationName The name of the configuration. - * @param dependencyNotation The dependency notation, in one of the notations decribed above. + * @param dependencyNotation The dependency notation, in one of the notations described above. * @return The dependency. */ Dependency add(String configurationName, Object dependencyNotation); @@ -104,9 +104,51 @@ public interface DependencyHandler { * Adds a dependency to the given configuration, and configures the dependency using the given closure/ * * @param configurationName The name of the configuration. - * @param dependencyNotation The dependency notation, in one of the notations decribed above. + * @param dependencyNotation The dependency notation, in one of the notations described above. * @param configureClosure The closure to use to configure the dependency. * @return The dependency. */ Dependency add(String configurationName, Object dependencyNotation, Closure configureClosure); + + /** + * Creates a dependency on a client module. + * + * @param notation The module notation, in one of the notations described above. + * @return The dependency. + */ + Dependency module(Object notation); + + /** + * Creates a dependency on a client module. The dependency is configured using the given closure before it is + * returned. + * + * @param notation The module notation, in one of the notations described above. + * @param configureClosure The closure to use to configure the dependency. + * @return The dependency. + */ + Dependency module(Object notation, Closure configureClosure); + + /** + * Creates a dependency on a project. + * + * @param notation The project notation, in one of the notations described above. + * @return The dependency. + */ + Dependency project(Object notation); + + /** + * Creates a dependency on a project. The dependency is configured using the given closure before it is returned. + * + * @param notation The project notation, in one of the notations described above. + * @param configureClosure The closure to use to configure the dependency. + * @return The dependency. + */ + Dependency project(Object notation, Closure configureClosure); + + /** + * Creates a dependency on the API of the current version of Gradle. + * + * @return The dependency. + */ + Dependency gradleApi(); } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/ClassPathRegistry.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/ClassPathRegistry.java new file mode 100755 index 000000000000..7c6c7de4ac16 --- /dev/null +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/ClassPathRegistry.java @@ -0,0 +1,26 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.api.internal; + +import java.io.File; +import java.net.URL; +import java.util.List; + +public interface ClassPathRegistry { + URL[] getClassPathUrls(String name); + + List getClassPathFiles(String name); +} diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathRegistry.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathRegistry.java new file mode 100755 index 000000000000..d7511f732ded --- /dev/null +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/DefaultClassPathRegistry.java @@ -0,0 +1,168 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.api.internal; + +import org.gradle.api.GradleException; +import org.gradle.api.UncheckedIOException; + +import java.io.File; +import java.net.*; +import java.util.*; +import java.util.regex.Pattern; + +public class DefaultClassPathRegistry implements ClassPathRegistry { + private final Scanner pluginLibDir; + private final Scanner runtimeLibDir; + private final List all = Arrays.asList(Pattern.compile(".+")); + private final Map> classPaths = new HashMap>(); + + public DefaultClassPathRegistry() { + URI location; + try { + location = DefaultClassPathRegistry.class.getProtectionDomain().getCodeSource().getLocation().toURI(); + } catch (URISyntaxException e) { + throw new UncheckedIOException(e); + } + if (!location.getScheme().equals("file")) { + throw new GradleException(String.format("Cannot determine Gradle home using codebase '%s'.", location)); + } + File codeSource = new File(location.getPath()); + if (codeSource.isFile()) { + File gradleHome = codeSource.getParentFile().getParentFile(); + runtimeLibDir = new DirScanner(new File(gradleHome + "/lib")); + pluginLibDir = new DirScanner(new File(gradleHome + "/lib/plugins")); + } else { + runtimeLibDir = new ClassPathScanner(codeSource); + pluginLibDir = new ClassPathScanner(codeSource); + } + + List groovyPatterns = toPatterns("groovy-all"); + classPaths.put("LOCAL_GROOVY", groovyPatterns); + List gradleApiPatterns = toPatterns("gradle-\\w+", "ivy"); + gradleApiPatterns.addAll(groovyPatterns); + classPaths.put("GRADLE_API", gradleApiPatterns); + classPaths.put("GRADLE_CORE", toPatterns("gradle-core")); + classPaths.put("ANT", toPatterns("ant", "ant-launcher")); + classPaths.put("ANT_JUNIT", toPatterns("ant", "ant-launcher", "ant-junit")); + classPaths.put("TEST_LISTENER", toPatterns("gradle-core", "gradle-plugins")); + classPaths.put("COMMONS_CLI", toPatterns("commons-cli")); + } + + private static List toPatterns(String... patternStrings) { + List patterns = new ArrayList(); + for (String patternString : patternStrings) { + patterns.add(Pattern.compile(patternString + "-.+")); + } + return patterns; + } + + public URL[] getClassPathUrls(String name) { + return toURIs(getClassPathFiles(name)); + } + + public List getClassPathFiles(String name) { + List matches = new ArrayList(); + if (name.equals("GRADLE_PLUGINS")) { + pluginLibDir.find(all, matches); + return matches; + } + if (name.equals("GRADLE_RUNTIME")) { + runtimeLibDir.find(all, matches); + return matches; + } + List classPathPatterns = classPaths.get(name); + if (classPathPatterns != null) { + runtimeLibDir.find(classPathPatterns, matches); + pluginLibDir.find(classPathPatterns, matches); + return matches; + } + throw new IllegalArgumentException(String.format("unknown classpath '%s' requested.", name)); + } + + private URL[] toURIs(List files) { + URL[] urls = new URL[files.size()]; + for (int i = 0; i < files.size(); i++) { + File file = files.get(i); + try { + urls[i] = file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new UncheckedIOException(e); + } + } + return urls; + } + + private static boolean matches(List patterns, String name) { + for (Pattern pattern : patterns) { + if (pattern.matcher(name).matches()) { + return true; + } + } + return false; + } + + private interface Scanner { + void find(List patterns, Collection into); + } + + private static class DirScanner implements Scanner { + private final File dir; + + private DirScanner(File dir) { + this.dir = dir; + } + + public void find(List patterns, Collection into) { + for (File file : dir.listFiles()) { + if (matches(patterns, file.getName())) { + into.add(file); + } + } + } + } + + private static class ClassPathScanner implements Scanner { + private final File classesDir; + + private ClassPathScanner(File classesDir) { + this.classesDir = classesDir; + } + + public void find(List patterns, Collection into) { + if (matches(patterns, "gradle-core-version.jar")) { + into.add(classesDir); + } + + ClassLoader classLoader = getClass().getClassLoader(); + if (classLoader instanceof URLClassLoader) { + URLClassLoader urlClassLoader = (URLClassLoader) classLoader; + URL[] urls = urlClassLoader.getURLs(); + for (URL url : urls) { + if (url.getProtocol().equals("file")) { + try { + File file = new File(url.toURI()); + if (matches(patterns, file.getName())) { + into.add(file); + } + } catch (URISyntaxException e) { + throw new UncheckedIOException(e); + } + } + } + } + } + } +} diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/SettingsInternal.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/SettingsInternal.java index 303be748e800..04575f46573b 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/SettingsInternal.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/SettingsInternal.java @@ -22,10 +22,8 @@ import org.gradle.groovy.scripts.ScriptSource; import org.gradle.initialization.DefaultProjectDescriptor; -import java.net.URLClassLoader; - public interface SettingsInternal extends Settings { - URLClassLoader createClassLoader(); + ClassLoader getClassLoader(); StartParameter getStartParameter(); diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/ClassPathDependencyFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/ClassPathDependencyFactory.java new file mode 100755 index 000000000000..6fcb6670eae1 --- /dev/null +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/ClassPathDependencyFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.api.internal.artifacts.dsl.dependencies; + +import org.gradle.api.IllegalDependencyNotation; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.file.FileCollection; +import org.gradle.api.internal.ClassGenerator; +import org.gradle.api.internal.ClassPathRegistry; +import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency; +import org.gradle.api.internal.file.FileResolver; + +public class ClassPathDependencyFactory implements IDependencyImplementationFactory { + private final ClassPathRegistry classPathRegistry; + private final ClassGenerator classGenerator; + private final FileResolver fileResolver; + + public ClassPathDependencyFactory(ClassGenerator classGenerator, ClassPathRegistry classPathRegistry, + FileResolver fileResolver) { + this.classGenerator = classGenerator; + this.classPathRegistry = classPathRegistry; + this.fileResolver = fileResolver; + } + + public T createDependency(Class type, Object userDependencyDescription) + throws IllegalDependencyNotation { + if (userDependencyDescription instanceof DependencyFactory.ClassPathNotation) { + DependencyFactory.ClassPathNotation classPathNotation + = (DependencyFactory.ClassPathNotation) userDependencyDescription; + FileCollection files = fileResolver.resolveFiles(classPathRegistry.getClassPathFiles(classPathNotation.name())); + return type.cast(classGenerator.newInstance(DefaultSelfResolvingDependency.class, files)); + } + + throw new IllegalDependencyNotation(); + } +} diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyFactory.java index 26a9823e2f7a..0f5a7017e038 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyFactory.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyFactory.java @@ -63,12 +63,13 @@ public Dependency createDependency(Object dependencyNotation) { // ignore } catch (Exception e) { - throw new GradleException("Dependency creation error.", e); + throw new GradleException(String.format("Could not create a dependency using notation: %s", dependencyNotation), e); } } if (dependency == null) { - throw new InvalidUserDataException("The dependency notation: " + dependencyNotation + " is invalid!"); + throw new InvalidUserDataException(String.format("The dependency notation: %s is invalid.", + dependencyNotation)); } return dependency; } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.groovy b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.groovy index 26a0103e8fcd..2413fae2b913 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.groovy +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandler.groovy @@ -68,6 +68,14 @@ class DefaultDependencyHandler implements DependencyHandler { return dependencyFactory.createModule(notation, configureClosure) } + public Dependency gradleApi() { + return dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.GRADLE_API); + } + + public Dependency localGroovy() { + return dependencyFactory.createDependency(DependencyFactory.ClassPathNotation.LOCAL_GROOVY); + } + public def methodMissing(String name, args) { Configuration configuration = configurationContainer.findByName(name) if (configuration == null) { diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java index b736d4f68292..17f90900ab40 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DependencyFactory.java @@ -24,6 +24,10 @@ * @author Hans Dockter */ public interface DependencyFactory { + enum ClassPathNotation { + GRADLE_API, LOCAL_GROOVY + } + Dependency createDependency(Object dependencyNotation, Closure closure); Dependency createDependency(Object dependencyNotation); diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy index 7ca569046b4f..6c6e4e5c47b9 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilder.groovy @@ -18,9 +18,15 @@ package org.gradle.api.internal.project import org.gradle.api.internal.project.ant.BasicAntBuilder import org.gradle.api.internal.project.ant.AntLoggingAdapter import org.gradle.util.* +import org.gradle.api.internal.ClassPathRegistry class DefaultIsolatedAntBuilder implements IsolatedAntBuilder { private final Map, Map> classloaders = [:] + private final ClassPathRegistry classPathRegistry + + def DefaultIsolatedAntBuilder(ClassPathRegistry classPathRegistry) { + this.classPathRegistry = classPathRegistry + } void execute(Iterable classpath, Closure antClosure) { List normalisedClasspath = classpath as List @@ -37,7 +43,8 @@ class DefaultIsolatedAntBuilder implements IsolatedAntBuilder { Closure converter = {File file -> file.toURI().toURL() } URL[] classpathUrls = fullClasspath.collect(converter) - URL[] gradleCoreUrls = BootstrapUtil.gradleCoreFiles.collect(converter) + // Need gradle core to pick up ant logging adapter + URL[] gradleCoreUrls = classPathRegistry.getClassPathUrls("GRADLE_CORE") FilteringClassLoader loggingLoader = new FilteringClassLoader(getClass().classLoader) loggingLoader.allowPackage('org.slf4j') diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/GlobalServicesRegistry.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/GlobalServicesRegistry.java index 048250e23910..fca07b8599bf 100755 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/GlobalServicesRegistry.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/GlobalServicesRegistry.java @@ -15,20 +15,20 @@ */ package org.gradle.api.internal.project; +import org.gradle.api.internal.ClassPathRegistry; +import org.gradle.api.internal.DefaultClassPathRegistry; import org.gradle.cache.CacheFactory; import org.gradle.cache.DefaultCacheFactory; -import org.gradle.initialization.CommandLine2StartParameterConverter; -import org.gradle.initialization.DefaultCommandLine2StartParameterConverter; -import org.gradle.initialization.DefaultLoggingConfigurer; -import org.gradle.initialization.LoggingConfigurer; +import org.gradle.initialization.*; /** * Contains the services shared by all builds in a given process. */ public class GlobalServicesRegistry extends DefaultServiceRegistry { public GlobalServicesRegistry() { - add(LoggingConfigurer.class, new DefaultLoggingConfigurer()); add(CommandLine2StartParameterConverter.class, new DefaultCommandLine2StartParameterConverter()); add(CacheFactory.class, new DefaultCacheFactory()); + add(ClassPathRegistry.class, new DefaultClassPathRegistry()); + add(ClassLoaderFactory.class, new DefaultClassLoaderFactory(get(ClassPathRegistry.class))); } } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistry.java b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistry.java index 58524abb8ccc..a6f192a3fb04 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistry.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistry.java @@ -23,10 +23,7 @@ import org.gradle.api.artifacts.dsl.RepositoryHandlerFactory; import org.gradle.api.artifacts.repositories.InternalRepository; import org.gradle.api.execution.TaskActionListener; -import org.gradle.api.internal.AsmBackedClassGenerator; -import org.gradle.api.internal.ClassGenerator; -import org.gradle.api.internal.ExceptionAnalyser; -import org.gradle.api.internal.GradleInternal; +import org.gradle.api.internal.*; import org.gradle.api.internal.artifacts.ConfigurationContainerFactory; import org.gradle.api.internal.artifacts.DefaultConfigurationContainerFactory; import org.gradle.api.internal.artifacts.DefaultModule; @@ -42,6 +39,7 @@ import org.gradle.api.internal.changedetection.DefaultHasher; import org.gradle.api.internal.changedetection.DefaultTaskArtifactStateRepository; import org.gradle.api.internal.changedetection.TaskArtifactStateRepository; +import org.gradle.api.internal.file.IdentityFileResolver; import org.gradle.api.internal.initialization.DefaultScriptHandlerFactory; import org.gradle.api.internal.initialization.ScriptHandlerFactory; import org.gradle.api.internal.tasks.DefaultTaskExecuter; @@ -196,7 +194,11 @@ protected DependencyFactory createDependencyFactory() { new ModuleDependencyFactory( classGenerator), new SelfResolvingDependencyFactory( - classGenerator)), + classGenerator), + new ClassPathDependencyFactory( + classGenerator, + get(ClassPathRegistry.class), + new IdentityFileResolver())), new DefaultClientModuleFactory( classGenerator), new DefaultProjectDependencyFactory( @@ -242,7 +244,7 @@ protected ScriptPluginFactory createScriptObjectConfigurerFactory() { } protected MultiParentClassLoader createRootClassLoader() { - return new MultiParentClassLoader(getClass().getClassLoader()); + return get(ClassLoaderFactory.class).createScriptClassLoader(); } protected InitScriptHandler createInitScriptHandler() { @@ -275,7 +277,7 @@ protected ScriptHandlerFactory createScriptHandlerFactory() { } protected IsolatedAntBuilder createIsolatedAntBuilder() { - return new DefaultIsolatedAntBuilder(); + return new DefaultIsolatedAntBuilder(get(ClassPathRegistry.class)); } public ServiceRegistryFactory createFor(Object domainObject) { diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java b/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java index 877d71c65885..f4eb703bf350 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/groovy/scripts/DefaultScriptCompilationHandler.java @@ -18,6 +18,7 @@ import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyCodeSource; import groovy.lang.Script; +import groovyjarjarasm.asm.ClassWriter; import org.codehaus.groovy.control.CompilationFailedException; import org.codehaus.groovy.control.CompilationUnit; import org.codehaus.groovy.control.CompilerConfiguration; @@ -28,8 +29,6 @@ import org.gradle.util.Clock; import org.gradle.util.GFileUtils; import org.gradle.util.WrapUtil; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,7 +69,7 @@ protected CompilationUnit createCompilationUnit(CompilerConfiguration compilerCo // Groovy will only put the filename into the class, but that does not help a debugger for Gradle // because it does not know where Gradle scripts might live. @Override - protected ClassVisitor createClassVisitor() { + protected groovyjarjarasm.asm.ClassVisitor createClassVisitor() { return new ClassWriter(ClassWriter.COMPUTE_MAXS) { // ignore the sourcePath that is given by Groovy (this is only the filename) and instead // insert the full path if our script source has a source file diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BaseSettings.java b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BaseSettings.java index d3f5af6e8c31..e2fdef4e24f0 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BaseSettings.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BaseSettings.java @@ -24,11 +24,9 @@ import org.gradle.api.internal.SettingsInternal; import org.gradle.api.internal.project.IProjectRegistry; import org.gradle.groovy.scripts.ScriptSource; -import org.gradle.util.ClasspathUtil; import java.io.File; import java.net.URLClassLoader; -import java.util.Collections; import java.util.Map; /** @@ -141,17 +139,6 @@ private String removeTrailingColon(String projectPath) { return projectPath; } - // todo We don't have command query separation here. This is a temporary thing. If our new classloader handling works out, which - // adds simply the build script jars to the context classloader we can remove the return argument and simplify our design. - public URLClassLoader createClassLoader() { - File toolsJar = ClasspathUtil.getToolsJar(); - if (toolsJar != null) { - ClasspathUtil.addUrl((URLClassLoader) classloader.getParent(), Collections.singleton(toolsJar)); - } - - return classloader; - } - public URLClassLoader getClassLoader() { return classloader; } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BuildSourceBuilder.java b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BuildSourceBuilder.java index 8710b491ed9e..48659ef83da2 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BuildSourceBuilder.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/BuildSourceBuilder.java @@ -43,12 +43,14 @@ public class BuildSourceBuilder { private GradleLauncherFactory gradleLauncherFactory; private CacheInvalidationStrategy cacheInvalidationStrategy; + private final ClassLoaderFactory classLoaderFactory; private static final String DEFAULT_BUILD_SOURCE_SCRIPT_RESOURCE = "defaultBuildSourceScript.txt"; - public BuildSourceBuilder(GradleLauncherFactory gradleLauncherFactory, CacheInvalidationStrategy cacheInvalidationStrategy) { + public BuildSourceBuilder(GradleLauncherFactory gradleLauncherFactory, CacheInvalidationStrategy cacheInvalidationStrategy, ClassLoaderFactory classLoaderFactory) { this.gradleLauncherFactory = gradleLauncherFactory; this.cacheInvalidationStrategy = cacheInvalidationStrategy; + this.classLoaderFactory = classLoaderFactory; } public URLClassLoader buildAndCreateClassLoader(StartParameter startParameter) @@ -67,7 +69,7 @@ public URLClassLoader buildAndCreateClassLoader(StartParameter startParameter) throw new UncheckedIOException(e); } } - return new URLClassLoader(urls, getClass().getClassLoader()); + return new URLClassLoader(urls, classLoaderFactory.getRootClassLoader()); } public Set createBuildSourceClasspath(StartParameter startParameter) { diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/ClassLoaderFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/ClassLoaderFactory.java new file mode 100755 index 000000000000..1314e7c5a908 --- /dev/null +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/ClassLoaderFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.initialization; + +import org.gradle.util.MultiParentClassLoader; + +public interface ClassLoaderFactory { + /** + * Returns the root ClassLoader shared by all builds. + */ + ClassLoader getRootClassLoader(); + + /** + * Creates the script ClassLoader for a build. + */ + MultiParentClassLoader createScriptClassLoader(); +} diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultClassLoaderFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultClassLoaderFactory.java new file mode 100755 index 000000000000..792af813659e --- /dev/null +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultClassLoaderFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.initialization; + +import org.gradle.api.internal.ClassPathRegistry; +import org.gradle.util.ClasspathUtil; +import org.gradle.util.MultiParentClassLoader; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collections; + +public class DefaultClassLoaderFactory implements ClassLoaderFactory { + private final URLClassLoader rootClassLoader; + + public DefaultClassLoaderFactory(ClassPathRegistry classPathRegistry) { + // Add in tools.jar + ClassLoader parent = getClass().getClassLoader(); + File toolsJar = ClasspathUtil.getToolsJar(); + if (toolsJar != null) { + ClasspathUtil.addUrl((URLClassLoader) parent, Collections.singleton(toolsJar)); + } + + // Add in libs for plugins + URL[] classPath = classPathRegistry.getClassPathUrls("GRADLE_PLUGINS"); + rootClassLoader = new URLClassLoader(classPath, parent); + } + + public ClassLoader getRootClassLoader() { + return rootClassLoader; + } + + public MultiParentClassLoader createScriptClassLoader() { + return new MultiParentClassLoader(rootClassLoader); + } +} diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java index 04a160599629..7ee0fc3b570e 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/DefaultGradleLauncherFactory.java @@ -17,10 +17,11 @@ import org.gradle.*; import org.gradle.api.internal.ExceptionAnalyser; -import org.gradle.api.internal.project.TopLevelBuildServiceRegistry; import org.gradle.api.internal.project.GlobalServicesRegistry; import org.gradle.api.internal.project.ProjectFactory; import org.gradle.api.internal.project.ServiceRegistry; +import org.gradle.api.internal.project.TopLevelBuildServiceRegistry; +import org.gradle.api.logging.LogLevel; import org.gradle.api.logging.Logging; import org.gradle.api.logging.StandardOutputListener; import org.gradle.configuration.BuildConfigurer; @@ -33,13 +34,15 @@ * @author Hans Dockter */ public class DefaultGradleLauncherFactory implements GradleLauncherFactory { - private final ServiceRegistry sharedServices = new GlobalServicesRegistry(); + private final ServiceRegistry sharedServices; private final NestedBuildTracker tracker = new NestedBuildTracker(); private LoggingConfigurer loggingConfigurer; private CommandLine2StartParameterConverter commandLine2StartParameterConverter; public DefaultGradleLauncherFactory() { - loggingConfigurer = sharedServices.get(LoggingConfigurer.class); + loggingConfigurer = new DefaultLoggingConfigurer(); + loggingConfigurer.configure(LogLevel.LIFECYCLE); + sharedServices = new GlobalServicesRegistry(); commandLine2StartParameterConverter = sharedServices.get(CommandLine2StartParameterConverter.class); } @@ -79,7 +82,8 @@ public GradleLauncher newInstance(StartParameter startParameter) { serviceRegistry.get(SettingsProcessor.class), new BuildSourceBuilder( this, - new DefaultCacheInvalidationStrategy() + new DefaultCacheInvalidationStrategy(), + serviceRegistry.get(ClassLoaderFactory.class) )), new DefaultGradlePropertiesLoader(), new BuildLoader( diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/SettingsHandler.java b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/SettingsHandler.java index 501a85179719..e02ae9846633 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/SettingsHandler.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/initialization/SettingsHandler.java @@ -63,7 +63,7 @@ public SettingsInternal findAndLoadSettings(GradleInternal gradle, IGradleProper } } - gradle.getScriptClassLoader().addParent(settings.createClassLoader()); + gradle.getScriptClassLoader().addParent(settings.getClassLoader()); return settings; } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/listener/dispatch/AsyncDispatch.java b/subprojects/gradle-core/src/main/groovy/org/gradle/listener/dispatch/AsyncDispatch.java index ae99818071b7..6b04dc47b9e2 100755 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/listener/dispatch/AsyncDispatch.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/listener/dispatch/AsyncDispatch.java @@ -16,6 +16,7 @@ package org.gradle.listener.dispatch; import java.util.ArrayList; +import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executor; @@ -28,17 +29,41 @@ public class AsyncDispatch implements CloseableDispatch { private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private final LinkedList queue = new LinkedList(); + private final int maxQueueSize; private boolean closed; + private boolean dispatching = true; public AsyncDispatch(Executor executor, final Dispatch dispatch) { + this(executor, dispatch, MAX_QUEUE_SIZE); + } + + public AsyncDispatch(Executor executor, final Dispatch dispatch, int maxQueueSize) { + this.maxQueueSize = maxQueueSize; executor.execute(new Runnable() { public void run() { - pushMessages(dispatch); + dispatchThreadMain(dispatch); } }); } - private void pushMessages(Dispatch dispatch) { + private void dispatchThreadMain(Dispatch dispatch) { + try { + dispatchMessages(dispatch); + } finally { + onDispatchThreadExit(); + } + } + + private void onDispatchThreadExit() { + lock.lock(); + try { + dispatching = false; + } finally { + lock.unlock(); + } + } + + private void dispatchMessages(Dispatch dispatch) { while (true) { List messages = new ArrayList(); lock.lock(); @@ -58,12 +83,14 @@ private void pushMessages(Dispatch dispatch) { } if (messages.isEmpty()) { + // Have been closed return; } + for (T message : messages) { dispatch.dispatch(message); } - + lock.lock(); try { queue.subList(0, messages.size()).clear(); @@ -77,7 +104,7 @@ private void pushMessages(Dispatch dispatch) { public void dispatch(final T message) { lock.lock(); try { - while (!closed && queue.size() >= MAX_QUEUE_SIZE) { + while (dispatching && !closed && queue.size() >= maxQueueSize) { try { condition.await(); } catch (InterruptedException e) { @@ -87,6 +114,9 @@ public void dispatch(final T message) { if (closed) { throw new IllegalStateException("This message dispatch has been closed."); } + if (!dispatching) { + throw new IllegalStateException("Cannot dispatch messages, as the dispatch thread has exited."); + } queue.add(message); condition.signalAll(); } finally { @@ -99,13 +129,20 @@ public void close() { try { closed = true; condition.signalAll(); - while (!queue.isEmpty()) { + Date expiry = new Date(System.currentTimeMillis() + (120 * 1000)); + while (dispatching && !queue.isEmpty()) { try { - condition.await(); + if (!condition.awaitUntil(expiry)) { + throw new IllegalStateException("Timeout waiting for messages to be flushed."); + } } catch (InterruptedException e) { throw new RuntimeException(e); } } + if (!queue.isEmpty()) { + throw new IllegalStateException( + "Cannot wait for messages to be flushed, as the dispatch thread has exited."); + } } finally { lock.unlock(); } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/listener/remote/RemoteReceiver.java b/subprojects/gradle-core/src/main/groovy/org/gradle/listener/remote/RemoteReceiver.java index 07826cfe76cb..2c40725a0c28 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/listener/remote/RemoteReceiver.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/listener/remote/RemoteReceiver.java @@ -42,14 +42,21 @@ public class RemoteReceiver implements Closeable { private final ServerSocketChannel serverSocket; private final ExceptionListener exceptionListener; private final ExecutorService executor; + private final ClassLoader classLoader; public RemoteReceiver(Dispatch broadcaster) throws IOException { - this(broadcaster, null); + this(broadcaster, null, Thread.currentThread().getContextClassLoader()); } - public RemoteReceiver(Dispatch broadcaster, ExceptionListener exceptionListener) throws IOException { + public RemoteReceiver(Dispatch broadcaster, ClassLoader classLoader) throws IOException { + this(broadcaster, null, classLoader); + } + + public RemoteReceiver(Dispatch broadcaster, ExceptionListener exceptionListener, + ClassLoader classLoader) throws IOException { this.broadcaster = broadcaster; this.exceptionListener = exceptionListener; + this.classLoader = classLoader; serverSocket = ServerSocketChannel.open(); serverSocket.socket().bind(new InetSocketAddress(InetAddress.getByName(null), 0)); executor = Executors.newCachedThreadPool(); @@ -76,11 +83,10 @@ public void run() { try { try { InputStream inputStream = new BufferedInputStream(Channels.newInputStream(socket)); - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); while (true) { Message message = Message.receive(inputStream, classLoader); if (message instanceof EndOfStream) { - // End of stream - finish with this + // End of stream - finish with this connection return; } @@ -90,6 +96,8 @@ public void run() { } catch (Exception e) { if (exceptionListener != null) { exceptionListener.receiverThrewException(e); + } else { + throw e; } } } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/util/BootstrapUtil.java b/subprojects/gradle-core/src/main/groovy/org/gradle/util/BootstrapUtil.java index 667151c36111..65ec2b4e191c 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/util/BootstrapUtil.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/util/BootstrapUtil.java @@ -66,61 +66,4 @@ public static List getGradleClasspath() { pathElements.addAll(getGradleHomeLibClasspath()); return pathElements; } - - public static List getGradleCoreFiles() { - return gradleLibClasspath("gradle-core"); - } - - public static List getGroovyFiles() { - return gradleLibClasspath("groovy", "antlr", "asm-all", "commons-cli"); - } - - public static List getCommonsCliFiles() { - return gradleLibClasspath("commons-cli"); - } - - public static List getAntJunitJarFiles() { - return gradleLibClasspath("ant", "ant-launcher", "ant-junit"); - } - - public static List getAntJarFiles() { - return gradleLibClasspath("ant", "ant-launcher"); - } - - public static List getGradleTestListenerFiles() { - return gradleLibClasspath("gradle-core", "gradle-plugins"); - } - - public static List gradleLibClasspath(String... prefixes) { - List files = new ArrayList(); - List classpath = getGradleClasspath(); - for (File pathElement : classpath) { - for (String searchPattern : prefixes) { - if (pathElement.getName().startsWith(searchPattern + '-')) { - files.add(pathElement); - } - } - } - - if (!files.isEmpty()) { - return files; - } - - for (String prefix : prefixes) { - if (prefix.startsWith("gradle-")) { - // Look for a classes dir - files = new ArrayList(); - for (File file : classpath) { - if (file.isDirectory()) { - if (new File(file, BootstrapUtil.class.getName().replace('.', '/') + ".class").isFile()) { - files.add(file); - } - } - } - return files; - } - } - - return files; - } } diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/util/FilteringClassLoader.java b/subprojects/gradle-core/src/main/groovy/org/gradle/util/FilteringClassLoader.java index ae9724e557e5..fbf1bd6c0fc1 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/util/FilteringClassLoader.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/util/FilteringClassLoader.java @@ -21,7 +21,8 @@ /** * A ClassLoader which hides all non-system classes, packages and resources from the parent ClassLoader. Allows certain - * non-system packages to be declared as visible. + * non-system packages to be declared as visible. By default, only the Java system classes, packages and resources are + * visible. */ public class FilteringClassLoader extends ClassLoader { private final Set packageNames = new HashSet(); diff --git a/subprojects/gradle-core/src/main/groovy/org/gradle/util/GFileUtils.java b/subprojects/gradle-core/src/main/groovy/org/gradle/util/GFileUtils.java index 84981199c9e4..dd53558224bc 100644 --- a/subprojects/gradle-core/src/main/groovy/org/gradle/util/GFileUtils.java +++ b/subprojects/gradle-core/src/main/groovy/org/gradle/util/GFileUtils.java @@ -109,6 +109,10 @@ public static File[] toFiles(URL[] urls) { return FileUtils.toFiles(urls); } + public static URL[] toURLs(Collection files) { + return toURLs(files.toArray(new File[files.size()])); + } + public static URL[] toURLs(File[] files) { try { return FileUtils.toURLs(files); diff --git a/subprojects/gradle-core/src/main/resources/org/gradle/initialization/defaultBuildSourceScript.txt b/subprojects/gradle-core/src/main/resources/org/gradle/initialization/defaultBuildSourceScript.txt index 9ecc5812539c..1162b70a6a1d 100644 --- a/subprojects/gradle-core/src/main/resources/org/gradle/initialization/defaultBuildSourceScript.txt +++ b/subprojects/gradle-core/src/main/resources/org/gradle/initialization/defaultBuildSourceScript.txt @@ -1,5 +1,5 @@ apply id: 'groovy' dependencies { - compile files(org.gradle.util.BootstrapUtil.gradleClasspath) - groovy files(org.gradle.util.BootstrapUtil.groovyFiles) + compile gradleApi() + groovy localGroovy() } diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/ClassPathDependencyFactoryTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/ClassPathDependencyFactoryTest.groovy new file mode 100755 index 000000000000..63dd03be95ba --- /dev/null +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/ClassPathDependencyFactoryTest.groovy @@ -0,0 +1,63 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.gradle.api.internal.artifacts.dsl.dependencies + + +import static org.junit.Assert.* +import static org.hamcrest.Matchers.* + +import org.gradle.util.JUnit4GroovyMockery +import org.jmock.integration.junit4.JMock +import org.junit.runner.RunWith +import org.junit.Test +import org.gradle.api.internal.ClassGenerator +import org.gradle.api.internal.artifacts.dependencies.DefaultSelfResolvingDependency +import org.gradle.api.internal.ClassPathRegistry +import org.gradle.api.internal.file.FileResolver +import org.gradle.api.file.FileCollection +import org.gradle.api.artifacts.Dependency + +@RunWith(JMock.class) +public class ClassPathDependencyFactoryTest { + private final JUnit4GroovyMockery context = new JUnit4GroovyMockery() + private final ClassGenerator classGenerator = context.mock(ClassGenerator.class) + private final ClassPathRegistry classPathRegistry = context.mock(ClassPathRegistry.class) + private final FileResolver fileResolver = context.mock(FileResolver.class) + private final ClassPathDependencyFactory factory = new ClassPathDependencyFactory(classGenerator, classPathRegistry, fileResolver) + + @Test + void createsDependencyForAClassPathNotation() { + Dependency dependency = context.mock(Dependency.class) + + context.checking { + List files = [] + FileCollection fileCollection = context.mock(FileCollection.class) + + one(classPathRegistry).getClassPathFiles('GRADLE_API') + will(returnValue(files)) + + one(fileResolver).resolveFiles(withParam(hasItemInArray(files))) + will(returnValue(fileCollection)) + + one(classGenerator).newInstance(DefaultSelfResolvingDependency.class, fileCollection) + will(returnValue(dependency)) + } + + assertThat(factory.createDependency(Dependency.class, DependencyFactory.ClassPathNotation.GRADLE_API), sameInstance(dependency)) + } +} + + diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy index 2ffa0c6f4578..51e169dc91d9 100644 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/artifacts/dsl/dependencies/DefaultDependencyHandlerTest.groovy @@ -17,12 +17,12 @@ package org.gradle.api.internal.artifacts.dsl.dependencies import org.gradle.util.ConfigureUtil import org.gradle.util.JUnit4GroovyMockery -import org.hamcrest.Matchers import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.gradle.api.artifacts.* -import static org.junit.Assert.assertThat +import static org.junit.Assert.* +import static org.hamcrest.Matchers.* /** * @author Hans Dockter @@ -58,7 +58,7 @@ class DefaultDependencyHandlerTest { one(configurationMock).addDependency(dependencyDummy); } - assertThat(dependencyHandler.add(TEST_CONF_NAME, someNotation), Matchers.equalTo(dependencyDummy)) + assertThat(dependencyHandler.add(TEST_CONF_NAME, someNotation), equalTo(dependencyDummy)) } @Test @@ -72,7 +72,7 @@ class DefaultDependencyHandlerTest { one(configurationMock).addDependency(dependencyDummy); } - assertThat(dependencyHandler.add(TEST_CONF_NAME, someNotation, closure), Matchers.equalTo(dependencyDummy)) + assertThat(dependencyHandler.add(TEST_CONF_NAME, someNotation, closure), equalTo(dependencyDummy)) } @Test @@ -84,7 +84,7 @@ class DefaultDependencyHandlerTest { one(configurationMock).addDependency(dependencyDummy); } - assertThat(dependencyHandler."$TEST_CONF_NAME"(someNotation), Matchers.equalTo(dependencyDummy)) + assertThat(dependencyHandler."$TEST_CONF_NAME"(someNotation), equalTo(dependencyDummy)) } @Test @@ -97,7 +97,7 @@ class DefaultDependencyHandlerTest { one(configurationMock).addDependency(dependencyDummy); } - assertThat(dependencyHandler."$TEST_CONF_NAME"(someNotation, configureClosure), Matchers.equalTo(dependencyDummy)) + assertThat(dependencyHandler."$TEST_CONF_NAME"(someNotation, configureClosure), equalTo(dependencyDummy)) } @Test @@ -137,7 +137,7 @@ class DefaultDependencyHandlerTest { ProjectDependency projectDependency = context.mock(ProjectDependency) Map someMapNotation = [:] Closure projectDependencyClosure = { - assertThat("$TEST_CONF_NAME"(project(someMapNotation)), Matchers.equalTo(projectDependency)) + assertThat("$TEST_CONF_NAME"(project(someMapNotation)), equalTo(projectDependency)) } context.checking { allowing(dependencyFactoryStub).createProject(projectFinderDummy, someMapNotation, null); will(returnValue(projectDependency)) @@ -154,7 +154,7 @@ class DefaultDependencyHandlerTest { Map someMapNotation = [:] Closure configureClosure = {} Closure projectDependencyClosure = { - assertThat("$TEST_CONF_NAME"(project(someMapNotation, configureClosure)), Matchers.equalTo(projectDependency)) + assertThat("$TEST_CONF_NAME"(project(someMapNotation, configureClosure)), equalTo(projectDependency)) } context.checking { allowing(dependencyFactoryStub).createProject(projectFinderDummy, someMapNotation, configureClosure); will(returnValue(projectDependency)) @@ -170,7 +170,7 @@ class DefaultDependencyHandlerTest { ClientModule clientModule = context.mock(ClientModule) String someNotation = "someNotation" Closure moduleClosure = { - assertThat("$TEST_CONF_NAME"(module(someNotation)), Matchers.equalTo(clientModule)) + assertThat("$TEST_CONF_NAME"(module(someNotation)), equalTo(clientModule)) } context.checking { allowing(dependencyFactoryStub).createModule(someNotation, null); will(returnValue(clientModule)) @@ -187,7 +187,7 @@ class DefaultDependencyHandlerTest { String someNotation = "someNotation" Closure configureClosure = {} Closure moduleClosure = { - assertThat("$TEST_CONF_NAME"(module(someNotation, configureClosure)), Matchers.equalTo(clientModule)) + assertThat("$TEST_CONF_NAME"(module(someNotation, configureClosure)), equalTo(clientModule)) } context.checking { allowing(dependencyFactoryStub).createModule(someNotation, configureClosure); will(returnValue(clientModule)) @@ -198,6 +198,44 @@ class DefaultDependencyHandlerTest { ConfigureUtil.configure(moduleClosure, dependencyHandler) } + @Test + void pushGradleApi() { + Dependency dependency = context.mock(Dependency) + context.checking { + one(dependencyFactoryStub).createDependency(DependencyFactory.ClassPathNotation.GRADLE_API) + will(returnValue(dependency)) + + one(dependencyFactoryStub).createDependency(dependency, null) + will(returnValue(dependency)) + + one(configurationMock).addDependency(dependency) + } + + Closure moduleClosure = { + assertThat("$TEST_CONF_NAME"(gradleApi()), sameInstance(dependency)) + } + ConfigureUtil.configure(moduleClosure, dependencyHandler) + } + + @Test + void pushLocalGroovy() { + Dependency dependency = context.mock(Dependency) + context.checking { + one(dependencyFactoryStub).createDependency(DependencyFactory.ClassPathNotation.LOCAL_GROOVY) + will(returnValue(dependency)) + + one(dependencyFactoryStub).createDependency(dependency, null) + will(returnValue(dependency)) + + one(configurationMock).addDependency(dependency) + } + + Closure moduleClosure = { + assertThat("$TEST_CONF_NAME"(localGroovy()), sameInstance(dependency)) + } + ConfigureUtil.configure(moduleClosure, dependencyHandler) + } + @Test (expected = MissingMethodException) void pushToUnknownConfiguration() { String unknownConf = TEST_CONF_NAME + "delta" diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilderTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilderTest.groovy index b72ce4931850..8e82875a62df 100644 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilderTest.groovy +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/DefaultIsolatedAntBuilderTest.groovy @@ -21,8 +21,9 @@ import org.apache.tools.ant.BuildException import org.apache.tools.ant.Project import org.apache.tools.ant.taskdefs.ConditionTask import org.gradle.api.GradleException +import org.gradle.api.internal.ClassPathRegistry +import org.gradle.api.internal.DefaultClassPathRegistry import org.gradle.api.internal.project.ant.BasicAntBuilder -import org.gradle.util.BootstrapUtil import org.junit.After import org.junit.Before import org.junit.Test @@ -31,12 +32,15 @@ import static org.hamcrest.Matchers.* import static org.junit.Assert.* class DefaultIsolatedAntBuilderTest { - private final DefaultIsolatedAntBuilder builder = new DefaultIsolatedAntBuilder() + private final ClassPathRegistry registry = new DefaultClassPathRegistry() + private final DefaultIsolatedAntBuilder builder = new DefaultIsolatedAntBuilder(registry) private TestAppender appender private ch.qos.logback.classic.Logger delegateLogger + private Collection classpath @Before public void attachAppender() { + classpath = registry.getClassPathFiles("ANT") + registry.getClassPathFiles("LOCAL_GROOVY") appender = new TestAppender() delegateLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger('ROOT') delegateLogger.addAppender(appender) @@ -53,7 +57,7 @@ class DefaultIsolatedAntBuilderTest { public void executesClosureAgainstDifferentVersionOfAntAndGroovy() { Object antBuilder = null Object antProject = null - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { antBuilder = delegate.builder antProject = delegate.antProject } @@ -82,7 +86,7 @@ class DefaultIsolatedAntBuilderTest { public void executesNestedClosures() { String propertyValue = null Object task = null - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { property(name: 'message', value: 'a message') task = condition(property: 'prop', value: 'a message') { isset(property: 'message') @@ -97,7 +101,7 @@ class DefaultIsolatedAntBuilderTest { @Test public void attachesLogger() { - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { property(name: 'message', value: 'a message') echo('${message}') } @@ -107,7 +111,7 @@ class DefaultIsolatedAntBuilderTest { @Test public void addsToolsJarToClasspath() { - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { delegate.builder.class.classLoader.loadClass('com.sun.tools.javac.Main') } } @@ -115,11 +119,11 @@ class DefaultIsolatedAntBuilderTest { @Test public void cachesClassloaderForGivenClassPath() { Object antBuilder1 = null - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { antBuilder1 = delegate.builder } Object antBuilder2 = null - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { antBuilder2 = delegate.builder } @@ -132,7 +136,7 @@ class DefaultIsolatedAntBuilderTest { ClassLoader contextLoader = null Object antProject = null - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { antProject = delegate.antProject contextLoader = Thread.currentThread().contextClassLoader } @@ -144,7 +148,7 @@ class DefaultIsolatedAntBuilderTest { @Test public void gradleClassesAreNotVisibleToAnt() { ClassLoader loader = null - builder.execute(BootstrapUtil.antJarFiles + BootstrapUtil.groovyFiles) { + builder.execute(classpath) { loader = antProject.getClass().classLoader } diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/GlobalServicesRegistryTest.java b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/GlobalServicesRegistryTest.java index c793281641e0..affaa1072455 100755 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/GlobalServicesRegistryTest.java +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/GlobalServicesRegistryTest.java @@ -15,12 +15,11 @@ */ package org.gradle.api.internal.project; +import org.gradle.api.internal.ClassPathRegistry; +import org.gradle.api.internal.DefaultClassPathRegistry; import org.gradle.cache.CacheFactory; import org.gradle.cache.DefaultCacheFactory; -import org.gradle.initialization.CommandLine2StartParameterConverter; -import org.gradle.initialization.DefaultCommandLine2StartParameterConverter; -import org.gradle.initialization.DefaultLoggingConfigurer; -import org.gradle.initialization.LoggingConfigurer; +import org.gradle.initialization.*; import org.junit.Test; import static org.hamcrest.Matchers.*; @@ -29,11 +28,6 @@ public class GlobalServicesRegistryTest { private final GlobalServicesRegistry registry = new GlobalServicesRegistry(); - @Test - public void providesALoggingConfigurer() { - assertThat(registry.get(LoggingConfigurer.class), instanceOf(DefaultLoggingConfigurer.class)); - } - @Test public void providesCommandLineArgsConverter() { assertThat(registry.get(CommandLine2StartParameterConverter.class), instanceOf( @@ -44,4 +38,14 @@ public void providesCommandLineArgsConverter() { public void providesACacheFactory() { assertThat(registry.get(CacheFactory.class), instanceOf(DefaultCacheFactory.class)); } + + @Test + public void providesAClassPathRegistry() { + assertThat(registry.get(ClassPathRegistry.class), instanceOf(DefaultClassPathRegistry.class)); + } + + @Test + public void providesAClassLoaderFactory() { + assertThat(registry.get(ClassLoaderFactory.class), instanceOf(DefaultClassLoaderFactory.class)); + } } diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistryTest.java b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistryTest.java index bd79150b7e81..7b31cc61a64e 100644 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistryTest.java +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/api/internal/project/TopLevelBuildServiceRegistryTest.java @@ -17,6 +17,7 @@ import org.gradle.StartParameter; import org.gradle.api.artifacts.dsl.RepositoryHandlerFactory; +import org.gradle.api.internal.ClassPathRegistry; import org.gradle.api.internal.ExceptionAnalyser; import org.gradle.api.internal.GradleInternal; import org.gradle.api.internal.artifacts.dsl.DefaultPublishArtifactFactory; @@ -31,12 +32,10 @@ import org.gradle.configuration.ScriptPluginFactory; import org.gradle.groovy.scripts.DefaultScriptCompilerFactory; import org.gradle.groovy.scripts.ScriptCompilerFactory; -import org.gradle.initialization.DefaultExceptionAnalyser; -import org.gradle.initialization.InitScriptHandler; -import org.gradle.initialization.PropertiesLoadingSettingsProcessor; -import org.gradle.initialization.SettingsProcessor; +import org.gradle.initialization.*; import org.gradle.listener.DefaultListenerManager; import org.gradle.listener.ListenerManager; +import org.gradle.util.MultiParentClassLoader; import org.gradle.util.TemporaryFolder; import org.jmock.Expectations; import org.jmock.integration.junit4.JMock; @@ -59,8 +58,9 @@ public class TopLevelBuildServiceRegistryTest { private final JUnit4Mockery context = new JUnit4Mockery(); private final ServiceRegistry parent = context.mock(ServiceRegistry.class); private final StartParameter startParameter = new StartParameter(); - private final TopLevelBuildServiceRegistry factory = new TopLevelBuildServiceRegistry(parent, startParameter); private final CacheFactory cacheFactory = context.mock(CacheFactory.class); + private final ClassPathRegistry classPathRegistry = context.mock(ClassPathRegistry.class); + private final TopLevelBuildServiceRegistry factory = new TopLevelBuildServiceRegistry(parent, startParameter); @Before public void setUp() { @@ -68,6 +68,9 @@ public void setUp() { context.checking(new Expectations(){{ allowing(parent).get(CacheFactory.class); will(returnValue(cacheFactory)); + allowing(parent).get(ClassPathRegistry.class); + will(returnValue(classPathRegistry)); + }}); } @@ -147,31 +150,46 @@ public void providesACacheRepository() { @Test public void providesAnInitScriptHandler() { + expectScriptClassLoaderCreated(); assertThat(factory.get(InitScriptHandler.class), instanceOf(InitScriptHandler.class)); assertThat(factory.get(InitScriptHandler.class), sameInstance(factory.get(InitScriptHandler.class))); } - + @Test public void providesAScriptObjectConfigurerFactory() { + expectScriptClassLoaderCreated(); assertThat(factory.get(ScriptPluginFactory.class), instanceOf(DefaultScriptPluginFactory.class)); assertThat(factory.get(ScriptPluginFactory.class), sameInstance(factory.get(ScriptPluginFactory.class))); } - + @Test public void providesASettingsProcessor() { + expectScriptClassLoaderCreated(); assertThat(factory.get(SettingsProcessor.class), instanceOf(PropertiesLoadingSettingsProcessor.class)); assertThat(factory.get(SettingsProcessor.class), sameInstance(factory.get(SettingsProcessor.class))); } - + @Test public void providesAnExceptionAnalyser() { assertThat(factory.get(ExceptionAnalyser.class), instanceOf(DefaultExceptionAnalyser.class)); assertThat(factory.get(ExceptionAnalyser.class), sameInstance(factory.get(ExceptionAnalyser.class))); } - + @Test public void providesAnIsolatedAntBuilder() { assertThat(factory.get(IsolatedAntBuilder.class), instanceOf(DefaultIsolatedAntBuilder.class)); assertThat(factory.get(IsolatedAntBuilder.class), sameInstance(factory.get(IsolatedAntBuilder.class))); } + + private void expectScriptClassLoaderCreated() { + context.checking(new Expectations() {{ + ClassLoaderFactory classLoaderFactory = context.mock(ClassLoaderFactory.class); + + allowing(parent).get(ClassLoaderFactory.class); + will(returnValue(classLoaderFactory)); + + one(classLoaderFactory).createScriptClassLoader(); + will(returnValue(new MultiParentClassLoader())); + }}); + } } diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/BuildSourceBuilderTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/BuildSourceBuilderTest.groovy index bd1b02feee1e..548381e4d2bc 100644 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/BuildSourceBuilderTest.groovy +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/BuildSourceBuilderTest.groovy @@ -65,7 +65,7 @@ class BuildSourceBuilderTest { rootProjectMock = context.mock(Project) configurationMock = context.mock(Configuration) cacheInvalidationStrategyMock = context.mock(CacheInvalidationStrategy) - buildSourceBuilder = new BuildSourceBuilder(gradleFactoryMock, cacheInvalidationStrategyMock) + buildSourceBuilder = new BuildSourceBuilder(gradleFactoryMock, cacheInvalidationStrategyMock, context.mock(ClassLoaderFactory)) expectedStartParameter = new StartParameter( searchUpwards: false, currentDir: testBuildSrcDir, diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy index 4f1e0af52c4a..2f762dfdf266 100644 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy @@ -153,7 +153,7 @@ class DefaultSettingsTest { @Test public void testCreateClassLoader() { StartParameter expectedStartParameter = settings.startParameter.newInstance() expectedStartParameter.setCurrentDir(new File(settingsDir, DefaultSettings.DEFAULT_BUILD_SRC_DIR)) - URLClassLoader createdClassLoader = settings.createClassLoader() + URLClassLoader createdClassLoader = settings.getClassLoader() assertSame(createdClassLoader, expectedClassLoader) } diff --git a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/SettingsHandlerTest.java b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/SettingsHandlerTest.java index d2f41d379f73..017b3b9b6d70 100644 --- a/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/SettingsHandlerTest.java +++ b/subprojects/gradle-core/src/test/groovy/org/gradle/initialization/SettingsHandlerTest.java @@ -75,7 +75,7 @@ private void prepareForExistingSettings() { allowing(settings).getProjectRegistry(); will(returnValue(projectRegistry)); - allowing(settings).createClassLoader(); + allowing(settings).getClassLoader(); will(returnValue(urlClassLoader)); allowing(gradle).getScriptClassLoader(); diff --git a/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml b/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml index ef8286715bf2..0dffb4cc6e5a 100644 --- a/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml +++ b/subprojects/gradle-docs/src/docs/userguide/depMngmt.xml @@ -278,6 +278,15 @@ +
+ Gradle API Dependency + You can declare a dependency on the API of the current version of Gradle by using the + method. This is + useful when you are developing custom Gradle tasks or plugins. + + + +
Excluding transitive dependencies You can exclude a transitive dependency either by configuration or by dependency: diff --git a/subprojects/gradle-docs/src/docs/userguide/organizeBuildLogic.xml b/subprojects/gradle-docs/src/docs/userguide/organizeBuildLogic.xml index ff3672fec7b7..be0d64ca9762 100644 --- a/subprojects/gradle-docs/src/docs/userguide/organizeBuildLogic.xml +++ b/subprojects/gradle-docs/src/docs/userguide/organizeBuildLogic.xml @@ -128,7 +128,7 @@ and the tasks property to specify which tasks to execute. - + diff --git a/subprojects/gradle-docs/src/docs/userguide/userguide.xml b/subprojects/gradle-docs/src/docs/userguide/userguide.xml index f4dcc29e1d79..9c8efc91355f 100644 --- a/subprojects/gradle-docs/src/docs/userguide/userguide.xml +++ b/subprojects/gradle-docs/src/docs/userguide/userguide.xml @@ -16,9 +16,9 @@ Gradle - A build system + A better way to build - 2007-2009 + 2007-2010 Hans Dockter, Adam Murdoch diff --git a/subprojects/gradle-docs/src/samples/java/multiproject/buildSrc/build.gradle b/subprojects/gradle-docs/src/samples/java/multiproject/buildSrc/build.gradle index 6dc1e75cbec4..f2c63b758e38 100644 --- a/subprojects/gradle-docs/src/samples/java/multiproject/buildSrc/build.gradle +++ b/subprojects/gradle-docs/src/samples/java/multiproject/buildSrc/build.gradle @@ -4,7 +4,11 @@ repositories { mavenCentral() } +// START SNIPPET gradle-api-dependencies dependencies { - compile files(BootstrapUtil.gradleClasspath) + compile gradleApi() +// END SNIPPET gradle-api-dependencies testCompile group: 'junit', name: 'junit', version: '4.7' +// START SNIPPET gradle-api-dependencies } +// END SNIPPET gradle-api-dependencies diff --git a/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/nestedBuild/build.gradle b/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/nestedBuild/build.gradle index 4c37941ba901..d84600d1ecf4 100755 --- a/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/nestedBuild/build.gradle +++ b/subprojects/gradle-docs/src/samples/userguide/organizeBuildLogic/nestedBuild/build.gradle @@ -1,4 +1,9 @@ +// START SNIPPET execute-build task build(type: GradleBuild) { buildFile = 'other.gradle' tasks = ['hello'] -} \ No newline at end of file +// END SNIPPET execute-build + startParameter.searchUpwards = false +// START SNIPPET execute-build +} +// END SNIPPET execute-build diff --git a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java index 5094515f23fe..4a6f2a5e3420 100644 --- a/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java +++ b/subprojects/gradle-jetty/src/main/java/org/gradle/api/plugins/jetty/AbstractJettyRunTask.java @@ -16,10 +16,14 @@ package org.gradle.api.plugins.jetty; -import org.gradle.api.*; -import org.gradle.api.plugins.jetty.internal.*; -import org.gradle.api.tasks.*; +import org.gradle.api.GradleException; import org.gradle.api.internal.ConventionTask; +import org.gradle.api.plugins.jetty.internal.ConsoleScanner; +import org.gradle.api.plugins.jetty.internal.JettyPluginServer; +import org.gradle.api.plugins.jetty.internal.JettyPluginWebAppContext; +import org.gradle.api.plugins.jetty.internal.Monitor; +import org.gradle.api.tasks.*; +import org.gradle.util.GFileUtils; import org.mortbay.jetty.Connector; import org.mortbay.jetty.RequestLog; import org.mortbay.jetty.Server; @@ -29,8 +33,6 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; import java.net.URLClassLoader; import java.util.*; @@ -158,19 +160,14 @@ public abstract class AbstractJettyRunTask extends ConventionTask { public abstract void finishConfigurationBeforeStart() throws Exception; - @org.gradle.api.tasks.TaskAction + @TaskAction protected void start() { - ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader(); - List additionalClasspath = new ArrayList(); + ClassLoader originalClassloader = Server.class.getClassLoader(); + List additionalClasspath = new ArrayList(); for (File additionalRuntimeJar : getAdditionalRuntimeJars()) { - try { - additionalClasspath.add(additionalRuntimeJar.toURI().toURL()); - } catch (MalformedURLException e) { - throw new InvalidUserDataException(e); - } + additionalClasspath.add(additionalRuntimeJar); } - URLClassLoader jettyClassloader = new URLClassLoader(additionalClasspath.toArray( - new URL[additionalClasspath.size()]), originalClassloader); + URLClassLoader jettyClassloader = new URLClassLoader(GFileUtils.toURLs(additionalClasspath), originalClassloader); try { Thread.currentThread().setContextClassLoader(jettyClassloader); startJetty(); diff --git a/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/GradleMain.java b/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/GradleMain.java index a1cf4d8ef386..2dc91df09d40 100644 --- a/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/GradleMain.java +++ b/subprojects/gradle-launcher/src/main/java/org/gradle/launcher/GradleMain.java @@ -16,7 +16,8 @@ package org.gradle.launcher; -import org.gradle.util.BootstrapUtil; +import org.gradle.api.internal.ClassPathRegistry; +import org.gradle.api.internal.DefaultClassPathRegistry; import java.io.File; import java.lang.reflect.Method; @@ -24,6 +25,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -38,13 +40,14 @@ public static void main(String[] args) throws Exception { processGradleHome(bootStrapDebug); processGradleUserHome(bootStrapDebug); - List classpath = toUrl(BootstrapUtil.getGradleClasspath()); + ClassPathRegistry classPathRegistry = new DefaultClassPathRegistry(); + URL[] classpath = classPathRegistry.getClassPathUrls("GRADLE_RUNTIME"); ClassLoader parentClassloader = ClassLoader.getSystemClassLoader().getParent(); if (bootStrapDebug) { System.out.println("Parent Classloader of new context classloader is: " + parentClassloader); - System.out.println("Adding the following files to new lib classloader: " + classpath); + System.out.println("Adding the following files to new lib classloader: " + Arrays.toString(classpath)); } - URLClassLoader libClassLoader = new URLClassLoader(classpath.toArray(new URL[classpath.size()]), parentClassloader); + URLClassLoader libClassLoader = new URLClassLoader(classpath, parentClassloader); Thread.currentThread().setContextClassLoader(libClassLoader); Class mainClass = libClassLoader.loadClass("org.gradle.launcher.Main"); Method mainMethod = mainClass.getMethod("main", String[].class); diff --git a/subprojects/gradle-plugins/plugins.gradle b/subprojects/gradle-plugins/plugins.gradle index 36c6b992cac3..61dab067238e 100644 --- a/subprojects/gradle-plugins/plugins.gradle +++ b/subprojects/gradle-plugins/plugins.gradle @@ -26,6 +26,7 @@ dependencies { libraries.commons_lang, libraries.commons_io, libraries.ivy, + libraries.asm_all, "biz.aQute:bndlib:0.0.384@jar", "org.apache.mina:mina-core:2.0.0-RC1", libraries.junit, @@ -39,3 +40,7 @@ dependencies { testCompile project(path: ':core', configuration: 'testFixtures') testRuntime project(path: ':core', configuration: 'testFixturesRuntime') } + +test { + options.fork(jvmArgs: ["-ea", "-Xms128m", "-Xmx256m", '-XX:+HeapDumpOnOutOfMemoryError']) +} diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AntGroovyc.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AntGroovyc.groovy index 348a7feea427..0b7ae8133b14 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AntGroovyc.groovy +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/AntGroovyc.groovy @@ -18,12 +18,12 @@ package org.gradle.api.tasks.compile import org.gradle.api.file.FileCollection import org.gradle.api.internal.project.IsolatedAntBuilder -import org.gradle.util.BootstrapUtil import org.slf4j.Logger import org.slf4j.LoggerFactory +import org.gradle.api.internal.ClassPathRegistry /** - * Please not: includeAntRuntime=false is ignored if groovyc is used in non fork mode. In this case the runtime classpath is + * Please note: includeAntRuntime=false is ignored if groovyc is used in non fork mode. In this case the runtime classpath is * added to the compile classpath. * See: http://jira.codehaus.org/browse/GROOVY-2717 * @@ -33,21 +33,29 @@ class AntGroovyc { private static Logger logger = LoggerFactory.getLogger(AntGroovyc) int numFilesCompiled; + private final IsolatedAntBuilder ant + private final ClassPathRegistry classPathRegistry List nonGroovycJavacOptions = ['verbose', 'deprecation', 'includeJavaRuntime', 'includeAntRuntime', 'optimize', 'fork', 'failonerror', 'listfiles', 'nowarn', 'depend'] - public void execute(IsolatedAntBuilder antNode, FileCollection source, File targetDir, List classpath, + + def AntGroovyc(IsolatedAntBuilder ant, ClassPathRegistry classPathRegistry) { + this.ant = ant; + this.classPathRegistry = classPathRegistry; + } + + public void execute(FileCollection source, File targetDir, List classpath, String sourceCompatibility, String targetCompatibility, GroovyCompileOptions groovyOptions, CompileOptions compileOptions, List groovyClasspath) { // Force a particular Ant version. Also add in commons-cli, as the Groovy POM does not. - List antBuilderClasspath = BootstrapUtil.antJarFiles + groovyClasspath + BootstrapUtil.commonsCliFiles - antNode.execute(antBuilderClasspath) { + List antBuilderClasspath = classPathRegistry.getClassPathFiles("ANT") + groovyClasspath + classPathRegistry.getClassPathFiles("COMMONS_CLI") + ant.execute(antBuilderClasspath) { taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc') def task = groovyc([includeAntRuntime: false, destdir: targetDir, classpath: (classpath + antBuilderClasspath).join(File.pathSeparator)] + groovyOptions.optionMap()) { source.addToAntBuilder(delegate, 'src', FileCollection.AntType.MatchingTask) - javac([source: sourceCompatibility, target: targetCompatibility] + filterNonGroovycOptions(compileOptions)) { - compileOptions.compilerArgs.each { value -> + javac([source: sourceCompatibility, target: targetCompatibility] + filterNonGroovycOptions(compileOptions)) { + compileOptions.compilerArgs.each {value -> compilerarg(value: value) } } diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java index 4a206ae0050e..90e5b746e40f 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/compile/GroovyCompile.java @@ -17,6 +17,7 @@ package org.gradle.api.tasks.compile; import org.gradle.api.InvalidUserDataException; +import org.gradle.api.internal.ClassPathRegistry; import org.gradle.api.internal.project.IsolatedAntBuilder; import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.InputFiles; @@ -31,12 +32,18 @@ * @author Hans Dockter */ public class GroovyCompile extends Compile { - private AntGroovyc antGroovyCompile = new AntGroovyc(); + private AntGroovyc antGroovyCompile; private FileCollection groovyClasspath; private GroovyCompileOptions groovyOptions = new GroovyCompileOptions(); + public GroovyCompile() { + IsolatedAntBuilder antBuilder = getServices().get(IsolatedAntBuilder.class); + ClassPathRegistry classPathRegistry = getServices().get(ClassPathRegistry.class); + antGroovyCompile = new AntGroovyc(antBuilder, classPathRegistry); + } + protected void compile() { if (getAntGroovyCompile() == null) { throw new InvalidUserDataException("The ant groovy compile command must be set!"); @@ -49,8 +56,7 @@ protected void compile() { // todo We need to understand why it is not good enough to put groovy and ant in the task classpath but also Junit. As we don't understand we put the whole testCompile in it right now. It doesn't hurt, but understanding is better :) List taskClasspath = new ArrayList(getGroovyClasspath().getFiles()); throwExceptionIfTaskClasspathIsEmpty(taskClasspath); - IsolatedAntBuilder builder = getServices().get(IsolatedAntBuilder.class); - antGroovyCompile.execute(builder, getSource(), getDestinationDir(), + antGroovyCompile.execute(getSource(), getDestinationDir(), classpath, getSourceCompatibility(), getTargetCompatibility(), getGroovyOptions(), getOptions(), taskClasspath); setDidWork(antGroovyCompile.getNumFilesCompiled() > 0); diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/AntGroovydoc.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/AntGroovydoc.groovy index 9d6dbddd31df..6e4a9d53b0df 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/AntGroovydoc.groovy +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/AntGroovydoc.groovy @@ -17,18 +17,26 @@ package org.gradle.api.tasks.javadoc import org.gradle.api.internal.project.IsolatedAntBuilder -import org.gradle.util.BootstrapUtil import org.gradle.api.file.FileCollection import org.gradle.api.Project import org.gradle.util.GradleUtil +import org.gradle.api.internal.ClassPathRegistry /** * @author Hans Dockter */ class AntGroovydoc { + private final IsolatedAntBuilder ant + private final ClassPathRegistry classPathRegistry + + def AntGroovydoc(IsolatedAntBuilder ant, ClassPathRegistry classPathRegistry) { + this.ant = ant; + this.classPathRegistry = classPathRegistry; + } + void execute(FileCollection source, File destDir, boolean use, String windowTitle, - String docTitle, String header, String footer, String overview, boolean includePrivate, Set links, IsolatedAntBuilder ant, - List groovyClasspath, Project project) { + String docTitle, String header, String footer, String overview, boolean includePrivate, Set links, + List groovyClasspath, Project project) { File tmpDir = new File(project.buildDir, "tmp/groovydoc") GradleUtil.deleteDir(tmpDir) @@ -41,23 +49,24 @@ class AntGroovydoc { args.sourcepath = tmpDir.toString() args.destdir = destDir args.use = use - args['private'] = includePrivate + args['private'] = includePrivate addToMapIfNotNull(args, 'windowtitle', windowTitle) addToMapIfNotNull(args, 'doctitle', docTitle) addToMapIfNotNull(args, 'header', header) addToMapIfNotNull(args, 'footer', footer) addToMapIfNotNull(args, 'overview', overview) - ant.execute(BootstrapUtil.antJarFiles + groovyClasspath) { + ant.execute(classPathRegistry.getClassPathFiles("ANT") + groovyClasspath) { taskdef(name: 'groovydoc', classname: 'org.codehaus.groovy.ant.Groovydoc') groovydoc(args) - links.each { link -> - link(packages: link.packages.join(','), href : link.url) + links.each {link -> + link(packages: link.packages.join(','), href: link.url) } } } void addToMapIfNotNull(Map map, String key, Object value) { - if (value != null) map.put(key, value) + if (value != null) + map.put(key, value) } } diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java index 995de1946ef0..7d494bd13c28 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/javadoc/Groovydoc.java @@ -18,6 +18,7 @@ import org.gradle.api.InvalidUserDataException; import org.gradle.api.file.FileCollection; +import org.gradle.api.internal.ClassPathRegistry; import org.gradle.api.internal.project.IsolatedAntBuilder; import org.gradle.api.logging.LogLevel; import org.gradle.api.tasks.*; @@ -38,7 +39,7 @@ public class Groovydoc extends SourceTask { private File destinationDir; - private AntGroovydoc antGroovydoc = new AntGroovydoc(); + private AntGroovydoc antGroovydoc; private boolean use; @@ -58,6 +59,9 @@ public class Groovydoc extends SourceTask { public Groovydoc() { captureStandardOutput(LogLevel.INFO); + IsolatedAntBuilder antBuilder = getServices().get(IsolatedAntBuilder.class); + ClassPathRegistry classPathRegistry = getServices().get(ClassPathRegistry.class); + antGroovydoc = new AntGroovydoc(antBuilder, classPathRegistry); } @TaskAction @@ -66,7 +70,7 @@ protected void generate() { throwExceptionIfTaskClasspathIsEmpty(taskClasspath); IsolatedAntBuilder builder = getServices().get(IsolatedAntBuilder.class); antGroovydoc.execute(getSource(), getDestinationDir(), isUse(), getWindowTitle(), getDocTitle(), getHeader(), - getFooter(), getOverview(), isIncludePrivate(), getLinks(), builder, taskClasspath, getProject()); + getFooter(), getOverview(), isIncludePrivate(), getLinks(), taskClasspath, getProject()); } private void throwExceptionIfTaskClasspathIsEmpty(List taskClasspath) { diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/AbstractTestTask.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/AbstractTestTask.java index 8c9a11045a56..9f0d1fa76ea2 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/AbstractTestTask.java +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/AbstractTestTask.java @@ -21,6 +21,7 @@ import org.gradle.api.GradleException; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTreeElement; +import org.gradle.api.internal.ClassPathRegistry; import org.gradle.api.internal.ConventionTask; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.*; @@ -90,6 +91,10 @@ public ListenerBroadcast getTestListenerBroadcaster() { return testListenerBroadcaster; } + public ClassPathRegistry getClassPathRegistry() { + return getServices().get(ClassPathRegistry.class); + } + /** * Registers a test listener with this task. This listener will NOT be notified of tests executed by other tasks. * To get that behavior, use {@link org.gradle.api.invocation.Gradle#addListener(Object)}. diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/AntJUnitExecute.groovy b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/AntJUnitExecute.groovy index 66ab19e77758..8d04f583469c 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/AntJUnitExecute.groovy +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/AntJUnitExecute.groovy @@ -17,12 +17,12 @@ package org.gradle.api.tasks.testing.junit import org.gradle.api.tasks.testing.AntTest -import org.gradle.util.BootstrapUtil import org.slf4j.Logger import org.slf4j.LoggerFactory import org.gradle.api.tasks.testing.TestListener import org.gradle.listener.remote.RemoteReceiver import org.gradle.listener.ListenerBroadcast +import org.gradle.api.internal.ClassPathRegistry /** * @author Hans Dockter @@ -32,21 +32,25 @@ import org.gradle.listener.ListenerBroadcast //todo: Find a more stable way to find the ant junit jars class AntJUnitExecute { private static Logger logger = LoggerFactory.getLogger(AntJUnitExecute) - private static final String CLASSPATH_ID = 'runtests.classpath' + private final ClassPathRegistry classPathRegistry + + def AntJUnitExecute(ClassPathRegistry classPathRegistry) { + this.classPathRegistry = classPathRegistry + } void execute(File compiledTestsClassesDir, List classPath, File testResultsDir, Collection includes, Collection excludes, JUnitOptions junitOptions, AntBuilder ant, ListenerBroadcast testListenerBroadcaster) { ant.mkdir(dir: testResultsDir.absolutePath) - createAntClassPath(ant, classPath + BootstrapUtil.antJunitJarFiles + BootstrapUtil.gradleTestListenerFiles) + createAntClassPath(ant, classPath + classPathRegistry.getClassPathFiles("ANT_JUNIT") + classPathRegistry.getClassPathFiles("TEST_LISTENER")) Map otherArgs = [ includeantruntime: 'false', errorproperty: AntTest.FAILURES_OR_ERRORS_PROPERTY, failureproperty: AntTest.FAILURES_OR_ERRORS_PROPERTY ] - final RemoteReceiver remoteReceiver = new RemoteReceiver(testListenerBroadcaster); + final RemoteReceiver remoteReceiver = new RemoteReceiver(testListenerBroadcaster, TestListenerFormatter.class.classLoader); logger.debug("Listening for test listener events on port {}.", remoteReceiver.boundPort) try { ant.junit(otherArgs + junitOptions.optionMap()) { diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/TestListenerFormatter.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/TestListenerFormatter.java index 0a356e44a0a1..aa62a83c313e 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/TestListenerFormatter.java +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/api/tasks/testing/junit/TestListenerFormatter.java @@ -23,6 +23,7 @@ import org.gradle.api.tasks.testing.TestListener; import org.gradle.api.tasks.testing.TestResult; import org.gradle.api.tasks.testing.TestSuite; +import org.gradle.listener.ListenerBroadcast; import org.gradle.listener.remote.RemoteSender; import org.gradle.util.shutdown.ShutdownHookActionRegister; @@ -30,26 +31,32 @@ import java.io.OutputStream; import java.io.Serializable; -/** - * An instance of this class is created for each test class. - */ public class TestListenerFormatter implements JUnitResultFormatter { private static final String PORT_VMARG = "test.listener.remote.port"; - private static RemoteSender sender; private static TestListener defaultSender; private TestListener remoteSender; private Throwable error; public TestListenerFormatter() throws IOException { + // An instance of this class is created for each test class, so use a singleton RemoteSender if (defaultSender == null) { - int port = Integer.parseInt(System.getProperty(PORT_VMARG, "0")); - if (port <= 0) { - throw new IllegalArgumentException(String.format("Invalid port '%s' specified for remote test listener.", - System.getProperty(PORT_VMARG))); + String portStr = System.getProperty(PORT_VMARG); + if (portStr == null) { + // This can happen when the listener is instantiated in the build process, for example, when the + // test vm crashes + defaultSender = new ListenerBroadcast(TestListener.class).getSource(); + } + else { + // Assume we're in the forked test process + int port = Integer.parseInt(portStr); + if (port <= 0) { + throw new IllegalArgumentException(String.format( + "Invalid port '%s' specified for remote test listener.", System.getProperty(PORT_VMARG))); + } + RemoteSender sender = new RemoteSender(TestListener.class, port); + ShutdownHookActionRegister.closeOnExit(sender); + defaultSender = sender.getSource(); } - sender = new RemoteSender(TestListener.class, port); - ShutdownHookActionRegister.closeOnExit(sender); - defaultSender = sender.getSource(); } remoteSender = defaultSender; } diff --git a/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/junit/JUnitTestFrameworkInstance.java b/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/junit/JUnitTestFrameworkInstance.java index f671f8f39199..c61843b1a4ce 100644 --- a/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/junit/JUnitTestFrameworkInstance.java +++ b/subprojects/gradle-plugins/src/main/groovy/org/gradle/external/junit/JUnitTestFrameworkInstance.java @@ -46,7 +46,7 @@ protected JUnitTestFrameworkInstance(AbstractTestTask testTask, JUnitTestFramewo } public void initialize(Project project, AbstractTestTask testTask) { - antJUnitExecute = new AntJUnitExecute(); + antJUnitExecute = new AntJUnitExecute(testTask.getClassPathRegistry()); antJUnitReport = new AntJUnitReport(); options = new JUnitOptions(testFramework); diff --git a/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/tasks/compile/GroovyCompileTest.java b/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/tasks/compile/GroovyCompileTest.java index c9bb5c23c73d..de5bad2c16f1 100644 --- a/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/tasks/compile/GroovyCompileTest.java +++ b/subprojects/gradle-plugins/src/test/groovy/org/gradle/api/tasks/compile/GroovyCompileTest.java @@ -76,7 +76,6 @@ public void testExecute(final int numFilesCompiled) { setUpMocksAndAttributes(testObj, TEST_GROOVY_CLASSPATH); context.checking(new Expectations(){{ one(antGroovycCompileMock).execute( - with(equalTo(ant)), with(hasSameItems(testObj.getSource())), with(equalTo(testObj.getDestinationDir())), with(equalTo(TEST_DEPENDENCY_MANAGER_CLASSPATH)), diff --git a/subprojects/gradle-plugins/src/test/groovy/org/gradle/external/junit/JUnitTestFrameworkInstanceTest.java b/subprojects/gradle-plugins/src/test/groovy/org/gradle/external/junit/JUnitTestFrameworkInstanceTest.java index 5b7ddf7928d8..71fe0bc68f55 100644 --- a/subprojects/gradle-plugins/src/test/groovy/org/gradle/external/junit/JUnitTestFrameworkInstanceTest.java +++ b/subprojects/gradle-plugins/src/test/groovy/org/gradle/external/junit/JUnitTestFrameworkInstanceTest.java @@ -17,6 +17,7 @@ import static junit.framework.Assert.assertNotNull; import org.gradle.api.file.FileVisitor; +import org.gradle.api.internal.ClassPathRegistry; import org.gradle.api.tasks.testing.*; import org.gradle.api.tasks.testing.junit.AntJUnitExecute; import org.gradle.api.tasks.testing.junit.AntJUnitReport; @@ -73,6 +74,7 @@ public void testInitialize() { one(jUnitForkOptionsMock).setDir(projectDir); one(testMock).getTestClassesDir();will(returnValue(testClassesDir)); one(testMock).getClasspath();will(returnValue(classpathMock)); + one(testMock).getClassPathRegistry();will(returnValue(context.mock(ClassPathRegistry.class))); one(classpathMock).getAsFileTree();will(returnValue(classpathAsFileTreeMock)); one(classpathAsFileTreeMock).visit(with(aNonNull(FileVisitor.class))); }}); diff --git a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java index 2e797e831f72..10f580d7ddd4 100644 --- a/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java +++ b/subprojects/gradle-wrapper/src/main/java/org/gradle/api/tasks/wrapper/Wrapper.java @@ -19,6 +19,7 @@ import org.apache.commons.io.FileUtils; import org.gradle.api.*; import org.gradle.api.DefaultTask; +import org.gradle.api.invocation.Gradle; import org.gradle.api.tasks.TaskAction; import org.gradle.util.GUtil; @@ -101,8 +102,8 @@ void generate() { String wrapperPropertiesPath = wrapperDir + WRAPPER_PROPERTIES; File jarFileDestination = new File(getProject().getProjectDir(), wrapperJar); File propertiesFileDestination = new File(getProject().getProjectDir(), wrapperPropertiesPath); - File jarFileSource = new File(getProject().getGradle().getGradleHomeDir() + "/lib", - WRAPPER_JAR_BASE_NAME + "-" + getProject().getGradle().getGradleVersion() + ".jar"); + Gradle gradle = getProject().getGradle(); + File jarFileSource = new File(gradle.getGradleHomeDir(), "lib/plugins/" + WRAPPER_JAR_BASE_NAME + "-" + gradle.getGradleVersion() + ".jar"); propertiesFileDestination.delete(); jarFileDestination.delete(); writeProperties(propertiesFileDestination); diff --git a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java index f1be961683e8..368eb2f760d9 100644 --- a/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java +++ b/subprojects/gradle-wrapper/src/test/groovy/org/gradle/api/tasks/wrapper/WrapperTest.java @@ -65,7 +65,7 @@ public void setUp() { wrapper.setGradleVersion("1.0"); testDir = tmpDir.getDir(); File testGradleHome = new File(testDir, "testGradleHome"); - File testGradleHomeLib = new File(testGradleHome, "lib"); + File testGradleHomeLib = new File(testGradleHome, "lib/plugins"); testGradleHomeLib.mkdirs(); createSourceWrapperJar(testGradleHomeLib); getProject().getGradle().getStartParameter().setGradleHomeDir(testGradleHome); diff --git a/subprojects/gradle-wrapper/wrapper.gradle b/subprojects/gradle-wrapper/wrapper.gradle index e1c3aaade952..aa6cff6a49ca 100644 --- a/subprojects/gradle-wrapper/wrapper.gradle +++ b/subprojects/gradle-wrapper/wrapper.gradle @@ -11,3 +11,17 @@ dependencies { } manifest.mainAttributes("Main-Class": 'org.gradle.wrapper.GradleWrapperMain') + +jar { + include 'org/gradle/wrapper/**' +} + +task taskJar(type: Jar) { + from sourceSets.main.classes + exclude 'org/gradle/wrapper/**' + baseName = "$jar.baseName-tasks" +} + +artifacts { + archives taskJar +}