Index: trunk/src/test/groovy/org/gradle/StartParameterTest.groovy
===================================================================
--- trunk/src/test/groovy/org/gradle/StartParameterTest.groovy	(revision 711)
+++ trunk/src/test/groovy/org/gradle/StartParameterTest.groovy	Tue Jul 22 07:54:58 EST 2008
@@ -32,7 +32,6 @@
                 buildFileName: 'buildfile',
                 taskNames: ['a'],
                 currentDir: new File('a'),
-                recursive: true,
                 searchUpwards: true,
                 projectProperties: [a: 'a'],
                 systemPropertiesArgs: [b: 'b'],
Index: trunk/src/main/groovy/org/gradle/execution/TaskSelector.java
===================================================================
--- trunk/src/main/groovy/org/gradle/execution/TaskSelector.java	Tue Jul 22 14:40:49 EST 2008
+++ trunk/src/main/groovy/org/gradle/execution/TaskSelector.java	Tue Jul 22 14:40:49 EST 2008
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.execution;
+
+import org.gradle.api.Task;
+import org.gradle.api.Project;
+
+/**
+ * Selects the groups of tasks to execute.
+ */
+public interface TaskSelector {
+    /**
+     * Returns true if this selector has another group of tasks to execute.
+     */
+    boolean hasNext();
+
+    /**
+     * Moves to the next group of tasks to execute.  The project is not rebuilt while executing a single group of
+     * tasks, but may be rebuilt between groups.
+     */
+    void select(Project project);
+
+    /**
+     * Returns the description of the current group.
+     */
+    String getDescription();
+
+    /**
+     * Returns the task of the current group.
+     */
+    Iterable<Task> getTasks();
+}
Index: trunk/src/main/groovy/org/gradle/Main.java
===================================================================
--- trunk/src/main/groovy/org/gradle/Main.java	(revision 711)
+++ trunk/src/main/groovy/org/gradle/Main.java	Tue Jul 22 07:54:58 EST 2008
@@ -54,7 +54,6 @@
     public final static String IMPORTS_FILE_NAME = "gradle-imports";
     public final static String NL = System.getProperty("line.separator");
 
-    private static final String NON_RECURSIVE = "n";
     private static final String NO_JVM_TERMINATION = "S";
     private static final String BOOTSTRAP_DEBUG_INFO = "B";
     private static final String NO_SEARCH_UPWARDS = "u";
@@ -89,7 +88,6 @@
 
         OptionParser parser = new OptionParser() {
             {
-                acceptsAll(WrapUtil.toList(NON_RECURSIVE, "non-recursive"), "Do not execute primary tasks of childprojects.");
                 acceptsAll(WrapUtil.toList(NO_JVM_TERMINATION), "Don't trigger a System.exit(0) for normal termination. Used for Gradle's internal testing.");
                 acceptsAll(WrapUtil.toList(NO_DEFAULT_IMPORTS, "no-imports"), "Disable usage of default imports for build script files.");
                 acceptsAll(WrapUtil.toList(NO_SEARCH_UPWARDS, "no-search-upward"), "Don't search in parent folders for a settings.gradle file.");
@@ -169,7 +167,6 @@
             }
         }
 
