Add ability to specify target for project.

Summary: First bit of slices.
diff --git a/src/com/facebook/buck/cli/ProjectCommand.java b/src/com/facebook/buck/cli/ProjectCommand.java
index 55b4b43..008232e 100644
--- a/src/com/facebook/buck/cli/ProjectCommand.java
+++ b/src/com/facebook/buck/cli/ProjectCommand.java
@@ -91,7 +91,8 @@
       exitCode = createIntellijProject(project,
           tempFile,
           executionContext.getProcessExecutor(),
-          console.getStdOut());
+          console.getStdOut(),
+          console.getStdErr());
       if (exitCode != 0) {
         return exitCode;
       }
@@ -133,9 +134,10 @@
   int createIntellijProject(Project project,
       File jsonTemplate,
       ProcessExecutor processExecutor,
-      PrintStream stdOut)
+      PrintStream stdOut,
+      PrintStream stdErr)
       throws IOException {
-    return project.createIntellijProject(jsonTemplate, processExecutor, stdOut);
+    return project.createIntellijProject(jsonTemplate, processExecutor, stdOut, stdErr);
   }
 
   /**
@@ -152,12 +154,26 @@
   @VisibleForTesting
   PartialGraph createPartialGraph(RawRulePredicate rulePredicate, ProjectCommandOptions options)
       throws BuildFileParseException, BuildTargetException, IOException {
-    return PartialGraph.createPartialGraph(
-        rulePredicate,
-        getProjectFilesystem(),
-        options.getDefaultIncludes(),
-        getParser(),
-        getBuckEventBus());
+    List<String> argumentsAsBuildTargets = options.getArgumentsFormattedAsBuildTargets();
+
+    if (argumentsAsBuildTargets.isEmpty()) {
+      return PartialGraph.createPartialGraph(
+          rulePredicate,
+          getProjectFilesystem(),
+          options.getDefaultIncludes(),
+          getParser(),
+          getBuckEventBus());
+    } else {
+      // If build targets were specified, generate a partial intellij project that contains the
+      // files needed to build the build targets specified.
+      ImmutableList<BuildTarget> targets = getBuildTargets(argumentsAsBuildTargets);
+
+      return PartialGraph.createPartialGraphFromRoots(targets,
+          rulePredicate,
+          options.getDefaultIncludes(),
+          getParser(),
+          getBuckEventBus());
+    }
   }
 
   @Override
diff --git a/src/com/facebook/buck/cli/ProjectCommandOptions.java b/src/com/facebook/buck/cli/ProjectCommandOptions.java
index 1ec546c..78ab8a3 100644
--- a/src/com/facebook/buck/cli/ProjectCommandOptions.java
+++ b/src/com/facebook/buck/cli/ProjectCommandOptions.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 
+import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
 import java.util.List;
@@ -33,10 +34,25 @@
   private String target;
 
 
+  @Argument
+  private List<String> arguments = Lists.newArrayList();
+
   ProjectCommandOptions(BuckConfig buckConfig) {
     super(buckConfig);
   }
 
+  public List<String> getArguments() {
+    return arguments;
+  }
+
+  public void setArguments(List<String> arguments) {
+    this.arguments = arguments;
+  }
+
+  public List<String> getArgumentsFormattedAsBuildTargets() {
+    return getCommandLineBuildTargetNormalizer().normalizeAll(getArguments());
+  }
+
   public String getTarget() {
     return target;
   }
diff --git a/src/com/facebook/buck/command/Project.java b/src/com/facebook/buck/command/Project.java
index 6e43b18..1cc14cc 100644
--- a/src/com/facebook/buck/command/Project.java
+++ b/src/com/facebook/buck/command/Project.java
@@ -48,6 +48,7 @@
 import com.facebook.buck.util.KeystoreProperties;
 import com.facebook.buck.util.ProcessExecutor;
 import com.facebook.buck.util.ProjectFilesystem;
+import com.facebook.buck.util.Verbosity;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -160,14 +161,15 @@
 
   public int createIntellijProject(File jsonTempFile,
       ProcessExecutor processExecutor,
-      PrintStream stdOut) throws IOException {
+      PrintStream stdOut,
+      PrintStream stdErr) throws IOException {
     List<Module> modules = createModulesForProjectConfigs();
     writeJsonConfig(jsonTempFile, modules);
 
     List<String> modifiedFiles = Lists.newArrayList();
 
     // Process the JSON config to generate the .xml and .iml files for IntelliJ.
-    ExitCodeAndStdOut result = processJsonConfig(jsonTempFile);
+    ExitCodeAndOutput result = processJsonConfig(jsonTempFile);
     if (result.exitCode != 0) {
       return result.exitCode;
     } else {
@@ -202,6 +204,8 @@
       SortedSet<String> modifiedFilesInSortedForder = Sets.newTreeSet(modifiedFiles);
       stdOut.printf("MODIFIED FILES:\n%s\n", Joiner.on('\n').join(modifiedFilesInSortedForder));
     }
+    // Blit stderr from intellij.py to parent stderr.
+    stdErr.print(result.stdErr);
 
     return 0;
   }
@@ -905,7 +909,7 @@
     }
   }
 
-  private ExitCodeAndStdOut processJsonConfig(File jsonTempFile) throws IOException {
+  private ExitCodeAndOutput processJsonConfig(File jsonTempFile) throws IOException {
     final ImmutableList<String> args = ImmutableList.of(
         pythonInterpreter, PATH_TO_INTELLIJ_PY, jsonTempFile.getAbsolutePath());
 
@@ -925,7 +929,7 @@
 
     Console console = executionContext.getConsole();
     Console childConsole = new Console(
-        console.getVerbosity(),
+        Verbosity.SILENT,
         console.getStdOut(),
         console.getStdErr(),
         Ansi.withoutTty());
@@ -934,15 +938,17 @@
         .setConsole(childConsole)
         .build();
     int exitCode = command.execute(childContext);
-    return new ExitCodeAndStdOut(exitCode, command.getStdout());
+    return new ExitCodeAndOutput(exitCode, command.getStdout(), command.getStderr());
   }
 
-  private static class ExitCodeAndStdOut {
+  private static class ExitCodeAndOutput {
     private final int exitCode;
     private final String stdOut;
-    ExitCodeAndStdOut(int exitCode, String stdOut) {
+    private final String stdErr;
+    ExitCodeAndOutput(int exitCode, String stdOut, String stdErr) {
       this.exitCode = exitCode;
       this.stdOut = Preconditions.checkNotNull(stdOut);
+      this.stdErr = Preconditions.checkNotNull(stdErr);
     }
   }
 
diff --git a/src/com/facebook/buck/command/intellij.py b/src/com/facebook/buck/command/intellij.py
index 2c166da..c0d5185 100644
--- a/src/com/facebook/buck/command/intellij.py
+++ b/src/com/facebook/buck/command/intellij.py
@@ -1,6 +1,9 @@
 import errno
+import fnmatch
 import json
 import os
+import re
+import subprocess
 import sys
 
 
@@ -105,6 +108,9 @@
 # and no files will need to be written.
 MODIFIED_FILES = []
 
+# Files that are part of the project being run.  We will delete all .iml files
+# that are not checked in and not in this set.
+PROJECT_FILES = set()
 
 def write_modules(modules):
   """Writes one XML file for each module."""
@@ -348,6 +354,7 @@
 
 
 def write_file_if_changed(path, content):
+  PROJECT_FILES.add(path)
   if os.path.exists(path):
     file_content_as_string = open(path, 'r').read()
     needs_update = content.strip() != file_content_as_string.strip()
@@ -372,8 +379,31 @@
       pass
     else: raise
 
+def clean_old_files():
+  if os.path.isdir('.git'):
+    try:
+      files_to_clean = subprocess.check_output(['git', 'ls-files', '--other'])
+      for file_name in files_to_clean.splitlines():
+        if file_name.endswith('.iml') and file_name not in PROJECT_FILES:
+          os.remove(file_name)
+      return
+    except Exception as e:
+      pass
+
 
 if __name__ == '__main__':
+  if not os.path.isdir('.git'):
+    for root, dirnames, filenames in os.walk('.'):
+      if fnmatch.filter(filenames, '*.iml'):
+        sys.stderr.write('\n'.join(
+          [ '  ::  "buck project" run from a directory not under Git source',
+            '  ::  control.  If invoking buck project with an argument, we are',
+            '  ::  not able to remove old .iml files, which can result in',
+            '  ::  IntelliJ being in a bad state.  Please close and re-open',
+            '  ::  IntelliJ if it\'s open.' ]))
+        sys.stderr.flush()
+        break
+
   json_file = sys.argv[1]
   parsed_json = json.load(open(json_file, 'r'))
 
@@ -384,6 +414,8 @@
   write_modules(modules)
   write_all_modules(modules)
   write_run_configs()
+  if PROJECT_FILES:
+    clean_old_files()
 
   # Write the list of modified files to stdout
   for path in MODIFIED_FILES: print path
diff --git a/src/com/facebook/buck/parser/Parser.java b/src/com/facebook/buck/parser/Parser.java
index 97c8f0b..740c7ac 100644
--- a/src/com/facebook/buck/parser/Parser.java
+++ b/src/com/facebook/buck/parser/Parser.java
@@ -605,6 +605,32 @@
     return filterTargets(filter);
   }
 
+
+  /**
+   * Takes a sequence of build targets and parses all of the build files that contain them and their
+   * transitive deps, producing a collection of "raw rules" that have been produced from the build
+   * files. The specified {@link RawRulePredicate} is applied to this collection. This method
+   * returns the collection of {@link BuildTarget}s that correspond to the raw rules that were
+   * matched by the predicate.
+   * <p>
+   * Because {@code project_config} rules are not transitive dependencies of rules such as
+   * {@code android_binary}, but are defined in the same build files as the transitive
+   * dependencies of an {@code android_binary}, this method is helpful in finding all of the
+   * {@code project_config} rules needed to produce an IDE configuration to build said
+   * {@code android_binary}. See {@link ProjectCommand#predicate} for an example of such
+   * a {@link RawRulePredicate}.
+   */
+  public synchronized List<BuildTarget> filterTargetsInProjectFromRoots(
+      Iterable<BuildTarget> roots,
+      Iterable<String> defaultIncludes,
+      BuckEventBus eventBus,
+      RawRulePredicate filter)
+      throws BuildFileParseException, BuildTargetException, IOException {
+    parseBuildFilesForTargets(roots, defaultIncludes, eventBus);
+
+    return filterTargets(filter);
+  }
+
   /**
    * Called when file change events are posted to the file change EventBus to invalidate cached
    * build rules if required.
diff --git a/src/com/facebook/buck/parser/PartialGraph.java b/src/com/facebook/buck/parser/PartialGraph.java
index d37275e..f05262b 100644
--- a/src/com/facebook/buck/parser/PartialGraph.java
+++ b/src/com/facebook/buck/parser/PartialGraph.java
@@ -69,15 +69,44 @@
       Iterable<String> includes,
       Parser parser,
       BuckEventBus eventBus) throws BuildTargetException, BuildFileParseException, IOException {
-
-    Preconditions.checkNotNull(parser);
+    Preconditions.checkNotNull(predicate);
 
     List<BuildTarget> targets = parser.filterAllTargetsInProject(filesystem, includes, predicate);
 
+    return parseAndCreateGraphFromTargets(targets, includes, parser, eventBus);
+  }
+
+  /**
+   * Creates a partial graph of all {@link BuildRule}s that are transitive dependencies of (rules
+   * that pass {@code predicate} and are contained in BUCK files that contain transitive
+   * dependencies of the {@link BuildTarget}s defined in {@code roots}).
+   */
+  public static PartialGraph createPartialGraphFromRoots(
+      Iterable<BuildTarget> roots,
+      RawRulePredicate predicate,
+      Iterable<String> includes,
+      Parser parser,
+      BuckEventBus eventBus) throws BuildTargetException, BuildFileParseException, IOException {
+    Preconditions.checkNotNull(predicate);
+
+    List<BuildTarget> targets = parser.filterTargetsInProjectFromRoots(
+        roots, includes, eventBus, predicate);
+
+    return parseAndCreateGraphFromTargets(targets, includes, parser, eventBus);
+  }
+
+  private static PartialGraph parseAndCreateGraphFromTargets(
+      Iterable<BuildTarget> targets,
+      Iterable<String> includes,
+      Parser parser,
+      BuckEventBus eventBus) throws BuildTargetException, BuildFileParseException, IOException {
+
+    Preconditions.checkNotNull(parser);
+
     // Now that the Parser is loaded up with the set of all build rules, use it to create a
     // DependencyGraph of only the targets we want to build.
     DependencyGraph graph = parser.parseBuildFilesForTargets(targets, includes, eventBus);
 
-    return new PartialGraph(graph, targets);
+    return new PartialGraph(graph, ImmutableList.copyOf(targets));
   }
 }
diff --git a/test/com/facebook/buck/cli/ProjectCommandTest.java b/test/com/facebook/buck/cli/ProjectCommandTest.java
index 4602a7d..a235e25 100644
--- a/test/com/facebook/buck/cli/ProjectCommandTest.java
+++ b/test/com/facebook/buck/cli/ProjectCommandTest.java
@@ -188,12 +188,14 @@
     int createIntellijProject(Project project,
         File jsonTemplate,
         ProcessExecutor processExecutor,
-        PrintStream stdOut)
+        PrintStream stdOut,
+        PrintStream stdErr)
         throws IOException {
       assertNotNull(project);
       assertNotNull(jsonTemplate);
       assertNotNull(processExecutor);
       assertNotNull(stdOut);
+      assertNotNull(stdErr);
       return 0;
     }
 
diff --git a/test/com/facebook/buck/cli/ProjectIntegrationTest.java b/test/com/facebook/buck/cli/ProjectIntegrationTest.java
index ec55e3f..8457953 100644
--- a/test/com/facebook/buck/cli/ProjectIntegrationTest.java
+++ b/test/com/facebook/buck/cli/ProjectIntegrationTest.java
@@ -16,8 +16,10 @@
 
 package com.facebook.buck.cli;
 
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
 import static org.junit.Assert.assertEquals;