-        startParameter.setRecursive(!options.has(NON_RECURSIVE));
         startParameter.setSearchUpwards(!options.has(NO_SEARCH_UPWARDS));
 
         if (options.has(PROJECT_DIR)) {
@@ -209,9 +206,9 @@
         }
         
         if (options.has(EMBEDDED_SCRIPT)) {
-            if (options.has(BUILD_FILE) || options.has(NON_RECURSIVE) || options.has(NO_SEARCH_UPWARDS)) {
-                logger.error(String.format("Error: The %s option can't be used together with the %s, %s or %s option.",
-                        EMBEDDED_SCRIPT, BUILD_FILE, NON_RECURSIVE, NO_SEARCH_UPWARDS));
+            if (options.has(BUILD_FILE) || options.has(NO_SEARCH_UPWARDS)) {
+                logger.error(String.format("Error: The %s option can't be used together with the %s or %s option.",
+                        EMBEDDED_SCRIPT, BUILD_FILE, NO_SEARCH_UPWARDS));
                 exitWithError(options, new InvalidUserDataException());
                 return;
             }
@@ -221,7 +218,6 @@
         logger.debug("gradle.home= " + gradleHome);
         logger.debug("Project dir: " + startParameter.getCurrentDir());
         logger.debug("Gradle user home: " + startParameter.getGradleUserHomeDir());
-        logger.info("Recursive: " + startParameter.isRecursive());
         logger.info("Buildfilename: " + startParameter.getBuildFileName());
         logger.debug("Plugin properties: " + startParameter.getPluginPropertiesFile());
         logger.debug("Default imports file: " + startParameter.getDefaultImportsFile());
Index: trunk/src/main/groovy/org/gradle/initialization/DefaultSettings.groovy
===================================================================
--- trunk/src/main/groovy/org/gradle/initialization/DefaultSettings.groovy	(revision 711)
+++ trunk/src/main/groovy/org/gradle/initialization/DefaultSettings.groovy	Tue Jul 22 07:54:58 EST 2008
@@ -64,7 +64,6 @@
         buildSrcStartParameter = new StartParameter(
                 buildFileName: Project.DEFAULT_PROJECT_FILE,
                 taskNames: [JavaPlugin.CLEAN, JavaPlugin.UPLOAD_LIBS],
-                recursive: true,
                 searchUpwards: true,
                 gradleUserHomeDir: startParameter.gradleUserHomeDir
         )
Index: trunk/src/main/groovy/org/gradle/util/WrapUtil.java
===================================================================
--- trunk/src/main/groovy/org/gradle/util/WrapUtil.java	(revision 711)
+++ trunk/src/main/groovy/org/gradle/util/WrapUtil.java	Tue Jul 22 10:36:23 EST 2008
@@ -28,6 +28,8 @@
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 /**
  * Common methods to wrap objects in generic collections.
@@ -89,6 +91,15 @@
     }
 
     /**
+     * Wraps the given key and value in a mutable sorted map.
+     */
+    public static <K, V> SortedMap<K, V> toSortedMap(K key, V value) {
+        SortedMap<K, V> map = new TreeMap<K,V>();
+        map.put(key, value);
+        return map;
+    }
+
+    /**
      * Wraps the given key and value in a mutable ordered map.
      */
     public static <K, V> Map<K, V> toLinkedMap(K key, V value) {
Index: trunk/src/main/groovy/org/gradle/execution/ProjectDefaultsTaskSelector.java
===================================================================
--- trunk/src/main/groovy/org/gradle/execution/ProjectDefaultsTaskSelector.java	Tue Jul 22 14:40:49 EST 2008
+++ trunk/src/main/groovy/org/gradle/execution/ProjectDefaultsTaskSelector.java	Tue Jul 22 14:40:49 EST 2008
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.execution;
+
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.InvalidUserDataException;
+
+import java.util.List;
+
+/**
+ * A {@link TaskSelector} which selects the default tasks for a project.
+ */
+public class ProjectDefaultsTaskSelector implements TaskSelector {
+    private TaskSelector selector;
+
+    public boolean hasNext() {
+        return selector == null || selector.hasNext();
+    }
+
+    public void select(Project project) {
+        if (selector == null) {
+            // Gather the default tasks from this first group project
+            List<String> defaultTasks = project.getDefaultTasks();
+            if (defaultTasks.size() == 0) {
+                throw new InvalidUserDataException("No tasks have been specified and the project has not defined any default tasks.");
+            }
+            selector = new NameResolvingTaskSelector(defaultTasks);
+        }
+
+        selector.select(project);
+    }
+
+    public Iterable<Task> getTasks() {
+        return selector.getTasks();
+    }
+
+    public String getDescription() {
+        return selector.getDescription();
+    }
+}
Index: trunk/src/test/groovy/org/gradle/initialization/EmbeddedBuildExecuterTest.java
===================================================================
--- trunk/src/test/groovy/org/gradle/initialization/EmbeddedBuildExecuterTest.java	(revision 711)
+++ trunk/src/test/groovy/org/gradle/initialization/EmbeddedBuildExecuterTest.java	Tue Jul 22 16:41:58 EST 2008
@@ -16,13 +16,9 @@
 
 package org.gradle.initialization;
 
-import groovy.mock.interceptor.MockFor;
 import org.gradle.Build;
-import org.gradle.api.internal.project.BuildScriptFinder;
-import org.gradle.api.internal.project.EmbeddedBuildScriptFinder;
 import org.gradle.StartParameter;
 import org.gradle.Build.BuildFactory;
-import org.gradle.util.JUnit4GroovyMockery;
 import org.gradle.util.WrapUtil;
 import org.junit.runner.RunWith;
 import org.jmock.lib.legacy.ClassImposteriser;
@@ -32,8 +28,6 @@
 import org.junit.Before;
 
 import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * @author Hans Dockter
@@ -68,7 +62,6 @@
     @Test
     public void testExecute() {
         final StartParameter localExpectedStartParameter = StartParameter.newInstance(expectedStartParameter);
-        localExpectedStartParameter.setRecursive(true);
         localExpectedStartParameter.setSearchUpwards(true);
         context.checking(new Expectations() {
             {
Index: trunk/src/test/groovy/org/gradle/execution/NameResolvingTaskSelectorTest.java
===================================================================
--- trunk/src/test/groovy/org/gradle/execution/NameResolvingTaskSelectorTest.java	Tue Jul 22 14:40:49 EST 2008
+++ trunk/src/test/groovy/org/gradle/execution/NameResolvingTaskSelectorTest.java	Tue Jul 22 14:40:49 EST 2008
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.execution;
+
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.UnknownTaskException;
+import org.gradle.util.WrapUtil;
+import static org.hamcrest.Matchers.*;
+import org.jmock.Expectations;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeSet;
+
+@RunWith (org.jmock.integration.junit4.JMock.class)
+public class NameResolvingTaskSelectorTest {
+    private final JUnit4Mockery context = new JUnit4Mockery();
+
+    @Test
+    public void selectsTaskWithMatchingPath() {
+        final Project project = context.mock(Project.class, "child");
+        final Project rootProject = context.mock(Project.class, "root");
+        final Task task = context.mock(Task.class);
+        final SortedMap<Project, Set<Task>> tasks = WrapUtil.toSortedMap(project, WrapUtil.toSet(task));
+
+        context.checking(new Expectations(){{
+            atLeast(1).of(project).absolutePath("a:b");
+            will(returnValue(":a:b"));
+
+            atLeast(1).of(project).getRootProject();
+            will(returnValue(rootProject));
+
+            atLeast(1).of(rootProject).getAllTasks(true);
+            will(returnValue(tasks));
+
+            allowing(task).getPath();
+            will(returnValue(":a:b"));
+        }});
+
+        TaskSelector selector = new NameResolvingTaskSelector(WrapUtil.toList("a:b"));
+        selector.select(project);
+        assertThat(selector.getDescription(), equalTo("primary task 'a:b'"));
+        assertThat(selector.getTasks(), equalTo((Iterable<Task>) WrapUtil.toSet(task)));
+    }
+
+    @Test
+    public void selectsAllTasksWithTheProvidedName() {
+        final Project project = context.mock(Project.class);
+        Task task1 = context.mock(Task.class, "task1");
+        Task task2 = context.mock(Task.class, "task2");
+        final Set<Task> tasks = WrapUtil.toSet(task1, task2);
+
+        context.checking(new Expectations() {{
+            atLeast(1).of(project).getTasksByName("name", true);
+            will(returnValue(tasks));
+        }});
+
+        TaskSelector selector = new NameResolvingTaskSelector(WrapUtil.toList("name"));
+        selector.select(project);
+        assertThat(selector.getDescription(), equalTo("primary task 'name'"));
+        assertThat(selector.getTasks(), equalTo((Iterable<Task>) tasks));
+    }
+
+    @Test
+    public void treatsEachProvidedNameAsASeparateGroup() {
+        final Project project1 = context.mock(Project.class, "project1");
+        final Project project2 = context.mock(Project.class, "project2");
+        final Task task1 = context.mock(Task.class, "task1");
+        final Task task2 = context.mock(Task.class, "task2");
+
+        context.checking(new Expectations() {{
+            allowing(project1).getTasksByName(with(aNonNull(String.class)), with(equalTo(true)));
+            will(returnValue(WrapUtil.toSet(task1)));
+            atLeast(1).of(project2).getTasksByName("name2", true);
+            will(returnValue(WrapUtil.toSet(task2)));
+        }});
+
+        TaskSelector selector = new NameResolvingTaskSelector(WrapUtil.toList("name1", "name2"));
+        selector.select(project1);
+        assertThat(selector.getDescription(), equalTo("primary task 'name1'"));
+        assertThat(selector.getTasks(), equalTo((Iterable<Task>) WrapUtil.toSet(task1)));
+
+        selector.select(project2);
+        assertThat(selector.getDescription(), equalTo("primary task 'name2'"));
+        assertThat(selector.getTasks(), equalTo((Iterable<Task>) WrapUtil.toSet(task2)));
+    }
+
+    @Test
+    public void hasNoNextGroupOnceAllNamesHaveBeenVisited() {
+        final Project project = context.mock(Project.class);
+        final Task task = context.mock(Task.class);
+
+        context.checking(new Expectations() {{
+            atLeast(1).of(project).getTasksByName("name1", true);
+            will(returnValue(WrapUtil.toSet(task)));
+            atLeast(1).of(project).getTasksByName("name2", true);
+            will(returnValue(WrapUtil.toSet(task)));
+        }});
+
+        TaskSelector selector = new NameResolvingTaskSelector(WrapUtil.toList("name1", "name2"));
+
+        assertThat(selector.hasNext(), equalTo(true));
+        selector.select(project);
+
+        assertThat(selector.hasNext(), equalTo(true));
+        selector.select(project);
+
+        assertThat(selector.hasNext(), equalTo(false));
+        selector.select(project);
+        assertThat(selector.getDescription(), equalTo(""));
+        assertThat(selector.getTasks(), equalTo((Iterable<Task>) new TreeSet<Task>()));
+    }
+
+    @Test
+    public void failsWhenUnknownTaskNameIsProvided() {
+        final Project project = context.mock(Project.class);
+        final Task task = context.mock(Task.class);
+
+        context.checking(new Expectations() {{
+            atLeast(1).of(project).getTasksByName("name1", true);
+            will(returnValue(WrapUtil.toSet()));
+            atLeast(1).of(project).getTasksByName("name2", true);
+            will(returnValue(WrapUtil.toSet(task)));
+        }});
+
+        TaskSelector selector = new NameResolvingTaskSelector(WrapUtil.toList("name1", "name2"));
+        try {
+            selector.select(project);
+            fail();
+        } catch (UnknownTaskException e) {
+            assertThat(e.getMessage(), equalTo("Task 'name1' not found in this project."));
+        }
+    }
+
+    @Test
+    public void failsWhenMultipleUnknownTaskNamesAreProvided() {
+        final Project project = context.mock(Project.class);
+
+        context.checking(new Expectations() {{
+            atLeast(1).of(project).getTasksByName("name1", true);
+            will(returnValue(WrapUtil.toSet()));
+            atLeast(1).of(project).getTasksByName("name2", true);
+            will(returnValue(WrapUtil.toSet()));
+        }});
+
+        TaskSelector selector = new NameResolvingTaskSelector(WrapUtil.toList("name1", "name2"));
+        try {
+            selector.select(project);
+            fail();
+        } catch (UnknownTaskException e) {
+            assertThat(e.getMessage(), equalTo("Tasks ['name1', 'name2'] not found in this project."));
+        }
+    }
+}
Index: trunk/src/test/groovy/org/gradle/MainTest.java
===================================================================
--- trunk/src/test/groovy/org/gradle/MainTest.java	(revision 711)
+++ trunk/src/test/groovy/org/gradle/MainTest.java	Tue Jul 22 15:47:20 EST 2008
@@ -29,7 +29,6 @@
 import org.jmock.integration.junit4.JUnit4Mockery;
 import org.jmock.Expectations;
 import static org.junit.Assert.*;
-import static org.hamcrest.Matchers.is;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.Before;
@@ -45,8 +44,6 @@
  */
 @RunWith(org.jmock.integration.junit4.JMock.class)
 public class MainTest {
-    private final static String TEST_DIR_NAME = "/testdir";
-
     // This property has to be also set as system property gradle.home when running this test
     private final static String TEST_GRADLE_HOME = "roadToNowhere";
 
@@ -59,7 +56,6 @@
     private List expectedTaskNames = WrapUtil.toList("clean", "compile");
     private Map expectedSystemProperties;
     private Map expectedProjectProperties;
-    private boolean expectedRecursive;
     private CacheUsage expectedCacheUsage;
     private boolean expectedSearchUpwards;
     private String expectedEmbeddedScript;
@@ -99,7 +95,6 @@
         expectedSystemProperties = new HashMap();
         expectedSettingsFileName = Settings.DEFAULT_SETTINGS_FILE;
         expectedBuildFileName = Project.DEFAULT_PROJECT_FILE;
-        expectedRecursive = true;
         expectedCacheUsage = CacheUsage.ON;
         expectedSearchUpwards = true;
         expectedEmbeddedScript = "somescript";
@@ -163,7 +158,6 @@
         assertEquals(expectedSettingsFileName, startParameter.getSettingsFileName());
         assertEquals(emptyTasks ? new ArrayList() : expectedTaskNames, startParameter.getTaskNames());
         assertEquals(expectedProjectDir.getAbsoluteFile(), startParameter.getCurrentDir().getAbsoluteFile());
-        assertEquals(expectedRecursive, startParameter.isRecursive());
         assertEquals(expectedCacheUsage, startParameter.getCacheUsage());
         assertEquals(expectedSearchUpwards, startParameter.isSearchUpwards());
         assertEquals(expectedProjectProperties, startParameter.getProjectProperties());
@@ -185,7 +179,6 @@
                     if (noTasks) {
                         one(buildMock).taskListNonRecursivelyWithCurrentDirAsRoot(with(new StartParameterMatcher(true)));
                     } else {
-                        ;
                         one(buildMock).runNonRecursivelyWithCurrentDirAsRoot(with(new StartParameterMatcher(false)));
                     }
                 } else {
@@ -292,16 +285,6 @@
     }
 
     @Test
-    public void testMainWithNonRecursiveFlagSet() throws Throwable {
-        expectedRecursive = false;
-        checkMain(new MainCall() {
-            public void execute() throws Throwable {
-                Main.main(args("-Sn"));
-            }
-        });
-    }
-
-    @Test
     public void testMainWithCacheOffFlagSet() throws Throwable {
         expectedCacheUsage = CacheUsage.OFF;
         checkMain(new MainCall() {
@@ -361,11 +344,6 @@
     }
 
     @Test(expected = InvalidUserDataException.class)
-    public void testMainWithEmbeddedScriptAndConflictingNonrecursiveOption() throws Throwable {
-        Main.main(new String[]{"-S", "-e", "someScript", "-n", "clean"});
-    }
-
-    @Test(expected = InvalidUserDataException.class)
     public void testMainWithEmbeddedScriptAndConflictingSpecifyBuildFileOption() throws Throwable {
         Main.main(new String[]{"-S", "-e", "someScript", "-bsomeFile", "clean"});
     }
@@ -411,7 +389,7 @@
     private String[] args(String... prefix) {
         List<String> allArgs = new ArrayList<String>(expectedTaskNames);
         allArgs.addAll(0, Arrays.asList(prefix));
-        return (String[]) allArgs.toArray(new String[allArgs.size()]);
+        return allArgs.toArray(new String[allArgs.size()]);
     }
 
     //    @Test void testMainWithException() {
Index: trunk/src/test/groovy/org/gradle/BuildTest.java
===================================================================
--- trunk/src/test/groovy/org/gradle/BuildTest.java	(revision 711)
+++ trunk/src/test/groovy/org/gradle/BuildTest.java	Tue Jul 22 16:09:53 EST 2008
@@ -26,6 +26,7 @@
 import org.gradle.util.WrapUtil;
 import org.gradle.api.Project;
 import org.gradle.api.UnknownTaskException;
+import org.gradle.api.Task;
 import org.gradle.initialization.RootFinder;
 import org.junit.runner.RunWith;
 import org.junit.Before;
@@ -59,18 +60,16 @@
     private DefaultProject expectedRootProject;
     private DefaultProject expectedCurrentProject;
     private URLClassLoader expectedClassLoader;
-    private boolean expectedRecursive;
     private DefaultSettings settingsMock;
     private boolean expectedSearchUpwards;
     private Map expectedProjectProperties;
     private Map expectedSystemPropertiesArgs;
-    private List expectedTaskNames;
+    private List<String> expectedTaskNames;
+    private List<Iterable<Task>> expectedTasks;
     private StartParameter expectedStartParams;
 
     private Map testGradleProperties = new HashMap();
 
-    private Build.BuildFactory testBuildFactory;
-
     private Build build;
 
     private BuildExecuter buildExecuterMock;
@@ -92,8 +91,6 @@
 
         testGradleProperties = WrapUtil.toMap(Project.SYSTEM_PROP_PREFIX + ".prop1", "value1");
         testGradleProperties.put("prop2", "value2");
-        expectedTaskNames = WrapUtil.toList("a", "b");
-        expectedRecursive = false;
         expectedSearchUpwards = false;
         expectedClassLoader = new URLClassLoader(new URL[0]);
         expectedProjectProperties = WrapUtil.toMap("prop", "value");
@@ -102,19 +99,19 @@
         expectedCurrentDir = new File("currentDir");
         expectedGradleUserHomeDir = new File(HelperUtil.TMP_DIR_FOR_TEST, "gradleUserHomeDir");
 
+        expectedRootProject = HelperUtil.createRootProject(new File("dir1"));
+        expectedCurrentProject = HelperUtil.createRootProject(new File("dir2"));
+
+        expectTasks("a", "b");
+        
         expectedStartParams = new StartParameter();
         expectedStartParams.setTaskNames(expectedTaskNames);
         expectedStartParams.setCurrentDir(expectedCurrentDir);
-        expectedStartParams.setRecursive(expectedRecursive);
         expectedStartParams.setSearchUpwards(expectedSearchUpwards);
         expectedStartParams.setGradleUserHomeDir(expectedGradleUserHomeDir);
         expectedStartParams.setSystemPropertiesArgs(expectedSystemPropertiesArgs);
         expectedStartParams.setProjectProperties(expectedProjectProperties);
 
-        expectedRootProject = HelperUtil.createRootProject(new File("dir1"));
-        expectedCurrentProject = HelperUtil.createRootProject(new File("dir2"));
-
-
         context.checking(new Expectations() {
             {
                 allowing(rootFinderMock).find(with(any(StartParameter.class)));
@@ -130,6 +127,14 @@
         });
     }
 
+    private void expectTasks(String... tasks) {
+        expectedTaskNames = WrapUtil.toList(tasks);
+        expectedTasks = new ArrayList<Iterable<Task>>();
+        for (String task : tasks) {
+            expectedTasks.add(WrapUtil.toSortedSet(expectedCurrentProject.createTask(task)));
+        }
+    }
+
     @After
     public void tearDown() {
         HelperUtil.deleteTestDir();
@@ -172,6 +177,7 @@
         expectedStartParams.setTaskNames(new ArrayList<String>());
         expectedTaskNames = WrapUtil.toList("c", "d");
         expectedCurrentProject.setDefaultTasks(expectedTaskNames);
+        expectTasks("c", "d");
         setRunExpectations(false);
         build.run(expectedStartParams);
         checkSystemProps(expectedSystemPropertiesArgs);
@@ -194,11 +200,9 @@
         context.checking(new Expectations() {
             {
                 one(buildConfigurerMock).process(expectedRootProject);
-                one(buildExecuterMock).unknownTasks(expectedTaskNames, expectedRecursive, expectedCurrentProject);
-                will(returnValue(new ArrayList()));
-                one(buildExecuterMock).execute((String) expectedTaskNames.get(0), expectedRecursive, expectedCurrentProject, expectedRootProject, true);
+                one(buildExecuterMock).execute(expectedTasks.get(0), expectedRootProject, true);
                 will(returnValue(rebuildDagReturnValue));
-                one(buildExecuterMock).execute((String) expectedTaskNames.get(1), expectedRecursive, expectedCurrentProject, expectedRootProject, false);
+                one(buildExecuterMock).execute(expectedTasks.get(1), expectedRootProject, false);
                 one(projectsLoaderMock).load(settingsMock, expectedClassLoader, expectedStartParams,
                         expectedProjectProperties, System.getProperties(), System.getenv());
                 if (rebuildDagReturnValue) {
@@ -212,6 +216,7 @@
 
     @Test(expected = UnknownTaskException.class)
     public void testRunWithUnknownTask() {
+        expectedStartParams.setTaskNames(WrapUtil.toList("unknown"));
         context.checking(new Expectations() {
             {
                 one(projectsLoaderMock).load(settingsMock, expectedClassLoader, expectedStartParams,
@@ -219,8 +224,6 @@
                 one(settingsProcessorMock).process(rootFinderMock, expectedStartParams);
                 will(returnValue(settingsMock));
                 one(buildConfigurerMock).process(expectedRootProject);
-                one(buildExecuterMock).unknownTasks(expectedTaskNames, expectedRecursive, expectedCurrentProject);
-                will(returnValue(WrapUtil.toList("a")));
             }
         });
         build.run(expectedStartParams);
@@ -261,7 +264,7 @@
     private void setTaskExpectations() {
         context.checking(new Expectations() {
             {
-                one(buildConfigurerMock).taskList(expectedRootProject, expectedRecursive, expectedCurrentProject);
+                one(buildConfigurerMock).taskList(expectedRootProject, true, expectedCurrentProject);
             }
         });
     }
Index: trunk/src/test/groovy/org/gradle/execution/ProjectDefaultsTaskSelectorTest.java
===================================================================
--- trunk/src/test/groovy/org/gradle/execution/ProjectDefaultsTaskSelectorTest.java	Tue Jul 22 14:40:49 EST 2008
+++ trunk/src/test/groovy/org/gradle/execution/ProjectDefaultsTaskSelectorTest.java	Tue Jul 22 14:40:49 EST 2008
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.execution;
+
+import org.gradle.api.InvalidUserDataException;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.util.WrapUtil;
+import static org.hamcrest.Matchers.*;
+import org.jmock.Expectations;
+import org.jmock.integration.junit4.JUnit4Mockery;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith (org.jmock.integration.junit4.JMock.class)
+public class ProjectDefaultsTaskSelectorTest {
+    private final JUnit4Mockery context = new JUnit4Mockery();
+
+    @Test public void usesProjectDefaultTasksFromInitialProject() {
+        final Project project = context.mock(Project.class);
+
+        context.checking(new Expectations() {{
+            one(project).getDefaultTasks();
+            will(returnValue(WrapUtil.toList("a", "b")));
+            Task task = context.mock(Task.class);
+            atLeast(1).of(project).getTasksByName("a", true);
+            will(returnValue(WrapUtil.toSet(task)));
+            atLeast(1).of(project).getTasksByName("b", true);
+            will(returnValue(WrapUtil.toSet(task)));
+        }});
+
+        TaskSelector selector = new ProjectDefaultsTaskSelector();
+        assertThat(selector.hasNext(), equalTo(true));
+        selector.select(project);
+    }
+
+    @Test public void failsWhenNoProjectDefaultTasksSpecified() {
+        final Project project = context.mock(Project.class);
+
+        context.checking(new Expectations() {{
+            one(project).getDefaultTasks();
+            will(returnValue(WrapUtil.toList()));
+        }});
+
+        TaskSelector selector = new ProjectDefaultsTaskSelector();
+        try {
+            selector.select(project);
+            fail();
+        } catch (InvalidUserDataException e) {
+            assertThat(e.getMessage(), equalTo("No tasks have been specified and the project has not defined any default tasks."));
+        }
+    }
+
+    @Test public void ignoresSubsequentProjects() {
+        final Project project1 = context.mock(Project.class, "project1");
+        final Project project2 = context.mock(Project.class, "project2");
+
+        context.checking(new Expectations() {{
+            one(project1).getDefaultTasks();
+            will(returnValue(WrapUtil.toList("a", "b")));
+            Task task = context.mock(Task.class);
+            atLeast(1).of(project1).getTasksByName("a", true);
+            will(returnValue(WrapUtil.toSet(task)));
+            atLeast(1).of(project1).getTasksByName("b", true);
+            will(returnValue(WrapUtil.toSet(task)));
+            atLeast(1).of(project2).getTasksByName("b", true);
+            will(returnValue(WrapUtil.toSet(task)));
+        }});
+
+        TaskSelector selector = new ProjectDefaultsTaskSelector();
+        selector.select(project1);
+        selector.select(project2);
+    }
+}
\ No newline at end of file
Index: trunk/src/test/groovy/org/gradle/execution/BuildExecuterTest.java
===================================================================
--- trunk/src/test/groovy/org/gradle/execution/BuildExecuterTest.java	(revision 711)
+++ trunk/src/test/groovy/org/gradle/execution/BuildExecuterTest.java	Tue Jul 22 09:51:57 EST 2008
@@ -16,10 +16,12 @@
 
 package org.gradle.execution;
 
-import org.gradle.api.*;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.UnknownProjectException;
+import org.gradle.api.UnknownTaskException;
 import org.gradle.api.internal.DefaultTask;
 import org.gradle.api.internal.project.DefaultProject;
-import org.gradle.util.GroovyJavaHelper;
 import org.gradle.util.HelperUtil;
 import org.gradle.util.WrapUtil;
 import org.hamcrest.Description;
@@ -28,16 +30,16 @@
 import org.jmock.api.Invocation;
 import org.jmock.integration.junit4.JUnit4Mockery;
 import org.jmock.lib.legacy.ClassImposteriser;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.File;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * @author Hans Dockter
@@ -68,9 +70,6 @@
 
     @Test
     public void testExecute() {
-        String expectedTaskName = "test";
-        boolean expectedRecursive = true;
-
         final Task rootCompile = new DefaultTask(root, "compile", dagMock);
         final Task rootTest = new DefaultTask(root, "test", dagMock);
         final Task childCompile = new DefaultTask(child, "compile", dagMock);
@@ -87,14 +86,14 @@
 
         setDagMockExpectations(WrapUtil.toSet(root, child), WrapUtil.toSet(rootCompile, rootTest, childCompile, childTest, childOther));
 
-        assertTrue(buildExecuter.execute(expectedTaskName, expectedRecursive, root, root, true));
+        assertTrue(buildExecuter.execute(WrapUtil.toList(rootTest, childTest), root, true));
     }
 
     @Test public void testExecuteWithRebuildDagFalse() {
         final Task rootCompile = new DefaultTask(root, "compile", dagMock);
         root.getTasks().put(rootCompile.getName(), rootCompile);
         setDagMockExpectations(WrapUtil.<Project>toSet(root), WrapUtil.toSet(rootCompile));
-        assertNull(buildExecuter.execute("compile", true, root, root, false));
+        assertNull(buildExecuter.execute(WrapUtil.toList(rootCompile), root, false));
     }
 
     @Test public void testExecuteWithRebuildDagAndDagNeutralTask() {
@@ -102,10 +101,10 @@
         rootCompile.setDagNeutral(true);
         root.getTasks().put(rootCompile.getName(), rootCompile);
         setDagMockExpectations(WrapUtil.<Project>toSet(root), WrapUtil.toSet(rootCompile));
-        assertFalse(buildExecuter.execute("compile", true, root, root, true));
+        assertFalse(buildExecuter.execute(WrapUtil.toList(rootCompile), root, true));
     }
 
-    public static class CollectDagTasksAction<T> implements Action {
+    public static class CollectDagTasksAction implements Action {
         Map<DefaultTask, Set<DefaultTask>> tasksMap = new HashMap<DefaultTask, Set<DefaultTask>>();
 
         public CollectDagTasksAction() {
@@ -139,42 +138,6 @@
     }
 
     @Test
-    public void testNoUnknownTasksWithrecursiveFalse() {
-        prepareUnknownTasksTest();
-        assertEquals(new ArrayList(), buildExecuter.unknownTasks(WrapUtil.toList("compile", "test"), false, root));
-    }
-
-    @Test
-    public void testNoUnknownTasksWithrecursiveTrue() {
-        prepareUnknownTasksTest();
-        assertEquals(WrapUtil.toList("test"), buildExecuter.unknownTasks(WrapUtil.toList("compile", "test"), true, child));
-    }
-
-    @Test
-    public void testNoUnknownTasksWithRecursiveTrueAndChildTaskOnly() {
-        prepareUnknownTasksTest();
-        assertEquals(new ArrayList(), buildExecuter.unknownTasks(WrapUtil.toList("compile", "other"), true, root));
-    }
-
-    @Test
-    public void testUnknownTasksWithRecursiceFalseAndChildTaskOnly() {
-        prepareUnknownTasksTest();
-        assertEquals(WrapUtil.toList("other"), buildExecuter.unknownTasks(WrapUtil.toList("compile", "other"), false, root));
-    }
-
-    private void prepareUnknownTasksTest() {
-        DefaultTask rootCompile = new DefaultTask(root, "compile", dagMock);
-        DefaultTask rootTest = new DefaultTask(root, "test", dagMock);
-        DefaultTask childCompile = new DefaultTask(child, "compile", dagMock);
-        DefaultTask childOtherTask = new DefaultTask(child, "other", dagMock);
-
-        root.getTasks().put(rootCompile.getName(), rootCompile);
-        root.getTasks().put(rootTest.getName(), rootTest);
-        child.getTasks().put(childCompile.getName(), childCompile);
-        child.getTasks().put(childOtherTask.getName(), childOtherTask);
-    }
-
-    @Test
     public void testExecuteWithTransitiveTargetDependecies() {
         Task task1 = new DefaultTask(root, "task1", dagMock);
         Task task2 = new DefaultTask(root, "task2", dagMock).dependsOn("task1");
@@ -185,7 +148,7 @@
         setDagMockExpectations(WrapUtil.toSet(root, child),
                 WrapUtil.toSet(task1, task2, task3));
 
-        buildExecuter.execute("task3", false, root, root, true);
+        buildExecuter.execute(WrapUtil.toList(task3), root, true);
 
         assertEquals(WrapUtil.toSet(task2), collectDagTasksAction.tasksMap.get(task3));
         assertEquals(WrapUtil.toSet(task1), collectDagTasksAction.tasksMap.get(task2));
@@ -196,46 +159,38 @@
     @Test(expected = UnknownTaskException.class)
     public void testExecuteWithNonExistingProjectForDependentTask() {
         final Project root = context.mock(Project.class);
-        final Task task = context.mock(Task.class);
-        final Set result = new HashSet();
         final String taskName = ":unknownchild:compile";
 
         context.checking(new Expectations() {{
-            allowing(root).getTasksByName("compile", false); will(returnValue(result));
             allowing(root).getRootProject(); will(returnValue(root));
             allowing(root).getPath(); will(returnValue("root"));
             allowing(root).absolutePath(taskName); will(returnValue(taskName));
             allowing(root).project(":unknownchild"); will(throwException(new UnknownProjectException()));
             allowing(dagMock).reset();
         }});
-        result.add(new DefaultTask(root, "compile", dagMock).dependsOn(taskName));
-        buildExecuter.execute("compile", false, root, root, true);
+        
+        Task compileTask = new DefaultTask(root, "compile", dagMock);
+        compileTask.dependsOn(taskName);
+
+        buildExecuter.execute(WrapUtil.toList(compileTask), root, true);
     }
 
     @Test(expected = UnknownTaskException.class)
     public void testExecuteWithNonExistingDependentTask() {
         final Project root = context.mock(Project.class);
-        final Task task = context.mock(Task.class);
-        final Set result = new HashSet();
         final String taskName = ":child:compile";
+
         context.checking(new Expectations() {{
-            allowing(root).getTasksByName("compile", false); will(returnValue(result));
             allowing(root).getRootProject(); will(returnValue(root));
             allowing(root).getPath(); will(returnValue("root"));
             allowing(root).absolutePath(taskName); will(returnValue(taskName));
+            allowing(root).project(":child"); will(returnValue(child));
             allowing(dagMock).reset();
         }});
-        result.add(new DefaultTask(root, "compile", dagMock).dependsOn(taskName));
-        buildExecuter.execute("compile", false, child, root, true);
-    }
 
-    @Test(expected = UnknownTaskException.class)
-    public void testExecuteWithNonExistingTask() {
-        final Project root = context.mock(Project.class);
-        context.checking(new Expectations() {{
-            allowing(root).getTasksByName("compil", true); will(returnValue(new HashSet()));
-        }});
-            buildExecuter.execute("compil", true, root, root, true);
-    }
+        Task compileTask = new DefaultTask(root, "compile", dagMock);
+        compileTask.dependsOn(taskName);
 
+        buildExecuter.execute(WrapUtil.toList(compileTask), root, true);
-}
+    }
+}
Index: trunk/src/main/groovy/org/gradle/execution/NameResolvingTaskSelector.java
===================================================================
--- trunk/src/main/groovy/org/gradle/execution/NameResolvingTaskSelector.java	Tue Jul 22 14:40:49 EST 2008
+++ trunk/src/main/groovy/org/gradle/execution/NameResolvingTaskSelector.java	Tue Jul 22 14:40:49 EST 2008
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.gradle.execution;
+
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.UnknownTaskException;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A {@link TaskSelector} which selects tasks which match the provided names. For each name, selects all tasks in
+ * all projects whose name is the given name.
+ */
+public class NameResolvingTaskSelector implements TaskSelector {
+    private final Iterable<String> names;
+    private Iterator<String> current;
+    private Set<Task> tasks;
+    private String description;
+
+    public NameResolvingTaskSelector(Iterable<String> names) {
+        this.names = names;
+    }
+
+    public boolean hasNext() {
+        return current == null || current.hasNext();
+    }
+
+    public void select(Project project) {
+        if (current == null) {
+            // First group, check for unknown tasks
+            current = names.iterator();
+            checkForUnknownTasks(project);
+        }
+
+        if (!current.hasNext()) {
+            tasks = Collections.emptySet();
+            description = "";
+            return;
+        }
+
+        String taskName = current.next();
+        description = String.format("primary task '%s'", taskName);
+        tasks = findTasks(project, taskName);
+    }
+
+    private void checkForUnknownTasks(Project project) {
+        Set<String> unknownTasks = new LinkedHashSet<String>();
+        for (String taskName : names) {
+            if (findTasks(project, taskName).size() == 0) {
+                unknownTasks.add(String.format("'%s'", taskName));
+            }
+        }
+        if (unknownTasks.size() == 0) {
+            return;
+        }
+        if (unknownTasks.size() == 1) {
+            throw new UnknownTaskException(String.format("Task %s not found in this project.", unknownTasks.iterator().next()));
+        } else {
+            throw new UnknownTaskException(String.format("Tasks %s not found in this project.", unknownTasks));
+        }
+    }
+
+    private Set<Task> findTasks(Project project, String taskName) {
+        if (taskName.contains(Project.PATH_SEPARATOR)) {
+            taskName = project.absolutePath(taskName);
+            Map<Project, Set<Task>> allTasks = project.getRootProject().getAllTasks(true);
+            for (Collection<Task> projectTasks : allTasks.values()) {
+                for (Task task : projectTasks) {
+                    if (task.getPath().equals(taskName)) {
+                        return Collections.singleton(task);
+                    }
+                }
+            }
+            return Collections.emptySet();
+        } else {
+            return project.getTasksByName(taskName, true);
+        }
+    }
+
+    public Iterable<Task> getTasks() {
+        return tasks;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}
Index: trunk/src/main/groovy/org/gradle/execution/BuildExecuter.java
===================================================================
--- trunk/src/main/groovy/org/gradle/execution/BuildExecuter.java	(revision 711)
+++ trunk/src/main/groovy/org/gradle/execution/BuildExecuter.java	Mon Jul 21 16:37:14 EST 2008
@@ -16,16 +16,19 @@
 
 package org.gradle.execution;
 
+import org.gradle.api.InvalidUserDataException;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.UnknownProjectException;
+import org.gradle.api.UnknownTaskException;
 import org.gradle.api.internal.DefaultTask;
 import org.gradle.api.internal.project.DefaultProject;
+import org.gradle.util.Clock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.gradle.api.*;
-import org.gradle.util.Clock;
-import org.gradle.util.WrapUtil;
-import org.gradle.api.internal.project.AbstractProject;
 
-import java.util.*;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * @author Hans Dockter
@@ -35,8 +38,6 @@
 
     Dag dag;
 
-    Map<String, Set<Task>> taskCache = new HashMap<String, Set<Task>>();
-
     public BuildExecuter() {
     }
 
@@ -44,20 +45,13 @@
         this.dag = dag;
     }
 
-    public Boolean execute(String taskName, boolean recursive, Project currentProject, Project rootProject, boolean checkForRebuildDag) {
-        assert taskName != null;
-        assert currentProject != null;
+    public Boolean execute(Iterable<Task> tasks, Project rootProject, boolean checkForRebuildDag) {
+        assert tasks != null;
+        assert rootProject != null;
 
-        logger.info(String.format("++ Executing: %s Recursive:%s Startproject: %s", taskName, recursive, currentProject));
-
-        Set<Task> calledTasks = getTasks(taskName, currentProject, recursive);
-        logger.debug("Found tasks: {}", calledTasks);
-        if (calledTasks.size() == 0) {           
-            throw new UnknownTaskException("No tasks available for " + taskName);
-        }
         Clock clock = new Clock();
         dag.reset();
-        fillDag(this.dag, calledTasks, rootProject);
+        fillDag(this.dag, tasks, rootProject);
         logger.info("Timing: Creating the DAG took " + clock.getTime());
         clock.reset();
         dag.execute();
@@ -65,7 +59,7 @@
         if (!checkForRebuildDag) {
             return null;
         }
-        for (Task calledTask : calledTasks) {
+        for (Task calledTask : tasks) {
             if (!calledTask.isDagNeutral()) {
                 return true;
             }
@@ -73,24 +67,7 @@
         return false;
     }
 
-    public List unknownTasks(List<String> taskNames, boolean recursive, Project currentProject) {
-        List<String> unknownTasks = new ArrayList<String>();
-        for (String taskName : taskNames) {
-            if (getTasks(taskName, currentProject, recursive).size() == 0) {
-                unknownTasks.add(taskName);
-            }
-        }
-        return unknownTasks;
-    }
-
-    private Set<Task> getTasks(String primaryTaskName, Project currentProject, boolean recursive) {
-        if (taskCache.get(primaryTaskName) == null) {
-            taskCache.put(primaryTaskName, currentProject.getTasksByName(primaryTaskName, recursive));
-        }
-        return taskCache.get(primaryTaskName);
-    }
-
-    private void fillDag(Dag dag, Collection<Task> tasks, Project rootProject) {
+    private void fillDag(Dag dag, Iterable<Task> tasks, Project rootProject) {
         for (Task task : tasks) {
             Set<Task> dependsOnTasks = findDependsOnTasks(task, rootProject);
             dag.addTask(task, dependsOnTasks);
Index: trunk/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy
===================================================================
--- trunk/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy	(revision 711)
+++ trunk/src/test/groovy/org/gradle/initialization/DefaultSettingsTest.groovy	Tue Jul 22 16:41:58 EST 2008
@@ -24,8 +24,6 @@
 import org.gradle.api.dependencies.ResolverContainer
 import org.gradle.api.plugins.JavaPlugin
 import org.apache.ivy.plugins.resolver.FileSystemResolver
-import org.apache.ivy.plugins.resolver.IBiblioResolver
-import org.gradle.api.dependencies.ResolverContainer
 import org.apache.ivy.plugins.resolver.DualResolver
 import org.gradle.StartParameter
 import static org.junit.Assert.*
@@ -80,7 +78,6 @@
         assertEquals(Project.DEFAULT_PROJECT_FILE, settings.buildSrcStartParameter.buildFileName)
         assertEquals([JavaPlugin.CLEAN, JavaPlugin.UPLOAD_LIBS], settings.buildSrcStartParameter.taskNames)
         assertTrue(settings.buildSrcStartParameter.searchUpwards)
-        assertTrue(settings.buildSrcStartParameter.recursive)
     }
 
     @Test public void testInclude() {
Index: trunk/src/main/groovy/org/gradle/Build.java
===================================================================
--- trunk/src/main/groovy/org/gradle/Build.java	(revision 711)
+++ trunk/src/main/groovy/org/gradle/Build.java	Tue Jul 22 16:12:39 EST 2008
@@ -16,25 +16,37 @@
 
 package org.gradle;
 
-import org.gradle.api.UnknownTaskException;
+import org.gradle.api.Project;
 import org.gradle.api.internal.dependencies.DefaultDependencyManagerFactory;
-import org.gradle.api.internal.project.*;
+import org.gradle.api.internal.project.BuildScriptProcessor;
+import org.gradle.api.internal.project.ImportsReader;
+import org.gradle.api.internal.project.PluginRegistry;
+import org.gradle.api.internal.project.ProjectFactory;
+import org.gradle.api.internal.project.ProjectRegistry;
+import org.gradle.api.internal.project.TaskFactory;
 import org.gradle.configuration.BuildConfigurer;
+import org.gradle.configuration.ProjectDependencies2TaskResolver;
 import org.gradle.configuration.ProjectTasksPrettyPrinter;
 import org.gradle.execution.BuildExecuter;
 import org.gradle.execution.Dag;
-import org.gradle.initialization.*;
+import org.gradle.execution.NameResolvingTaskSelector;
+import org.gradle.execution.ProjectDefaultsTaskSelector;
+import org.gradle.execution.TaskSelector;
+import org.gradle.groovy.scripts.DefaultProjectScriptMetaData;
+import org.gradle.groovy.scripts.DefaultScriptHandler;
+import org.gradle.groovy.scripts.DefaultScriptProcessor;
+import org.gradle.groovy.scripts.DefaultSettingsScriptMetaData;
+import org.gradle.initialization.DefaultSettings;
+import org.gradle.initialization.ProjectsLoader;
+import org.gradle.initialization.RootFinder;
+import org.gradle.initialization.SettingsFactory;
+import org.gradle.initialization.SettingsProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.gradle.api.Project;
-import org.gradle.api.InvalidUserDataException;
-import org.gradle.configuration.ProjectDependencies2TaskResolver;
-import org.gradle.util.GUtil;
-import org.gradle.groovy.scripts.*;
 
+import java.io.File;
 import java.util.List;
 import java.util.Map;
-import java.io.File;
 
 /**
  * @author Hans Dockter
@@ -63,7 +75,6 @@
     }
 
     public void runNonRecursivelyWithCurrentDirAsRoot(StartParameter startParameter) {
-        startParameter.setRecursive(false);
         runInternal(initWithCurrentDirAsRoot(startParameter), startParameter);
     }
 
@@ -76,8 +87,10 @@
         ClassLoader classLoader = settings.createClassLoader();
         Boolean rebuildDag = true;
         List<String> taskNames = startParameter.getTaskNames();
-        int i = 0;
-        do {
+        TaskSelector selector = taskNames.size() == 0
+                ? new ProjectDefaultsTaskSelector()
+                : new NameResolvingTaskSelector(taskNames);
+        while (selector.hasNext()) {
             if (rebuildDag) {
                 projectLoader.load(settings, classLoader, startParameter, startParameter.getProjectProperties(),
                         getAllSystemProperties(), getAllEnvProperties());
@@ -85,35 +98,15 @@
             } else {
                 logger.info("DAG must not be rebuild as the task chain before was dag neutral!");
             }
-            if (i == 0) {
-                if (taskNames.size() == 0) {
-                    taskNames = projectLoader.getCurrentProject().getDefaultTasks();
+            selector.select(projectLoader.getCurrentProject());
+            logger.info(String.format("++++ Starting build for %s.", selector.getDescription()));
+            logger.debug(String.format("Selected for execution: %s.", selector.getTasks()));
+            rebuildDag = buildExecuter.execute(selector.getTasks(), projectLoader.getRootProject(), selector.hasNext());
-                }
+        }
-                if (!GUtil.isTrue(taskNames)) {
-                    throw new InvalidUserDataException("No task names have been specified and the project has not defined any default tasks!");
-                }
+    }
-                List unknownTasks = buildExecuter.unknownTasks(taskNames, startParameter.isRecursive(),
-                        projectLoader.getCurrentProject());
-                if (GUtil.isTrue(unknownTasks)) {
-                    throw new UnknownTaskException("Task(s) " + unknownTasks + " are unknown!");
-                }
-            }
-            String taskName = taskNames.get(i);
-            logger.info("++++ Starting build for primary task: " + taskName);
-            boolean lastTask = isLastElement(taskNames, i);
-            rebuildDag = buildExecuter.execute(taskName, startParameter.isRecursive(), projectLoader.getCurrentProject(),
-                    projectLoader.getRootProject(), !lastTask);
-        } while (++i < taskNames.size());
-    }
 
-
-    private boolean isLastElement(List<String> taskNames, int i) {
-        return (i == taskNames.size() - 1);
-    }
-
     public String taskListNonRecursivelyWithCurrentDirAsRoot(StartParameter startParameter) {
         StartParameter newStartParameter = StartParameter.newInstance(startParameter);
-        newStartParameter.setRecursive(false);
         return taskListInternal(initWithCurrentDirAsRoot(newStartParameter), newStartParameter);
     }
 
@@ -124,7 +117,7 @@
     private String taskListInternal(DefaultSettings settings, StartParameter startParameter) {
         projectLoader.load(settings, settings.createClassLoader(), startParameter, startParameter.getProjectProperties(),
                 getAllSystemProperties(), getAllEnvProperties());
-        return buildConfigurer.taskList(projectLoader.getRootProject(), startParameter.isRecursive(), projectLoader.getCurrentProject());
+        return buildConfigurer.taskList(projectLoader.getRootProject(), true, projectLoader.getCurrentProject());
     }
 
     private DefaultSettings init(StartParameter startParameter) {
Index: trunk/src/main/groovy/org/gradle/StartParameter.java
===================================================================
--- trunk/src/main/groovy/org/gradle/StartParameter.java	(revision 711)
+++ trunk/src/main/groovy/org/gradle/StartParameter.java	Tue Jul 22 07:54:58 EST 2008
@@ -28,13 +28,10 @@
  * @author Hans Dockter
  */
 public class StartParameter {
-    ;
-    
     private String settingsFileName;
     private String buildFileName;
     private List<String> taskNames;
     private File currentDir;
-    private boolean recursive;
     private boolean searchUpwards;
     private Map projectProperties = new HashMap();
     private Map systemPropertiesArgs = new HashMap();
@@ -46,12 +43,11 @@
     public StartParameter() {
     }
 
-    public StartParameter(String settingsFileName, String buildFileName, List<String> taskNames, File currentDir, boolean recursive, boolean searchUpwards, Map projectProperties, Map systemPropertiesArgs, File gradleUserHomeDir, File defaultImportsFile, File pluginPropertiesFile, CacheUsage cacheUsage) {
+    public StartParameter(String settingsFileName, String buildFileName, List<String> taskNames, File currentDir, boolean searchUpwards, Map projectProperties, Map systemPropertiesArgs, File gradleUserHomeDir, File defaultImportsFile, File pluginPropertiesFile, CacheUsage cacheUsage) {
         this.settingsFileName = settingsFileName;
         this.buildFileName = buildFileName;
         this.taskNames = taskNames;
         this.currentDir = currentDir;
-        this.recursive = recursive;
         this.searchUpwards = searchUpwards;
         this.projectProperties = projectProperties;
         this.systemPropertiesArgs = systemPropertiesArgs;
@@ -67,7 +63,6 @@
         startParameter.buildFileName = startParameterSrc.buildFileName;
         startParameter.taskNames = startParameterSrc.taskNames;
         startParameter.currentDir = startParameterSrc.currentDir;
-        startParameter.recursive = startParameterSrc.recursive;
         startParameter.searchUpwards = startParameterSrc.searchUpwards;
         startParameter.projectProperties = startParameterSrc.projectProperties;
         startParameter.systemPropertiesArgs = startParameterSrc.systemPropertiesArgs;
@@ -111,14 +106,6 @@
         this.currentDir = currentDir;
     }
 
-    public boolean isRecursive() {
-        return recursive;
-    }
-
-    public void setRecursive(boolean recursive) {
-        this.recursive = recursive;
-    }
-
     public boolean isSearchUpwards() {
         return searchUpwards;
     }