-
+import static org.junit.Assert.assertThat;
 import com.facebook.buck.testutil.integration.DebuggableTemporaryFolder;
 import com.facebook.buck.testutil.integration.ProjectWorkspace;
 import com.facebook.buck.testutil.integration.ProjectWorkspace.ProcessResult;
@@ -62,6 +64,57 @@
           "modules/tip/module_modules_tip.iml"
         ) + '\n',
         result.getStdout());
+
+    assertThat(
+        "`buck project` should contain warning about being run from directory without git.",
+        result.getStderr(),
+        not(containsString(Joiner.on('\n').join(
+            "  ::  \"buck project\" run from a directory not under Git source",
+            "  ::  control.  If invoking buck project with an argument, we are",
+            "  ::  not able to remove old .iml files, which can result in",
+            "  ::  IntelliJ being in a bad state.  Please close and re-open",
+            "  ::  IntelliJ if it's open."))));
+  }
+
+  /**
+   * Verify that if we build a project by specifying a target, the resulting project only contains
+   * the transitive deps of that target.  In this example, that means everything except
+   * //modules/tip.
+   */
+  @Test
+  public void testBuckProjectSlice() throws IOException {
+    ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(
+        this, "project_slice", temporaryFolder);
+    workspace.setUp();
+
+    ProcessResult result = workspace.runBuckCommand("project", "//modules/dep1:dep1");
+    result.assertExitCode("buck project should exit cleanly", 0);
+
+    workspace.verify();
+
+    assertEquals(
+        "`buck project` should report the files it modified.",
+        Joiner.on('\n').join(
+            "MODIFIED FILES:",
+            ".idea/compiler.xml",
+            ".idea/libraries/libs_guava_jar.xml",
+            ".idea/libraries/libs_jsr305_jar.xml",
+            ".idea/libraries/libs_junit_jar.xml",
+            ".idea/modules.xml",
+            ".idea/runConfigurations/Debug_Buck_test.xml",
+            "modules/dep1/module_modules_dep1.iml"
+        ) + '\n',
+        result.getStdout());
+
+    assertThat(
+        "`buck project` should contain warning about being run from directory without git.",
+        result.getStderr(),
+        containsString(Joiner.on('\n').join(
+            "  ::  \"buck project\" run from a directory not under Git source",
+            "  ::  control.  If invoking buck project with an argument, we are",
+            "  ::  not able to remove old .iml files, which can result in",
+            "  ::  IntelliJ being in a bad state.  Please close and re-open",
+            "  ::  IntelliJ if it's open.")));
   }
 
   /**
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/.buckconfig b/test/com/facebook/buck/cli/testdata/project_slice/.buckconfig
new file mode 100644
index 0000000..23528f4
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/.buckconfig
@@ -0,0 +1,2 @@
+[color]
+  ui = false
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/.idea/modules.xml.expected b/test/com/facebook/buck/cli/testdata/project_slice/.idea/modules.xml.expected
new file mode 100644
index 0000000..0724339
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/.idea/modules.xml.expected
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/modules/dep1/module_modules_dep1.iml" filepath="$PROJECT_DIR$/modules/dep1/module_modules_dep1.iml" />
+    </modules>
+  </component>
+</project>
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/libs/BUCK b/test/com/facebook/buck/cli/testdata/project_slice/libs/BUCK
new file mode 100644
index 0000000..5e53ca8
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/libs/BUCK
@@ -0,0 +1,23 @@
+prebuilt_jar(
+  name = 'guava',
+  binary_jar = 'guava.jar',
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+prebuilt_jar(
+  name = 'jsr305',
+  binary_jar = 'jsr305.jar',
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+prebuilt_jar(
+  name = 'junit',
+  binary_jar = 'junit.jar',
+  visibility = [
+    'PUBLIC',
+  ],
+)
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/libs/guava.jar b/test/com/facebook/buck/cli/testdata/project_slice/libs/guava.jar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/libs/guava.jar
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/libs/jsr305.jar b/test/com/facebook/buck/cli/testdata/project_slice/libs/jsr305.jar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/libs/jsr305.jar
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/libs/junit.jar b/test/com/facebook/buck/cli/testdata/project_slice/libs/junit.jar
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/libs/junit.jar
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/modules/dep1/BUCK b/test/com/facebook/buck/cli/testdata/project_slice/modules/dep1/BUCK
new file mode 100644
index 0000000..32dc7e2
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/modules/dep1/BUCK
@@ -0,0 +1,28 @@
+android_library(
+  name = 'dep1',
+  srcs = glob(['src/**/*.java']),
+  deps = [
+    '//libs:guava',
+    '//libs:jsr305',
+  ],
+  visibility = [
+    'PUBLIC',
+  ],
+)
+
+java_test(
+  name = 'test',
+  srcs = glob(['test/**/*Test.java']),
+  deps = [
+    ':dep1',
+    '//libs:guava',
+    '//libs:junit',
+  ],
+)
+
+project_config(
+  src_target = ':dep1',
+  src_roots = [ 'src' ],
+  test_target = ':test',
+  test_roots = [ 'test' ],
+)
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/modules/dep1/module_modules_dep1.iml.expected b/test/com/facebook/buck/cli/testdata/project_slice/modules/dep1/module_modules_dep1.iml.expected
new file mode 100644
index 0000000..66d9ff0
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/modules/dep1/module_modules_dep1.iml.expected
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="GEN_FOLDER_RELATIVE_PATH_APT" value="/../../buck-out/android/modules/dep1/gen" />
+        <option name="GEN_FOLDER_RELATIVE_PATH_AIDL" value="/../../buck-out/android/modules/dep1/gen" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/res" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/assets" />
+        <option name="LIBS_FOLDER_RELATIVE_PATH" value="/libs" />
+        <option name="USE_CUSTOM_APK_RESOURCE_FOLDER" value="false" />
+        <option name="CUSTOM_APK_RESOURCE_FOLDER" value="" />
+        <option name="USE_CUSTOM_COMPILER_MANIFEST" value="false" />
+        <option name="CUSTOM_COMPILER_MANIFEST" value="" />
+        <option name="APK_PATH" value="" />
+        <option name="LIBRARY_PROJECT" value="true" />
+        <option name="RUN_PROCESS_RESOURCES_MAVEN_TASK" value="true" />
+        <option name="GENERATE_UNSIGNED_APK" value="false" />
+        <option name="CUSTOM_DEBUG_KEYSTORE_PATH" value="" />
+        <option name="PACK_TEST_CODE" value="false" />
+        <option name="RUN_PROGUARD" value="false" />
+        <option name="PROGUARD_CFG_PATH" value="/proguard.cfg" />
+        <resOverlayFolders />
+        <includeSystemProguardFile>false</includeSystemProguardFile>
+        <includeAssetsFromLibraries>true</includeAssetsFromLibraries>
+        <additionalNativeLibs />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <content url="file://$MODULE_DIR$/../../buck-out/android/modules/dep1/gen">
+      <sourceFolder url="file://$MODULE_DIR$/../../buck-out/android/modules/dep1/gen" isTestSource="false" />
+    </content>
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" exported="" scope="TEST" name="libs_junit_jar" level="project" />
+    <orderEntry type="library" exported="" name="libs_guava_jar" level="project" />
+    <orderEntry type="library" exported="" name="libs_jsr305_jar" level="project" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/modules/tip/BUCK b/test/com/facebook/buck/cli/testdata/project_slice/modules/tip/BUCK
new file mode 100644
index 0000000..3dba30b
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/modules/tip/BUCK
@@ -0,0 +1,27 @@
+android_library(
+  name = 'tip',
+  srcs = glob(['src/**/*.java']),
+  deps = [
+    '//libs:guava',
+    '//libs:jsr305',
+    '//modules/dep1:dep1',
+  ],
+)
+
+java_test(
+  name = 'test',
+  srcs = glob(['test/**/*Test.java']),
+  deps = [
+    ':tip',
+    '//libs:guava',
+    '//libs:jsr305',
+    '//libs:junit',
+  ],
+)
+
+project_config(
+  src_target = ':tip',
+  src_roots = [ 'src' ],
+  test_target = ':test',
+  test_roots = [ 'test' ],
+)
diff --git a/test/com/facebook/buck/cli/testdata/project_slice/modules/tip/module_modules_tip.iml b/test/com/facebook/buck/cli/testdata/project_slice/modules/tip/module_modules_tip.iml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/com/facebook/buck/cli/testdata/project_slice/modules/tip/module_modules_tip.iml