Merge pull request #22 from brendandouglas/master
Project import generated by Copybara.
diff --git a/.gitignore b/.gitignore
index ac51a05..6d8ad95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-bazel-*
+bazel-*
\ No newline at end of file
diff --git a/BUILD b/BUILD
index ca39524..9d98461 100644
--- a/BUILD
+++ b/BUILD
@@ -2,15 +2,17 @@
# Description: Blaze plugin for various IntelliJ products.
#
+licenses(["notice"]) # Apache 2.0
+
# IJwB tests, run with an IntelliJ plugin SDK
test_suite(
name = "ijwb_tests",
tests = [
- "//blaze-base:integration_tests",
- "//blaze-base:unit_tests",
- "//blaze-java:integration_tests",
- "//blaze-java:unit_tests",
- "//blaze-plugin-dev:integration_tests",
+ "//base:integration_tests",
+ "//base:unit_tests",
+ "//java:integration_tests",
+ "//java:unit_tests",
+ "//plugin_dev:integration_tests",
],
)
@@ -19,15 +21,29 @@
name = "aswb_tests",
tests = [
"//aswb:unit_tests",
- "//blaze-base:unit_tests",
- "//blaze-java:unit_tests",
+ "//base:unit_tests",
+ "//java:unit_tests",
],
)
-# Version file
-filegroup(
- name = "version",
- srcs = ["VERSION"],
- visibility = ["//visibility:public"],
+# CLwB tests, run with a CLion plugin SDK
+test_suite(
+ name = "clwb_tests",
+ tests = [
+ "//base:unit_tests",
+ ],
)
+load(
+ ":version.bzl",
+ "VERSION",
+)
+
+# Version file
+genrule(
+ name = "version",
+ srcs = [],
+ outs = ["VERSION"],
+ cmd = "echo '%s' > $@" % VERSION,
+ visibility = ["//visibility:public"],
+)
diff --git a/README.md b/README.md
index f6f2a87..0fc36c1 100644
--- a/README.md
+++ b/README.md
@@ -25,4 +25,4 @@
Install Bazel, then run 'bazel build //ijwb:ijwb_bazel' from
the project root. This will create a plugin jar in
-'bazel-genfiles/ijwb/ijwb_bazel.jar'.
+'bazel-genfiles/ijwb/ijwb_bazel.jar'.
\ No newline at end of file
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 2b26b8d..0000000
--- a/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-1.5.9
diff --git a/WORKSPACE b/WORKSPACE
index e9e2b96..f443141 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -4,25 +4,64 @@
# and run integration tests.
new_http_archive(
name = "intellij_latest",
- build_file = "remote_platform_sdks/BUILD.idea",
- sha256 = "d1cd3f9fd650c00ba85181da6d66b4b80b8e48ce5f4f15b5f4dc67453e96a179",
- url = "https://download.jetbrains.com/idea/ideaIC-2016.1.3.tar.gz",
+ build_file = "intellij_platform_sdk/BUILD.idea",
+ url = "https://download.jetbrains.com/idea/ideaIC-2016.2.1.tar.gz",
)
# The plugin api for CLion 2016.1.3. This is required to build CLwB,
# and run integration tests.
new_http_archive(
name = "clion_latest",
- build_file = "remote_platform_sdks/BUILD.clion",
- sha256 = "470063f1bb65ba03c6e1aba354cb81e2c04bd280d9b8da98622be1ba6b0a9c88",
- url = "https://download.jetbrains.com/cpp/CLion-2016.1.3.tar.gz",
+ build_file = "intellij_platform_sdk/BUILD.clion",
+ url = "https://download.jetbrains.com/cpp/CLion-2016.2.1.tar.gz",
)
-# The plugin api for Android Studio 2.2. preview 4. This is required to build ASwB,
+# The plugin api for Android Studio 2.2 stable. This is required to build ASwB,
# and run integration tests.
new_http_archive(
name = "android_studio_latest",
- build_file = "remote_platform_sdks/BUILD.android_studio",
- sha256 = "530b630914b42f9ad9f5442a36b421214838443429a4a1b96194d45a5d586f17",
- url = "https://dl.google.com/dl/android/studio/ide-zips/2.2.0.3/android-studio-ide-145.3001415-linux.zip",
+ build_file = "intellij_platform_sdk/BUILD.android_studio",
+ url = "https://dl.google.com/dl/android/studio/ide-zips/2.2.0.12/android-studio-ide-145.3276617-linux.zip",
+)
+
+# LICENSE: Common Public License 1.0
+maven_jar(
+ name = "junit",
+ artifact = "junit:junit:4.11",
+ sha1 = "4e031bb61df09069aeb2bffb4019e7a5034a4ee0",
+)
+
+# LICENSE: The Apache Software License, Version 2.0
+maven_jar(
+ name = "jsr305_annotations",
+ artifact = "com.google.code.findbugs:jsr305:3.0.1",
+ sha1 = "f7be08ec23c21485b9b5a1cf1654c2ec8c58168d",
+)
+
+# LICENSE: The Apache Software License, Version 2.0
+maven_jar(
+ name = "truth",
+ artifact = "com.google.truth:truth:0.30",
+ sha1 = "9d591b5a66eda81f0b88cf1c748ab8853d99b18b",
+)
+
+# LICENSE: The Apache Software License, Version 2.0
+maven_jar(
+ name = "mockito",
+ artifact = "org.mockito:mockito-all:1.9.5",
+ sha1 = "79a8984096fc6591c1e3690e07d41be506356fa5",
+)
+
+# LICENSE: The Apache Software License, Version 2.0
+maven_jar(
+ name = "objenesis",
+ artifact = "org.objenesis:objenesis:1.3",
+ sha1 = "dc13ae4faca6df981fc7aeb5a522d9db446d5d50",
+)
+
+# LICENSE: The Apache Software License, Version 2.0
+maven_jar(
+ name = "jarjar",
+ artifact = "com.googlecode.jarjar:jarjar:1.3",
+ sha1 = "b81c2719c63fa8e6f3eca5b11b8e9b5ad79463db",
)
diff --git a/aswb/.bazelproject b/aswb/.bazelproject
index 3cbf8dc..2fdb3b8 100644
--- a/aswb/.bazelproject
+++ b/aswb/.bazelproject
@@ -3,10 +3,11 @@
-ijwb
-blaze-plugin-dev
-clwb
- -blaze-cpp
+ -blaze-cpp/src/com/google/idea/blaze/cpp/versioned/v162
targets:
//aswb:aswb_bazel
+ //aswb:aswb_blaze
//:aswb_tests
workspace_type: intellij_plugin
diff --git a/aswb/BUILD b/aswb/BUILD
index 01df2a6..2312a96 100644
--- a/aswb/BUILD
+++ b/aswb/BUILD
@@ -2,25 +2,30 @@
# Description: Builds ASwB for blaze and bazel
#
+licenses(["notice"]) # Apache 2.0
+
load(
"//build_defs:build_defs.bzl",
+ "intellij_plugin",
"merged_plugin_xml",
"stamped_plugin_xml",
- "intellij_plugin",
)
merged_plugin_xml(
name = "merged_plugin_xml_common",
srcs = [
"src/META-INF/aswb.xml",
- "//blaze-base:plugin_xml",
- "//blaze-cpp:plugin_xml",
- "//blaze-java:plugin_xml",
+ "//base:plugin_xml",
+ "//cpp:plugin_xml",
+ "//java:plugin_xml",
+ ],
+ visibility = [
+ "//visibility:public",
],
)
merged_plugin_xml(
- name = "merged_plugin_xml_bazel",
+ name = "merged_plugin_xml",
srcs = [
"src/META-INF/aswb_bazel.xml",
":merged_plugin_xml_common",
@@ -28,9 +33,11 @@
)
stamped_plugin_xml(
- name = "stamped_plugin_xml_bazel",
+ name = "stamped_plugin_xml",
include_product_code_in_stamp = True,
- plugin_xml = ":merged_plugin_xml_bazel",
+ plugin_id = "com.google.idea.bazel.aswb",
+ plugin_name = "Android Studio with Bazel",
+ plugin_xml = ":merged_plugin_xml",
stamp_since_build = True,
version_file = "//:version",
)
@@ -39,44 +46,46 @@
name = "aswb_lib",
srcs = glob(["src/**/*.java"]),
resources = glob(["resources/**/*"]),
- visibility = ["//visibility:public"],
+ visibility = [
+ "//visibility:public",
+ ],
deps = [
- "//blaze-base",
- "//blaze-base:proto-deps",
- "//blaze-cpp",
- "//blaze-java",
- "//intellij-platform-sdk:bundled_plugins",
- "//intellij-platform-sdk:plugin_api",
- "//third_party:jsr305",
+ "//base",
+ "//common/experiments",
+ "//cpp",
+ "//intellij_platform_sdk:plugin_api",
+ "//java",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
],
)
load(
"//intellij_test:test_defs.bzl",
- "intellij_test",
+ "intellij_unit_test_suite",
)
-intellij_test(
+intellij_unit_test_suite(
name = "unit_tests",
srcs = glob(["tests/unittests/**/*.java"]),
test_package_root = "com.google.idea.blaze.android",
deps = [
":aswb_lib",
- "//blaze-base",
- "//blaze-base:proto-deps",
- "//blaze-base:unit_test_utils",
- "//blaze-java",
- "//intellij-platform-sdk:bundled_plugins_for_tests",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//intellij_test:lib",
- "//third_party:jsr305",
- "//third_party:test_lib",
+ "//base",
+ "//base:unit_test_utils",
+ "//common/experiments",
+ "//common/experiments:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//java",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
],
)
intellij_plugin(
name = "aswb_bazel",
- plugin_xml = ":stamped_plugin_xml_bazel",
+ plugin_xml = ":stamped_plugin_xml",
deps = [
":aswb_lib",
],
diff --git a/aswb/aswb.iml b/aswb/aswb.iml
new file mode 100644
index 0000000..37230b3
--- /dev/null
+++ b/aswb/aswb.iml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/tests/unittests" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" relativeOutputPath="aswb/resources" />
+ </content>
+ <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="module" module-name="blaze-base-aswb" />
+ <orderEntry type="module" module-name="blaze-cpp-aswb" />
+ <orderEntry type="module" module-name="blaze-java-aswb" />
+ <orderEntry type="module" module-name="execution-openapi" />
+ <orderEntry type="module" module-name="java-impl" />
+ <orderEntry type="module" module-name="openapi" />
+ <orderEntry type="module" module-name="execution-impl" />
+ <orderEntry type="module" module-name="junit" />
+ <orderEntry type="library" scope="TEST" name="mockito" level="project" />
+ <orderEntry type="module" module-name="community-main" scope="RUNTIME" />
+ <orderEntry type="module" module-name="debugger-impl" />
+ <orderEntry type="module" module-name="android" />
+ <orderEntry type="module" module-name="dom-openapi" />
+ <orderEntry type="module" module-name="cidr-lang" />
+ <orderEntry type="module" module-name="android-ndk" />
+ <orderEntry type="module" module-name="cidr-common" />
+ <orderEntry type="module" module-name="instant-run-client" />
+ <orderEntry type="module" module-name="external-system-api" />
+ </component>
+</module>
\ No newline at end of file
diff --git a/aswb/src/META-INF/aswb.xml b/aswb/src/META-INF/aswb.xml
index 87eb089..f7b42c3 100644
--- a/aswb/src/META-INF/aswb.xml
+++ b/aswb/src/META-INF/aswb.xml
@@ -14,17 +14,15 @@
~ limitations under the License.
-->
<idea-plugin>
- <id>com.google.idea.blaze.aswb</id>
<vendor>Google</vendor>
- <depends optional="true">com.intellij.modules.androidstudio</depends>
+ <depends>com.intellij.modules.androidstudio</depends>
<depends>org.jetbrains.android</depends>
<extensions defaultExtensionNs="com.intellij">
<java.elementFinder implementation="com.google.idea.blaze.android.resources.AndroidResourceClassFinder"
order="first, before java"/>
<java.elementFinder implementation="com.google.idea.blaze.android.resources.AndroidResourcePackageFinder"/>
- <stepsBeforeRunProvider implementation="com.google.idea.blaze.android.run.BlazeBeforeRunTaskProvider"/>
<projectService serviceImplementation="com.google.idea.blaze.android.resources.LightResourceClassService"/>
<runConfigurationProducer
implementation="com.google.idea.blaze.android.run.test.BlazeAndroidTestClassRunConfigurationProducer"
@@ -53,9 +51,11 @@
<SyncListener implementation="com.google.idea.blaze.android.sync.BlazeAndroidSyncListener"/>
<SyncListener implementation="com.google.idea.blaze.android.cppimpl.BlazeNdkSupportEnabler"/>
<SyncListener implementation="com.google.idea.blaze.android.manifest.ManifestParser$ClearManifestParser"/>
- <RuleConfigurationFactory implementation="com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryRunConfigurationType$BlazeAndroidBinaryRuleConfigurationFactory"/>
- <RuleConfigurationFactory implementation="com.google.idea.blaze.android.run.test.BlazeAndroidTestRunConfigurationType$BlazeAndroidTestRuleConfigurationFactory"/>
+ <RuleConfigurationFactory implementation="com.google.idea.blaze.android.run.BlazeAndroidRuleConfigurationFactory"/>
<java.JavaSyncAugmenter implementation="com.google.idea.blaze.android.sync.BlazeAndroidJavaSyncAugmenter"/>
+ <PrefetchFileSource implementation="com.google.idea.blaze.android.sync.AndroidPrefetchFileSource"/>
+ <BlazeCommandRunConfigurationHandlerProvider implementation="com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryRunConfigurationHandlerProvider"/>
+ <BlazeCommandRunConfigurationHandlerProvider implementation="com.google.idea.blaze.android.run.test.BlazeAndroidTestRunConfigurationHandlerProvider"/>
</extensions>
<extensions defaultExtensionNs="com.android.ide">
diff --git a/aswb/src/META-INF/aswb_bazel.xml b/aswb/src/META-INF/aswb_bazel.xml
index abcc021..4b89d60 100644
--- a/aswb/src/META-INF/aswb_bazel.xml
+++ b/aswb/src/META-INF/aswb_bazel.xml
@@ -14,6 +14,5 @@
~ limitations under the License.
-->
<idea-plugin>
- <name>Android Studio with Bazel</name>
<description>Provides the ability to import Bazel projects in Android Studio.</description>
</idea-plugin>
diff --git a/aswb/src/META-INF/aswb_blaze.xml b/aswb/src/META-INF/aswb_blaze.xml
deleted file mode 100644
index 0e3acf7..0000000
--- a/aswb/src/META-INF/aswb_blaze.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
- ~ Copyright 2016 The Bazel Authors. All rights reserved.
- ~
- ~ 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.
- -->
-<idea-plugin>
- <name>Android Studio with Blaze</name>
- <description>Provides the ability to import Blaze projects in Android Studio.</description>
-</idea-plugin>
diff --git a/aswb/src/com/google/idea/blaze/android/cppapi/BlazeNativeDebuggerIdProvider.java b/aswb/src/com/google/idea/blaze/android/cppapi/BlazeNativeDebuggerIdProvider.java
index 4ecc40d..1645aaa 100644
--- a/aswb/src/com/google/idea/blaze/android/cppapi/BlazeNativeDebuggerIdProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/cppapi/BlazeNativeDebuggerIdProvider.java
@@ -16,9 +16,9 @@
package com.google.idea.blaze.android.cppapi;
import com.intellij.openapi.components.ServiceManager;
-
import javax.annotation.Nullable;
+/** Provides the ID of the native debugger to use */
public abstract class BlazeNativeDebuggerIdProvider {
@Nullable
public static BlazeNativeDebuggerIdProvider getInstance() {
diff --git a/aswb/src/com/google/idea/blaze/android/cppapi/NdkSupport.java b/aswb/src/com/google/idea/blaze/android/cppapi/NdkSupport.java
index 8435113..506dfe6 100644
--- a/aswb/src/com/google/idea/blaze/android/cppapi/NdkSupport.java
+++ b/aswb/src/com/google/idea/blaze/android/cppapi/NdkSupport.java
@@ -15,8 +15,9 @@
*/
package com.google.idea.blaze.android.cppapi;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.common.experiments.BoolExperiment;
+/** Contains the experiment that turns on NDK support */
public class NdkSupport {
public static final BoolExperiment NDK_SUPPORT = new BoolExperiment("ndk.support", false);
}
diff --git a/aswb/src/com/google/idea/blaze/android/cppimpl/BlazeNdkSupportEnabler.java b/aswb/src/com/google/idea/blaze/android/cppimpl/BlazeNdkSupportEnabler.java
index a162635..1918b2c 100644
--- a/aswb/src/com/google/idea/blaze/android/cppimpl/BlazeNdkSupportEnabler.java
+++ b/aswb/src/com/google/idea/blaze/android/cppimpl/BlazeNdkSupportEnabler.java
@@ -15,6 +15,8 @@
*/
package com.google.idea.blaze.android.cppimpl;
+import static com.jetbrains.cidr.lang.OCLanguage.LANGUAGE_SUPPORT_DISABLED;
+
import com.android.tools.ndk.NdkHelper;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
@@ -27,29 +29,25 @@
import com.jetbrains.cidr.lang.workspace.OCWorkspace;
import org.jetbrains.annotations.NotNull;
-import static com.jetbrains.cidr.lang.OCLanguage.LANGUAGE_SUPPORT_DISABLED;
-
-public final class BlazeNdkSupportEnabler implements SyncListener {
- @Override
- public void onSyncStart(Project project) {
- }
+final class BlazeNdkSupportEnabler extends SyncListener.Adapter {
@Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
boolean enabled = blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C);
enableCSupportInIde(project, enabled);
}
/**
- * If {@code enabled} is true, this method will enable C support in the IDE if it is not already enabled. if {@code enabled} is false this
- * method will clear out any currently stored information in the IDE about C and will disable C support in the IDE, unless support is
- * already disabled.
- *
- * </p>
- * In either case, if the value of enabled matches what the IDE currently does, this method will do nothing.
+ * If {@code enabled} is true, this method will enable C support in the IDE if it is not already
+ * enabled. if {@code enabled} is false this method will clear out any currently stored
+ * information in the IDE about C and will disable C support in the IDE, unless support is already
+ * disabled. In either case, if the value of enabled matches what the IDE currently does, this
+ * method will do nothing.
*
* @param project the project to enable or disable c support in.
* @param enabled if true, turn on C support in the IDE. If false, turn off C support in the IDE.
@@ -64,18 +62,20 @@
}
private static void rebuildSymbols(@NotNull Project project, @NotNull OCWorkspace workspace) {
- ApplicationManager.getApplication().runReadAction(() -> {
- if (project.isDisposed()) {
- return;
- }
- // Notifying BuildSettingsChangeTracker in unitTestMode will leads to a dead lock. See b/23087433 for more information.
- if (!ApplicationManager.getApplication().isUnitTestMode()) {
- workspace.getModificationTrackers().getBuildSettingsChangesTracker().incModificationCount();
- }
- });
- }
-
- @Override
- public void afterSync(Project project, boolean successful) {
+ ApplicationManager.getApplication()
+ .runReadAction(
+ () -> {
+ if (project.isDisposed()) {
+ return;
+ }
+ // Notifying BuildSettingsChangeTracker in unitTestMode will leads to a dead lock.
+ // See b/23087433 for more information.
+ if (!ApplicationManager.getApplication().isUnitTestMode()) {
+ workspace
+ .getModificationTrackers()
+ .getBuildSettingsChangesTracker()
+ .incModificationCount();
+ }
+ });
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAndroidNativeDebuggerLanguageSupportFactory.java b/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAndroidNativeDebuggerLanguageSupportFactory.java
index 9ca88db..2f08b63 100644
--- a/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAndroidNativeDebuggerLanguageSupportFactory.java
+++ b/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAndroidNativeDebuggerLanguageSupportFactory.java
@@ -15,7 +15,7 @@
*/
package com.google.idea.blaze.android.cppimpl.debug;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfiguration;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandler;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
@@ -35,21 +35,19 @@
import com.jetbrains.cidr.lang.OCFileType;
import com.jetbrains.cidr.lang.OCLanguage;
import com.jetbrains.cidr.lang.util.OCElementFactory;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import javax.annotation.Nullable;
-
-public class BlazeAndroidNativeDebuggerLanguageSupportFactory extends OCDebuggerLanguageSupportFactory {
+class BlazeAndroidNativeDebuggerLanguageSupportFactory extends OCDebuggerLanguageSupportFactory {
@Override
public XDebuggerEditorsProvider createEditor(RunProfile profile) {
if (profile == null) {
return new DebuggerEditorsProvider();
}
- if (profile instanceof BlazeAndroidRunConfiguration) {
- BlazeAndroidRunConfiguration runConfig = (BlazeAndroidRunConfiguration)profile;
- if (runConfig.getCommonState().isNativeDebuggingEnabled()) {
- return new DebuggerEditorsProvider();
- }
+ BlazeAndroidRunConfigurationHandler handler =
+ BlazeAndroidRunConfigurationHandler.getHandlerFrom(profile);
+ if (handler != null && handler.getCommonState().isNativeDebuggingEnabled()) {
+ return new DebuggerEditorsProvider();
}
return null;
}
@@ -63,25 +61,28 @@
@NotNull
@Override
- public Document createDocument(final Project project,
- final String text,
- @Nullable XSourcePosition sourcePosition,
- final EvaluationMode mode) {
+ public Document createDocument(
+ final Project project,
+ final String text,
+ @Nullable XSourcePosition sourcePosition,
+ final EvaluationMode mode) {
final PsiElement context = OCDebuggerTypesHelper.getContextElement(sourcePosition, project);
- if (context != null && context.getLanguage() == OCLanguage.getInstance()) {
+ if (context != null && context.getLanguage() == OCLanguage.getInstance()) {
return new WriteAction<Document>() {
@Override
protected void run(Result<Document> result) throws Throwable {
- PsiFile fragment = mode == EvaluationMode.EXPRESSION
- ? OCElementFactory.expressionCodeFragment(text, project, context, true, false)
- : OCElementFactory.expressionOrStatementsCodeFragment(text, project, context, true, false);
+ PsiFile fragment =
+ mode == EvaluationMode.EXPRESSION
+ ? OCElementFactory.expressionCodeFragment(text, project, context, true, false)
+ : OCElementFactory.expressionOrStatementsCodeFragment(
+ text, project, context, true, false);
//noinspection ConstantConditions
result.setResult(PsiDocumentManager.getInstance(project).getDocument(fragment));
}
}.execute().getResultObject();
- }
- else {
- final LightVirtualFile plainTextFile = new LightVirtualFile("oc-debug-editor-when-no-source-position-available.txt", text);
+ } else {
+ final LightVirtualFile plainTextFile =
+ new LightVirtualFile("oc-debug-editor-when-no-source-position-available.txt", text);
//noinspection ConstantConditions
return FileDocumentManager.getInstance().getDocument(plainTextFile);
}
diff --git a/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAutoAndroidDebugger.java b/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAutoAndroidDebugger.java
index 2434eb9..821ddd1 100644
--- a/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAutoAndroidDebugger.java
+++ b/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeAutoAndroidDebugger.java
@@ -22,13 +22,15 @@
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
-public class BlazeAutoAndroidDebugger extends AutoAndroidDebugger {
+class BlazeAutoAndroidDebugger extends AutoAndroidDebugger {
public static String ID = "BlazeAuto";
@Override
protected boolean isNativeProject(@NotNull Project project) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- return blazeProjectData != null && blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C);
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ return blazeProjectData != null
+ && blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C);
}
@NotNull
diff --git a/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeNativeAndroidDebuggerIdProviderImpl.java b/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeNativeAndroidDebuggerIdProviderImpl.java
index c87b3ac..f9a9dc0 100644
--- a/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeNativeAndroidDebuggerIdProviderImpl.java
+++ b/aswb/src/com/google/idea/blaze/android/cppimpl/debug/BlazeNativeAndroidDebuggerIdProviderImpl.java
@@ -17,7 +17,7 @@
import com.google.idea.blaze.android.cppapi.BlazeNativeDebuggerIdProvider;
-public class BlazeNativeAndroidDebuggerIdProviderImpl extends BlazeNativeDebuggerIdProvider {
+class BlazeNativeAndroidDebuggerIdProviderImpl extends BlazeNativeDebuggerIdProvider {
@Override
public String getDebuggerId() {
diff --git a/aswb/src/com/google/idea/blaze/android/manifest/ManifestParser.java b/aswb/src/com/google/idea/blaze/android/manifest/ManifestParser.java
index cae3b0f..00cbe6b 100644
--- a/aswb/src/com/google/idea/blaze/android/manifest/ManifestParser.java
+++ b/aswb/src/com/google/idea/blaze/android/manifest/ManifestParser.java
@@ -30,21 +30,17 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.util.ArrayUtil;
-import org.jetbrains.android.dom.manifest.Manifest;
-import org.jetbrains.android.util.AndroidUtils;
-
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
-
import javax.annotation.Nullable;
+import org.jetbrains.android.dom.manifest.Manifest;
+import org.jetbrains.android.util.AndroidUtils;
-/**
- * Parses manifests from the project.
- */
+/** Parses manifests from the project. */
public class ManifestParser {
private static final Logger LOG = Logger.getInstance(ManifestParser.class);
private final Project project;
@@ -69,9 +65,9 @@
}
final VirtualFile virtualFile;
if (ApplicationManager.getApplication().isDispatchThread()) {
- virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
+ virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
} else {
- virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
+ virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
}
if (virtualFile == null) {
LOG.error("Could not find manifest: " + file);
@@ -83,24 +79,29 @@
}
public void refreshManifests(Collection<File> manifestFiles) {
- List<VirtualFile> manifestVirtualFiles = manifestFiles.stream()
- .map(file -> VfsUtil.findFileByIoFile(file, false))
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
+ List<VirtualFile> manifestVirtualFiles =
+ manifestFiles
+ .stream()
+ .map(file -> VfsUtil.findFileByIoFile(file, false))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
- VfsUtil.markDirtyAndRefresh(false, false, false, ArrayUtil.toObjectArray(manifestVirtualFiles, VirtualFile.class));
- ApplicationManager.getApplication().invokeAndWait(
- () -> PsiDocumentManager.getInstance(project).commitAllDocuments(),
- ModalityState.any()
- );
+ VfsUtil.markDirtyAndRefresh(
+ false, false, false, ArrayUtil.toObjectArray(manifestVirtualFiles, VirtualFile.class));
+ ApplicationManager.getApplication()
+ .invokeAndWait(
+ () -> PsiDocumentManager.getInstance(project).commitAllDocuments(),
+ ModalityState.any());
}
- public static class ClearManifestParser extends SyncListener.Adapter {
+ static class ClearManifestParser extends SyncListener.Adapter {
@Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
getInstance(project).manifestFileMap.clear();
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/plugin/AswbPlugin.java b/aswb/src/com/google/idea/blaze/android/plugin/AswbPlugin.java
index a9e5866..ff54441 100644
--- a/aswb/src/com/google/idea/blaze/android/plugin/AswbPlugin.java
+++ b/aswb/src/com/google/idea/blaze/android/plugin/AswbPlugin.java
@@ -15,16 +15,20 @@
*/
package com.google.idea.blaze.android.plugin;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.plugin.BlazePluginId;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-/**
- * ASwB plugin configuration information.
- */
+/** ASwB plugin configuration information. */
public class AswbPlugin implements BlazePluginId {
- private static final String PLUGIN_ID = "com.google.idea.blaze.aswb"; // Please keep up-to-date with plugin.xml
@Override
public String getPluginId() {
- return PLUGIN_ID;
+ // Please keep these up-to-date with plugin xmls
+ BuildSystem type = BuildSystemProvider.defaultBuildSystem().buildSystem();
+ if (type == BuildSystem.Blaze) {
+ return "com.google.idea.blaze.aswb";
+ }
+ return "com.google.idea.bazel.aswb";
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/plugin/PluginCompatibilityEnforcer.java b/aswb/src/com/google/idea/blaze/android/plugin/PluginCompatibilityEnforcer.java
index a4a62d7..bb2ff51 100644
--- a/aswb/src/com/google/idea/blaze/android/plugin/PluginCompatibilityEnforcer.java
+++ b/aswb/src/com/google/idea/blaze/android/plugin/PluginCompatibilityEnforcer.java
@@ -25,21 +25,20 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.BuildNumber;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
/**
- * Checks META-INF/product-build.txt for a product build number and compares
- * them against the build. If incompatible, it informs the user.
+ * Checks META-INF/product-build.txt for a product build number and compares them against the build.
+ * If incompatible, it informs the user.
*/
public class PluginCompatibilityEnforcer implements ApplicationComponent {
private static final Logger LOG = Logger.getInstance(PluginCompatibilityEnforcer.class);
private static final NotificationGroup NOTIFICATION_GROUP =
- new NotificationGroup("ASwB Plugin Version", NotificationDisplayType.BALLOON, true);
+ new NotificationGroup("ASwB Plugin Version", NotificationDisplayType.BALLOON, true);
public void checkPluginCompatibility() {
String pluginProductBuildString = readProductBuildTxt();
@@ -57,12 +56,13 @@
}
if (!isCompatible(pluginProductBuild)) {
- String message = Joiner.on(' ').join(
- "Invalid Android Studio version for the ASwB plugin.",
- "Android Studio version: " + ApplicationInfo.getInstance().getBuild(),
- "Compatible version: " + pluginProductBuild,
- "Please update the ASwB plugin from the plugin manager."
- );
+ String message =
+ Joiner.on(' ')
+ .join(
+ "Invalid Android Studio version for the ASwB plugin.",
+ "Android Studio version: " + ApplicationInfo.getInstance().getBuild(),
+ "Compatible version: " + pluginProductBuild,
+ "Please update the ASwB plugin from the plugin manager.");
NOTIFICATION_GROUP.createNotification(message, MessageType.ERROR).notify(null);
LOG.warn(message);
}
@@ -81,7 +81,8 @@
@Nullable
private String readProductBuildTxt() {
- try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("META-INF/product-build.txt")) {
+ try (InputStream inputStream =
+ getClass().getClassLoader().getResourceAsStream("META-INF/product-build.txt")) {
if (inputStream == null) {
return null;
}
@@ -98,9 +99,7 @@
}
@Override
- public void disposeComponent() {
-
- }
+ public void disposeComponent() {}
@NotNull
@Override
diff --git a/aswb/src/com/google/idea/blaze/android/projectview/AndroidSdkPlatformSection.java b/aswb/src/com/google/idea/blaze/android/projectview/AndroidSdkPlatformSection.java
index 1cec804..b2c7177 100644
--- a/aswb/src/com/google/idea/blaze/android/projectview/AndroidSdkPlatformSection.java
+++ b/aswb/src/com/google/idea/blaze/android/projectview/AndroidSdkPlatformSection.java
@@ -15,20 +15,19 @@
*/
package com.google.idea.blaze.android.projectview;
-import com.google.common.base.CharMatcher;
import com.google.idea.blaze.base.projectview.parser.ParseContext;
import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
import com.google.idea.blaze.base.projectview.section.ScalarSection;
import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
import com.google.idea.blaze.base.projectview.section.SectionKey;
import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.Nullable;
-/**
- * Allows manual override of the android sdk.
- */
+/** Allows manual override of the android sdk. */
public class AndroidSdkPlatformSection {
- public static final SectionKey<String, ScalarSection<String>> KEY = SectionKey.of("android_sdk_platform");
+ public static final SectionKey<String, ScalarSection<String>> KEY =
+ SectionKey.of("android_sdk_platform");
public static final SectionParser PARSER = new AndroidSdkPlatformParser();
private static class AndroidSdkPlatformParser extends ScalarSectionParser<String> {
@@ -38,11 +37,8 @@
@Nullable
@Override
- protected String parseItem(
- ProjectViewParser parser,
- ParseContext parseContext,
- String rest) {
- return CharMatcher.is('\"').trimFrom(rest.trim());
+ protected String parseItem(ProjectViewParser parser, ParseContext parseContext, String rest) {
+ return StringUtil.unquoteString(rest);
}
@Override
diff --git a/aswb/src/com/google/idea/blaze/android/resources/AndroidPackageRClass.java b/aswb/src/com/google/idea/blaze/android/resources/AndroidPackageRClass.java
index f875247..b1802aa 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/AndroidPackageRClass.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/AndroidPackageRClass.java
@@ -16,7 +16,7 @@
package com.google.idea.blaze.android.resources;
import com.android.resources.ResourceType;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
@@ -30,6 +30,9 @@
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
import org.jetbrains.android.augment.AndroidLightClassBase;
import org.jetbrains.android.augment.ResourceTypeClass;
import org.jetbrains.android.dom.converters.ResourceReferenceConverter;
@@ -38,35 +41,27 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Represents a dynamic "class R" for resources in an Android module.
- */
+/** Represents a dynamic "class R" for resources in an Android module. */
public class AndroidPackageRClass extends AndroidLightClassBase {
private static final Logger LOG = Logger.getInstance(AndroidPackageRClass.class);
- private static final BoolExperiment USE_OUT_OF_CODE_MOD_COUNT = new BoolExperiment("use.out.of.code.modcount.for.r.class.cache", true);
+ private static final BoolExperiment USE_OUT_OF_CODE_MOD_COUNT =
+ new BoolExperiment("use.out.of.code.modcount.for.r.class.cache", true);
- @NotNull
- private final PsiFile myFile;
- @NotNull
- private final String myFullyQualifiedName;
- @NotNull
- private final Module myModule;
+ @NotNull private final PsiFile myFile;
+ @NotNull private final String myFullyQualifiedName;
+ @NotNull private final Module myModule;
private CachedValue<PsiClass[]> myClassCache;
- public AndroidPackageRClass(@NotNull PsiManager psiManager,
- @NotNull String packageName,
- @NotNull Module module) {
+ public AndroidPackageRClass(
+ @NotNull PsiManager psiManager, @NotNull String packageName, @NotNull Module module) {
super(psiManager);
myModule = module;
myFullyQualifiedName = packageName + AndroidResourceClassFinder.INTERNAL_R_CLASS_SHORTNAME;
- myFile = PsiFileFactory.getInstance(myManager.getProject())
- .createFileFromText("R.java", JavaFileType.INSTANCE, "package " + packageName + ";");
+ myFile =
+ PsiFileFactory.getInstance(myManager.getProject())
+ .createFileFromText("R.java", JavaFileType.INSTANCE, "package " + packageName + ";");
this.putUserData(ModuleUtilCore.KEY_MODULE, module);
// Some scenarios move up to the file level and then attempt to get the module from the file.
@@ -110,16 +105,19 @@
@Override
public PsiClass[] getInnerClasses() {
if (myClassCache == null) {
- myClassCache = CachedValuesManager.getManager(getProject())
- .createCachedValue(new CachedValueProvider<PsiClass[]>() {
- @Override
- public Result<PsiClass[]> compute() {
- return Result.create(doGetInnerClasses(),
- USE_OUT_OF_CODE_MOD_COUNT.getValue() ?
- PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT :
- PsiModificationTracker.MODIFICATION_COUNT);
- }
- });
+ myClassCache =
+ CachedValuesManager.getManager(getProject())
+ .createCachedValue(
+ new CachedValueProvider<PsiClass[]>() {
+ @Override
+ public Result<PsiClass[]> compute() {
+ return Result.create(
+ doGetInnerClasses(),
+ USE_OUT_OF_CODE_MOD_COUNT.getValue()
+ ? PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
+ : PsiModificationTracker.MODIFICATION_COUNT);
+ }
+ });
}
return myClassCache.getValue();
}
@@ -136,7 +134,8 @@
return new PsiClass[0];
}
- final Set<ResourceType> types = ResourceReferenceConverter.getResourceTypesInCurrentModule(facet);
+ final Set<ResourceType> types =
+ ResourceReferenceConverter.getResourceTypesInCurrentModule(facet);
final List<PsiClass> result = new ArrayList<PsiClass>();
for (ResourceType type : types) {
diff --git a/aswb/src/com/google/idea/blaze/android/resources/AndroidResourceClassFinder.java b/aswb/src/com/google/idea/blaze/android/resources/AndroidResourceClassFinder.java
index 3cc85e1..9de9176 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/AndroidResourceClassFinder.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/AndroidResourceClassFinder.java
@@ -21,14 +21,11 @@
import com.intellij.psi.PsiElementFinder;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
+import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-
-/**
- * Provides dynamic Android Resource classes (class R {...} ).
- */
+/** Provides dynamic Android Resource classes (class R {...} ). */
public class AndroidResourceClassFinder extends PsiElementFinder {
static final String INTERNAL_R_CLASS_SHORTNAME = ".R";
private final Project project;
diff --git a/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackage.java b/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackage.java
index 3cd62a1..b016394 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackage.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackage.java
@@ -18,9 +18,7 @@
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.file.PsiPackageImpl;
-/**
- * A generated stub PsiPackage for generated R classes.
- */
+/** A generated stub PsiPackage for generated R classes. */
public class AndroidResourcePackage extends PsiPackageImpl {
public AndroidResourcePackage(PsiManager manager, String qualifiedName) {
super(manager, qualifiedName);
diff --git a/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackageFinder.java b/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackageFinder.java
index 6c37015..ee7dec2 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackageFinder.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/AndroidResourcePackageFinder.java
@@ -23,9 +23,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-/**
- * Provides dynamic Android resource packages.
- */
+/** Provides dynamic Android resource packages. */
public class AndroidResourcePackageFinder extends PsiElementFinder {
private final Project project;
diff --git a/aswb/src/com/google/idea/blaze/android/resources/LightResourceClassService.java b/aswb/src/com/google/idea/blaze/android/resources/LightResourceClassService.java
index e8d1cdc..183221f 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/LightResourceClassService.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/LightResourceClassService.java
@@ -17,7 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -25,34 +25,31 @@
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
+import java.util.List;
+import java.util.Map;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A service for storing and finding light R classes.
- */
+/** A service for storing and finding light R classes. */
public class LightResourceClassService {
- @NotNull
- private Map<String, AndroidPackageRClass> rClasses = Maps.newHashMap();
- @NotNull
- private Map<String, PsiPackage> rClassPackages = Maps.newHashMap();
+ @NotNull private Map<String, AndroidPackageRClass> rClasses = Maps.newHashMap();
+ @NotNull private Map<String, PsiPackage> rClassPackages = Maps.newHashMap();
- // It should be harmless to create stub resource PsiPackages which shadow any "real" PsiPackages. Based on the ordering
- // of PsiElementFinder it would prefer the real package (PsiElementFinderImpl has 'order="first"').
+ // It should be harmless to create stub resource PsiPackages which shadow any "real" PsiPackages.
+ // Based on the ordering of PsiElementFinder it would prefer the real package
+ // (PsiElementFinderImpl has 'order="first"').
// Put under experiment just in case we find a problem w/ other element finders.
- private static final BoolExperiment CREATE_STUB_RESOURCE_PACKAGES = new BoolExperiment("create.stub.resource.packages", true);
+ private static final BoolExperiment CREATE_STUB_RESOURCE_PACKAGES =
+ new BoolExperiment("create.stub.resource.packages", true);
- public LightResourceClassService() {
- }
+ public LightResourceClassService() {}
public static LightResourceClassService getInstance(@NotNull Project project) {
return ServiceManager.getService(project, LightResourceClassService.class);
}
+ /** Builds light R classes */
public static class Builder {
Map<String, AndroidPackageRClass> rClassMap = Maps.newHashMap();
Map<String, PsiPackage> rClassPackages = Maps.newHashMap();
@@ -64,11 +61,8 @@
}
public void addRClass(String resourceJavaPackage, Module module) {
- AndroidPackageRClass rClass = new AndroidPackageRClass(
- psiManager,
- resourceJavaPackage,
- module
- );
+ AndroidPackageRClass rClass =
+ new AndroidPackageRClass(psiManager, resourceJavaPackage, module);
rClassMap.put(getQualifiedRClassName(resourceJavaPackage), rClass);
if (CREATE_STUB_RESOURCE_PACKAGES.getValue()) {
addStubPackages(resourceJavaPackage);
@@ -85,7 +79,8 @@
if (rClassPackages.containsKey(resourceJavaPackage)) {
return;
}
- rClassPackages.put(resourceJavaPackage, new AndroidResourcePackage(psiManager, resourceJavaPackage));
+ rClassPackages.put(
+ resourceJavaPackage, new AndroidResourcePackage(psiManager, resourceJavaPackage));
int nextIndex = resourceJavaPackage.lastIndexOf('.');
if (nextIndex < 0) {
return;
@@ -102,7 +97,7 @@
@NotNull
public List<PsiClass> getLightRClasses(
- @NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
+ @NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
AndroidPackageRClass rClass = this.rClasses.get(qualifiedName);
if (rClass != null) {
if (scope.isSearchInModuleContent(rClass.getModule())) {
diff --git a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceDirectoryDialog.java b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceDirectoryDialog.java
index 64d46f4..aa1857b 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceDirectoryDialog.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceDirectoryDialog.java
@@ -20,6 +20,7 @@
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
@@ -33,6 +34,15 @@
import com.intellij.ui.components.JBLabel;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Insets;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
import org.jetbrains.android.actions.CreateResourceDirectoryDialogBase;
import org.jetbrains.android.actions.ElementCreatingValidator;
import org.jetbrains.android.uipreview.DeviceConfiguratorPanel;
@@ -40,12 +50,9 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
-import java.awt.*;
-
/**
- * Dialog to decide where to create a res/ subdirectory (e.g., layout/, values-foo/, etc.)
- * and how to name the subdirectory based on resource type and chosen configuration.
+ * Dialog to decide where to create a res/ subdirectory (e.g., layout/, values-foo/, etc.) and how
+ * to name the subdirectory based on resource type and chosen configuration.
*/
public class BlazeCreateResourceDirectoryDialog extends CreateResourceDirectoryDialogBase {
@@ -63,36 +70,40 @@
private PsiDirectory myResDirectory;
private DataContext myDataContext;
- public BlazeCreateResourceDirectoryDialog(Project project,
- @Nullable Module module,
- @Nullable ResourceFolderType resType,
- @Nullable PsiDirectory resDirectory,
- @Nullable DataContext dataContext,
- ValidatorFactory validatorFactory) {
+ public BlazeCreateResourceDirectoryDialog(
+ Project project,
+ @Nullable Module module,
+ @Nullable ResourceFolderType resType,
+ @Nullable PsiDirectory resDirectory,
+ @Nullable DataContext dataContext,
+ ValidatorFactory validatorFactory) {
super(project);
setupUi();
myResDirectory = resDirectory;
myDataContext = dataContext;
myValidatorFactory = validatorFactory;
myResourceTypeComboBox.setModel(new EnumComboBoxModel<>(ResourceFolderType.class));
- myResourceTypeComboBox.setRenderer(new ListCellRendererWrapper() {
- @Override
- public void customize(JList list, Object value, int index, boolean selected, boolean hasFocus) {
- if (value instanceof ResourceFolderType) {
- setText(((ResourceFolderType)value).getName());
- }
- }
- });
+ myResourceTypeComboBox.setRenderer(
+ new ListCellRendererWrapper() {
+ @Override
+ public void customize(
+ JList list, Object value, int index, boolean selected, boolean hasFocus) {
+ if (value instanceof ResourceFolderType) {
+ setText(((ResourceFolderType) value).getName());
+ }
+ }
+ });
- myDeviceConfiguratorPanel = setupDeviceConfigurationPanel(myResourceTypeComboBox, myDirectoryNameTextField, myErrorLabel);
+ myDeviceConfiguratorPanel =
+ setupDeviceConfigurationPanel(
+ myResourceTypeComboBox, myDirectoryNameTextField, myErrorLabel);
myDeviceConfiguratorWrapper.add(myDeviceConfiguratorPanel, BorderLayout.CENTER);
myResourceTypeComboBox.addActionListener(e -> myDeviceConfiguratorPanel.applyEditors());
if (resType != null) {
myResourceTypeComboBox.setSelectedItem(resType);
myResourceTypeComboBox.setEnabled(false);
- }
- else {
+ } else {
// Select values by default if not otherwise specified
myResourceTypeComboBox.setSelectedItem(ResourceFolderType.VALUES);
}
@@ -100,6 +111,8 @@
// If myResDirectory is known before this, just use that.
myResDirLabel.setVisible(false);
myResDirCombo.setVisible(false);
+ myResDirCombo.addBrowseFolderListener(
+ project, FileChooserDescriptorFactory.createSingleFolderDescriptor());
if (myResDirectory == null) {
assert dataContext != null;
assert module != null;
@@ -107,14 +120,17 @@
VirtualFile contextFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
if (contextFile != null) {
PsiManager manager = PsiManager.getInstance(project);
- VirtualFile virtualDirectory = BlazeCreateResourceUtils.getResDirFromDataContext(contextFile);
- PsiDirectory directory = virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null;
+ VirtualFile virtualDirectory =
+ BlazeCreateResourceUtils.getResDirFromDataContext(contextFile);
+ PsiDirectory directory =
+ virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null;
if (directory != null) {
myResDirectory = directory;
- }
- else {
- // As a last resort, if we have poor context, e.g., from File > New w/ a .java file open, set up the UI.
- BlazeCreateResourceUtils.setupResDirectoryChoices(module.getProject(), contextFile, myResDirLabel, myResDirCombo);
+ } else {
+ // As a last resort, if we have poor context
+ // e.g., from File > New w/ a .java file open, set up the UI.
+ BlazeCreateResourceUtils.setupResDirectoryChoices(
+ module.getProject(), contextFile, myResDirLabel, myResDirCombo);
}
}
}
@@ -131,8 +147,8 @@
PsiDirectory resourceDirectory = getResourceDirectory();
if (resourceDirectory == null) {
Module module = LangDataKeys.MODULE.getData(myDataContext);
- Messages.showErrorDialog(AndroidBundle.message("check.resource.dir.error", module),
- CommonBundle.getErrorTitle());
+ Messages.showErrorDialog(
+ AndroidBundle.message("check.resource.dir.error", module), CommonBundle.getErrorTitle());
// Not much the user can do, just close the dialog.
super.doOKAction();
return;
@@ -152,8 +168,7 @@
public JComponent getPreferredFocusedComponent() {
if (myResourceTypeComboBox.isEnabled()) {
return myResourceTypeComboBox;
- }
- else {
+ } else {
return myDirectoryNameTextField;
}
}
@@ -183,62 +198,160 @@
return myContentPanel;
}
- /**
- * Initially generated by IntelliJ from a .form file.
- */
+ /** Initially generated by IntelliJ from a .form file. */
private void setupUi() {
myContentPanel = new JPanel();
myContentPanel.setLayout(new GridLayoutManager(5, 2, new Insets(0, 0, 0, 0), -1, -1));
myContentPanel.setPreferredSize(new Dimension(800, 400));
myResourceTypeComboBox = new JComboBox();
- myContentPanel.add(myResourceTypeComboBox, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED,
- null, null, null, 0, false));
+ myContentPanel.add(
+ myResourceTypeComboBox,
+ new GridConstraints(
+ 1,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
final JBLabel jBLabel1 = new JBLabel();
jBLabel1.setText("Resource type:");
jBLabel1.setDisplayedMnemonic('R');
jBLabel1.setDisplayedMnemonicIndex(0);
- myContentPanel.add(jBLabel1, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null,
- 0, false));
+ myContentPanel.add(
+ jBLabel1,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myDeviceConfiguratorWrapper = new JPanel();
myDeviceConfiguratorWrapper.setLayout(new BorderLayout(0, 0));
- myContentPanel.add(myDeviceConfiguratorWrapper,
- new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0,
- false));
+ myContentPanel.add(
+ myDeviceConfiguratorWrapper,
+ new GridConstraints(
+ 3,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ null,
+ null,
+ null,
+ 0,
+ false));
final JLabel label1 = new JLabel();
label1.setText("Directory name:");
label1.setDisplayedMnemonic('D');
label1.setDisplayedMnemonicIndex(0);
- myContentPanel.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
- false));
+ myContentPanel.add(
+ label1,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myDirectoryNameTextField = new JTextField();
myDirectoryNameTextField.setEnabled(true);
- myContentPanel.add(myDirectoryNameTextField,
- new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
- new Dimension(150, -1), null, 0, false));
+ myContentPanel.add(
+ myDirectoryNameTextField,
+ new GridConstraints(
+ 0,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ new Dimension(150, -1),
+ null,
+ 0,
+ false));
myErrorLabel = new JBLabel();
- myContentPanel.add(myErrorLabel, new GridConstraints(4, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null,
- null, 0, false));
+ myContentPanel.add(
+ myErrorLabel,
+ new GridConstraints(
+ 4,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResDirLabel = new JBLabel();
myResDirLabel.setText("Base directory:");
myResDirLabel.setDisplayedMnemonic('B');
myResDirLabel.setDisplayedMnemonicIndex(0);
- myContentPanel.add(myResDirLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null,
- null, 0, false));
+ myContentPanel.add(
+ myResDirLabel,
+ new GridConstraints(
+ 2,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResDirCombo = new ComboboxWithBrowseButton();
- myContentPanel.add(myResDirCombo, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null,
- null, 0, false));
+ myContentPanel.add(
+ myResDirCombo,
+ new GridConstraints(
+ 2,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
jBLabel1.setLabelFor(myResourceTypeComboBox);
label1.setLabelFor(myDirectoryNameTextField);
myResDirLabel.setLabelFor(myResourceTypeComboBox);
}
-
}
diff --git a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceFileDialog.java b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceFileDialog.java
index a0bee66..6c132b0 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceFileDialog.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceFileDialog.java
@@ -15,16 +15,16 @@
*/
package com.google.idea.blaze.android.resources.actions;
-import com.google.common.annotations.VisibleForTesting;
-
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.resources.ResourceConstants;
import com.android.resources.ResourceFolderType;
import com.android.tools.idea.res.ResourceNameValidator;
+import com.google.common.annotations.VisibleForTesting;
import com.intellij.CommonBundle;
import com.intellij.ide.actions.TemplateKindCombo;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
@@ -39,6 +39,17 @@
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.util.PlatformIcons;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
import org.jetbrains.android.actions.CreateResourceFileDialogBase;
import org.jetbrains.android.actions.CreateTypedResourceFileAction;
import org.jetbrains.android.actions.ElementCreatingValidator;
@@ -46,16 +57,9 @@
import org.jetbrains.android.uipreview.DeviceConfiguratorPanel;
import org.jetbrains.android.util.AndroidBundle;
-import javax.annotation.Nullable;
-import javax.swing.*;
-import javax.swing.event.DocumentEvent;
-import java.awt.*;
-import java.util.Collection;
-import java.util.List;
-
/**
- * Dialog to decide where and how to create a resource file of a given type
- * (which base res/ directory, which subdirectory, and how to name the new file).
+ * Dialog to decide where and how to create a resource file of a given type (which base res/
+ * directory, which subdirectory, and how to name the new file).
*/
public class BlazeCreateResourceFileDialog extends CreateResourceFileDialogBase {
private JTextField myFileNameField;
@@ -79,17 +83,18 @@
private final AndroidFacet myFacet;
private PsiDirectory myResDirectory;
- public BlazeCreateResourceFileDialog(AndroidFacet facet,
- Collection<CreateTypedResourceFileAction> actions,
- ResourceFolderType folderType,
- String filename,
- String rootElement,
- FolderConfiguration folderConfiguration,
- boolean chooseFileName,
- boolean chooseModule,
- PsiDirectory resDirectory,
- DataContext dataContext,
- ValidatorFactory validatorFactory) {
+ public BlazeCreateResourceFileDialog(
+ AndroidFacet facet,
+ Collection<CreateTypedResourceFileAction> actions,
+ ResourceFolderType folderType,
+ String filename,
+ String rootElement,
+ FolderConfiguration folderConfiguration,
+ boolean chooseFileName,
+ boolean chooseModule,
+ PsiDirectory resDirectory,
+ DataContext dataContext,
+ ValidatorFactory validatorFactory) {
super(facet.getModule().getProject());
setupUi();
myFacet = facet;
@@ -101,15 +106,19 @@
myUpDownHint.setIcon(PlatformIcons.UP_DOWN_ARROWS);
String selectedTemplate = setupSubActions(actions, myResourceTypeCombo, folderType);
- myDeviceConfiguratorPanel = setupDeviceConfigurationPanel(myDirectoryNameTextField, myResourceTypeCombo, myErrorLabel);
+ myDeviceConfiguratorPanel =
+ setupDeviceConfigurationPanel(myDirectoryNameTextField, myResourceTypeCombo, myErrorLabel);
if (folderConfiguration != null) {
myDeviceConfiguratorPanel.init(folderConfiguration);
}
- myResourceTypeCombo.getComboBox().addActionListener(e -> {
- myDeviceConfiguratorPanel.applyEditors();
- updateRootElementTextField();
- });
+ myResourceTypeCombo
+ .getComboBox()
+ .addActionListener(
+ e -> {
+ myDeviceConfiguratorPanel.applyEditors();
+ updateRootElementTextField();
+ });
if (folderType != null && selectedTemplate != null) {
final boolean v = folderType == ResourceFolderType.LAYOUT;
@@ -139,29 +148,34 @@
myFileNameField.setText(filename);
}
+ Project project = myFacet.getModule().getProject();
// Set up UI to choose the base directory if needed (use context to prune selection).
// There may be a resource directory already pre-selected, in which case hide the UI by default.
- myResDirCombo.setVisible(false);
myResDirLabel.setVisible(false);
- Project project = myFacet.getModule().getProject();
+ myResDirCombo.setVisible(false);
+ myResDirCombo.addBrowseFolderListener(
+ project, FileChooserDescriptorFactory.createSingleFolderDescriptor());
if (myResDirectory == null) {
// Try to figure out from context (e.g., right click in project view).
VirtualFile contextFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
if (contextFile != null) {
PsiManager manager = PsiManager.getInstance(project);
- VirtualFile virtualDirectory = BlazeCreateResourceUtils.getResDirFromDataContext(contextFile);
- PsiDirectory directory = virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null;
+ VirtualFile virtualDirectory =
+ BlazeCreateResourceUtils.getResDirFromDataContext(contextFile);
+ PsiDirectory directory =
+ virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null;
if (directory != null) {
myResDirectory = directory;
+ } else {
+ // As a last resort, if we have poor context,
+ // e.g., from File > New w/ a .java file open, set up the UI.
+ BlazeCreateResourceUtils.setupResDirectoryChoices(
+ project, contextFile, myResDirLabel, myResDirCombo);
}
- else {
- // As a last resort, if we have poor context, e.g., from File > New w/ a .java file open, set up the UI.
- BlazeCreateResourceUtils.setupResDirectoryChoices(project, contextFile, myResDirLabel, myResDirCombo);
- }
- }
- else {
+ } else {
// As a last resort, if we have no context, set up the UI.
- BlazeCreateResourceUtils.setupResDirectoryChoices(project, null, myResDirLabel, myResDirCombo);
+ BlazeCreateResourceUtils.setupResDirectoryChoices(
+ project, null, myResDirLabel, myResDirCombo);
}
}
@@ -179,12 +193,15 @@
setTitle(AndroidBundle.message("new.resource.dialog.title"));
- myFileNameField.getDocument().addDocumentListener(new DocumentAdapter() {
- @Override
- public void textChanged(DocumentEvent event) {
- validateName();
- }
- });
+ myFileNameField
+ .getDocument()
+ .addDocumentListener(
+ new DocumentAdapter() {
+ @Override
+ public void textChanged(DocumentEvent event) {
+ validateName();
+ }
+ });
myResourceTypeCombo.getComboBox().addActionListener(actionEvent -> validateName());
if (validateImmediately) {
validateName();
@@ -222,12 +239,14 @@
if (action != null) {
final List<String> allowedTagNames = action.getSortedAllowedTagNames(myFacet);
- myRootElementField = new TextFieldWithAutoCompletion<>(
- myFacet.getModule().getProject(), new StringsCompletionProvider(allowedTagNames, null), true, null);
+ myRootElementField =
+ new TextFieldWithAutoCompletion<>(
+ myFacet.getModule().getProject(),
+ new StringsCompletionProvider(allowedTagNames, null),
+ true,
+ null);
myRootElementField.setEnabled(allowedTagNames.size() > 1);
- myRootElementField.setText(!action.isChooseTagName()
- ? action.getDefaultRootTag()
- : "");
+ myRootElementField.setText(!action.isChooseTagName() ? action.getDefaultRootTag() : "");
myRootElementFieldWrapper.removeAll();
myRootElementFieldWrapper.add(myRootElementField, BorderLayout.CENTER);
myRootElementLabel.setLabelFor(myRootElementField);
@@ -247,19 +266,28 @@
assert action != null;
if (fileName.length() == 0) {
- Messages.showErrorDialog(myPanel, AndroidBundle.message("file.name.not.specified.error"), CommonBundle.getErrorTitle());
+ Messages.showErrorDialog(
+ myPanel,
+ AndroidBundle.message("file.name.not.specified.error"),
+ CommonBundle.getErrorTitle());
return;
}
String rootElement = getRootElement();
if (!action.isChooseTagName() && rootElement.length() == 0) {
- Messages.showErrorDialog(myPanel, AndroidBundle.message("root.element.not.specified.error"), CommonBundle.getErrorTitle());
+ Messages.showErrorDialog(
+ myPanel,
+ AndroidBundle.message("root.element.not.specified.error"),
+ CommonBundle.getErrorTitle());
return;
}
final String subdirName = getSubdirName();
if (subdirName.length() == 0) {
- Messages.showErrorDialog(myPanel, AndroidBundle.message("directory.not.specified.error"), CommonBundle.getErrorTitle());
+ Messages.showErrorDialog(
+ myPanel,
+ AndroidBundle.message("directory.not.specified.error"),
+ CommonBundle.getErrorTitle());
return;
}
@@ -270,8 +298,10 @@
}
PsiDirectory resDir = getResourceDirectory();
if (resDir == null) {
- Messages.showErrorDialog(myPanel, AndroidBundle.message("check.resource.dir.error", myFacet.getModule()),
- CommonBundle.getErrorTitle());
+ Messages.showErrorDialog(
+ myPanel,
+ AndroidBundle.message("check.resource.dir.error", myFacet.getModule()),
+ CommonBundle.getErrorTitle());
super.doOKAction();
return;
}
@@ -297,7 +327,8 @@
if (myResDirectory != null) {
return myResDirectory;
}
- return BlazeCreateResourceUtils.getResDirFromUI(myFacet.getModule().getProject(), myResDirCombo);
+ return BlazeCreateResourceUtils.getResDirFromUI(
+ myFacet.getModule().getProject(), myResDirCombo);
}
private String getSubdirName() {
@@ -318,19 +349,15 @@
String name = myFileNameField.getText();
if (name.length() == 0 || getNameError(name) != null) {
return myFileNameField;
- }
- else if (myResourceTypeCombo.isVisible()) {
+ } else if (myResourceTypeCombo.isVisible()) {
return myResourceTypeCombo;
- }
- else if (myRootElementFieldWrapper.isVisible()) {
+ } else if (myRootElementFieldWrapper.isVisible()) {
return myRootElementField;
}
return myDirectoryNameTextField;
}
- /**
- * Initially generated by IntelliJ from a .form file.
- */
+ /** Initially generated by IntelliJ from a .form file. */
private void setupUi() {
myPanel = new JPanel();
myPanel.setLayout(new GridLayoutManager(7, 3, new Insets(0, 0, 0, 0), -1, -1));
@@ -339,78 +366,244 @@
myFileNameLabel.setText("File name:");
myFileNameLabel.setDisplayedMnemonic('F');
myFileNameLabel.setDisplayedMnemonicIndex(0);
- myPanel.add(myFileNameLabel,
- new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myFileNameLabel,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myFileNameField = new JTextField();
- myPanel.add(myFileNameField, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
- new Dimension(150, -1), null, 0, false));
+ myPanel.add(
+ myFileNameField,
+ new GridConstraints(
+ 0,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ new Dimension(150, -1),
+ null,
+ 0,
+ false));
myResTypeLabel = new JLabel();
myResTypeLabel.setText("Resource type:");
myResTypeLabel.setDisplayedMnemonic('R');
myResTypeLabel.setDisplayedMnemonicIndex(0);
- myPanel.add(myResTypeLabel,
- new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myResTypeLabel,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myUpDownHint = new JLabel();
myUpDownHint.setToolTipText("Pressing Up or Down arrows while in editor changes the kind");
- myPanel.add(myUpDownHint,
- new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myUpDownHint,
+ new GridConstraints(
+ 0,
+ 2,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResourceTypeCombo = new TemplateKindCombo();
- myPanel.add(myResourceTypeCombo, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myResourceTypeCombo,
+ new GridConstraints(
+ 1,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myDeviceConfiguratorWrapper = new JPanel();
myDeviceConfiguratorWrapper.setLayout(new BorderLayout(0, 0));
- myPanel.add(myDeviceConfiguratorWrapper, new GridConstraints(5, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_CAN_SHRINK |
- GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_CAN_SHRINK |
- GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+ myPanel.add(
+ myDeviceConfiguratorWrapper,
+ new GridConstraints(
+ 5,
+ 0,
+ 1,
+ 3,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ null,
+ null,
+ null,
+ 0,
+ false));
myErrorLabel = new JBLabel();
- myPanel.add(myErrorLabel,
- new GridConstraints(6, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myErrorLabel,
+ new GridConstraints(
+ 6,
+ 0,
+ 1,
+ 3,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
final JBLabel jBLabel1 = new JBLabel();
jBLabel1.setText("Sub-directory:");
jBLabel1.setDisplayedMnemonic('Y');
jBLabel1.setDisplayedMnemonicIndex(12);
- myPanel.add(jBLabel1,
- new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ jBLabel1,
+ new GridConstraints(
+ 4,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myDirectoryNameTextField = new JTextField();
myDirectoryNameTextField.setEditable(true);
myDirectoryNameTextField.setEnabled(true);
- myPanel.add(myDirectoryNameTextField, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
- new Dimension(150, -1), null, 0, false));
+ myPanel.add(
+ myDirectoryNameTextField,
+ new GridConstraints(
+ 4,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ new Dimension(150, -1),
+ null,
+ 0,
+ false));
myRootElementLabel = new JBLabel();
myRootElementLabel.setText("Root element:");
myRootElementLabel.setDisplayedMnemonic('E');
myRootElementLabel.setDisplayedMnemonicIndex(5);
- myPanel.add(myRootElementLabel,
- new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myRootElementLabel,
+ new GridConstraints(
+ 2,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myRootElementFieldWrapper = new JPanel();
myRootElementFieldWrapper.setLayout(new BorderLayout(0, 0));
- myPanel.add(myRootElementFieldWrapper, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myRootElementFieldWrapper,
+ new GridConstraints(
+ 2,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResDirLabel = new JBLabel();
myResDirLabel.setText("Base directory:");
myResDirLabel.setDisplayedMnemonic('B');
myResDirLabel.setDisplayedMnemonicIndex(0);
- myPanel.add(myResDirLabel,
- new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myResDirLabel,
+ new GridConstraints(
+ 3,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResDirCombo = new ComboboxWithBrowseButton();
- myPanel.add(myResDirCombo, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null,
- 0, false));
+ myPanel.add(
+ myResDirCombo,
+ new GridConstraints(
+ 3,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myFileNameLabel.setLabelFor(myFileNameField);
jBLabel1.setLabelFor(myDirectoryNameTextField);
}
-
}
diff --git a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtils.java b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtils.java
index 03ce15c..2b98ee9 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtils.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtils.java
@@ -25,36 +25,37 @@
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.ide.util.DirectoryUtil;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import com.intellij.ui.ComboboxWithBrowseButton;
import com.intellij.ui.components.JBLabel;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
import java.io.File;
import java.util.Set;
+import javax.swing.JComboBox;
+import org.jetbrains.annotations.Nullable;
-/**
- * Utilities for setting up create resource actions and dialogs.
- */
+/** Utilities for setting up create resource actions and dialogs. */
class BlazeCreateResourceUtils {
- private static final String PLACEHOLDER_TEXT = "choose a res/ directory with dropdown or browse button";
+ private static final String PLACEHOLDER_TEXT =
+ "choose a res/ directory with dropdown or browse button";
- static void setupResDirectoryChoices(@NotNull Project project, @Nullable VirtualFile contextFile,
- @NotNull JBLabel resDirLabel,
- @NotNull ComboboxWithBrowseButton resDirComboAndBrowser) {
- resDirComboAndBrowser.addBrowseFolderListener(
- project, FileChooserDescriptorFactory.createSingleFolderDescriptor());
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ static void setupResDirectoryChoices(
+ Project project,
+ @Nullable VirtualFile contextFile,
+ JBLabel resDirLabel,
+ ComboboxWithBrowseButton resDirComboAndBrowser) {
+ // Reset the item list before filling it back up.
+ resDirComboAndBrowser.getComboBox().removeAllItems();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
if (blazeProjectData != null) {
BlazeAndroidSyncData syncData = blazeProjectData.syncState.get(BlazeAndroidSyncData.class);
if (syncData != null) {
@@ -62,23 +63,30 @@
File fileFromContext = null;
if (contextFile != null) {
fileFromContext = VfsUtilCore.virtualToIoFile(contextFile);
- labelsRelatedToContext = SourceToRuleMap.getInstance(project).getTargetsForSourceFile(fileFromContext);
+ labelsRelatedToContext =
+ SourceToRuleMap.getInstance(project).getTargetsForSourceFile(fileFromContext);
if (labelsRelatedToContext.isEmpty()) {
labelsRelatedToContext = null;
}
}
// Sort:
- // - the "closest" thing to the contextFile at the top
- // - the rest of the direct dirs, then transitive dirs of the context rules, then any known res dir in the project
+ // - contextFile/res if contextFile is a directory,
+ // to optimize the right click on directory case, or the "closest" string
+ // match to the contextFile from the res directories known to blaze
+ // - the rest of the direct dirs, then transitive dirs of the context rules,
+ // then any known res dir in the project
// as a backup, in alphabetical order.
Set<File> resourceDirs = Sets.newTreeSet();
Set<File> transitiveDirs = Sets.newTreeSet();
Set<File> allResDirs = Sets.newTreeSet();
- for (AndroidResourceModule androidResourceModule : syncData.importResult.androidResourceModules) {
- // labelsRelatedToContext should include deps, but as a first pass we only check the rules themselves
+ for (AndroidResourceModule androidResourceModule :
+ syncData.importResult.androidResourceModules) {
+ // labelsRelatedToContext should include deps,
+ // but as a first pass we only check the rules themselves
// for resources. If we come up empty, then have anyResDir as a backup.
allResDirs.addAll(androidResourceModule.transitiveResources);
- if (labelsRelatedToContext != null && !labelsRelatedToContext.contains(androidResourceModule.label)) {
+ if (labelsRelatedToContext != null
+ && !labelsRelatedToContext.contains(androidResourceModule.label)) {
continue;
}
for (File resDir : androidResourceModule.resources) {
@@ -90,13 +98,36 @@
}
// No need to show some directories twice.
transitiveDirs.removeAll(resourceDirs);
- File closestDirToContext = null;
- if (fileFromContext != null) {
- closestDirToContext = findClosestDirToContext(fileFromContext.getPath(), resourceDirs);
- closestDirToContext = closestDirToContext != null ? closestDirToContext :
- findClosestDirToContext(fileFromContext.getPath(), transitiveDirs);
- }
+
JComboBox resDirCombo = resDirComboAndBrowser.getComboBox();
+ // Allow the user to browse and overwrite some of the entries,
+ // in case our inference is wrong.
+ resDirCombo.setEditable(true);
+ // Optimize the right-click on a non-res directory (consider res directory right under that)
+ // After the use confirms the choice, a directory will be created if it is missing.
+ if (fileFromContext != null && fileFromContext.isDirectory()) {
+ File closestDirToContext = new File(fileFromContext.getPath(), "res");
+ resDirCombo.setSelectedItem(closestDirToContext);
+ } else {
+ // If we're not completely sure, let people know there are options
+ // via the placeholder text, and put the most likely on top.
+ String placeHolder = PLACEHOLDER_TEXT;
+ resDirCombo.addItem(placeHolder);
+ resDirCombo.setSelectedItem(placeHolder);
+ if (fileFromContext != null) {
+ File closestDirToContext =
+ findClosestDirToContext(fileFromContext.getPath(), resourceDirs);
+ closestDirToContext =
+ closestDirToContext != null
+ ? closestDirToContext
+ : findClosestDirToContext(fileFromContext.getPath(), transitiveDirs);
+ if (closestDirToContext != null) {
+ resDirCombo.addItem(closestDirToContext);
+ resourceDirs.remove(closestDirToContext);
+ transitiveDirs.remove(closestDirToContext);
+ }
+ }
+ }
if (!resourceDirs.isEmpty() || !transitiveDirs.isEmpty()) {
for (File resourceDir : resourceDirs) {
resDirCombo.addItem(resourceDir);
@@ -104,22 +135,11 @@
for (File resourceDir : transitiveDirs) {
resDirCombo.addItem(resourceDir);
}
- }
- else {
+ } else {
for (File resourceDir : allResDirs) {
resDirCombo.addItem(resourceDir);
}
}
- // Allow the user to browse and overwrite some of the entries.
- resDirCombo.setEditable(true);
- if (closestDirToContext != null) {
- resDirCombo.setSelectedItem(closestDirToContext);
- }
- else {
- String placeHolder = PLACEHOLDER_TEXT;
- resDirCombo.insertItemAt(placeHolder, 0);
- resDirCombo.setSelectedItem(placeHolder);
- }
resDirComboAndBrowser.setVisible(true);
resDirLabel.setVisible(true);
}
@@ -141,24 +161,33 @@
static PsiDirectory getResDirFromUI(Project project, ComboboxWithBrowseButton directoryCombo) {
PsiManager psiManager = PsiManager.getInstance(project);
- Object selectedItem = directoryCombo.getComboBox().getSelectedItem();
- VirtualFile file = null;
- if(selectedItem instanceof File) {
- file = VfsUtil.findFileByIoFile((File)selectedItem, true);
+ Object selectedItem = directoryCombo.getComboBox().getEditor().getItem();
+ File selectedFile = null;
+ if (selectedItem instanceof File) {
+ selectedFile = (File) selectedItem;
} else if (selectedItem instanceof String) {
- String selectedDir = (String)selectedItem;
+ String selectedDir = (String) selectedItem;
if (!selectedDir.equals(PLACEHOLDER_TEXT)) {
- file = VfsUtil.findFileByIoFile(new File(selectedDir), true);
+ selectedFile = new File(selectedDir);
}
}
- if (file != null) {
- return psiManager.findDirectory(file);
+ if (selectedFile == null) {
+ return null;
}
- return null;
+ final File finalSelectedFile = selectedFile;
+ return ApplicationManager.getApplication()
+ .runWriteAction(
+ new Computable<PsiDirectory>() {
+ @Override
+ public PsiDirectory compute() {
+ return DirectoryUtil.mkdirs(psiManager, finalSelectedFile.getPath());
+ }
+ });
}
- static VirtualFile getResDirFromDataContext(VirtualFile contextFile) {
- // Check if the contextFile is somewhere in the <path>/res/resType/foo.xml hierarchy and return <path>/res/.
+ static VirtualFile getResDirFromDataContext(VirtualFile contextFile) {
+ // Check if the contextFile is somewhere in
+ // the <path>/res/resType/foo.xml hierarchy and return <path>/res/.
if (contextFile.isDirectory()) {
if (contextFile.getName().equalsIgnoreCase(SdkConstants.FD_RES)) {
return contextFile;
@@ -169,11 +198,11 @@
return parent;
}
}
- }
- else {
+ } else {
VirtualFile parent = contextFile.getParent();
if (parent != null && ResourceFolderType.getFolderType(parent.getName()) != null) {
- // Otherwise, the contextFile is a file w/ a parent that is plausible. Recurse one level, on the parent.
+ // Otherwise, the contextFile is a file w/ a parent that is plausible.
+ // Recurse one level, on the parent.
return getResDirFromDataContext(parent);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateXmlResourcePanel.java b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateXmlResourcePanel.java
index 15b79fb..cf4a6d8 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateXmlResourcePanel.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeCreateXmlResourcePanel.java
@@ -19,6 +19,7 @@
import com.android.resources.ResourceType;
import com.android.tools.idea.res.ResourceNameValidator;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ValidationInfo;
@@ -30,6 +31,20 @@
import com.intellij.ui.components.JBLabel;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
import org.jetbrains.android.actions.CreateXmlResourceDialog;
import org.jetbrains.android.actions.CreateXmlResourcePanel;
import org.jetbrains.android.actions.CreateXmlResourceSubdirPanel;
@@ -38,17 +53,11 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-import java.util.function.Function;
-
/**
- * Embeddable UI for selecting how to create a new resource value (which XML file and directories to place it).
+ * Embeddable UI for selecting how to create a new resource value (which XML file and directories to
+ * place it).
*/
-public class BlazeCreateXmlResourcePanel implements CreateXmlResourcePanel,
- Parent {
+public class BlazeCreateXmlResourcePanel implements CreateXmlResourcePanel, Parent {
private JPanel myPanel;
private JTextField myNameField;
@@ -60,28 +69,29 @@
private ComboboxWithBrowseButton myResDirCombo;
private JBLabel myFileNameLabel;
- private final @NotNull Module myModule;
- private final @NotNull ResourceType myResourceType;
+ private final Module myModule;
+ private final ResourceType myResourceType;
private JPanel myDirectoriesPanel;
private JBLabel myDirectoriesLabel;
private CreateXmlResourceSubdirPanel mySubdirPanel;
private ResourceNameValidator myResourceNameValidator;
- private @Nullable VirtualFile myContextFile;
- private @Nullable VirtualFile myResDirectory;
+ @Nullable private VirtualFile myContextFile;
+ @Nullable private VirtualFile myResDirectory;
- public BlazeCreateXmlResourcePanel(@NotNull Module module,
- @NotNull ResourceType resourceType,
- @NotNull ResourceFolderType folderType,
- @Nullable String resourceName,
- @Nullable String resourceValue,
- boolean chooseName,
- boolean chooseValue,
- boolean chooseFilename,
- @Nullable VirtualFile defaultFile,
- @Nullable VirtualFile contextFile,
- @NotNull Function<Module, ResourceNameValidator> nameValidatorFactory) {
+ public BlazeCreateXmlResourcePanel(
+ @NotNull Module module,
+ @NotNull ResourceType resourceType,
+ @NotNull ResourceFolderType folderType,
+ @Nullable String resourceName,
+ @Nullable String resourceValue,
+ boolean chooseName,
+ boolean chooseValue,
+ boolean chooseFilename,
+ @Nullable VirtualFile defaultFile,
+ @Nullable VirtualFile contextFile,
+ @NotNull Function<Module, ResourceNameValidator> nameValidatorFactory) {
setupUi();
setChangeNameVisible(false);
setChangeValueVisible(false);
@@ -90,9 +100,9 @@
myContextFile = contextFile;
if (chooseName) {
setChangeNameVisible(true);
- if (!StringUtil.isEmpty(resourceName)) {
- myNameField.setText(resourceName);
- }
+ }
+ if (!StringUtil.isEmpty(resourceName)) {
+ myNameField.setText(resourceName);
}
if (chooseValue) {
@@ -106,8 +116,10 @@
ApplicationManager.getApplication().assertReadAccessAllowed();
// Set up UI to choose the base directory if needed (use context to prune selection).
- myResDirCombo.setVisible(false);
myResDirLabel.setVisible(false);
+ myResDirCombo.setVisible(false);
+ myResDirCombo.addBrowseFolderListener(
+ module.getProject(), FileChooserDescriptorFactory.createSingleFolderDescriptor());
setupResourceDirectoryCombo();
if (defaultFile == null) {
@@ -119,7 +131,8 @@
}
myDirectoriesLabel.setLabelFor(myDirectoriesPanel);
- mySubdirPanel = new CreateXmlResourceSubdirPanel(module.getProject(), folderType, myDirectoriesPanel, this);
+ mySubdirPanel =
+ new CreateXmlResourceSubdirPanel(module.getProject(), folderType, myDirectoriesPanel, this);
myResourceNameValidator = nameValidatorFactory.apply(getModule());
if (defaultFile != null) {
@@ -130,23 +143,27 @@
private void setupResourceDirectoryCombo() {
Project project = myModule.getProject();
if (myContextFile != null) {
- // Try to figure out res/ dir from context (e.g., while refactoring an xml file that's a child of a res/ directory).
+ // Try to figure out res/ dir from context
+ // (e.g., while refactoring an xml file that's a child of a res/ directory).
// We currently take the parent and hide the combo box.
PsiManager manager = PsiManager.getInstance(project);
- VirtualFile virtualDirectory = BlazeCreateResourceUtils.getResDirFromDataContext(myContextFile);
- PsiDirectory directory = virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null;
+ VirtualFile virtualDirectory =
+ BlazeCreateResourceUtils.getResDirFromDataContext(myContextFile);
+ PsiDirectory directory =
+ virtualDirectory != null ? manager.findDirectory(virtualDirectory) : null;
if (directory != null) {
myResDirectory = directory.getVirtualFile();
- }
- else {
- // As a last resort, if we have poor context, e.g., quick fix from within a .java file, set up the UI
+ } else {
+ // As a last resort, if we have poor context,
+ // e.g., quick fix from within a .java file, set up the UI
// based on the deps of the .java file.
- BlazeCreateResourceUtils.setupResDirectoryChoices(project, myContextFile, myResDirLabel, myResDirCombo);
+ BlazeCreateResourceUtils.setupResDirectoryChoices(
+ project, myContextFile, myResDirLabel, myResDirCombo);
}
- }
- else {
+ } else {
// As a last resort, if we have no context at all, set up some UI.
- BlazeCreateResourceUtils.setupResDirectoryChoices(project, null, myResDirLabel, myResDirCombo);
+ BlazeCreateResourceUtils.setupResDirectoryChoices(
+ project, null, myResDirLabel, myResDirCombo);
}
}
@@ -193,7 +210,8 @@
return myResDirectory;
}
if (myResDirCombo.isVisible()) {
- PsiDirectory directory = BlazeCreateResourceUtils.getResDirFromUI(myModule.getProject(), myResDirCombo);
+ PsiDirectory directory =
+ BlazeCreateResourceUtils.getResDirFromUI(myModule.getProject(), myResDirCombo);
return directory != null ? directory.getVirtualFile() : null;
}
return null;
@@ -206,7 +224,7 @@
@Override
public String getFileName() {
- return ((String)myFileNameCombo.getEditor().getItem()).trim();
+ return ((String) myFileNameCombo.getEditor().getItem()).trim();
}
@Override
@@ -218,22 +236,19 @@
if (myNameField.isVisible() && resourceName.isEmpty()) {
return new ValidationInfo("specify resource name", myNameField);
- }
- else if (myNameField.isVisible() && !AndroidResourceUtil.isCorrectAndroidResourceName(resourceName)) {
+ } else if (myNameField.isVisible()
+ && !AndroidResourceUtil.isCorrectAndroidResourceName(resourceName)) {
return new ValidationInfo(resourceName + " is not correct resource name", myNameField);
- }
- else if (fileName.isEmpty()) {
+ } else if (fileName.isEmpty()) {
return new ValidationInfo("specify file name", myFileNameCombo);
- }
- else if (resourceDir == null) {
+ } else if (resourceDir == null) {
return new ValidationInfo("specify a resource directory", myResDirCombo);
- }
- else if (directoryNames.isEmpty()) {
+ } else if (directoryNames.isEmpty()) {
return new ValidationInfo("choose directories", myDirectoriesPanel);
}
- return CreateXmlResourceDialog.checkIfResourceAlreadyExists(myModule.getProject(), resourceDir, resourceName,
- myResourceType, directoryNames, fileName);
+ return CreateXmlResourceDialog.checkIfResourceAlreadyExists(
+ myModule.getProject(), resourceDir, resourceName, myResourceType, directoryNames, fileName);
}
@Override
@@ -247,19 +262,15 @@
return myModule;
}
- /**
- * @see CreateXmlResourceDialog#getPreferredFocusedComponent()
- */
+ /** @see CreateXmlResourceDialog#getPreferredFocusedComponent() */
@Override
public JComponent getPreferredFocusedComponent() {
String name = myNameField.getText();
if (name.isEmpty()) {
return myNameField;
- }
- else if (myValueField.isVisible()) {
+ } else if (myValueField.isVisible()) {
return myValueField;
- }
- else {
+ } else {
return myFileNameCombo;
}
}
@@ -301,9 +312,7 @@
myFileNameCombo.getEditor().setItem(oldItem);
}
- /**
- * Initially generated by IntelliJ from a .form file.
- */
+ /** Initially generated by IntelliJ from a .form file. */
private void setupUi() {
myPanel = new JPanel();
myPanel.setLayout(new GridLayoutManager(6, 2, new Insets(0, 0, 5, 0), -1, -1));
@@ -311,63 +320,191 @@
myNameLabel.setText("Resource name:");
myNameLabel.setDisplayedMnemonic('N');
myNameLabel.setDisplayedMnemonicIndex(9);
- myPanel.add(myNameLabel,
- new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myNameLabel,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myNameField = new JTextField();
- myPanel.add(myNameField, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
- new Dimension(150, -1), null, 0, false));
+ myPanel.add(
+ myNameField,
+ new GridConstraints(
+ 0,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ new Dimension(150, -1),
+ null,
+ 0,
+ false));
myFileNameLabel = new JBLabel();
myFileNameLabel.setText("File name:");
myFileNameLabel.setDisplayedMnemonic('F');
myFileNameLabel.setDisplayedMnemonicIndex(0);
- myPanel.add(myFileNameLabel,
- new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myFileNameLabel,
+ new GridConstraints(
+ 3,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myDirectoriesPanel = new JPanel();
myDirectoriesPanel.setLayout(new BorderLayout(0, 0));
- myPanel.add(myDirectoriesPanel, new GridConstraints(5, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null,
- null, null, 0, false));
+ myPanel.add(
+ myDirectoriesPanel,
+ new GridConstraints(
+ 5,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ null,
+ null,
+ null,
+ 0,
+ false));
myDirectoriesLabel = new JBLabel();
myDirectoriesLabel.setText("Create the resource in directories:");
myDirectoriesLabel.setDisplayedMnemonic('C');
myDirectoriesLabel.setDisplayedMnemonicIndex(0);
- myPanel.add(myDirectoriesLabel,
- new GridConstraints(4, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myDirectoriesLabel,
+ new GridConstraints(
+ 4,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myValueLabel = new JBLabel();
myValueLabel.setText("Resource value:");
myValueLabel.setDisplayedMnemonic('V');
myValueLabel.setDisplayedMnemonicIndex(9);
- myPanel.add(myValueLabel,
- new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myValueLabel,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myValueField = new JTextField();
- myPanel.add(myValueField, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null,
- new Dimension(150, -1), null, 0, false));
+ myPanel.add(
+ myValueField,
+ new GridConstraints(
+ 1,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ new Dimension(150, -1),
+ null,
+ 0,
+ false));
myFileNameCombo = new JComboBox();
myFileNameCombo.setEditable(true);
- myPanel.add(myFileNameCombo, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null,
- null, 0, false));
+ myPanel.add(
+ myFileNameCombo,
+ new GridConstraints(
+ 3,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResDirLabel = new JBLabel();
myResDirLabel.setText("Base directory:");
myResDirLabel.setDisplayedMnemonic('B');
myResDirLabel.setDisplayedMnemonicIndex(0);
- myPanel.add(myResDirLabel,
- new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ myPanel.add(
+ myResDirLabel,
+ new GridConstraints(
+ 2,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myResDirCombo = new ComboboxWithBrowseButton();
- myPanel.add(myResDirCombo, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null,
- 0, false));
+ myPanel.add(
+ myResDirCombo,
+ new GridConstraints(
+ 2,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
myNameLabel.setLabelFor(myNameField);
myFileNameLabel.setLabelFor(myFileNameCombo);
myValueLabel.setLabelFor(myValueField);
}
-
}
diff --git a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeNewResourceCreationHandler.java b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeNewResourceCreationHandler.java
index 03a34a9..6bf7deb 100644
--- a/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeNewResourceCreationHandler.java
+++ b/aswb/src/com/google/idea/blaze/android/resources/actions/BlazeNewResourceCreationHandler.java
@@ -25,17 +25,18 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
-import org.jetbrains.android.actions.*;
+import java.util.Collection;
+import java.util.function.Function;
+import org.jetbrains.android.actions.CreateResourceDirectoryDialogBase;
+import org.jetbrains.android.actions.CreateResourceFileDialogBase;
+import org.jetbrains.android.actions.CreateTypedResourceFileAction;
+import org.jetbrains.android.actions.CreateXmlResourcePanel;
+import org.jetbrains.android.actions.NewResourceCreationHandler;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.Collection;
-import java.util.function.Function;
-
-/**
- * Decides which create resource dialogs to use for Blaze projects.
- */
+/** Decides which create resource dialogs to use for Blaze projects. */
public class BlazeNewResourceCreationHandler implements NewResourceCreationHandler {
@Override
@@ -46,47 +47,68 @@
@NotNull
@Override
public CreateResourceDirectoryDialogBase createNewResourceDirectoryDialog(
- @NotNull Project project,
- @Nullable Module module,
- @Nullable ResourceFolderType resType,
- @Nullable PsiDirectory resDirectory,
- @Nullable DataContext dataContext,
- @NotNull CreateResourceDirectoryDialogBase.ValidatorFactory validatorFactory) {
- return new BlazeCreateResourceDirectoryDialog(project, module, resType, resDirectory, dataContext, validatorFactory);
+ @NotNull Project project,
+ @Nullable Module module,
+ @Nullable ResourceFolderType resType,
+ @Nullable PsiDirectory resDirectory,
+ @Nullable DataContext dataContext,
+ @NotNull CreateResourceDirectoryDialogBase.ValidatorFactory validatorFactory) {
+ return new BlazeCreateResourceDirectoryDialog(
+ project, module, resType, resDirectory, dataContext, validatorFactory);
}
@NotNull
@Override
public CreateResourceFileDialogBase createNewResourceFileDialog(
- @NotNull AndroidFacet facet,
- @NotNull Collection<CreateTypedResourceFileAction> actions,
- @Nullable ResourceFolderType folderType,
- @Nullable String filename,
- @Nullable String rootElement,
- @Nullable FolderConfiguration folderConfiguration,
- boolean chooseFileName,
- boolean chooseModule,
- @Nullable PsiDirectory resDirectory,
- @Nullable DataContext dataContext,
- @NotNull CreateResourceFileDialogBase.ValidatorFactory validatorFactory) {
- return new BlazeCreateResourceFileDialog(facet, actions, folderType, filename, rootElement, folderConfiguration, chooseFileName,
- chooseModule, resDirectory, dataContext, validatorFactory);
+ @NotNull AndroidFacet facet,
+ @NotNull Collection<CreateTypedResourceFileAction> actions,
+ @Nullable ResourceFolderType folderType,
+ @Nullable String filename,
+ @Nullable String rootElement,
+ @Nullable FolderConfiguration folderConfiguration,
+ boolean chooseFileName,
+ boolean chooseModule,
+ @Nullable PsiDirectory resDirectory,
+ @Nullable DataContext dataContext,
+ @NotNull CreateResourceFileDialogBase.ValidatorFactory validatorFactory) {
+ return new BlazeCreateResourceFileDialog(
+ facet,
+ actions,
+ folderType,
+ filename,
+ rootElement,
+ folderConfiguration,
+ chooseFileName,
+ chooseModule,
+ resDirectory,
+ dataContext,
+ validatorFactory);
}
@Override
public CreateXmlResourcePanel createNewResourceValuePanel(
- @NotNull Module module,
- @NotNull ResourceType resourceType,
- @NotNull ResourceFolderType folderType,
- @Nullable String resourceName,
- @Nullable String resourceValue,
- boolean chooseName,
- boolean chooseValue,
- boolean chooseFilename,
- @Nullable VirtualFile defaultFile,
- @Nullable VirtualFile contextFile,
- @NotNull Function<Module, ResourceNameValidator> nameValidatorFactory) {
- return new BlazeCreateXmlResourcePanel(module, resourceType, folderType, resourceName, resourceValue,
- chooseName, chooseValue, chooseFilename, defaultFile, contextFile, nameValidatorFactory);
+ @NotNull Module module,
+ @NotNull ResourceType resourceType,
+ @NotNull ResourceFolderType folderType,
+ @Nullable String resourceName,
+ @Nullable String resourceValue,
+ boolean chooseName,
+ boolean chooseValue,
+ boolean chooseFilename,
+ @Nullable VirtualFile defaultFile,
+ @Nullable VirtualFile contextFile,
+ @NotNull Function<Module, ResourceNameValidator> nameValidatorFactory) {
+ return new BlazeCreateXmlResourcePanel(
+ module,
+ resourceType,
+ folderType,
+ resourceName,
+ resourceValue,
+ chooseName,
+ chooseValue,
+ chooseFilename,
+ defaultFile,
+ contextFile,
+ nameValidatorFactory);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRuleConfigurationFactory.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRuleConfigurationFactory.java
new file mode 100644
index 0000000..008982a
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRuleConfigurationFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
+
+/** Creates run configurations for android_binary and android_test. */
+public class BlazeAndroidRuleConfigurationFactory extends BlazeRuleConfigurationFactory {
+ @Override
+ public boolean handlesRule(
+ WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule) {
+ return rule.kindIsOneOf(Kind.ANDROID_BINARY, Kind.ANDROID_TEST);
+ }
+
+ @Override
+ protected ConfigurationFactory getConfigurationFactory() {
+ return BlazeCommandRunConfigurationType.getInstance().getFactory();
+ }
+
+ @Override
+ public void setupConfiguration(RunConfiguration configuration, RuleIdeInfo rule) {
+ final BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) configuration;
+ blazeConfig.setTarget(rule.label);
+ blazeConfig.setGeneratedName();
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfiguration.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfiguration.java
deleted file mode 100644
index ff5dc7f..0000000
--- a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfiguration.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.android.run;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationRunner;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.run.BlazeRunConfiguration;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.android.facet.AndroidFacet;
-
-/**
- * Common interface between android_binary and android_test configurations.
- */
-public interface BlazeAndroidRunConfiguration extends BlazeRunConfiguration {
-
- BlazeAndroidRunContext createRunContext(Project project,
- AndroidFacet facet,
- ExecutionEnvironment env,
- ImmutableList<String> buildFlags);
-
- BlazeAndroidRunConfigurationRunner getRunner();
-
- BlazeAndroidRunConfigurationCommonState getCommonState();
-
- @Override
- Label getTarget();
-}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonState.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonState.java
index 06b4262..2acea9b 100644
--- a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonState.java
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonState.java
@@ -15,55 +15,30 @@
*/
package com.google.idea.blaze.android.run;
-import com.android.tools.idea.run.ValidationError;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.DefaultJDOMExternalizer;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMExternalizable;
-import com.intellij.openapi.util.WriteExternalException;
-import org.jdom.Element;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
import static com.google.idea.blaze.android.cppapi.NdkSupport.NDK_SUPPORT;
+import com.google.common.collect.ImmutableList;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import java.util.List;
+import org.jdom.Element;
+
/**
- * A shared state class for run configurations targeting Blaze Android rules.
- * We implement the deprecated JDomExternalizable to fit with the other run configs.
+ * A shared state class for run configurations targeting Blaze Android rules. We implement the
+ * deprecated JDomExternalizable to fit with the other run configs.
*/
-public class BlazeAndroidRunConfigurationCommonState implements JDOMExternalizable {
- private static final String TARGET_ATTR = "blaze-target";
+public class BlazeAndroidRunConfigurationCommonState implements BlazeAndroidRunConfigurationState {
private static final String USER_FLAG_TAG = "blaze-user-flag";
private static final String NATIVE_DEBUG_ATTR = "blaze-native-debug";
- @Nullable private Label target;
private List<String> userFlags;
private boolean nativeDebuggingEnabled = false;
- /**
- * Creates a configuration state initialized with the given rule and flags.
- */
- public BlazeAndroidRunConfigurationCommonState(@Nullable Label target, List<String> userFlags) {
- this.target = target;
+ /** Creates a configuration state initialized with the given flags. */
+ public BlazeAndroidRunConfigurationCommonState(List<String> userFlags) {
this.userFlags = userFlags;
}
- @Nullable
- public Label getTarget() {
- return target;
- }
-
- public void setTarget(@Nullable Label target) {
- this.target = target;
- }
-
public List<String> getUserFlags() {
return userFlags;
}
@@ -80,34 +55,8 @@
this.nativeDebuggingEnabled = nativeDebuggingEnabled;
}
- public void checkConfiguration(Project project, Kind kind, List<ValidationError> errors) {
- RuleIdeInfo rule = target != null ? RuleFinder.getInstance().ruleForTarget(project, target) : null;
- if (rule == null) {
- errors.add(ValidationError.fatal(
- String.format("No existing %s rule selected.", Blaze.buildSystemName(project))
- ));
- }
- else if (!rule.kindIsOneOf(kind)) {
- errors.add(ValidationError.fatal(
- String.format("Selected %s rule is not %s", Blaze.buildSystemName(project), kind.toString())
- ));
- }
- }
-
@Override
public void readExternal(Element element) throws InvalidDataException {
- DefaultJDOMExternalizer.readExternal(this, element);
-
- target = null;
- String targetString = element.getAttributeValue(TARGET_ATTR);
- if (targetString != null) {
- try {
- target = new Label(targetString);
- }
- catch (IllegalArgumentException e) {
- throw new InvalidDataException("Bad configuration target", e);
- }
- }
ImmutableList.Builder<String> flagsBuilder = ImmutableList.builder();
for (Element e : element.getChildren(USER_FLAG_TAG)) {
String flag = e.getTextTrim();
@@ -121,11 +70,6 @@
@Override
public void writeExternal(Element element) throws WriteExternalException {
- DefaultJDOMExternalizer.writeExternal(this, element);
-
- if (target != null) {
- element.setAttribute(TARGET_ATTR, target.toString());
- }
for (String flag : userFlags) {
Element child = new Element(USER_FLAG_TAG);
child.setText(flag);
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateEditor.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateEditor.java
index 04b74ae..3a0c511 100644
--- a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateEditor.java
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateEditor.java
@@ -17,51 +17,27 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
import com.google.idea.blaze.android.cppapi.NdkSupport;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.ui.ComboWrapper;
-import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
-import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.util.execution.ParametersListUtil;
-
-import javax.swing.*;
import java.util.List;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JTextArea;
/**
- * A simplified, Blaze-specific variant of
- * {@link org.jetbrains.android.run.AndroidRunConfigurationEditor}.
+ * A simplified, Blaze-specific variant of {@link
+ * org.jetbrains.android.run.AndroidRunConfigurationEditor}.
*/
public class BlazeAndroidRunConfigurationCommonStateEditor {
- private static final Ordering<RuleIdeInfo> ALPHABETICAL = Ordering.usingToString().onResultOf((ruleIdeInfo) -> ruleIdeInfo.label);
-
private final Project project;
- private final Kind kind;
- private final ComboWrapper<RuleIdeInfo> ruleCombo;
private final JTextArea userFlagsField;
private final JCheckBox enableNativeDebuggingCheckBox;
- public BlazeAndroidRunConfigurationCommonStateEditor(
- Project project,
- Kind kind) {
+ public BlazeAndroidRunConfigurationCommonStateEditor(Project project) {
this.project = project;
- this.kind = kind;
-
- ruleCombo = ComboWrapper.create();
- List<RuleIdeInfo> rules = ALPHABETICAL.sortedCopy(RuleFinder.getInstance().rulesOfKinds(project, kind));
- ruleCombo.setItems(rules);
- ruleCombo.setRenderer(new ListCellRendererWrapper<RuleIdeInfo>() {
- @Override
- public void customize(JList list, RuleIdeInfo value, int index,
- boolean selected, boolean hasFocus) {
- setText(value == null ? "" : value.label.toString());
- }
- });
userFlagsField = new JTextArea(3 /* rows */, 50 /* columns */);
userFlagsField.setToolTipText("e.g. --config=android_arm");
@@ -69,33 +45,24 @@
}
public void resetEditorFrom(BlazeAndroidRunConfigurationCommonState runConfigurationState) {
- Label target = runConfigurationState.getTarget();
- RuleIdeInfo rule = target != null ? RuleFinder.getInstance().ruleForTarget(project, target) : null;
- ruleCombo.setSelectedItem(rule);
userFlagsField.setText(ParametersListUtil.join(runConfigurationState.getUserFlags()));
enableNativeDebuggingCheckBox.setSelected(runConfigurationState.isNativeDebuggingEnabled());
}
- public void applyEditorTo(BlazeAndroidRunConfigurationCommonState runConfigurationState)
- throws ConfigurationException {
- RuleIdeInfo rule = ruleCombo.getSelectedItem();
- Label target = rule != null ? rule.label : null;
- runConfigurationState.setTarget(target);
- List<String> userFlags = ParametersListUtil.parse(Strings.nullToEmpty(userFlagsField.getText()));
+ public void applyEditorTo(BlazeAndroidRunConfigurationCommonState runConfigurationState) {
+ List<String> userFlags =
+ ParametersListUtil.parse(Strings.nullToEmpty(userFlagsField.getText()));
runConfigurationState.setUserFlags(userFlags);
runConfigurationState.setNativeDebuggingEnabled(enableNativeDebuggingCheckBox.isSelected());
}
public List<JComponent> getComponents() {
- List<JComponent> result = Lists.newArrayList(
- new JLabel(kind.toString() + " rule:"),
- ruleCombo.getCombo(),
- new JLabel(String.format("Custom %s build flags:", Blaze.buildSystemName(project))),
- userFlagsField
- );
-
+ List<JComponent> result =
+ Lists.newArrayList(
+ new JLabel(String.format("Custom %s build flags:", Blaze.buildSystemName(project))),
+ userFlagsField);
if (NdkSupport.NDK_SUPPORT.getValue()) {
- result.add(enableNativeDebuggingCheckBox);
+ result.add(enableNativeDebuggingCheckBox);
}
return result;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationHandler.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationHandler.java
new file mode 100644
index 0000000..ed5a394
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationHandler.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.annotations.Nullable;
+
+/** Common interface for Blaze Android run configuration handlers. */
+public interface BlazeAndroidRunConfigurationHandler extends BlazeCommandRunConfigurationHandler {
+ /**
+ * A convenience method for getting a {@link BlazeAndroidRunConfigurationHandler} from a {@link
+ * RunProfile}, without having to do repetitive casts. Returns null if the given profile is not a
+ * {@link BlazeCommandRunConfiguration} with a {@link BlazeAndroidRunConfigurationHandler} for its
+ * handler.
+ */
+ @Nullable
+ static BlazeAndroidRunConfigurationHandler getHandlerFrom(RunProfile profile) {
+ if (!(profile instanceof BlazeCommandRunConfiguration)) {
+ return null;
+ }
+ BlazeCommandRunConfiguration blazeConfiguration = (BlazeCommandRunConfiguration) profile;
+ return blazeConfiguration.getHandlerIfType(BlazeAndroidRunConfigurationHandler.class);
+ }
+
+ /** @return A {@link BlazeAndroidRunContext} for this handler with the given settings. */
+ BlazeAndroidRunContext createRunContext(
+ Project project,
+ AndroidFacet facet,
+ ExecutionEnvironment env,
+ ImmutableList<String> buildFlags);
+
+ /**
+ * @return The {@link Label} this handler's configuration targets, or null if it does not target a
+ * Label.
+ */
+ @Nullable
+ Label getLabel();
+
+ /** @return This handler's common state. */
+ BlazeAndroidRunConfigurationCommonState getCommonState();
+
+ /** @return This handler's type-specific state. */
+ BlazeAndroidRunConfigurationState getConfigState();
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationHandlerEditor.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationHandlerEditor.java
new file mode 100644
index 0000000..e23f0a8
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationHandlerEditor.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerEditor;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.openapi.project.Project;
+import java.awt.Component;
+import java.util.List;
+import javax.swing.JComponent;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A simplified, Blaze-specific variant of {@link
+ * org.jetbrains.android.run.AndroidRunConfigurationEditor}.
+ */
+public class BlazeAndroidRunConfigurationHandlerEditor
+ implements BlazeCommandRunConfigurationHandlerEditor {
+ private final BlazeAndroidRunConfigurationCommonStateEditor commonStateEditor;
+ private final BlazeAndroidRunConfigurationStateEditor kindSpecificEditor;
+
+ public BlazeAndroidRunConfigurationHandlerEditor(
+ Project project, BlazeAndroidRunConfigurationStateEditor kindSpecificEditor) {
+ this.commonStateEditor = new BlazeAndroidRunConfigurationCommonStateEditor(project);
+ this.kindSpecificEditor = kindSpecificEditor;
+ }
+
+ @Override
+ public void resetEditorFrom(BlazeCommandRunConfigurationHandler h) {
+ BlazeAndroidRunConfigurationHandler handler = (BlazeAndroidRunConfigurationHandler) h;
+ commonStateEditor.resetEditorFrom(handler.getCommonState());
+ kindSpecificEditor.resetEditorFrom(handler.getConfigState());
+ }
+
+ @Override
+ public void applyEditorTo(BlazeCommandRunConfigurationHandler h) {
+ BlazeAndroidRunConfigurationHandler handler = (BlazeAndroidRunConfigurationHandler) h;
+ commonStateEditor.applyEditorTo(handler.getCommonState());
+ kindSpecificEditor.applyEditorTo(handler.getConfigState());
+ }
+
+ @Override
+ @NotNull
+ public JComponent createEditor() {
+ List<Component> components = Lists.newArrayList();
+ components.addAll(commonStateEditor.getComponents());
+ components.add(kindSpecificEditor.getComponent());
+ return UiUtil.createBox(components);
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationState.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationState.java
new file mode 100644
index 0000000..1d13b56
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationState.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run;
+
+import com.intellij.openapi.util.JDOMExternalizable;
+
+/** Indicates a class stores state for a Blaze Android run configuration. */
+public interface BlazeAndroidRunConfigurationState extends JDOMExternalizable {}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationStateEditor.java b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationStateEditor.java
new file mode 100644
index 0000000..7cbd815
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationStateEditor.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run;
+
+import java.awt.Component;
+
+/** An editor for Blaze Android run configuration state. */
+public interface BlazeAndroidRunConfigurationStateEditor {
+
+ void resetEditorFrom(BlazeAndroidRunConfigurationState state);
+
+ void applyEditorTo(BlazeAndroidRunConfigurationState state);
+
+ Component getComponent();
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/BlazeBeforeRunTaskProvider.java b/aswb/src/com/google/idea/blaze/android/run/BlazeBeforeRunTaskProvider.java
deleted file mode 100644
index 87358f5..0000000
--- a/aswb/src/com/google/idea/blaze/android/run/BlazeBeforeRunTaskProvider.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.android.run;
-
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationRunner;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.execution.BeforeRunTask;
-import com.intellij.execution.BeforeRunTaskProvider;
-import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Key;
-import icons.BlazeIcons;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * Provides a before run task provider that immediately transfers control
- * to {@link BlazeAndroidRunConfigurationRunner}
- */
-public final class BlazeBeforeRunTaskProvider extends BeforeRunTaskProvider<BlazeBeforeRunTaskProvider.Task> {
- @NotNull
- public static final Key<Task> ID = Key.create("Android.Blaze.BeforeRunTask");
- private static final String TASK_NAME = "Blaze before-run task";
-
- public static class Task extends BeforeRunTask<Task> {
- private Task() {
- super(ID);
- setEnabled(true);
- }
- }
-
- @NotNull
- private final Project project;
-
- public BlazeBeforeRunTaskProvider(@NotNull Project project) {
- this.project = project;
- }
-
- @Override
- public Key<Task> getId() {
- return ID;
- }
-
- @Nullable
- @Override
- public Icon getIcon() {
- return BlazeIcons.Blaze;
- }
-
- @Nullable
- @Override
- public Icon getTaskIcon(Task task) {
- return BlazeIcons.Blaze;
- }
-
- @Override
- public String getName() {
- return Blaze.guessBuildSystemName() + "before-run task";
- }
-
- @Override
- public String getDescription(Task task) {
- return Blaze.guessBuildSystemName() + "before-run task";
- }
-
- @Override
- public boolean isConfigurable() {
- return false;
- }
-
- @Nullable
- @Override
- public Task createTask(RunConfiguration runConfiguration) {
- if (runConfiguration instanceof BlazeAndroidRunConfiguration) {
- return new Task();
- }
- else {
- return null;
- }
- }
-
- @Override
- public boolean configureTask(RunConfiguration runConfiguration, Task task) {
- return false;
- }
-
- @Override
- public boolean canExecuteTask(RunConfiguration configuration, Task task) {
- return configuration instanceof BlazeAndroidRunConfiguration;
- }
-
- @Override
- public boolean executeTask(
- final DataContext dataContext,
- final RunConfiguration configuration,
- final ExecutionEnvironment env,
- Task task) {
- if (!canExecuteTask(configuration, task)) {
- return false;
- }
-
- final BlazeAndroidRunConfiguration blazeConfiguration = (BlazeAndroidRunConfiguration)configuration;
- return blazeConfiguration.getRunner().executeBuild(env);
- }
-}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationIdProvider.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationIdProvider.java
index 51a0f66..d89f58e 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationIdProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationIdProvider.java
@@ -27,15 +27,13 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-/**
- * Application id provider for android_binary.
- */
+/** Application id provider for android_binary. */
public class BlazeAndroidBinaryApplicationIdProvider implements ApplicationIdProvider {
private final Project project;
private final ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture;
- public BlazeAndroidBinaryApplicationIdProvider(Project project,
- ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture) {
+ public BlazeAndroidBinaryApplicationIdProvider(
+ Project project, ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture) {
this.project = project;
this.deployInfoFuture = deployInfoFuture;
}
@@ -46,13 +44,15 @@
BlazeAndroidDeployInfo deployInfo = Futures.get(deployInfoFuture, ApkProvisionException.class);
Manifest manifest = deployInfo.getMergedManifest();
if (manifest == null) {
- throw new ApkProvisionException("Could not find merged manifest: " + deployInfo.getMergedManifestFile());
+ throw new ApkProvisionException(
+ "Could not find merged manifest: " + deployInfo.getMergedManifestFile());
}
- String applicationId = ApplicationManager.getApplication().runReadAction(
- (Computable<String>)() -> manifest.getPackage().getValue()
- );
+ String applicationId =
+ ApplicationManager.getApplication()
+ .runReadAction((Computable<String>) () -> manifest.getPackage().getValue());
if (applicationId == null) {
- throw new ApkProvisionException("No application id in merged manifest: " + deployInfo.getMergedManifestFile());
+ throw new ApkProvisionException(
+ "No application id in merged manifest: " + deployInfo.getMergedManifestFile());
}
return applicationId;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationLaunchTaskProvider.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationLaunchTaskProvider.java
index 9233f20..f450693 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationLaunchTaskProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryApplicationLaunchTaskProvider.java
@@ -25,47 +25,51 @@
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-
import java.io.File;
-/**
- * Provides the launch task for android_binary
- */
+/** Provides the launch task for android_binary */
public class BlazeAndroidBinaryApplicationLaunchTaskProvider {
- private static final Logger LOG = Logger.getInstance(BlazeAndroidBinaryApplicationLaunchTaskProvider.class);
+ private static final Logger LOG =
+ Logger.getInstance(BlazeAndroidBinaryApplicationLaunchTaskProvider.class);
- public static LaunchTask getApplicationLaunchTask(Project project,
- ApplicationIdProvider applicationIdProvider,
- File mergedManifestFile,
- BlazeAndroidBinaryRunConfigurationState configState,
- StartActivityFlagsProvider startActivityFlagsProvider,
- ProcessHandlerLaunchStatus processHandlerLaunchStatus) {
+ public static LaunchTask getApplicationLaunchTask(
+ Project project,
+ ApplicationIdProvider applicationIdProvider,
+ File mergedManifestFile,
+ BlazeAndroidBinaryRunConfigurationState configState,
+ StartActivityFlagsProvider startActivityFlagsProvider,
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus) {
try {
String applicationId = applicationIdProvider.getPackageName();
final LaunchTask launchTask;
- switch (configState.MODE) {
+ switch (configState.getMode()) {
case BlazeAndroidBinaryRunConfigurationState.DO_NOTHING:
launchTask = null;
break;
case BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY:
- BlazeDefaultActivityLocator activityLocator = new BlazeDefaultActivityLocator(project, mergedManifestFile);
- launchTask = new DefaultActivityLaunchTask(applicationId, activityLocator, startActivityFlagsProvider);
+ BlazeDefaultActivityLocator activityLocator =
+ new BlazeDefaultActivityLocator(project, mergedManifestFile);
+ launchTask =
+ new DefaultActivityLaunchTask(
+ applicationId, activityLocator, startActivityFlagsProvider);
break;
case BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY:
- launchTask = new SpecificActivityLaunchTask(applicationId, configState.ACTIVITY_CLASS, startActivityFlagsProvider);
+ launchTask =
+ new SpecificActivityLaunchTask(
+ applicationId, configState.getActivityClass(), startActivityFlagsProvider);
break;
case BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEEP_LINK:
- launchTask = new AndroidDeepLinkLaunchTask(configState.DEEP_LINK, startActivityFlagsProvider);
+ launchTask =
+ new AndroidDeepLinkLaunchTask(configState.getDeepLink(), startActivityFlagsProvider);
break;
default:
launchTask = null;
break;
}
return launchTask;
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
LOG.error(e);
processHandlerLaunchStatus.terminateLaunch("Unable to identify application id");
return null;
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryConsoleProvider.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryConsoleProvider.java
index 776f16d..32183ef 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryConsoleProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryConsoleProvider.java
@@ -26,9 +26,7 @@
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
-/**
- * Console provider for android_binary
- */
+/** Console provider for android_binary */
public class BlazeAndroidBinaryConsoleProvider implements ConsoleProvider {
private final Project project;
@@ -38,11 +36,11 @@
@NotNull
@Override
- public ConsoleView createAndAttach(@NotNull Disposable parent,
- @NotNull ProcessHandler handler,
- @NotNull Executor executor)
- throws ExecutionException {
- final TextConsoleBuilder builder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
+ public ConsoleView createAndAttach(
+ @NotNull Disposable parent, @NotNull ProcessHandler handler, @NotNull Executor executor)
+ throws ExecutionException {
+ final TextConsoleBuilder builder =
+ TextConsoleBuilderFactory.getInstance().createBuilder(project);
ConsoleView console = builder.getConsole();
console.attachToProcess(handler);
return console;
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryNormalBuildRunContext.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryNormalBuildRunContext.java
index 6adef27..412c341 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryNormalBuildRunContext.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryNormalBuildRunContext.java
@@ -16,7 +16,12 @@
package com.google.idea.blaze.android.run.binary;
import com.android.ddmlib.IDevice;
-import com.android.tools.idea.run.*;
+import com.android.tools.idea.run.ApkInfo;
+import com.android.tools.idea.run.ApkProvisionException;
+import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.ConsolePrinter;
+import com.android.tools.idea.run.ConsoleProvider;
+import com.android.tools.idea.run.LaunchOptions;
import com.android.tools.idea.run.activity.DefaultStartActivityFlagsProvider;
import com.android.tools.idea.run.activity.StartActivityFlagsProvider;
import com.android.tools.idea.run.editor.AndroidDebugger;
@@ -28,27 +33,27 @@
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.deployinfo.BlazeAndroidDeployInfo;
import com.google.idea.blaze.android.run.deployinfo.BlazeApkProvider;
-import com.google.idea.blaze.android.run.runner.*;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidLaunchTasksProvider;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationDebuggerManager;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.android.run.runner.BlazeApkBuildStep;
+import com.google.idea.blaze.android.run.runner.BlazeApkBuildStepNormalBuild;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import java.util.Collection;
+import java.util.Set;
+import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
-import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * Run context for android_binary.
- */
+/** Run context for android_binary. */
class BlazeAndroidBinaryNormalBuildRunContext implements BlazeAndroidRunContext {
- private static final Logger LOG = Logger.getInstance(BlazeAndroidBinaryNormalBuildRunContext.class);
private final Project project;
private final AndroidFacet facet;
@@ -60,27 +65,28 @@
private final BlazeApkProvider apkProvider;
private final ApplicationIdProvider applicationIdProvider;
- public BlazeAndroidBinaryNormalBuildRunContext(Project project,
- AndroidFacet facet,
- RunConfiguration runConfiguration,
- ExecutionEnvironment env,
- BlazeAndroidRunConfigurationCommonState commonState,
- BlazeAndroidBinaryRunConfigurationState configState,
- ImmutableList<String> buildFlags) {
+ public BlazeAndroidBinaryNormalBuildRunContext(
+ Project project,
+ AndroidFacet facet,
+ RunConfiguration runConfiguration,
+ ExecutionEnvironment env,
+ BlazeAndroidBinaryRunConfigurationState configState,
+ Label label,
+ ImmutableList<String> buildFlags) {
this.project = project;
this.facet = facet;
this.runConfiguration = runConfiguration;
this.env = env;
this.configState = configState;
this.consoleProvider = new BlazeAndroidBinaryConsoleProvider(project);
- this.buildStep = new BlazeApkBuildStepNormalBuild(project, commonState, buildFlags);
+ this.buildStep = new BlazeApkBuildStepNormalBuild(project, label, buildFlags);
this.apkProvider = new BlazeApkProvider(project, buildStep.getDeployInfo());
- this.applicationIdProvider = new BlazeAndroidBinaryApplicationIdProvider(project, buildStep.getDeployInfo());
+ this.applicationIdProvider =
+ new BlazeAndroidBinaryApplicationIdProvider(project, buildStep.getDeployInfo());
}
@Override
- public void augmentEnvironment(ExecutionEnvironment env) {
- }
+ public void augmentEnvironment(ExecutionEnvironment env) {}
@Override
public BlazeAndroidDeviceSelector getDeviceSelector() {
@@ -89,10 +95,7 @@
@Override
public void augmentLaunchOptions(@NotNull LaunchOptions.Builder options) {
- options
- .setDeploy(true)
- .setPmInstallOptions(configState.ACTIVITY_EXTRA_FLAGS)
- .setOpenLogcatAutomatically(true);
+ options.setDeploy(true).setOpenLogcatAutomatically(true);
}
@NotNull
@@ -113,56 +116,71 @@
@Override
public LaunchTasksProvider getLaunchTasksProvider(
- LaunchOptions launchOptions,
- BlazeAndroidRunConfigurationDebuggerManager debuggerManager) throws ExecutionException {
- return new BlazeAndroidLaunchTasksProvider(project, this, applicationIdProvider, launchOptions, debuggerManager);
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidRunConfigurationDebuggerManager debuggerManager)
+ throws ExecutionException {
+ return new BlazeAndroidLaunchTasksProvider(
+ project, this, applicationIdProvider, launchOptionsBuilder, isDebug, debuggerManager);
}
@Nullable
@Override
- public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions) throws ExecutionException {
+ public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions)
+ throws ExecutionException {
Collection<ApkInfo> apks;
try {
apks = apkProvider.getApks(device);
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
throw new ExecutionException(e);
}
return ImmutableList.of(new DeployApkTask(project, launchOptions, apks));
}
@Override
- public LaunchTask getApplicationLaunchTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- ProcessHandlerLaunchStatus processHandlerLaunchStatus) throws ExecutionException {
- final StartActivityFlagsProvider startActivityFlagsProvider = new DefaultStartActivityFlagsProvider(
- androidDebugger,
- androidDebuggerState,
- project,
- launchOptions.isDebug(),
- configState.ACTIVITY_EXTRA_FLAGS
- );
+ public LaunchTask getApplicationLaunchTask(
+ LaunchOptions launchOptions,
+ @Nullable Integer userId,
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus)
+ throws ExecutionException {
+ final StartActivityFlagsProvider startActivityFlagsProvider =
+ new DefaultStartActivityFlagsProvider(
+ androidDebugger,
+ androidDebuggerState,
+ project,
+ launchOptions.isDebug(),
+ UserIdHelper.getFlagsFromUserId(userId));
- BlazeAndroidDeployInfo deployInfo = Futures.get(buildStep.getDeployInfo(), ExecutionException.class);
+ BlazeAndroidDeployInfo deployInfo =
+ Futures.get(buildStep.getDeployInfo(), ExecutionException.class);
return BlazeAndroidBinaryApplicationLaunchTaskProvider.getApplicationLaunchTask(
- project,
- applicationIdProvider,
- deployInfo.getMergedManifestFile(),
- configState,
- startActivityFlagsProvider,
- processHandlerLaunchStatus
- );
+ project,
+ applicationIdProvider,
+ deployInfo.getMergedManifestFile(),
+ configState,
+ startActivityFlagsProvider,
+ processHandlerLaunchStatus);
}
@Nullable
@Override
- public DebugConnectorTask getDebuggerTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- Set<String> packageIds) throws ExecutionException {
+ public DebugConnectorTask getDebuggerTask(
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ Set<String> packageIds)
+ throws ExecutionException {
//noinspection unchecked
- return androidDebugger.getConnectDebuggerTask(env, null, packageIds,facet, androidDebuggerState, runConfiguration.getType().getId());
+ return androidDebugger.getConnectDebuggerTask(
+ env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
+ }
+
+ @Nullable
+ @Override
+ public Integer getUserId(IDevice device, ConsolePrinter consolePrinter)
+ throws ExecutionException {
+ return UserIdHelper.getUserIdFromConfigurationState(device, consolePrinter, configState);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryProgramRunner.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryProgramRunner.java
index b178b12..5c41e6a 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryProgramRunner.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryProgramRunner.java
@@ -17,9 +17,11 @@
import com.android.tools.idea.fd.InstantRunUtils;
import com.android.tools.idea.run.AndroidSessionInfo;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandler;
import com.google.idea.blaze.android.run.binary.mobileinstall.IncrementalInstallDebugExecutor;
import com.google.idea.blaze.android.run.binary.mobileinstall.IncrementalInstallRunExecutor;
import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.executors.DefaultDebugExecutor;
@@ -30,37 +32,51 @@
import com.intellij.execution.ui.RunContentDescriptor;
import org.jetbrains.annotations.NotNull;
-/**
- * Program runner for {@link BlazeAndroidBinaryRunConfiguration}
- */
+/** Program runner for {@link BlazeAndroidRunConfiguration} */
public class BlazeAndroidBinaryProgramRunner extends DefaultProgramRunner {
@Override
public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
- if (!(profile instanceof BlazeAndroidBinaryRunConfiguration)) {
+ BlazeAndroidRunConfigurationHandler handler =
+ BlazeAndroidRunConfigurationHandler.getHandlerFrom(profile);
+ if (handler == null) {
return false;
}
- BlazeAndroidBinaryRunConfiguration runConfiguration = (BlazeAndroidBinaryRunConfiguration) profile;
- if (runConfiguration.getConfigState().isMobileInstall()) {
- return (IncrementalInstallDebugExecutor.EXECUTOR_ID.equals(executorId)
- || IncrementalInstallRunExecutor.EXECUTOR_ID.equals(executorId));
+ // In practice, the stock runner will probably handle all non-incremental-install configs.
+ if (DefaultDebugExecutor.EXECUTOR_ID.equals(executorId)
+ || DefaultRunExecutor.EXECUTOR_ID.equals(executorId)) {
+ return true;
}
-
- return DefaultDebugExecutor.EXECUTOR_ID.equals(executorId) || DefaultRunExecutor.EXECUTOR_ID.equals(executorId);
+ // Otherwise, the configuration must be a Blaze incremental install configuration running with
+ // an incremental install executor.
+ if (!(handler instanceof BlazeAndroidBinaryRunConfigurationHandler)) {
+ return false;
+ }
+ return ((BlazeAndroidBinaryRunConfigurationHandler) handler).getConfigState().mobileInstall()
+ && (IncrementalInstallDebugExecutor.EXECUTOR_ID.equals(executorId)
+ || IncrementalInstallRunExecutor.EXECUTOR_ID.equals(executorId));
}
@Override
- protected RunContentDescriptor doExecute(@NotNull final RunProfileState state, @NotNull final ExecutionEnvironment env)
- throws ExecutionException {
+ protected RunContentDescriptor doExecute(
+ @NotNull final RunProfileState state, @NotNull final ExecutionEnvironment env)
+ throws ExecutionException {
RunContentDescriptor descriptor = super.doExecute(state, env);
if (descriptor != null) {
ProcessHandler processHandler = descriptor.getProcessHandler();
assert processHandler != null;
RunProfile runProfile = env.getRunProfile();
- int uniqueId = (runProfile instanceof BlazeAndroidBinaryRunConfiguration)
- ? ((BlazeAndroidBinaryRunConfiguration)runProfile).getUniqueID() : -1;
- AndroidSessionInfo sessionInfo = new AndroidSessionInfo(processHandler, descriptor, uniqueId, env.getExecutor().getId(),
- InstantRunUtils.isInstantRunEnabled(env));
+ int uniqueId =
+ (runProfile instanceof RunConfigurationBase)
+ ? ((RunConfigurationBase) runProfile).getUniqueID()
+ : -1;
+ AndroidSessionInfo sessionInfo =
+ new AndroidSessionInfo(
+ processHandler,
+ descriptor,
+ uniqueId,
+ env.getExecutor().getId(),
+ InstantRunUtils.isInstantRunEnabled(env));
processHandler.putUserData(AndroidSessionInfo.KEY, sessionInfo);
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfiguration.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfiguration.java
deleted file mode 100644
index 7a02c45..0000000
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfiguration.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.android.run.binary;
-
-import com.android.sdklib.AndroidVersion;
-import com.android.tools.idea.fd.InstantRunManager;
-import com.android.tools.idea.run.AndroidSessionInfo;
-import com.android.tools.idea.run.ValidationError;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfiguration;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
-import com.google.idea.blaze.android.run.binary.instantrun.BlazeAndroidBinaryInstantRunContext;
-import com.google.idea.blaze.android.run.binary.mobileinstall.BlazeAndroidBinaryMobileInstallRunContext;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationRunner;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
-import com.google.idea.blaze.android.sync.projectstructure.BlazeAndroidProjectStructureSyncer;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.Executor;
-import com.intellij.execution.RunnerIconProvider;
-import com.intellij.execution.configurations.*;
-import com.intellij.execution.executors.DefaultRunExecutor;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
-import icons.AndroidIcons;
-import org.jdom.Element;
-import org.jetbrains.android.facet.AndroidFacet;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.util.List;
-
-/**
- * An extension of the normal Android Studio run configuration for launching Android applications,
- * adapted specifically for selecting and launching android_binary targets.
- */
-public final class BlazeAndroidBinaryRunConfiguration extends LocatableConfigurationBase
- implements BlazeAndroidRunConfiguration, RunConfiguration, RunnerIconProvider {
- private static final Logger LOG = Logger.getInstance(BlazeAndroidBinaryRunConfiguration.class);
- private final Project project;
- private final BlazeAndroidRunConfigurationCommonState commonState;
- private final BlazeAndroidBinaryRunConfigurationState configState = new BlazeAndroidBinaryRunConfigurationState();
- private final BlazeAndroidRunConfigurationRunner runner;
-
- public BlazeAndroidBinaryRunConfiguration(Project project, ConfigurationFactory factory) {
- super(project, factory, "");
- this.project = project;
-
- RuleIdeInfo rule = RuleFinder.getInstance().firstRuleOfKinds(project, Kind.ANDROID_BINARY);
- this.commonState = new BlazeAndroidRunConfigurationCommonState(rule != null ? rule.label : null, ImmutableList.of());
- this.runner = new BlazeAndroidRunConfigurationRunner(project, this, this.commonState, false, getUniqueID());
- }
-
- @Nullable
- @Override
- public final Label getTarget() {
- return commonState.getTarget();
- }
-
- public final void setTarget(@Nullable Label target) {
- commonState.setTarget(target);
- }
-
- @Override
- public BlazeAndroidRunConfigurationCommonState getCommonState() {
- return commonState;
- }
-
- @Override
- public BlazeAndroidRunConfigurationRunner getRunner() {
- return runner;
- }
-
- @Override
- public BlazeAndroidRunContext createRunContext(Project project,
- AndroidFacet facet,
- ExecutionEnvironment env,
- ImmutableList<String> buildFlags) {
- if (configState.isInstantRun()) {
- return new BlazeAndroidBinaryInstantRunContext(project, facet, this, env, commonState, configState, buildFlags);
- }
- else if (configState.isMobileInstall()) {
- return new BlazeAndroidBinaryMobileInstallRunContext(project, facet, this, env, commonState, configState, buildFlags);
- }
- else {
- return new BlazeAndroidBinaryNormalBuildRunContext(project, facet, this, env, commonState, configState, buildFlags);
- }
- }
-
- @Override
- @NotNull
- public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
- return new BlazeAndroidBinaryRunConfigurationEditor(
- getProject(),
- new BlazeAndroidBinaryRunConfigurationStateEditor(getProject())
- );
- }
-
- @Override
- public final void checkConfiguration() throws RuntimeConfigurationException {
- List<ValidationError> errors = validate();
- if (errors.isEmpty()) {
- return;
- }
- // TODO: Do something with the extra error information? Error count?
- ValidationError topError = Ordering.natural().max(errors);
- if (topError.isFatal()) {
- throw new RuntimeConfigurationError(topError.getMessage(), topError.getQuickfix());
- }
- throw new RuntimeConfigurationWarning(topError.getMessage(), topError.getQuickfix());
- }
-
- private List<ValidationError> validate() {
- List<ValidationError> errors = Lists.newArrayList();
- errors.addAll(runner.validate(getModule()));
- commonState.checkConfiguration(getProject(), Kind.ANDROID_BINARY, errors);
- return errors;
- }
-
- private Module getModule() {
- return BlazeAndroidProjectStructureSyncer.ensureRunConfigurationModule(project, getTarget());
- }
-
- @Override
- @Nullable
- public final RunProfileState getState(@NotNull final Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
- final Module module = getModule();
- return runner.getState(module, executor, env);
- }
-
- @NotNull
- public BlazeAndroidBinaryRunConfigurationState getConfigState() {
- return configState;
- }
-
- @Nullable
- @Override
- public Icon getExecutorIcon(@NotNull RunConfiguration configuration, @NotNull Executor executor) {
- if (!configState.isInstantRun()) {
- return null;
- }
-
- AndroidSessionInfo info = AndroidSessionInfo.findOldSession(getProject(), null, getUniqueID());
- if (info == null || !info.isInstantRun() || !info.getExecutorId().equals(executor.getId())) {
- return null;
- }
-
- // Make sure instant run is supported on the relevant device, if found.
- AndroidVersion androidVersion = InstantRunManager.getMinDeviceApiLevel(info.getProcessHandler());
- if (!InstantRunManager.isInstantRunCapableDeviceVersion(androidVersion)) {
- return null;
- }
-
- return executor instanceof DefaultRunExecutor
- ? AndroidIcons.RunIcons.Replay
- : AndroidIcons.RunIcons.DebugReattach;
- }
-
- @Override
- public void readExternal(Element element) throws InvalidDataException {
- super.readExternal(element);
-
- commonState.readExternal(element);
- runner.readExternal(element);;
- configState.readExternal(element);
- }
-
- @Override
- public void writeExternal(Element element) throws WriteExternalException {
- super.writeExternal(element);
-
- commonState.writeExternal(element);
- runner.writeExternal(element);;
- configState.writeExternal(element);
- }
-
- @Override
- public RunConfiguration clone() {
- final Element element = new Element("dummy");
- try {
- writeExternal(element);
- BlazeAndroidBinaryRunConfiguration clone = new BlazeAndroidBinaryRunConfiguration(
- getProject(), getFactory());
- clone.readExternal(element);
- return clone;
- } catch (InvalidDataException e) {
- LOG.error(e);
- return null;
- } catch (WriteExternalException e) {
- LOG.error(e);
- return null;
- }
- }
-}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationEditor.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationEditor.java
deleted file mode 100644
index 54d0ee8..0000000
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationEditor.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.android.run.binary;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonStateEditor;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.List;
-
-/**
- * A simplified, Blaze-specific variant of
- * {@link org.jetbrains.android.run.AndroidRunConfigurationEditor}.
- */
-class BlazeAndroidBinaryRunConfigurationEditor extends SettingsEditor<BlazeAndroidBinaryRunConfiguration> {
-
- private final BlazeAndroidBinaryRunConfigurationStateEditor kindSpecificEditor;
- private final BlazeAndroidRunConfigurationCommonStateEditor commonStateEditor;
-
- public BlazeAndroidBinaryRunConfigurationEditor(
- Project project,
- BlazeAndroidBinaryRunConfigurationStateEditor kindSpecificEditor) {
- this.kindSpecificEditor = kindSpecificEditor;
- this.commonStateEditor = new BlazeAndroidRunConfigurationCommonStateEditor(project, Kind.ANDROID_BINARY);
- }
-
- @Override
- protected void resetEditorFrom(BlazeAndroidBinaryRunConfiguration configuration) {
- commonStateEditor.resetEditorFrom(configuration.getCommonState());
- kindSpecificEditor.resetFrom(configuration);
- }
-
- @Override
- protected void applyEditorTo(@NotNull BlazeAndroidBinaryRunConfiguration configuration)
- throws ConfigurationException {
- commonStateEditor.applyEditorTo(configuration.getCommonState());
- kindSpecificEditor.applyTo(configuration);
- }
-
- @Override
- @NotNull
- protected JComponent createEditor() {
- List<Component> components = Lists.newArrayList();
- components.addAll(commonStateEditor.getComponents());
- components.add(kindSpecificEditor.getComponent());
- return UiUtil.createBox(components);
- }
-}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandler.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandler.java
new file mode 100644
index 0000000..2bd07cc
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandler.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run.binary;
+
+import com.android.sdklib.AndroidVersion;
+import com.android.tools.idea.fd.InstantRunManager;
+import com.android.tools.idea.run.AndroidSessionInfo;
+import com.android.tools.idea.run.ValidationError;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandler;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandlerEditor;
+import com.google.idea.blaze.android.run.binary.instantrun.BlazeAndroidBinaryInstantRunContext;
+import com.google.idea.blaze.android.run.binary.mobileinstall.BlazeAndroidBinaryMobileInstallRunContext;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationRunner;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.android.sync.projectstructure.BlazeAndroidProjectStructureSyncer;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerEditor;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationError;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.configurations.RuntimeConfigurationWarning;
+import com.intellij.execution.executors.DefaultRunExecutor;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import icons.AndroidIcons;
+import java.util.List;
+import javax.swing.Icon;
+import org.jdom.Element;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * {@link com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler} for
+ * android_binary targets.
+ */
+public class BlazeAndroidBinaryRunConfigurationHandler
+ implements BlazeAndroidRunConfigurationHandler {
+ private static final Logger LOG =
+ Logger.getInstance(BlazeAndroidBinaryRunConfigurationHandler.class);
+
+ private final BlazeCommandRunConfiguration configuration;
+ private final BlazeAndroidRunConfigurationCommonState commonState;
+ private final BlazeAndroidBinaryRunConfigurationState configState;
+ private final BlazeAndroidRunConfigurationRunner runner;
+
+ BlazeAndroidBinaryRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ this.configuration = configuration;
+ commonState = new BlazeAndroidRunConfigurationCommonState(ImmutableList.of());
+ configState = new BlazeAndroidBinaryRunConfigurationState();
+ runner =
+ new BlazeAndroidRunConfigurationRunner(
+ configuration.getProject(), this, commonState, false, configuration.getUniqueID());
+ }
+
+ @Override
+ public BlazeAndroidRunContext createRunContext(
+ Project project,
+ AndroidFacet facet,
+ ExecutionEnvironment env,
+ ImmutableList<String> buildFlags) {
+ if (configState.instantRun()) {
+ return new BlazeAndroidBinaryInstantRunContext(
+ project, facet, configuration, env, configState, getLabel(), buildFlags);
+ } else if (configState.mobileInstall()) {
+ return new BlazeAndroidBinaryMobileInstallRunContext(
+ project, facet, configuration, env, configState, getLabel(), buildFlags);
+ } else {
+ return new BlazeAndroidBinaryNormalBuildRunContext(
+ project, facet, configuration, env, configState, getLabel(), buildFlags);
+ }
+ }
+
+ @Override
+ @Nullable
+ public Label getLabel() {
+ TargetExpression target = configuration.getTarget();
+ if (target instanceof Label) {
+ return (Label) target;
+ }
+ return null;
+ }
+
+ @Override
+ public BlazeAndroidRunConfigurationCommonState getCommonState() {
+ return commonState;
+ }
+
+ @Override
+ public BlazeAndroidBinaryRunConfigurationState getConfigState() {
+ return configState;
+ }
+
+ @Nullable
+ private Module getModule() {
+ Label target = getLabel();
+ return target != null
+ ? BlazeAndroidProjectStructureSyncer.ensureRunConfigurationModule(
+ configuration.getProject(), target)
+ : null;
+ }
+
+ @Override
+ public final void checkConfiguration() throws RuntimeConfigurationException {
+ List<ValidationError> errors = validate();
+ if (errors.isEmpty()) {
+ return;
+ }
+ // TODO: Do something with the extra error information? Error count?
+ ValidationError topError = Ordering.natural().max(errors);
+ if (topError.isFatal()) {
+ throw new RuntimeConfigurationError(topError.getMessage(), topError.getQuickfix());
+ }
+ throw new RuntimeConfigurationWarning(topError.getMessage(), topError.getQuickfix());
+ }
+
+ private List<ValidationError> validate() {
+ List<ValidationError> errors = Lists.newArrayList();
+ errors.addAll(runner.validate(getModule()));
+ validateLabel(errors);
+ return errors;
+ }
+
+ private void validateLabel(List<ValidationError> errors) {
+ Project project = configuration.getProject();
+ Label target = getLabel();
+ Kind kind = Kind.ANDROID_BINARY;
+ RuleIdeInfo rule =
+ target != null ? RuleFinder.getInstance().ruleForTarget(project, target) : null;
+ if (rule == null) {
+ errors.add(
+ ValidationError.fatal(
+ String.format("No existing %s rule selected.", Blaze.buildSystemName(project))));
+ } else if (!rule.kindIsOneOf(kind)) {
+ errors.add(
+ ValidationError.fatal(
+ String.format(
+ "Selected %s rule is not %s", Blaze.buildSystemName(project), kind.toString())));
+ }
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ commonState.readExternal(element);
+ runner.readExternal(element);
+ configState.readExternal(element);
+ }
+
+ @Override
+ public void writeExternal(Element element) throws WriteExternalException {
+ commonState.writeExternal(element);
+ runner.writeExternal(element);
+ configState.writeExternal(element);
+ }
+
+ @Override
+ public BlazeAndroidBinaryRunConfigurationHandler cloneFor(
+ BlazeCommandRunConfiguration configuration) {
+ final Element element = new Element("dummy");
+ try {
+ writeExternal(element);
+ final BlazeAndroidBinaryRunConfigurationHandler handler =
+ new BlazeAndroidBinaryRunConfigurationHandler(configuration);
+ handler.readExternal(element);
+ return handler;
+ } catch (InvalidDataException | WriteExternalException e) {
+ LOG.error(e);
+ return null;
+ }
+ }
+
+ @Override
+ @Nullable
+ public final RunProfileState getState(
+ @NotNull final Executor executor, @NotNull ExecutionEnvironment env)
+ throws ExecutionException {
+ final Module module = getModule();
+ return runner.getState(module, executor, env);
+ }
+
+ @Override
+ public boolean executeBeforeRunTask(ExecutionEnvironment environment) {
+ return runner.executeBuild(environment);
+ }
+
+ @Override
+ @Nullable
+ public String suggestedName() {
+ Label target = getLabel();
+ if (target == null) {
+ return null;
+ }
+ // buildSystemName and commandName are intentionally omitted.
+ return new BlazeConfigurationNameBuilder().setTargetString(target).build();
+ }
+
+ @Override
+ public boolean isGeneratedName(boolean hasGeneratedFlag) {
+ return Comparing.equal(configuration.getName(), suggestedName());
+ }
+
+ @Override
+ @Nullable
+ public String getCommandName() {
+ return null;
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "Android Binary Handler";
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(@NotNull RunConfiguration configuration, @NotNull Executor executor) {
+ if (!configState.instantRun()) {
+ return null;
+ }
+
+ AndroidSessionInfo info =
+ AndroidSessionInfo.findOldSession(
+ this.configuration.getProject(), null, this.configuration.getUniqueID());
+ if (info == null || !info.isInstantRun() || !info.getExecutorId().equals(executor.getId())) {
+ return null;
+ }
+
+ // Make sure instant run is supported on the relevant device, if found.
+ AndroidVersion androidVersion =
+ InstantRunManager.getMinDeviceApiLevel(info.getProcessHandler());
+ if (!InstantRunManager.isInstantRunCapableDeviceVersion(androidVersion)) {
+ return null;
+ }
+
+ return executor instanceof DefaultRunExecutor
+ ? AndroidIcons.RunIcons.Replay
+ : AndroidIcons.RunIcons.DebugReattach;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandlerEditor getHandlerEditor() {
+ Project project = configuration.getProject();
+ return new BlazeAndroidRunConfigurationHandlerEditor(
+ project, new BlazeAndroidBinaryRunConfigurationStateEditor(project));
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandlerProvider.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..5af756b
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandlerProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run.binary;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+
+/** Handler provider for android_binary targets. */
+public class BlazeAndroidBinaryRunConfigurationHandlerProvider
+ implements BlazeCommandRunConfigurationHandlerProvider {
+
+ public static BlazeAndroidBinaryRunConfigurationHandlerProvider getInstance() {
+ return BlazeCommandRunConfigurationHandlerProvider.EP_NAME.findExtension(
+ BlazeAndroidBinaryRunConfigurationHandlerProvider.class);
+ }
+
+ @Override
+ public boolean canHandleKind(Kind kind) {
+ return kind == Kind.ANDROID_BINARY;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config) {
+ return new BlazeAndroidBinaryRunConfigurationHandler(config);
+ }
+
+ @Override
+ public String getId() {
+ return "BlazeAndroidBinaryRunConfigurationHandlerProvider";
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationState.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationState.java
index e048889..aab1abc 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationState.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationState.java
@@ -15,35 +15,43 @@
*/
package com.google.idea.blaze.android.run.binary;
-import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.android.tools.idea.run.util.LaunchUtils;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationState;
import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
+import java.util.Map;
import org.jdom.Element;
-/**
- * State specific to the android binary run configuration.
- */
-public final class BlazeAndroidBinaryRunConfigurationState implements JDOMExternalizable {
+/** State specific to the android binary run configuration. */
+public final class BlazeAndroidBinaryRunConfigurationState
+ implements BlazeAndroidRunConfigurationState {
public static final String LAUNCH_DEFAULT_ACTIVITY = "default_activity";
public static final String LAUNCH_SPECIFIC_ACTIVITY = "specific_activity";
public static final String DO_NOTHING = "do_nothing";
public static final String LAUNCH_DEEP_LINK = "launch_deep_link";
- public String DEEP_LINK = "";
- public String ACTIVITY_CLASS = "";
-
- public String MODE = LAUNCH_DEFAULT_ACTIVITY;
- // Launch options
- public String ACTIVITY_EXTRA_FLAGS = "";
private static final String MOBILE_INSTALL_ATTR = "blaze-mobile-install";
private static final String USE_SPLIT_APKS_IF_POSSIBLE = "use-split-apks-if-possible";
private static final String INSTANT_RUN_ATTR = "instant-run";
+ private static final String WORK_PROFILE_ATTR = "use-work-profile-if-present";
+ private static final String USER_ID_ATTR = "user-id";
private boolean mobileInstall = false;
private boolean useSplitApksIfPossible = true;
private boolean instantRun = false;
+ private boolean useWorkProfileIfPresent = false;
+ private Integer userId;
- boolean isMobileInstall() {
+ private static final String DEEP_LINK = "DEEP_LINK";
+ private static final String ACTIVITY_CLASS = "ACTIVITY_CLASS";
+ private static final String MODE = "MODE";
+ private static final String ACTIVITY_EXTRA_FLAGS = "ACTIVITY_EXTRA_FLAGS";
+ private String deepLink = "";
+ private String activityClass = "";
+ private String mode = LAUNCH_DEFAULT_ACTIVITY;
+
+ boolean mobileInstall() {
return mobileInstall;
}
@@ -51,7 +59,7 @@
this.mobileInstall = mobileInstall;
}
- public boolean isUseSplitApksIfPossible() {
+ public boolean useSplitApksIfPossible() {
return useSplitApksIfPossible;
}
@@ -59,7 +67,7 @@
this.useSplitApksIfPossible = useSplitApksIfPossible;
}
- boolean isInstantRun() {
+ boolean instantRun() {
return instantRun;
}
@@ -67,19 +75,108 @@
this.instantRun = instantRun;
}
+ public boolean useWorkProfileIfPresent() {
+ return useWorkProfileIfPresent;
+ }
+
+ void setUseWorkProfileIfPresent(boolean useWorkProfileIfPresent) {
+ this.useWorkProfileIfPresent = useWorkProfileIfPresent;
+ }
+
+ Integer getUserId() {
+ return userId;
+ }
+
+ void setUserId(Integer userId) {
+ this.userId = userId;
+ }
+
+ public String getDeepLink() {
+ return deepLink;
+ }
+
+ public void setDeepLink(String deepLink) {
+ this.deepLink = deepLink;
+ }
+
+ public String getActivityClass() {
+ return activityClass;
+ }
+
+ public void setActivityClass(String activityClass) {
+ this.activityClass = activityClass;
+ }
+
+ public String getMode() {
+ return mode;
+ }
+
+ public void setMode(String mode) {
+ this.mode = mode;
+ }
+
@Override
public void readExternal(Element element) throws InvalidDataException {
- DefaultJDOMExternalizer.readExternal(this, element);
+ setDeepLink(Strings.nullToEmpty(element.getAttributeValue(DEEP_LINK)));
+ setActivityClass(Strings.nullToEmpty(element.getAttributeValue(ACTIVITY_CLASS)));
+ setMode(Strings.nullToEmpty(element.getAttributeValue(MODE)));
setMobileInstall(Boolean.parseBoolean(element.getAttributeValue(MOBILE_INSTALL_ATTR)));
- setUseSplitApksIfPossible(Boolean.parseBoolean(element.getAttributeValue(USE_SPLIT_APKS_IF_POSSIBLE)));
+ setUseSplitApksIfPossible(
+ Boolean.parseBoolean(element.getAttributeValue(USE_SPLIT_APKS_IF_POSSIBLE)));
setInstantRun(Boolean.parseBoolean(element.getAttributeValue(INSTANT_RUN_ATTR)));
+ setUseWorkProfileIfPresent(Boolean.parseBoolean(element.getAttributeValue(WORK_PROFILE_ATTR)));
+
+ String userIdString = element.getAttributeValue(USER_ID_ATTR);
+ if (userIdString != null) {
+ setUserId(Integer.parseInt(userIdString));
+ }
+
+ for (Map.Entry<String, String> entry : getLegacyValues(element).entrySet()) {
+ String value = entry.getValue();
+ switch (entry.getKey()) {
+ case DEEP_LINK:
+ deepLink = Strings.nullToEmpty(value);
+ break;
+ case ACTIVITY_CLASS:
+ activityClass = Strings.nullToEmpty(value);
+ break;
+ case MODE:
+ mode = Strings.nullToEmpty(value);
+ break;
+ case ACTIVITY_EXTRA_FLAGS:
+ if (userId == null) {
+ userId = LaunchUtils.getUserIdFromFlags(value);
+ }
+ break;
+ default:
+ break;
+ }
+ }
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
- DefaultJDOMExternalizer.writeExternal(this, element);
+ element.setAttribute(DEEP_LINK, deepLink);
+ element.setAttribute(ACTIVITY_CLASS, activityClass);
+ element.setAttribute(MODE, mode);
element.setAttribute(MOBILE_INSTALL_ATTR, Boolean.toString(mobileInstall));
element.setAttribute(USE_SPLIT_APKS_IF_POSSIBLE, Boolean.toString(useSplitApksIfPossible));
element.setAttribute(INSTANT_RUN_ATTR, Boolean.toString(instantRun));
+ element.setAttribute(WORK_PROFILE_ATTR, Boolean.toString(useWorkProfileIfPresent));
+
+ if (userId != null) {
+ element.setAttribute(USER_ID_ATTR, Integer.toString(userId));
+ }
+ }
+
+ /** Imports legacy values in the old reflective JDOM externalizer manner. Can be removed ~2.0+. */
+ private static Map<String, String> getLegacyValues(Element element) {
+ Map<String, String> result = Maps.newHashMap();
+ for (Element option : element.getChildren("option")) {
+ String name = option.getAttributeValue("name");
+ String value = option.getAttributeValue("value");
+ result.put(name, value);
+ }
+ return result;
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateEditor.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateEditor.java
index e85da80..ddcbf9a 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateEditor.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateEditor.java
@@ -15,9 +15,9 @@
*/
package com.google.idea.blaze.android.run.binary;
-import com.android.tools.idea.run.ConfigurationSpecificEditor;
import com.android.tools.idea.run.activity.ActivityLocatorUtils;
-import com.android.tools.idea.run.util.LaunchUtils;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationState;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationStateEditor;
import com.google.idea.blaze.android.run.binary.instantrun.InstantRunExperiment;
import com.google.idea.blaze.base.ui.IntegerTextField;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
@@ -39,31 +39,37 @@
import com.intellij.ui.LanguageTextField;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
-import org.jetbrains.android.util.AndroidBundle;
-import org.jetbrains.android.util.AndroidUtils;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import javax.swing.border.TitledBorder;
-import java.awt.*;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ResourceBundle;
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.border.TitledBorder;
+import org.jetbrains.android.util.AndroidBundle;
+import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.annotations.Nullable;
/**
- * The part of the Blaze Android run configuration editor that allows the user to pick an
- * android_binary target and an activity to launch.
- * Patterned after {@link org.jetbrains.android.run.ApplicationRunParameters}.
+ * The part of the Blaze Android Binary handler editor that allows the user to pick an activity to
+ * launch. Patterned after {@link org.jetbrains.android.run.ApplicationRunParameters}.
*/
-class BlazeAndroidBinaryRunConfigurationStateEditor implements ConfigurationSpecificEditor<BlazeAndroidBinaryRunConfiguration> {
- public static final Key<BlazeAndroidBinaryRunConfigurationStateEditor> ACTIVITY_CLASS_TEXT_FIELD_KEY =
- Key.create("BlazeActivityClassTextField");
+class BlazeAndroidBinaryRunConfigurationStateEditor
+ implements BlazeAndroidRunConfigurationStateEditor {
+ public static final Key<BlazeAndroidBinaryRunConfigurationStateEditor>
+ ACTIVITY_CLASS_TEXT_FIELD_KEY = Key.create("BlazeActivityClassTextField");
- @NotNull
private final Project project;
- @Nullable
- private JPanel panel;
+
+ @Nullable private JPanel panel;
private ComponentWithBrowseButton<EditorTextField> activityField;
private JRadioButton launchNothingButton;
private JRadioButton launchDefaultButton;
@@ -71,45 +77,56 @@
private JCheckBox mobileInstallCheckBox;
private JCheckBox splitApksCheckBox;
private JCheckBox instantRunCheckBox;
+ private JCheckBox useWorkProfileIfPresentCheckBox;
+ private JLabel userIdLabel;
private IntegerTextField userIdField;
- BlazeAndroidBinaryRunConfigurationStateEditor(@NotNull final Project project) {
+ BlazeAndroidBinaryRunConfigurationStateEditor(Project project) {
this.project = project;
setupUI();
userIdField.setMinValue(0);
- activityField.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- if (!project.isInitialized()) {
- return;
- }
- // We find all Activity classes in the module for the selected variant (or any of its deps).
- final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
- PsiClass activityBaseClass = facade.findClass(
- AndroidUtils.ACTIVITY_BASE_CLASS_NAME, ProjectScope.getAllScope(project));
- if (activityBaseClass == null) {
- Messages
- .showErrorDialog(panel, AndroidBundle.message("cant.find.activity.class.error"));
- return;
- }
- GlobalSearchScope searchScope = GlobalSearchScope.projectScope(project);
- PsiClass initialSelection = facade.findClass(
- activityField.getChildComponent().getText(), searchScope);
- TreeClassChooser chooser = TreeClassChooserFactory.getInstance(project)
- .createInheritanceClassChooser("Select Activity Class",
- searchScope, activityBaseClass,
- initialSelection, null);
- chooser.showDialog();
- PsiClass selClass = chooser.getSelected();
- if (selClass != null) {
- // This must be done because Android represents inner static class paths differently than java.
- String qualifiedActivityName = ActivityLocatorUtils.getQualifiedActivityName(selClass);
- activityField.getChildComponent().setText(qualifiedActivityName);
- }
- }
- });
+ activityField.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (!project.isInitialized()) {
+ return;
+ }
+ // We find all Activity classes in the module for the selected variant
+ // (or any of its deps).
+ final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
+ PsiClass activityBaseClass =
+ facade.findClass(
+ AndroidUtils.ACTIVITY_BASE_CLASS_NAME, ProjectScope.getAllScope(project));
+ if (activityBaseClass == null) {
+ Messages.showErrorDialog(
+ panel, AndroidBundle.message("cant.find.activity.class.error"));
+ return;
+ }
+ GlobalSearchScope searchScope = GlobalSearchScope.projectScope(project);
+ PsiClass initialSelection =
+ facade.findClass(activityField.getChildComponent().getText(), searchScope);
+ TreeClassChooser chooser =
+ TreeClassChooserFactory.getInstance(project)
+ .createInheritanceClassChooser(
+ "Select Activity Class",
+ searchScope,
+ activityBaseClass,
+ initialSelection,
+ null);
+ chooser.showDialog();
+ PsiClass selClass = chooser.getSelected();
+ if (selClass != null) {
+ // This must be done because Android represents
+ // inner static class paths differently than java.
+ String qualifiedActivityName =
+ ActivityLocatorUtils.getQualifiedActivityName(selClass);
+ activityField.getChildComponent().setText(qualifiedActivityName);
+ }
+ }
+ });
ActionListener listener = e -> activityField.setEnabled(launchCustomButton.isSelected());
launchCustomButton.addActionListener(listener);
launchDefaultButton.addActionListener(listener);
@@ -117,48 +134,64 @@
instantRunCheckBox.setVisible(InstantRunExperiment.INSTANT_RUN_ENABLED.getValue());
- /**
- * Only one of mobile-install and instant run can be selected at any one time
- */
- mobileInstallCheckBox.addActionListener(e -> {
- if (mobileInstallCheckBox.isSelected()) {
- instantRunCheckBox.setSelected(false);
- }
- });
- instantRunCheckBox.addActionListener(e -> {
- if (instantRunCheckBox.isSelected()) {
- mobileInstallCheckBox.setSelected(false);
- }
- });
+ /** Only one of mobile-install and instant run can be selected at any one time */
+ mobileInstallCheckBox.addActionListener(
+ e -> {
+ if (mobileInstallCheckBox.isSelected()) {
+ instantRunCheckBox.setSelected(false);
+ }
+ });
+ instantRunCheckBox.addActionListener(
+ e -> {
+ if (instantRunCheckBox.isSelected()) {
+ mobileInstallCheckBox.setSelected(false);
+ }
+ });
- mobileInstallCheckBox.addActionListener(e -> splitApksCheckBox.setVisible(mobileInstallCheckBox.isSelected()));
+ mobileInstallCheckBox.addActionListener(
+ e -> splitApksCheckBox.setVisible(mobileInstallCheckBox.isSelected()));
+
+ useWorkProfileIfPresentCheckBox.addActionListener(
+ e -> {
+ setUserIdEnabled(!useWorkProfileIfPresentCheckBox.isSelected());
+ });
}
@Override
- public void resetFrom(BlazeAndroidBinaryRunConfiguration configuration) {
- BlazeAndroidBinaryRunConfigurationState configState = configuration.getConfigState();
- boolean launchSpecificActivity = configState.MODE.equals(BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY);
- if (configState.MODE.equals(BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY)) {
+ public void resetEditorFrom(BlazeAndroidRunConfigurationState state) {
+ BlazeAndroidBinaryRunConfigurationState configState =
+ (BlazeAndroidBinaryRunConfigurationState) state;
+ boolean launchSpecificActivity =
+ configState
+ .getMode()
+ .equals(BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY);
+ if (configState
+ .getMode()
+ .equals(BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY)) {
launchDefaultButton.setSelected(true);
- }
- else if (launchSpecificActivity) {
+ } else if (launchSpecificActivity) {
launchCustomButton.setSelected(true);
- }
- else {
+ } else {
launchNothingButton.setSelected(true);
}
activityField.setEnabled(launchSpecificActivity);
if (launchSpecificActivity) {
- activityField.getChildComponent().setText(configState.ACTIVITY_CLASS);
+ activityField.getChildComponent().setText(configState.getActivityClass());
}
- mobileInstallCheckBox.setSelected(configState.isMobileInstall());
- splitApksCheckBox.setSelected(configState.isUseSplitApksIfPossible());
- instantRunCheckBox.setSelected(configState.isInstantRun());
+ mobileInstallCheckBox.setSelected(configState.mobileInstall());
+ splitApksCheckBox.setSelected(configState.useSplitApksIfPossible());
+ instantRunCheckBox.setSelected(configState.instantRun());
+ useWorkProfileIfPresentCheckBox.setSelected(configState.useWorkProfileIfPresent());
- userIdField.setEnabled(!configState.MODE.equals(BlazeAndroidBinaryRunConfigurationState.DO_NOTHING));
- userIdField.setValue(LaunchUtils.getUserIdFromFlags(configState.ACTIVITY_EXTRA_FLAGS));
- splitApksCheckBox.setVisible(configState.isMobileInstall());
+ userIdField.setValue(configState.getUserId());
+ setUserIdEnabled(!configState.useWorkProfileIfPresent());
+ splitApksCheckBox.setVisible(configState.mobileInstall());
+ }
+
+ private void setUserIdEnabled(boolean enabled) {
+ userIdLabel.setEnabled(enabled);
+ userIdField.setEnabled(enabled);
}
@Override
@@ -167,121 +200,291 @@
}
@Override
- public void applyTo(BlazeAndroidBinaryRunConfiguration configuration) {
- BlazeAndroidBinaryRunConfigurationState configState = configuration.getConfigState();
- configState.ACTIVITY_EXTRA_FLAGS = getFlagsFromUserId((Number)userIdField.getValue());
+ public void applyEditorTo(BlazeAndroidRunConfigurationState state) {
+ BlazeAndroidBinaryRunConfigurationState configState =
+ (BlazeAndroidBinaryRunConfigurationState) state;
+ configState.setUserId((Integer) userIdField.getValue());
if (launchDefaultButton.isSelected()) {
- configState.MODE = BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY;
- }
- else if (launchCustomButton.isSelected()) {
- configState.MODE = BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY;
- configState.ACTIVITY_CLASS = activityField.getChildComponent().getText();
- }
- else {
- configState.MODE = BlazeAndroidBinaryRunConfigurationState.DO_NOTHING;
+ configState.setMode(BlazeAndroidBinaryRunConfigurationState.LAUNCH_DEFAULT_ACTIVITY);
+ } else if (launchCustomButton.isSelected()) {
+ configState.setMode(BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY);
+ configState.setActivityClass(activityField.getChildComponent().getText());
+ } else {
+ configState.setMode(BlazeAndroidBinaryRunConfigurationState.DO_NOTHING);
}
configState.setMobileInstall(mobileInstallCheckBox.isSelected());
configState.setUseSplitApksIfPossible(splitApksCheckBox.isSelected());
configState.setInstantRun(instantRunCheckBox.isSelected());
- }
-
- @Override
- public JComponent getAnchor() {
- return null;
- }
-
- @Override
- public void setAnchor(JComponent anchor) {
+ configState.setUseWorkProfileIfPresent(useWorkProfileIfPresentCheckBox.isSelected());
}
private void createUIComponents() {
- final EditorTextField editorTextField = new LanguageTextField(PlainTextLanguage.INSTANCE,
- project, "") {
- @Override
- protected EditorEx createEditor() {
- final EditorEx editor = super.createEditor();
- final PsiFile file =
- PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+ final EditorTextField editorTextField =
+ new LanguageTextField(PlainTextLanguage.INSTANCE, project, "") {
+ @Override
+ protected EditorEx createEditor() {
+ final EditorEx editor = super.createEditor();
+ final PsiFile file =
+ PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
- if (file != null) {
- DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(file, false);
- }
- editor.putUserData(ACTIVITY_CLASS_TEXT_FIELD_KEY, BlazeAndroidBinaryRunConfigurationStateEditor.this);
- return editor;
- }
- };
+ if (file != null) {
+ DaemonCodeAnalyzer.getInstance(project).setHighlightingEnabled(file, false);
+ }
+ editor.putUserData(
+ ACTIVITY_CLASS_TEXT_FIELD_KEY, BlazeAndroidBinaryRunConfigurationStateEditor.this);
+ return editor;
+ }
+ };
activityField = new ComponentWithBrowseButton<EditorTextField>(editorTextField, null);
}
- @NotNull
- private static String getFlagsFromUserId(@Nullable Number userId) {
- return userId != null ? ("--user " + userId.intValue()) : "";
- }
-
- /**
- * Initially generated by IntelliJ from a .form file, then checked in as source.
- */
+ /** Initially generated by IntelliJ from a .form file, then checked in as source. */
private void setupUI() {
createUIComponents();
panel = new JPanel();
- panel.setLayout(new GridLayoutManager(4, 2, new Insets(0, 0, 0, 0), -1, -1));
- final JPanel panel1 = new JPanel();
- panel1.setLayout(new GridLayoutManager(4, 2, new Insets(0, 0, 0, 0), -1, -1));
- panel.add(panel1, new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0,
- false));
- panel1.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Activity", TitledBorder.DEFAULT_JUSTIFICATION,
- TitledBorder.DEFAULT_POSITION,
- new Font(panel1.getFont().getName(), panel1.getFont().getStyle(),
- panel1.getFont().getSize()), new Color(-16777216)));
+ panel.setLayout(new GridLayoutManager(5, 2, new Insets(0, 0, 0, 0), -1, -1));
+ final JPanel activityPanel = new JPanel();
+ activityPanel.setLayout(new GridLayoutManager(4, 2, new Insets(0, 0, 0, 0), -1, -1));
+ panel.add(
+ activityPanel,
+ new GridConstraints(
+ 3,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ activityPanel.setBorder(
+ BorderFactory.createTitledBorder(
+ BorderFactory.createEtchedBorder(),
+ "Activity",
+ TitledBorder.DEFAULT_JUSTIFICATION,
+ TitledBorder.DEFAULT_POSITION,
+ new Font(
+ activityPanel.getFont().getName(),
+ activityPanel.getFont().getStyle(),
+ activityPanel.getFont().getSize()),
+ new Color(-16777216)));
+ final JPanel userPanel = new JPanel();
+ userPanel.setLayout(new GridLayoutManager(2, 2, new Insets(0, 0, 0, 0), -1, -1));
+ panel.add(
+ userPanel,
+ new GridConstraints(
+ 4,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ userPanel.setBorder(
+ BorderFactory.createTitledBorder(
+ BorderFactory.createEtchedBorder(),
+ "User",
+ TitledBorder.DEFAULT_JUSTIFICATION,
+ TitledBorder.DEFAULT_POSITION,
+ new Font(
+ userPanel.getFont().getName(),
+ userPanel.getFont().getStyle(),
+ userPanel.getFont().getSize()),
+ new Color(-16777216)));
launchNothingButton = new JRadioButton();
- this.loadButtonText(launchNothingButton,
- ResourceBundle.getBundle("messages/AndroidBundle").getString("android.run.configuration.do.nothing.label"));
- panel1.add(launchNothingButton, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ this.loadButtonText(
+ launchNothingButton,
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.do.nothing.label"));
+ activityPanel.add(
+ launchNothingButton,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
launchDefaultButton = new JRadioButton();
launchDefaultButton.setText("Launch default Activity");
launchDefaultButton.setMnemonic('L');
launchDefaultButton.setDisplayedMnemonicIndex(0);
- panel1.add(launchDefaultButton, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ activityPanel.add(
+ launchDefaultButton,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
launchCustomButton = new JRadioButton();
launchCustomButton.setText("Launch:");
launchCustomButton.setMnemonic('A');
launchCustomButton.setDisplayedMnemonicIndex(1);
- panel1.add(launchCustomButton,
- new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- panel1.add(activityField, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- final JLabel label1 = new JLabel();
- label1.setText("User ID");
- panel1.add(label1,
- new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1, false));
+ activityPanel.add(
+ launchCustomButton,
+ new GridConstraints(
+ 2,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ activityPanel.add(
+ activityField,
+ new GridConstraints(
+ 2,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_BOTH,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ useWorkProfileIfPresentCheckBox = new JCheckBox();
+ useWorkProfileIfPresentCheckBox.setText(" Use work profile if present");
+ userPanel.add(
+ useWorkProfileIfPresentCheckBox,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ userIdLabel = new JLabel();
+ userIdLabel.setText("User ID");
+ userPanel.add(
+ userIdLabel,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 1,
+ false));
userIdField = new IntegerTextField();
- panel1.add(userIdField, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0,
- false));
+ userPanel.add(
+ userIdField,
+ new GridConstraints(
+ 1,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
mobileInstallCheckBox = new JCheckBox();
- mobileInstallCheckBox.setText(" Use blaze mobile-install (go/as-mi)");
- panel.add(mobileInstallCheckBox, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ mobileInstallCheckBox.setText(" Use mobile-install");
+ panel.add(
+ mobileInstallCheckBox,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
splitApksCheckBox = new JCheckBox();
splitApksCheckBox.setText(" Use --split_apks where possible");
- panel.add(splitApksCheckBox, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ panel.add(
+ splitApksCheckBox,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
instantRunCheckBox = new JCheckBox();
instantRunCheckBox.setText(" Use InstantRun");
- panel.add(instantRunCheckBox, new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ panel.add(
+ instantRunCheckBox,
+ new GridConstraints(
+ 2,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
ButtonGroup buttonGroup;
buttonGroup = new ButtonGroup();
buttonGroup.add(launchDefaultButton);
@@ -289,9 +492,7 @@
buttonGroup.add(launchNothingButton);
}
- /**
- * Initially generated by IntelliJ from a .form file.
- */
+ /** Initially generated by IntelliJ from a .form file. */
private void loadButtonText(AbstractButton component, String text) {
StringBuffer result = new StringBuffer();
boolean haveMnemonic = false;
@@ -300,7 +501,9 @@
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == '&') {
i++;
- if (i == text.length()) break;
+ if (i == text.length()) {
+ break;
+ }
if (!haveMnemonic && text.charAt(i) != '&') {
haveMnemonic = true;
mnemonic = text.charAt(i);
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationType.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationType.java
index d4f9e6a..bfc5a02 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationType.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationType.java
@@ -15,57 +15,54 @@
*/
package com.google.idea.blaze.android.run.binary;
-import com.google.idea.blaze.android.run.BlazeBeforeRunTaskProvider;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.intellij.execution.BeforeRunTask;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.configurations.ConfigurationTypeUtil;
+import com.intellij.execution.configurations.UnknownConfigurationType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import icons.AndroidIcons;
+import javax.swing.Icon;
import org.jetbrains.annotations.NotNull;
-import javax.swing.*;
-
/**
* A type for Android application run configurations adapted specifically to run android_binary
* targets.
+ *
+ * @deprecated See {@link com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType}. Retained
+ * in 1.9 for legacy purposes, to allow existing BlazeAndroidBinaryRunConfigurations to be
+ * updated to BlazeCommandRunConfigurations. Intended to be removed in 2.1.
*/
-public class BlazeAndroidBinaryRunConfigurationType implements ConfigurationType {
+// Hack: extend UnknownConfigurationType to completely hide it in the Run/Debug Configurations UI.
+@Deprecated
+public class BlazeAndroidBinaryRunConfigurationType extends UnknownConfigurationType {
private final BlazeAndroidBinaryRunConfigurationFactory factory =
- new BlazeAndroidBinaryRunConfigurationFactory(this);
+ new BlazeAndroidBinaryRunConfigurationFactory(this);
- public static class BlazeAndroidBinaryRuleConfigurationFactory implements BlazeRuleConfigurationFactory {
- @Override
- public boolean handlesRule(WorkspaceLanguageSettings workspaceLanguageSettings, @NotNull RuleIdeInfo rule) {
- return rule.kindIsOneOf(Kind.ANDROID_BINARY);
- }
-
- @Override
- @NotNull
- public RunnerAndConfigurationSettings createForRule(@NotNull RunManager runManager, @NotNull RuleIdeInfo rule) {
- return getInstance().factory.createForRule(runManager, rule);
- }
- }
-
- public static class BlazeAndroidBinaryRunConfigurationFactory
- extends ConfigurationFactory {
+ static class BlazeAndroidBinaryRunConfigurationFactory extends ConfigurationFactory {
protected BlazeAndroidBinaryRunConfigurationFactory(@NotNull ConfigurationType type) {
super(type);
}
@Override
+ public String getName() {
+ // Used to look up this ConfigurationFactory.
+ // Preserve value so legacy configurations can be loaded.
+ return Blaze.defaultBuildSystemName() + " Android Binary";
+ }
+
+ @Override
@NotNull
- public BlazeAndroidBinaryRunConfiguration createTemplateConfiguration(@NotNull Project project) {
- return new BlazeAndroidBinaryRunConfiguration(project, this);
+ public BlazeCommandRunConfiguration createTemplateConfiguration(@NotNull Project project) {
+ // Create a BlazeCommandRunConfiguration instead, to update legacy configurations.
+ return BlazeCommandRunConfigurationType.getInstance()
+ .getFactory()
+ .createTemplateConfiguration(project);
}
@Override
@@ -75,23 +72,13 @@
@Override
public boolean isApplicable(@NotNull Project project) {
- return Blaze.isBlazeProject(project);
+ return false;
}
@Override
public void configureBeforeRunTaskDefaults(
- Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
- task.setEnabled(providerID.equals(BlazeBeforeRunTaskProvider.ID));
- }
-
- @NotNull
- public RunnerAndConfigurationSettings createForRule(@NotNull RunManager runManager, @NotNull RuleIdeInfo rule) {
- final RunnerAndConfigurationSettings settings =
- runManager.createRunConfiguration(rule.label.toString(), this);
- final BlazeAndroidBinaryRunConfiguration configuration =
- (BlazeAndroidBinaryRunConfiguration) settings.getConfiguration();
- configuration.setTarget(rule.label);
- return settings;
+ Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
+ // Removed BlazeAndroidBeforeRunTaskProvider; this method won't be called anymore anyhow.
}
@Override
@@ -102,19 +89,20 @@
@NotNull
public static BlazeAndroidBinaryRunConfigurationType getInstance() {
- return
- ConfigurationTypeUtil.findConfigurationType(BlazeAndroidBinaryRunConfigurationType.class);
+ return ConfigurationTypeUtil.findConfigurationType(
+ BlazeAndroidBinaryRunConfigurationType.class);
}
@Override
@NotNull
public String getDisplayName() {
- return Blaze.defaultBuildSystemName() + " Android Binary";
+ return "Legacy " + Blaze.defaultBuildSystemName() + " Android Binary";
}
@Override
public String getConfigurationTypeDescription() {
- return "Launch/debug configuration for android_binary rules";
+ return "Launch/debug configuration for android_binary rules. "
+ + "Use Blaze Command instead; this legacy configuration type is being removed.";
}
@Override
@@ -125,11 +113,13 @@
@Override
@NotNull
public String getId() {
+ // Used to look up this ConfigurationType.
+ // Preserve value so legacy configurations can be loaded.
return "BlazeAndroidBinaryRunConfigurationType";
}
@Override
public BlazeAndroidBinaryRunConfigurationFactory[] getConfigurationFactories() {
- return new BlazeAndroidBinaryRunConfigurationFactory[]{factory};
+ return new BlazeAndroidBinaryRunConfigurationFactory[] {factory};
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeDefaultActivityLocator.java b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeDefaultActivityLocator.java
index 0891fb8..d6fcd4a 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeDefaultActivityLocator.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeDefaultActivityLocator.java
@@ -22,11 +22,10 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
+import java.io.File;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.annotations.NotNull;
-import java.io.File;
-
/**
* An activity launcher which extracts the default launch activity from a generated APK and starts
* it.
@@ -35,17 +34,13 @@
private final Project project;
private final File mergedManifestFile;
- public BlazeDefaultActivityLocator(
- Project project,
- File mergedManifestFile
- ) {
+ public BlazeDefaultActivityLocator(Project project, File mergedManifestFile) {
this.project = project;
this.mergedManifestFile = mergedManifestFile;
}
@Override
- public void validate() throws ActivityLocatorException {
- }
+ public void validate() throws ActivityLocatorException {}
@NotNull
@Override
@@ -54,9 +49,11 @@
if (manifest == null) {
throw new ActivityLocatorException("Could not locate merged manifest");
}
- String activityName = ApplicationManager.getApplication().runReadAction(
- (Computable<String>)() -> DefaultActivityLocator.getDefaultLauncherActivityName(project, manifest)
- );
+ String activityName =
+ ApplicationManager.getApplication()
+ .runReadAction(
+ (Computable<String>)
+ () -> DefaultActivityLocator.getDefaultLauncherActivityName(project, manifest));
if (activityName == null) {
throw new ActivityLocatorException("Could not locate default activity to launch.");
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/UserIdHelper.java b/aswb/src/com/google/idea/blaze/android/run/binary/UserIdHelper.java
new file mode 100644
index 0000000..0ca4ec5
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/UserIdHelper.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run.binary;
+
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.CollectingOutputReceiver;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.ShellCommandUnresponsiveException;
+import com.android.ddmlib.TimeoutException;
+import com.android.tools.idea.run.ConsolePrinter;
+import com.intellij.execution.ExecutionException;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** Helpers for user id */
+public final class UserIdHelper {
+ private static final Pattern USER_ID_REGEX =
+ Pattern.compile("UserInfo\\{([0-9]+):Work profile:[0-9]+\\}");
+
+ @Nullable
+ public static Integer getUserIdFromConfigurationState(
+ IDevice device, ConsolePrinter consolePrinter, BlazeAndroidBinaryRunConfigurationState state)
+ throws ExecutionException {
+ if (state.useWorkProfileIfPresent()) {
+ try {
+ Integer userId = getWorkProfileId(device);
+ if (userId == null) {
+ consolePrinter.stderr(
+ "Could not locate work profile on selected device. Launching default user.\n");
+ }
+ return userId;
+ } catch (TimeoutException
+ | AdbCommandRejectedException
+ | ShellCommandUnresponsiveException
+ | IOException e) {
+ throw new ExecutionException(e);
+ }
+ }
+ return state.getUserId();
+ }
+
+ @Nullable
+ public static Integer getWorkProfileId(IDevice device)
+ throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException,
+ IOException {
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ device.executeShellCommand("pm list users", receiver);
+ String result = receiver.getOutput();
+ Matcher matcher = USER_ID_REGEX.matcher(result);
+ if (matcher.find()) {
+ return Integer.parseInt(matcher.group(1));
+ }
+ return null;
+ }
+
+ public static String getFlagsFromUserId(@Nullable Integer userId) {
+ return userId != null ? ("--user " + userId.intValue()) : "";
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeAndroidBinaryInstantRunContext.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeAndroidBinaryInstantRunContext.java
index 4d260c0..f365e5d 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeAndroidBinaryInstantRunContext.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeAndroidBinaryInstantRunContext.java
@@ -19,6 +19,7 @@
import com.android.tools.idea.fd.InstantRunBuildAnalyzer;
import com.android.tools.idea.fd.InstantRunUtils;
import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.ConsolePrinter;
import com.android.tools.idea.run.ConsoleProvider;
import com.android.tools.idea.run.LaunchOptions;
import com.android.tools.idea.run.activity.DefaultStartActivityFlagsProvider;
@@ -32,27 +33,27 @@
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryApplicationLaunchTaskProvider;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryConsoleProvider;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryRunConfigurationState;
-import com.google.idea.blaze.android.run.runner.*;
+import com.google.idea.blaze.android.run.binary.UserIdHelper;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidLaunchTasksProvider;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationDebuggerManager;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.android.run.runner.BlazeApkBuildStep;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import java.util.Set;
+import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
-import javax.annotation.Nullable;
-import java.util.Set;
-
-/**
- * Run context for InstantRun.
- */
+/** Run context for InstantRun. */
public class BlazeAndroidBinaryInstantRunContext implements BlazeAndroidRunContext {
- private static final Logger LOG = Logger.getInstance(BlazeAndroidBinaryInstantRunContext.class);
private final Project project;
private final AndroidFacet facet;
@@ -63,20 +64,21 @@
private final BlazeAndroidBinaryConsoleProvider consoleProvider;
private final BlazeApkBuildStepInstantRun buildStep;
- public BlazeAndroidBinaryInstantRunContext(Project project,
- AndroidFacet facet,
- RunConfiguration runConfiguration,
- ExecutionEnvironment env,
- BlazeAndroidRunConfigurationCommonState commonState,
- BlazeAndroidBinaryRunConfigurationState configState,
- ImmutableList<String> buildFlags) {
+ public BlazeAndroidBinaryInstantRunContext(
+ Project project,
+ AndroidFacet facet,
+ RunConfiguration runConfiguration,
+ ExecutionEnvironment env,
+ BlazeAndroidBinaryRunConfigurationState configState,
+ Label label,
+ ImmutableList<String> buildFlags) {
this.project = project;
this.facet = facet;
this.runConfiguration = runConfiguration;
this.env = env;
this.configState = configState;
this.consoleProvider = new BlazeAndroidBinaryConsoleProvider(project);
- this.buildStep = new BlazeApkBuildStepInstantRun(project, env, commonState, buildFlags);
+ this.buildStep = new BlazeApkBuildStepInstantRun(project, env, label, buildFlags);
}
@Override
@@ -91,10 +93,7 @@
@Override
public void augmentLaunchOptions(@NotNull LaunchOptions.Builder options) {
- options
- .setDeploy(true)
- .setPmInstallOptions(configState.ACTIVITY_EXTRA_FLAGS)
- .setOpenLogcatAutomatically(true);
+ options.setDeploy(true).setOpenLogcatAutomatically(true);
}
@NotNull
@@ -115,59 +114,77 @@
@Override
public LaunchTasksProvider getLaunchTasksProvider(
- LaunchOptions launchOptions,
- BlazeAndroidRunConfigurationDebuggerManager debuggerManager) throws ExecutionException {
- InstantRunBuildAnalyzer analyzer = Futures.get(buildStep.getInstantRunBuildAnalyzer(), ExecutionException.class);
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidRunConfigurationDebuggerManager debuggerManager)
+ throws ExecutionException {
+ InstantRunBuildAnalyzer analyzer =
+ Futures.get(buildStep.getInstantRunBuildAnalyzer(), ExecutionException.class);
if (analyzer.canReuseProcessHandler()) {
return new UpdateSessionTasksProvider(analyzer);
}
- return new BlazeAndroidLaunchTasksProvider(project, this, getApplicationIdProvider(), launchOptions, debuggerManager);
+ return new BlazeAndroidLaunchTasksProvider(
+ project, this, getApplicationIdProvider(), launchOptionsBuilder, isDebug, debuggerManager);
}
@Override
- public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions) throws ExecutionException {
- InstantRunBuildAnalyzer analyzer = Futures.get(buildStep.getInstantRunBuildAnalyzer(), ExecutionException.class);
+ public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions)
+ throws ExecutionException {
+ InstantRunBuildAnalyzer analyzer =
+ Futures.get(buildStep.getInstantRunBuildAnalyzer(), ExecutionException.class);
return ImmutableList.<LaunchTask>builder()
- .addAll(analyzer.getDeployTasks(launchOptions))
- .add(analyzer.getNotificationTask())
- .build();
+ .addAll(analyzer.getDeployTasks(launchOptions))
+ .add(analyzer.getNotificationTask())
+ .build();
}
@Nullable
@Override
- public LaunchTask getApplicationLaunchTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- ProcessHandlerLaunchStatus processHandlerLaunchStatus) throws ExecutionException {
- BlazeApkBuildStepInstantRun.BuildResult buildResult = Futures.get(buildStep.getBuildResult(), ExecutionException.class);
+ public LaunchTask getApplicationLaunchTask(
+ LaunchOptions launchOptions,
+ @Nullable Integer userId,
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus)
+ throws ExecutionException {
+ BlazeApkBuildStepInstantRun.BuildResult buildResult =
+ Futures.get(buildStep.getBuildResult(), ExecutionException.class);
- final StartActivityFlagsProvider startActivityFlagsProvider = new DefaultStartActivityFlagsProvider(
- androidDebugger,
- androidDebuggerState,
- project,
- launchOptions.isDebug(),
- configState.ACTIVITY_EXTRA_FLAGS
- );
+ final StartActivityFlagsProvider startActivityFlagsProvider =
+ new DefaultStartActivityFlagsProvider(
+ androidDebugger,
+ androidDebuggerState,
+ project,
+ launchOptions.isDebug(),
+ UserIdHelper.getFlagsFromUserId(userId));
ApplicationIdProvider applicationIdProvider = getApplicationIdProvider();
return BlazeAndroidBinaryApplicationLaunchTaskProvider.getApplicationLaunchTask(
- project,
- applicationIdProvider,
- buildResult.mergedManifestFile,
- configState,
- startActivityFlagsProvider,
- processHandlerLaunchStatus
- );
+ project,
+ applicationIdProvider,
+ buildResult.mergedManifestFile,
+ configState,
+ startActivityFlagsProvider,
+ processHandlerLaunchStatus);
}
@Nullable
@Override
- public DebugConnectorTask getDebuggerTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- Set<String> packageIds) throws ExecutionException {
+ public DebugConnectorTask getDebuggerTask(
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ Set<String> packageIds)
+ throws ExecutionException {
//noinspection unchecked
- return androidDebugger.getConnectDebuggerTask(env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
+ return androidDebugger.getConnectDebuggerTask(
+ env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
+ }
+
+ @Nullable
+ @Override
+ public Integer getUserId(IDevice device, ConsolePrinter consolePrinter)
+ throws ExecutionException {
+ return UserIdHelper.getUserIdFromConfigurationState(device, consolePrinter, configState);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeApkBuildStepInstantRun.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeApkBuildStepInstantRun.java
index 46ca755..75821b1 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeApkBuildStepInstantRun.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeApkBuildStepInstantRun.java
@@ -16,16 +16,24 @@
package com.google.idea.blaze.android.run.binary.instantrun;
import com.android.ddmlib.IDevice;
-import com.android.tools.idea.fd.*;
+import com.android.tools.idea.fd.InstantRunBuildAnalyzer;
+import com.android.tools.idea.fd.InstantRunBuilder;
+import com.android.tools.idea.fd.InstantRunContext;
+import com.android.tools.idea.fd.InstantRunUtils;
+import com.android.tools.idea.fd.RunAsValidityService;
import com.android.tools.idea.gradle.run.MakeBeforeRunTaskProvider;
-import com.android.tools.idea.run.*;
+import com.android.tools.idea.run.AndroidDevice;
+import com.android.tools.idea.run.AndroidRunConfigContext;
+import com.android.tools.idea.run.AndroidSessionInfo;
+import com.android.tools.idea.run.ApkProvisionException;
+import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.DeviceFutures;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.google.idea.blaze.android.manifest.ManifestParser;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
import com.google.idea.blaze.android.run.runner.BlazeApkBuildStep;
import com.google.idea.blaze.base.async.executor.BlazeExecutor;
@@ -36,8 +44,10 @@
import com.google.idea.blaze.base.command.BlazeFlags;
import com.google.idea.blaze.base.command.ExperimentalShowArtifactsLineProcessor;
import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.ScopedTask;
@@ -51,74 +61,82 @@
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
-/**
- * Builds the APK using normal blaze build.
- */
+/** Builds the APK using normal blaze build. */
class BlazeApkBuildStepInstantRun implements BlazeApkBuildStep {
private static final Logger LOG = Logger.getInstance(BlazeApkBuildStepInstantRun.class);
private final Project project;
private final Executor executor;
private final ExecutionEnvironment env;
- private final BlazeAndroidRunConfigurationCommonState commonState;
+ private final Label label;
private final ImmutableList<String> buildFlags;
private final File instantRunArtifactDirectory;
private final File instantRunGradleBuildFile;
private final File instantRunBuildInfoFile;
private final File instantRunGradlePropertiesFile;
-
public static class BuildResult {
public final File executionRoot;
public final File mergedManifestFile;
public final File apkManifestProtoFile;
public final ApkManifestOuterClass.ApkManifest apkManifestProto;
- public BuildResult(File executionRoot,
- File mergedManifestFile,
- File apkManifestProtoFile,
- ApkManifestOuterClass.ApkManifest apkManifestProto) {
+
+ public BuildResult(
+ File executionRoot,
+ File mergedManifestFile,
+ File apkManifestProtoFile,
+ ApkManifestOuterClass.ApkManifest apkManifestProto) {
this.executionRoot = executionRoot;
this.mergedManifestFile = mergedManifestFile;
this.apkManifestProtoFile = apkManifestProtoFile;
this.apkManifestProto = apkManifestProto;
}
}
- private final SettableFuture<BuildResult> buildResultFuture = SettableFuture.create();
- private final SettableFuture<ApplicationIdProvider> applicationIdProviderFuture = SettableFuture.create();
- private final SettableFuture<InstantRunContext> instantRunContextFuture = SettableFuture.create();
- private final SettableFuture<InstantRunBuildAnalyzer> instantRunBuildAnalyzerFuture = SettableFuture.create();
- public BlazeApkBuildStepInstantRun(Project project,
- ExecutionEnvironment env,
- BlazeAndroidRunConfigurationCommonState commonState,
- ImmutableList<String> buildFlags) {
+ private final SettableFuture<BuildResult> buildResultFuture = SettableFuture.create();
+ private final SettableFuture<ApplicationIdProvider> applicationIdProviderFuture =
+ SettableFuture.create();
+ private final SettableFuture<InstantRunContext> instantRunContextFuture = SettableFuture.create();
+ private final SettableFuture<InstantRunBuildAnalyzer> instantRunBuildAnalyzerFuture =
+ SettableFuture.create();
+
+ public BlazeApkBuildStepInstantRun(
+ Project project, ExecutionEnvironment env, Label label, ImmutableList<String> buildFlags) {
this.project = project;
this.executor = env.getExecutor();
this.env = env;
- this.commonState = commonState;
+ this.label = label;
this.buildFlags = buildFlags;
- this.instantRunArtifactDirectory = BlazeInstantRunGradleIntegration.getInstantRunArtifactDirectory(project, commonState.getTarget());
- this.instantRunBuildInfoFile = new File(instantRunArtifactDirectory, "build/reload-dex/debug/build-info.xml");
+ this.instantRunArtifactDirectory =
+ BlazeInstantRunGradleIntegration.getInstantRunArtifactDirectory(project, label);
+ this.instantRunBuildInfoFile =
+ new File(instantRunArtifactDirectory, "build/reload-dex/debug/build-info.xml");
this.instantRunGradleBuildFile = new File(instantRunArtifactDirectory, "build.gradle");
- this.instantRunGradlePropertiesFile = new File(instantRunArtifactDirectory, "gradle.properties");
+ this.instantRunGradlePropertiesFile =
+ new File(instantRunArtifactDirectory, "gradle.properties");
}
@Override
- public boolean build(BlazeContext context, BlazeAndroidDeviceSelector.DeviceSession deviceSession) {
+ public boolean build(
+ BlazeContext context, BlazeAndroidDeviceSelector.DeviceSession deviceSession) {
if (!instantRunArtifactDirectory.exists() && !instantRunArtifactDirectory.mkdirs()) {
- IssueOutput.error("Could not create instant run artifact directory: " + instantRunArtifactDirectory).submit(context);
+ IssueOutput.error(
+ "Could not create instant run artifact directory: " + instantRunArtifactDirectory)
+ .submit(context);
return false;
}
@@ -132,18 +150,16 @@
return false;
}
- ApplicationIdProvider applicationIdProvider = new BlazeInstantRunApplicationIdProvider(project, buildResult);
+ ApplicationIdProvider applicationIdProvider =
+ new BlazeInstantRunApplicationIdProvider(project, buildResult);
applicationIdProviderFuture.set(applicationIdProvider);
// Write build.gradle
try (PrintWriter printWriter = new PrintWriter(instantRunGradleBuildFile)) {
- printWriter.print(BlazeInstantRunGradleIntegration.getGradleBuildInfoString(
- gradleUrl,
- buildResult.executionRoot,
- buildResult.apkManifestProtoFile
- ));
- }
- catch (IOException e) {
+ printWriter.print(
+ BlazeInstantRunGradleIntegration.getGradleBuildInfoString(
+ gradleUrl, buildResult.executionRoot, buildResult.apkManifestProtoFile));
+ } catch (IOException e) {
IssueOutput.error("Could not write build.gradle file: " + e).submit(context);
return false;
}
@@ -151,8 +167,7 @@
// Write gradle.properties
try (PrintWriter printWriter = new PrintWriter(instantRunGradlePropertiesFile)) {
printWriter.print(BlazeInstantRunGradleIntegration.getGradlePropertiesString());
- }
- catch (IOException e) {
+ } catch (IOException e) {
IssueOutput.error("Could not write build.gradle file: " + e).submit(context);
return false;
}
@@ -160,8 +175,7 @@
String applicationId = null;
try {
applicationId = applicationIdProvider.getPackageName();
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
return false;
}
@@ -169,78 +183,79 @@
}
private BuildResult buildApkManifest(BlazeContext context) {
- final ScopedTask buildTask = new ScopedTask(context) {
- @Override
- protected void execute(@NotNull BlazeContext context) {
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- String executionRoot = getExecutionRoot(context, workspaceRoot);
- if (executionRoot == null) {
- IssueOutput.error("Could not get execution root").submit(context);
- return;
- }
+ final ScopedTask buildTask =
+ new ScopedTask(context) {
+ @Override
+ protected void execute(@NotNull BlazeContext context) {
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ String executionRoot = getExecutionRoot(context, workspaceRoot);
+ if (executionRoot == null) {
+ IssueOutput.error("Could not get execution root").submit(context);
+ return;
+ }
- BlazeCommand.Builder command = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD);
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD);
- command
- .addTargets(commonState.getTarget())
- .addBlazeFlags(buildFlags)
- .addBlazeFlags("--output_groups=apk_manifest")
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS)
- ;
+ command
+ .addTargets(label)
+ .addBlazeFlags(buildFlags)
+ .addBlazeFlags("--output_groups=apk_manifest")
+ .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS);
- List<File> apkManifestFiles = Lists.newArrayList();
+ List<File> apkManifestFiles = Lists.newArrayList();
- SaveUtil.saveAllFiles();
- int retVal = ExternalTask.builder(workspaceRoot, command.build())
- .context(context)
- .stderr(LineProcessingOutputStream.of(
- new ExperimentalShowArtifactsLineProcessor(apkManifestFiles, "apk_manifest"),
- new IssueOutputLineProcessor(project, context, workspaceRoot)
- ))
- .build()
- .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
- LocalFileSystem.getInstance().refresh(true);
+ SaveUtil.saveAllFiles();
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command.build())
+ .context(context)
+ .stderr(
+ LineProcessingOutputStream.of(
+ new ExperimentalShowArtifactsLineProcessor(
+ apkManifestFiles, "apk_manifest"),
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
+ FileCaches.refresh(project);
- if (retVal != 0) {
- context.setHasError();
- return;
- }
+ if (retVal != 0) {
+ context.setHasError();
+ return;
+ }
- File apkManifestFile = Iterables.getOnlyElement(apkManifestFiles, null);
- if (apkManifestFile == null) {
- IssueOutput.error("Could not find APK manifest file").submit(context);
- return;
- }
+ File apkManifestFile = Iterables.getOnlyElement(apkManifestFiles, null);
+ if (apkManifestFile == null) {
+ IssueOutput.error("Could not find APK manifest file").submit(context);
+ return;
+ }
- ApkManifestOuterClass.ApkManifest apkManifestProto;
- try (InputStream inputStream = new FileInputStream(apkManifestFile)) {
- apkManifestProto = ApkManifestOuterClass.ApkManifest.parseFrom(inputStream);
- }
- catch (IOException e) {
- LOG.error(e);
- IssueOutput.error("Error parsing apk proto").submit(context);
- return;
- }
+ ApkManifestOuterClass.ApkManifest apkManifestProto;
+ try (InputStream inputStream = new FileInputStream(apkManifestFile)) {
+ apkManifestProto = ApkManifestOuterClass.ApkManifest.parseFrom(inputStream);
+ } catch (IOException e) {
+ LOG.error(e);
+ IssueOutput.error("Error parsing apk proto").submit(context);
+ return;
+ }
- // Refresh the manifest
- File mergedManifestFile = new File(executionRoot, apkManifestProto.getAndroidManifest().getExecRootPath());
- ManifestParser.getInstance(project).refreshManifests(ImmutableList.of(mergedManifestFile));
+ // Refresh the manifest
+ File mergedManifestFile =
+ new File(executionRoot, apkManifestProto.getAndroidManifest().getExecRootPath());
+ ManifestParser.getInstance(project)
+ .refreshManifests(ImmutableList.of(mergedManifestFile));
- BuildResult buildResult = new BuildResult(
- new File(executionRoot),
- mergedManifestFile,
- apkManifestFile,
- apkManifestProto
- );
- buildResultFuture.set(buildResult);
- }
- };
+ BuildResult buildResult =
+ new BuildResult(
+ new File(executionRoot), mergedManifestFile, apkManifestFile, apkManifestProto);
+ buildResultFuture.set(buildResult);
+ }
+ };
BlazeExecutor.submitTask(
- project,
- String.format("Executing %s apk build", Blaze.buildSystemName(project)),
- buildTask
- );
+ project,
+ String.format("Executing %s apk build", Blaze.buildSystemName(project)),
+ buildTask);
try {
BuildResult buildResult = buildResultFuture.get();
@@ -248,30 +263,25 @@
return null;
}
return buildResult;
- }
- catch (InterruptedException|ExecutionException e) {
+ } catch (InterruptedException | ExecutionException e) {
context.setHasError();
- }
- catch (CancellationException e) {
+ } catch (CancellationException e) {
context.setCancelled();
}
return null;
}
- private boolean invokeGradleIrTasks(BlazeContext context,
- BlazeAndroidDeviceSelector.DeviceSession deviceSession,
- BuildResult buildResult,
- String applicationId) {
- InstantRunContext instantRunContext = new BlazeInstantRunContext(
- project,
- buildResult.apkManifestProto,
- applicationId,
- instantRunBuildInfoFile
- );
+ private boolean invokeGradleIrTasks(
+ BlazeContext context,
+ BlazeAndroidDeviceSelector.DeviceSession deviceSession,
+ BuildResult buildResult,
+ String applicationId) {
+ InstantRunContext instantRunContext =
+ new BlazeInstantRunContext(
+ project, buildResult.apkManifestProto, applicationId, instantRunBuildInfoFile);
instantRunContextFuture.set(instantRunContext);
- ProcessHandler previousSessionProcessHandler = deviceSession.sessionInfo != null
- ? deviceSession.sessionInfo.getProcessHandler()
- : null;
+ ProcessHandler previousSessionProcessHandler =
+ deviceSession.sessionInfo != null ? deviceSession.sessionInfo.getProcessHandler() : null;
DeviceFutures deviceFutures = deviceSession.deviceFutures;
assert deviceFutures != null;
List<AndroidDevice> targetDevices = deviceFutures.getDevices();
@@ -282,42 +292,39 @@
runConfigContext.setTargetDevices(deviceFutures);
AndroidSessionInfo info = deviceSession.sessionInfo;
- runConfigContext.setSameExecutorAsPreviousSession(info != null && executor.getId().equals(info.getExecutorId()));
+ runConfigContext.setSameExecutorAsPreviousSession(
+ info != null && executor.getId().equals(info.getExecutorId()));
runConfigContext.setCleanRerun(InstantRunUtils.isCleanReRun(env));
- InstantRunBuilder instantRunBuilder = new InstantRunBuilder(
- device,
- instantRunContext,
- runConfigContext,
- new BlazeInstantRunTasksProvider(),
- RunAsValidityService.getInstance()
- );
+ InstantRunBuilder instantRunBuilder =
+ new InstantRunBuilder(
+ device,
+ instantRunContext,
+ runConfigContext,
+ new BlazeInstantRunTasksProvider(),
+ RunAsValidityService.getInstance());
try {
List<String> cmdLineArgs = Lists.newArrayList();
cmdLineArgs.addAll(MakeBeforeRunTaskProvider.getDeviceSpecificArguments(targetDevices));
- BlazeInstantRunGradleTaskRunner taskRunner = new BlazeInstantRunGradleTaskRunner(project, context, instantRunGradleBuildFile);
+ BlazeInstantRunGradleTaskRunner taskRunner =
+ new BlazeInstantRunGradleTaskRunner(project, context, instantRunGradleBuildFile);
boolean success = instantRunBuilder.build(taskRunner, cmdLineArgs);
LOG.info("Gradle invocation complete, success = " + success);
if (!success) {
return false;
}
- }
- catch (InvocationTargetException e) {
+ } catch (InvocationTargetException e) {
LOG.info("Unexpected error while launching gradle before run tasks", e);
return false;
- }
- catch (InterruptedException e) {
+ } catch (InterruptedException e) {
LOG.info("Interrupted while launching gradle before run tasks");
Thread.currentThread().interrupt();
return false;
}
- InstantRunBuildAnalyzer analyzer = new InstantRunBuildAnalyzer(
- project,
- instantRunContext,
- previousSessionProcessHandler
- );
+ InstantRunBuildAnalyzer analyzer =
+ new InstantRunBuildAnalyzer(project, instantRunContext, previousSessionProcessHandler);
instantRunBuildAnalyzerFuture.set(analyzer);
return true;
}
@@ -339,19 +346,19 @@
}
private String getExecutionRoot(BlazeContext context, WorkspaceRoot workspaceRoot) {
- ListenableFuture<String> execRootFuture = BlazeInfo.getInstance().runBlazeInfo(
- context, Blaze.getBuildSystem(project),
- workspaceRoot,
- buildFlags,
- BlazeInfo.EXECUTION_ROOT_KEY
- );
+ ListenableFuture<String> execRootFuture =
+ BlazeInfo.getInstance()
+ .runBlazeInfo(
+ context,
+ Blaze.getBuildSystem(project),
+ workspaceRoot,
+ buildFlags,
+ BlazeInfo.EXECUTION_ROOT_KEY);
try {
return execRootFuture.get();
- }
- catch (InterruptedException e) {
+ } catch (InterruptedException e) {
context.setCancelled();
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
LOG.error(e);
context.setHasError();
}
@@ -367,12 +374,10 @@
try {
return device.getLaunchedDevice().get(1, TimeUnit.MILLISECONDS);
- }
- catch (InterruptedException e) {
+ } catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
- }
- catch (ExecutionException | TimeoutException e) {
+ } catch (ExecutionException | TimeoutException e) {
return null;
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunApplicationIdProvider.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunApplicationIdProvider.java
index 7349986..ab1461e 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunApplicationIdProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunApplicationIdProvider.java
@@ -21,21 +21,18 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
+import java.io.File;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.File;
-
-/**
- * Application id provider for blaze instant run.
- */
+/** Application id provider for blaze instant run. */
public class BlazeInstantRunApplicationIdProvider implements ApplicationIdProvider {
private final Project project;
private final BlazeApkBuildStepInstantRun.BuildResult buildResult;
- public BlazeInstantRunApplicationIdProvider(Project project,
- BlazeApkBuildStepInstantRun.BuildResult buildResult) {
+ public BlazeInstantRunApplicationIdProvider(
+ Project project, BlazeApkBuildStepInstantRun.BuildResult buildResult) {
this.project = project;
this.buildResult = buildResult;
}
@@ -43,14 +40,17 @@
@NotNull
@Override
public String getPackageName() throws ApkProvisionException {
- File manifestFile = new File(buildResult.executionRoot, buildResult.apkManifestProto.getAndroidManifest().getExecRootPath());
+ File manifestFile =
+ new File(
+ buildResult.executionRoot,
+ buildResult.apkManifestProto.getAndroidManifest().getExecRootPath());
Manifest manifest = ManifestParser.getInstance(project).getManifest(manifestFile);
if (manifest == null) {
throw new ApkProvisionException("Could not find merged manifest: " + manifestFile);
}
- String applicationId = ApplicationManager.getApplication().runReadAction(
- (Computable<String>)() -> manifest.getPackage().getValue()
- );
+ String applicationId =
+ ApplicationManager.getApplication()
+ .runReadAction((Computable<String>) () -> manifest.getPackage().getValue());
if (applicationId == null) {
throw new ApkProvisionException("No application id in merged manifest: " + manifestFile);
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunContext.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunContext.java
index 2d86199..9ea7c03 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunContext.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunContext.java
@@ -23,18 +23,15 @@
import com.google.repackaged.devtools.build.lib.rules.android.apkmanifest.ApkManifestOuterClass;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
-/**
- * Blaze implementation of instant run context.
- */
+/** Blaze implementation of instant run context. */
public class BlazeInstantRunContext implements InstantRunContext {
private static final Logger LOG = Logger.getInstance(BlazeInstantRunContext.class);
private final Project project;
@@ -43,10 +40,11 @@
private final File instantRunBuildInfoFile;
private BuildSelection buildSelection;
- BlazeInstantRunContext(Project project,
- ApkManifestOuterClass.ApkManifest apkManifest,
- String applicationId,
- File instantRunBuildInfoFile) {
+ BlazeInstantRunContext(
+ Project project,
+ ApkManifestOuterClass.ApkManifest apkManifest,
+ String applicationId,
+ File instantRunBuildInfoFile) {
this.project = project;
this.apkManifest = apkManifest;
this.applicationId = applicationId;
@@ -83,10 +81,12 @@
public InstantRunBuildInfo getInstantRunBuildInfo() {
if (instantRunBuildInfoFile.exists()) {
try {
- String xml = new String(Files.readAllBytes(Paths.get(instantRunBuildInfoFile.getPath())), StandardCharsets.UTF_8);
+ String xml =
+ new String(
+ Files.readAllBytes(Paths.get(instantRunBuildInfoFile.getPath())),
+ StandardCharsets.UTF_8);
return InstantRunBuildInfo.get(xml);
- }
- catch (IOException e) {
+ } catch (IOException e) {
LOG.error(e);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunDeviceSelector.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunDeviceSelector.java
index 0bebd20..8c26fc4 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunDeviceSelector.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunDeviceSelector.java
@@ -20,35 +20,35 @@
import com.android.tools.idea.fd.InstantRunUtils;
import com.android.tools.idea.run.AndroidSessionInfo;
import com.android.tools.idea.run.DeviceFutures;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationDeployTargetManager;
import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationDeployTargetManager;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.project.Project;
+import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * Tries to reuse devices from a previous session.
- */
+/** Tries to reuse devices from a previous session. */
public class BlazeInstantRunDeviceSelector implements BlazeAndroidDeviceSelector {
NormalDeviceSelector normalDeviceSelector = new NormalDeviceSelector();
@Override
- public DeviceSession getDevice(Project project,
- AndroidFacet facet,
- BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager,
- Executor executor,
- ExecutionEnvironment env,
- AndroidSessionInfo info,
- boolean debug,
- int runConfigId) throws ExecutionException {
+ public DeviceSession getDevice(
+ Project project,
+ AndroidFacet facet,
+ BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager,
+ Executor executor,
+ ExecutionEnvironment env,
+ AndroidSessionInfo info,
+ boolean debug,
+ int runConfigId)
+ throws ExecutionException {
DeviceFutures deviceFutures = null;
if (info != null) {
- // if there is an existing previous session, then see if we can detect devices to fast deploy to
+ // if there is an existing previous session,
+ // then see if we can detect devices to fast deploy to
deviceFutures = getFastDeployDevices(executor, info);
if (InstantRunUtils.isReRun(env)) {
@@ -62,27 +62,32 @@
}
// Fall back to normal device selection
- return normalDeviceSelector.getDevice(project, facet, deployTargetManager, executor, env, info, debug, runConfigId);
+ return normalDeviceSelector.getDevice(
+ project, facet, deployTargetManager, executor, env, info, debug, runConfigId);
}
@Nullable
- private static DeviceFutures getFastDeployDevices(Executor executor,
- AndroidSessionInfo info) {
+ private static DeviceFutures getFastDeployDevices(Executor executor, AndroidSessionInfo info) {
if (!info.getExecutorId().equals(executor.getId())) {
- String msg = String.format("Cannot Instant Run since old executor (%1$s) doesn't match current executor (%2$s)", info.getExecutorId(),
- executor.getId());
+ String msg =
+ String.format(
+ "Cannot Instant Run since old executor (%1$s) doesn't match current executor (%2$s)",
+ info.getExecutorId(), executor.getId());
InstantRunManager.LOG.info(msg);
return null;
}
List<IDevice> devices = info.getDevices();
if (devices == null || devices.isEmpty()) {
- InstantRunManager.LOG.info("Cannot Instant Run since we could not locate the devices from the existing launch session");
+ InstantRunManager.LOG.info(
+ "Cannot Instant Run since we could not locate "
+ + "the devices from the existing launch session");
return null;
}
if (devices.size() > 1) {
- InstantRunManager.LOG.info("Last run was on > 1 device, not reusing devices and prompting again");
+ InstantRunManager.LOG.info(
+ "Last run was on > 1 device, not reusing devices and prompting again");
return null;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleIntegration.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleIntegration.java
index c95f42e..a9873ca 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleIntegration.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleIntegration.java
@@ -17,42 +17,39 @@
import com.android.SdkConstants;
import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
import com.google.common.hash.Hashing;
import com.google.idea.blaze.base.async.process.ExternalTask;
import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
import com.google.idea.blaze.base.async.process.PrintOutputLineProcessor;
-import com.google.idea.blaze.base.experiments.DeveloperFlag;
-import com.google.idea.blaze.base.experiments.StringExperiment;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleDataStorage;
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.google.idea.common.experiments.DeveloperFlag;
+import com.google.idea.common.experiments.StringExperiment;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
import java.io.File;
+import javax.annotation.Nullable;
-/**
- * Defines where instant run storage and artifacts go.
- */
+/** Defines where instant run storage and artifacts go. */
class BlazeInstantRunGradleIntegration {
private static final String INSTANT_RUN_SUBDIRECTORY = "instantrun";
- private static StringExperiment LOCAL_GRADLE_VERSION = new StringExperiment("use.local.gradle.version");
- private static DeveloperFlag REBUILD_LOCAL_GRADLE = new DeveloperFlag("rebuild.local.gradle");
+ private static final StringExperiment LOCAL_GRADLE_VERSION =
+ new StringExperiment("use.local.gradle.version");
+ private static final DeveloperFlag REBUILD_LOCAL_GRADLE =
+ new DeveloperFlag("rebuild.local.gradle");
- /**
- * Gets a unique directory for a given target that can be used for the build process.
- */
+ /** Gets a unique directory for a given target that can be used for the build process. */
static File getInstantRunArtifactDirectory(Project project, Label target) {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
assert importSettings != null;
- File dataSubDirectory = new File(importSettings.getProjectDataDirectory(), ModuleDataStorage.DATA_SUBDIRECTORY);
+ File dataSubDirectory = BlazeDataStorage.getProjectDataDir(importSettings);
File instantRunDirectory = new File(dataSubDirectory, INSTANT_RUN_SUBDIRECTORY);
String targetHash = Hashing.md5().hashUnencodedChars(target.toString()).toString();
return new File(instantRunDirectory, targetHash);
@@ -67,14 +64,18 @@
String toolsIdeaPath = PathManager.getHomePath();
File toolsDir = new File(toolsIdeaPath).getParentFile();
File repoDir = toolsDir.getParentFile();
- File localGradleDirectory = new File(new File(repoDir, "out/repo/com/android/tools/build/builder"), localGradleVersion);
+ File localGradleDirectory =
+ new File(
+ new File(repoDir, "out/repo/com/android/tools/build/builder"), localGradleVersion);
if (REBUILD_LOCAL_GRADLE.getValue() || !localGradleDirectory.exists()) {
// Build gradle
- context.output(PrintOutput.output("Building local Gradle..."));
- int retVal = ExternalTask.builder(toolsDir, ImmutableList.of("./gradlew", ":init", ":publishLocal"))
- .stdout(LineProcessingOutputStream.of(new PrintOutputLineProcessor(context)))
- .build()
- .run();
+ context.output(new StatusOutput("Building local Gradle..."));
+ int retVal =
+ ExternalTask.builder(toolsDir)
+ .args("./gradlew", ":init", ":publishLocal")
+ .stdout(LineProcessingOutputStream.of(new PrintOutputLineProcessor(context)))
+ .build()
+ .run();
if (retVal != 0) {
IssueOutput.error("Gradle build failed.").submit(context);
@@ -85,42 +86,41 @@
}
// Not supported yet
- IssueOutput.error("You must specify 'use.local.gradle.version' experiment, non-local gradle not supported yet.").submit(context);
+ IssueOutput.error(
+ "You must specify 'use.local.gradle.version' experiment, "
+ + "non-local gradle not supported yet.")
+ .submit(context);
return null;
}
static String getGradlePropertiesString() {
- return Joiner.on('\n').join(
- "org.gradle.daemon=true",
- "org.gradle.jvmargs=-XX:MaxPermSize=1024m -Xmx4096m"
- );
+ return Joiner.on('\n')
+ .join("org.gradle.daemon=true", "org.gradle.jvmargs=-XX:MaxPermSize=1024m -Xmx4096m");
}
- static String getGradleBuildInfoString(String gradleUrl, File executionRoot, File apkManifestFile) {
- String template = Joiner.on('\n').join(
- "buildscript {",
- " repositories {",
- " jcenter()",
- " maven { url '%s' }",
- " }",
- " dependencies {",
- " classpath 'com.android.tools.build:gradle:%s'",
- " }",
- "}",
- "apply plugin: 'com.android.external.build'",
- "externalBuild {",
- " executionRoot = '%s'",
- " buildManifestPath = '%s'",
- "}"
- );
+ static String getGradleBuildInfoString(
+ String gradleUrl, File executionRoot, File apkManifestFile) {
+ String template =
+ Joiner.on('\n')
+ .join(
+ "buildscript {",
+ " repositories {",
+ " jcenter()",
+ " maven { url '%s' }",
+ " }",
+ " dependencies {",
+ " classpath 'com.android.tools.build:gradle:%s'",
+ " }",
+ "}",
+ "apply plugin: 'com.android.external.build'",
+ "externalBuild {",
+ " executionRoot = '%s'",
+ " buildManifestPath = '%s'",
+ "}");
String gradleVersion = LOCAL_GRADLE_VERSION.getValue();
gradleVersion = gradleVersion != null ? gradleVersion : SdkConstants.GRADLE_LATEST_VERSION;
- return String.format(template,
- gradleUrl,
- gradleVersion,
- executionRoot.getPath(),
- apkManifestFile.getPath()
- );
+ return String.format(
+ template, gradleUrl, gradleVersion, executionRoot.getPath(), apkManifestFile.getPath());
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleTaskRunner.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleTaskRunner.java
index 51554b2..bdeab5a 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleTaskRunner.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunGradleTaskRunner.java
@@ -15,6 +15,9 @@
*/
package com.google.idea.blaze.android.run.binary.instantrun;
+import static com.android.tools.idea.gradle.util.GradleUtil.GRADLE_SYSTEM_ID;
+import static com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType.EXECUTE_TASK;
+
import com.android.builder.model.AndroidProject;
import com.android.tools.idea.gradle.invoker.GradleInvocationResult;
import com.android.tools.idea.gradle.invoker.GradleInvoker;
@@ -30,33 +33,33 @@
import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListenerAdapter;
import com.intellij.openapi.project.Project;
import com.intellij.util.concurrency.Semaphore;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.swing.SwingUtilities;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
-import static com.android.tools.idea.gradle.util.GradleUtil.GRADLE_SYSTEM_ID;
-import static com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskType.EXECUTE_TASK;
-
-public class BlazeInstantRunGradleTaskRunner implements GradleTaskRunner {
+class BlazeInstantRunGradleTaskRunner implements GradleTaskRunner {
private final Project project;
private final BlazeContext context;
private final File instantRunGradleBuildFile;
- public BlazeInstantRunGradleTaskRunner(Project project, BlazeContext context, File instantRunGradleBuildFile) {
+ public BlazeInstantRunGradleTaskRunner(
+ Project project, BlazeContext context, File instantRunGradleBuildFile) {
this.project = project;
this.context = context;
this.instantRunGradleBuildFile = instantRunGradleBuildFile;
}
@Override
- public boolean run(@NotNull List<String> tasks, @Nullable BuildMode buildMode, @NotNull List<String> commandLineArguments)
- throws InvocationTargetException, InterruptedException {
+ public boolean run(
+ @NotNull List<String> tasks,
+ @Nullable BuildMode buildMode,
+ @NotNull List<String> commandLineArguments)
+ throws InvocationTargetException, InterruptedException {
assert !ApplicationManager.getApplication().isDispatchThread();
final GradleInvoker gradleInvoker = GradleInvoker.getInstance(project);
@@ -65,40 +68,47 @@
final Semaphore done = new Semaphore();
done.down();
- final GradleInvoker.AfterGradleInvocationTask afterTask = new GradleInvoker.AfterGradleInvocationTask() {
- @Override
- public void execute(@NotNull GradleInvocationResult result) {
- success.set(result.isBuildSuccessful());
- gradleInvoker.removeAfterGradleInvocationTask(this);
- done.up();
- }
- };
+ final GradleInvoker.AfterGradleInvocationTask afterTask =
+ new GradleInvoker.AfterGradleInvocationTask() {
+ @Override
+ public void execute(@NotNull GradleInvocationResult result) {
+ success.set(result.isBuildSuccessful());
+ gradleInvoker.removeAfterGradleInvocationTask(this);
+ done.up();
+ }
+ };
- ExternalSystemTaskId taskId = ExternalSystemTaskId.create(GRADLE_SYSTEM_ID, EXECUTE_TASK, project);
+ ExternalSystemTaskId taskId =
+ ExternalSystemTaskId.create(GRADLE_SYSTEM_ID, EXECUTE_TASK, project);
List<String> jvmArguments = ImmutableList.of();
- // https://code.google.com/p/android/issues/detail?id=213040 - make split apks only available if an env var is set
+ // https://code.google.com/p/android/issues/detail?id=213040 -
+ // make split apks only available if an env var is set
List<String> args = new ArrayList<>(commandLineArguments);
if (!Boolean.valueOf(System.getenv(GradleTaskRunner.USE_SPLIT_APK))) {
// force multi dex when the env var is not set to true
- args.add(AndroidGradleSettings.createProjectProperty(AndroidProject.PROPERTY_SIGNING_COLDSWAP_MODE, "MULTIDEX"));
+ args.add(
+ AndroidGradleSettings.createProjectProperty(
+ AndroidProject.PROPERTY_SIGNING_COLDSWAP_MODE, "MULTIDEX"));
}
- // To ensure that the "Run Configuration" waits for the Gradle tasks to be executed, we use SwingUtilities.invokeAndWait. I tried
- // using Application.invokeAndWait but it never worked. IDEA also uses SwingUtilities in this scenario (see CompileStepBeforeRun.)
- SwingUtilities.invokeAndWait(() -> {
- gradleInvoker.addAfterGradleInvocationTask(afterTask);
- gradleInvoker.executeTasks(
- tasks,
- jvmArguments,
- args,
- taskId,
- new GradleNotificationListener(),
- instantRunGradleBuildFile,
- false,
- true
- );
- });
+ // To ensure that the "Run Configuration" waits for the Gradle tasks to be executed,
+ // we use SwingUtilities.invokeAndWait. I tried
+ // using Application.invokeAndWait but it never worked.
+ // IDEA also uses SwingUtilities in this scenario (see CompileStepBeforeRun.)
+ SwingUtilities.invokeAndWait(
+ () -> {
+ gradleInvoker.addAfterGradleInvocationTask(afterTask);
+ gradleInvoker.executeTasks(
+ tasks,
+ jvmArguments,
+ args,
+ taskId,
+ new GradleNotificationListener(),
+ instantRunGradleBuildFile,
+ false,
+ true);
+ });
done.waitFor();
return success.get();
@@ -106,11 +116,14 @@
class GradleNotificationListener extends ExternalSystemTaskNotificationListenerAdapter {
@Override
- public void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
+ public void onTaskOutput(
+ @NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
super.onTaskOutput(id, text, stdOut);
String toPrint = text.trim();
if (!Strings.isNullOrEmpty(toPrint)) {
- context.output(new PrintOutput(toPrint, stdOut ? PrintOutput.OutputType.NORMAL : PrintOutput.OutputType.ERROR));
+ context.output(
+ new PrintOutput(
+ toPrint, stdOut ? PrintOutput.OutputType.NORMAL : PrintOutput.OutputType.ERROR));
}
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunTasksProvider.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunTasksProvider.java
index f528f25..52a82f7 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunTasksProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/BlazeInstantRunTasksProvider.java
@@ -17,13 +17,10 @@
import com.android.tools.idea.fd.InstantRunTasksProvider;
import com.google.common.collect.ImmutableList;
+import java.util.List;
import org.jetbrains.annotations.NotNull;
-import java.util.List;
-
-/**
- * Returns blaze-specific instant run tasks.
- */
+/** Returns blaze-specific instant run tasks. */
public class BlazeInstantRunTasksProvider implements InstantRunTasksProvider {
@NotNull
@Override
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/InstantRunExperiment.java b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/InstantRunExperiment.java
index ef58a9b..148b1d9 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/InstantRunExperiment.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/instantrun/InstantRunExperiment.java
@@ -15,11 +15,10 @@
*/
package com.google.idea.blaze.android.run.binary.instantrun;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.common.experiments.BoolExperiment;
-/**
- * Holds the instant run experiment
- */
+/** Holds the instant run experiment */
public class InstantRunExperiment {
- public static final BoolExperiment INSTANT_RUN_ENABLED = new BoolExperiment("instant.run.enabled", false);
+ public static final BoolExperiment INSTANT_RUN_ENABLED =
+ new BoolExperiment("instant.run.enabled", false);
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeAndroidBinaryMobileInstallRunContext.java b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeAndroidBinaryMobileInstallRunContext.java
index f7603b7..205c95c 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeAndroidBinaryMobileInstallRunContext.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeAndroidBinaryMobileInstallRunContext.java
@@ -17,6 +17,7 @@
import com.android.ddmlib.IDevice;
import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.ConsolePrinter;
import com.android.tools.idea.run.ConsoleProvider;
import com.android.tools.idea.run.LaunchOptions;
import com.android.tools.idea.run.activity.DefaultStartActivityFlagsProvider;
@@ -29,26 +30,28 @@
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryApplicationIdProvider;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryApplicationLaunchTaskProvider;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryConsoleProvider;
import com.google.idea.blaze.android.run.binary.BlazeAndroidBinaryRunConfigurationState;
+import com.google.idea.blaze.android.run.binary.UserIdHelper;
import com.google.idea.blaze.android.run.deployinfo.BlazeAndroidDeployInfo;
-import com.google.idea.blaze.android.run.runner.*;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidLaunchTasksProvider;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationDebuggerManager;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.android.run.runner.BlazeApkBuildStep;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.project.Project;
+import java.util.Set;
+import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
-import javax.annotation.Nullable;
-import java.util.Set;
-
-/**
- * Run context for android_binary.
- */
+/** Run context for android_binary. */
public class BlazeAndroidBinaryMobileInstallRunContext implements BlazeAndroidRunContext {
private final Project project;
@@ -60,21 +63,25 @@
private final ApplicationIdProvider applicationIdProvider;
private final BlazeApkBuildStepMobileInstall buildStep;
- public BlazeAndroidBinaryMobileInstallRunContext(Project project,
- AndroidFacet facet,
- RunConfiguration runConfiguration,
- ExecutionEnvironment env,
- BlazeAndroidRunConfigurationCommonState commonState,
- BlazeAndroidBinaryRunConfigurationState configState,
- ImmutableList<String> buildFlags) {
+ public BlazeAndroidBinaryMobileInstallRunContext(
+ Project project,
+ AndroidFacet facet,
+ RunConfiguration runConfiguration,
+ ExecutionEnvironment env,
+ BlazeAndroidBinaryRunConfigurationState configState,
+ Label label,
+ ImmutableList<String> buildFlags) {
this.project = project;
this.facet = facet;
this.runConfiguration = runConfiguration;
this.env = env;
this.configState = configState;
this.consoleProvider = new BlazeAndroidBinaryConsoleProvider(project);
- this.buildStep = new BlazeApkBuildStepMobileInstall(project, env, commonState, buildFlags, configState.isUseSplitApksIfPossible());
- this.applicationIdProvider = new BlazeAndroidBinaryApplicationIdProvider(project, buildStep.getDeployInfo());
+ this.buildStep =
+ new BlazeApkBuildStepMobileInstall(
+ project, env, label, buildFlags, configState.useSplitApksIfPossible());
+ this.applicationIdProvider =
+ new BlazeAndroidBinaryApplicationIdProvider(project, buildStep.getDeployInfo());
}
@Override
@@ -83,15 +90,11 @@
}
@Override
- public void augmentEnvironment(ExecutionEnvironment env) {
- }
+ public void augmentEnvironment(ExecutionEnvironment env) {}
@Override
public void augmentLaunchOptions(@NotNull LaunchOptions.Builder options) {
- options
- .setDeploy(false)
- .setPmInstallOptions(configState.ACTIVITY_EXTRA_FLAGS)
- .setOpenLogcatAutomatically(true);
+ options.setDeploy(false).setOpenLogcatAutomatically(true);
}
@NotNull
@@ -112,48 +115,64 @@
@Override
public LaunchTasksProvider getLaunchTasksProvider(
- LaunchOptions launchOptions,
- BlazeAndroidRunConfigurationDebuggerManager debuggerManager) throws ExecutionException {
- return new BlazeAndroidLaunchTasksProvider(project, this, applicationIdProvider, launchOptions, debuggerManager);
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidRunConfigurationDebuggerManager debuggerManager)
+ throws ExecutionException {
+ return new BlazeAndroidLaunchTasksProvider(
+ project, this, applicationIdProvider, launchOptionsBuilder, isDebug, debuggerManager);
}
@Override
- public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions) throws ExecutionException {
+ public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions)
+ throws ExecutionException {
return ImmutableList.of();
}
@Override
- public LaunchTask getApplicationLaunchTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- ProcessHandlerLaunchStatus processHandlerLaunchStatus) throws ExecutionException {
- final StartActivityFlagsProvider startActivityFlagsProvider = new DefaultStartActivityFlagsProvider(
- androidDebugger,
- androidDebuggerState,
- project,
- launchOptions.isDebug(),
- configState.ACTIVITY_EXTRA_FLAGS
- );
+ public LaunchTask getApplicationLaunchTask(
+ LaunchOptions launchOptions,
+ @Nullable Integer userId,
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus)
+ throws ExecutionException {
+ final StartActivityFlagsProvider startActivityFlagsProvider =
+ new DefaultStartActivityFlagsProvider(
+ androidDebugger,
+ androidDebuggerState,
+ project,
+ launchOptions.isDebug(),
+ UserIdHelper.getFlagsFromUserId(userId));
- BlazeAndroidDeployInfo deployInfo = Futures.get(buildStep.getDeployInfo(), ExecutionException.class);
+ BlazeAndroidDeployInfo deployInfo =
+ Futures.get(buildStep.getDeployInfo(), ExecutionException.class);
return BlazeAndroidBinaryApplicationLaunchTaskProvider.getApplicationLaunchTask(
- project,
- applicationIdProvider,
- deployInfo.getMergedManifestFile(),
- configState,
- startActivityFlagsProvider,
- processHandlerLaunchStatus
- );
+ project,
+ applicationIdProvider,
+ deployInfo.getMergedManifestFile(),
+ configState,
+ startActivityFlagsProvider,
+ processHandlerLaunchStatus);
}
@Nullable
@Override
- public DebugConnectorTask getDebuggerTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- Set<String> packageIds) throws ExecutionException {
+ public DebugConnectorTask getDebuggerTask(
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ Set<String> packageIds)
+ throws ExecutionException {
//noinspection unchecked
- return androidDebugger.getConnectDebuggerTask(env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
+ return androidDebugger.getConnectDebuggerTask(
+ env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
+ }
+
+ @Nullable
+ @Override
+ public Integer getUserId(IDevice device, ConsolePrinter consolePrinter)
+ throws ExecutionException {
+ return UserIdHelper.getUserIdFromConfigurationState(device, consolePrinter, configState);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeApkBuildStepMobileInstall.java b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeApkBuildStepMobileInstall.java
index 9923856..24d49b6 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeApkBuildStepMobileInstall.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/BlazeApkBuildStepMobileInstall.java
@@ -23,7 +23,6 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.deployinfo.BlazeAndroidDeployInfo;
import com.google.idea.blaze.android.run.deployinfo.BlazeApkDeployInfoProtoHelper;
import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
@@ -36,132 +35,135 @@
import com.google.idea.blaze.base.command.BlazeCommand;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.ScopedTask;
import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.blaze.base.util.SaveUtil;
+import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import org.jetbrains.android.sdk.AndroidSdkUtils;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
import java.io.File;
import java.nio.file.Paths;
import java.util.concurrent.CancellationException;
+import javax.annotation.Nullable;
+import org.jetbrains.android.sdk.AndroidSdkUtils;
+import org.jetbrains.annotations.NotNull;
-/**
- * Builds and installs the APK using mobile-install.
- */
+/** Builds and installs the APK using mobile-install. */
public class BlazeApkBuildStepMobileInstall implements BlazeApkBuildStep {
private static final BoolExperiment USE_SDK_ADB = new BoolExperiment("use.sdk.adb", true);
private final Project project;
private final ExecutionEnvironment env;
- private final BlazeAndroidRunConfigurationCommonState commonState;
+ private final Label label;
private final ImmutableList<String> buildFlags;
private final boolean useSplitApksIfPossible;
private final SettableFuture<BlazeAndroidDeployInfo> deployInfoFuture = SettableFuture.create();
- public BlazeApkBuildStepMobileInstall(Project project,
- ExecutionEnvironment env,
- BlazeAndroidRunConfigurationCommonState commonState,
- ImmutableList<String> buildFlags,
- boolean useSplitApksIfPossible) {
+ public BlazeApkBuildStepMobileInstall(
+ Project project,
+ ExecutionEnvironment env,
+ Label label,
+ ImmutableList<String> buildFlags,
+ boolean useSplitApksIfPossible) {
this.project = project;
this.env = env;
- this.commonState = commonState;
+ this.label = label;
this.buildFlags = buildFlags;
this.useSplitApksIfPossible = useSplitApksIfPossible;
}
@Override
- public boolean build(BlazeContext context, BlazeAndroidDeviceSelector.DeviceSession deviceSession) {
- final ScopedTask buildTask = new ScopedTask(context) {
- @Override
- protected void execute(@NotNull BlazeContext context) {
- boolean incrementalInstall = env.getExecutor() instanceof IncrementalInstallExecutor;
+ public boolean build(
+ BlazeContext context, BlazeAndroidDeviceSelector.DeviceSession deviceSession) {
+ final ScopedTask buildTask =
+ new ScopedTask(context) {
+ @Override
+ protected void execute(@NotNull BlazeContext context) {
+ boolean incrementalInstall = env.getExecutor() instanceof IncrementalInstallExecutor;
- DeviceFutures deviceFutures = deviceSession.deviceFutures;
- assert deviceFutures != null;
- IDevice device = resolveDevice(context, deviceFutures);
- if (device == null) {
- return;
- }
- BlazeCommand.Builder command = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.MOBILE_INSTALL);
- command.addBlazeFlags(BlazeFlags.adbSerialFlags(device.getSerialNumber()));
+ DeviceFutures deviceFutures = deviceSession.deviceFutures;
+ assert deviceFutures != null;
+ IDevice device = resolveDevice(context, deviceFutures);
+ if (device == null) {
+ return;
+ }
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(
+ Blaze.getBuildSystem(project), BlazeCommandName.MOBILE_INSTALL);
+ command.addBlazeFlags(BlazeFlags.adbSerialFlags(device.getSerialNumber()));
- if (USE_SDK_ADB.getValue()) {
- File adb = getSdkAdb(project);
- if (adb != null) {
- command.addBlazeFlags(ImmutableList.of("--adb", adb.toString()));
+ if (USE_SDK_ADB.getValue()) {
+ File adb = getSdkAdb(project);
+ if (adb != null) {
+ command.addBlazeFlags(ImmutableList.of("--adb", adb.toString()));
+ }
+ }
+
+ // split-apks only supported for API level 23 and above
+ if (useSplitApksIfPossible && device.getVersion().getApiLevel() >= 23) {
+ command.addBlazeFlags(BlazeFlags.SPLIT_APKS);
+ } else if (incrementalInstall) {
+ command.addBlazeFlags(BlazeFlags.INCREMENTAL);
+ }
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+
+ command
+ .addTargets(label)
+ .addBlazeFlags(buildFlags)
+ .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS);
+
+ BlazeApkDeployInfoProtoHelper deployInfoHelper =
+ new BlazeApkDeployInfoProtoHelper(project, buildFlags);
+
+ SaveUtil.saveAllFiles();
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command.build())
+ .context(context)
+ .stderr(
+ LineProcessingOutputStream.of(
+ deployInfoHelper.getLineProcessor(),
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run();
+ FileCaches.refresh(project);
+
+ if (retVal != 0) {
+ context.setHasError();
+ return;
+ }
+
+ BlazeAndroidDeployInfo deployInfo = deployInfoHelper.readDeployInfo(context);
+ if (deployInfo == null) {
+ IssueOutput.error("Could not read apk deploy info from build").submit(context);
+ return;
+ }
+ deployInfoFuture.set(deployInfo);
}
- }
+ };
- // split-apks only supported for API level 23 and above
- if (useSplitApksIfPossible && device.getVersion().getApiLevel() >= 23) {
- command.addBlazeFlags(BlazeFlags.SPLIT_APKS);
- }
- else if (incrementalInstall) {
- command.addBlazeFlags(BlazeFlags.INCREMENTAL);
- }
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
-
- command
- .addTargets(commonState.getTarget())
- .addBlazeFlags(buildFlags)
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS)
- ;
-
- BlazeApkDeployInfoProtoHelper deployInfoHelper = new BlazeApkDeployInfoProtoHelper(project, buildFlags);
-
- SaveUtil.saveAllFiles();
- int retVal = ExternalTask.builder(workspaceRoot, command.build())
- .context(context)
- .stderr(LineProcessingOutputStream.of(
- deployInfoHelper.getLineProcessor(),
- new IssueOutputLineProcessor(project, context, workspaceRoot)))
- .build()
- .run();
- LocalFileSystem.getInstance().refresh(true);
-
- if (retVal != 0) {
- context.setHasError();
- return;
- }
-
- BlazeAndroidDeployInfo deployInfo = deployInfoHelper.readDeployInfo(context);
- if (deployInfo == null) {
- IssueOutput.error("Could not read apk deploy info from build").submit(context);
- return;
- }
- deployInfoFuture.set(deployInfo);
- }
- };
-
- ListenableFuture<Void> buildFuture = BlazeExecutor.submitTask(
- project,
- String.format("Executing %s apk build", Blaze.buildSystemName(project)),
- buildTask
- );
+ ListenableFuture<Void> buildFuture =
+ BlazeExecutor.submitTask(
+ project,
+ String.format("Executing %s apk build", Blaze.buildSystemName(project)),
+ buildTask);
try {
Futures.get(buildFuture, ExecutionException.class);
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
context.setHasError();
- }
- catch (CancellationException e) {
+ } catch (CancellationException e) {
context.setCancelled();
}
return context.shouldContinue();
@@ -172,7 +174,8 @@
}
private static File getSdkAdb(Project project) {
- BlazeProjectData projectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ BlazeProjectData projectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
if (projectData == null) {
return null;
}
@@ -200,23 +203,17 @@
}
@Nullable
- private static IDevice resolveDevice(@NotNull BlazeContext context, @NotNull DeviceFutures deviceFutures) {
+ private static IDevice resolveDevice(
+ @NotNull BlazeContext context, @NotNull DeviceFutures deviceFutures) {
if (deviceFutures.get().size() != 1) {
- IssueOutput
- .error("Only one device can be used with mobile-install.")
- .submit(context);
+ IssueOutput.error("Only one device can be used with mobile-install.").submit(context);
return null;
}
- context.output(new PrintOutput("Waiting for mobile-install device target..."));
+ context.output(new StatusOutput("Waiting for mobile-install device target..."));
try {
- return Futures.get(
- Iterables.getOnlyElement(deviceFutures.get()),
- ExecutionException.class
- );
- } catch (ExecutionException|UncheckedExecutionException e) {
- IssueOutput
- .error("Could not get device: " + e.getMessage())
- .submit(context);
+ return Futures.get(Iterables.getOnlyElement(deviceFutures.get()), ExecutionException.class);
+ } catch (ExecutionException | UncheckedExecutionException e) {
+ IssueOutput.error("Could not get device: " + e.getMessage()).submit(context);
return null;
} catch (CancellationException e) {
// The user cancelled the device launch.
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallDebugExecutor.java b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallDebugExecutor.java
index c20f13c..88accc8 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallDebugExecutor.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallDebugExecutor.java
@@ -18,17 +18,16 @@
import com.google.idea.blaze.base.settings.Blaze;
import com.intellij.execution.executors.DefaultDebugExecutor;
import icons.BlazeAndroidIcons;
+import javax.swing.Icon;
import org.jetbrains.annotations.NotNull;
-import javax.swing.*;
-
/**
* Executor for running blaze mobile-install --incremental and then launching the current run
* configuration in debug mode. This executor adds a launch button that is only enabled for
* mobile-install run configurations.
*/
-public class IncrementalInstallDebugExecutor
- extends DefaultDebugExecutor implements IncrementalInstallExecutor {
+public class IncrementalInstallDebugExecutor extends DefaultDebugExecutor
+ implements IncrementalInstallExecutor {
public static final String EXECUTOR_ID = "blaze.incremental.install.debug";
@NotNull
@@ -56,7 +55,8 @@
@Override
public String getDescription() {
- return Blaze.guessBuildSystemName().toLowerCase() + " mobile-install --incremental, launch with debugger";
+ return Blaze.guessBuildSystemName().toLowerCase()
+ + " mobile-install --incremental, launch with debugger";
}
@NotNull
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallExecutor.java b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallExecutor.java
index e8bba2e..c33463c 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallExecutor.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallExecutor.java
@@ -16,8 +16,6 @@
package com.google.idea.blaze.android.run.binary.mobileinstall;
/**
- * A marker interface for executors that specify --incremental should be used
- * with mobile-install.
+ * A marker interface for executors that specify --incremental should be used with mobile-install.
*/
-public interface IncrementalInstallExecutor {
-}
+public interface IncrementalInstallExecutor {}
diff --git a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallRunExecutor.java b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallRunExecutor.java
index 3e98d87..5c21041 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallRunExecutor.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/mobileinstall/IncrementalInstallRunExecutor.java
@@ -18,17 +18,16 @@
import com.google.idea.blaze.base.settings.Blaze;
import com.intellij.execution.executors.DefaultRunExecutor;
import icons.BlazeAndroidIcons;
+import javax.swing.Icon;
import org.jetbrains.annotations.NotNull;
-import javax.swing.*;
-
/**
* Executor for running blaze mobile-install --incremental and then launching the current run
* configuration. This executor adds a launch button that is only enabled for mobile-install run
* configurations.
*/
-public class IncrementalInstallRunExecutor
- extends DefaultRunExecutor implements IncrementalInstallExecutor {
+public class IncrementalInstallRunExecutor extends DefaultRunExecutor
+ implements IncrementalInstallExecutor {
public static final String EXECUTOR_ID = "blaze.incremental.install.run";
@NotNull
diff --git a/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeAndroidDeployInfo.java b/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeAndroidDeployInfo.java
index 1e3c0bd..f3ca382 100644
--- a/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeAndroidDeployInfo.java
+++ b/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeAndroidDeployInfo.java
@@ -19,25 +19,23 @@
import com.google.idea.blaze.android.manifest.ManifestParser;
import com.google.repackaged.devtools.build.lib.rules.android.deployinfo.AndroidDeployInfoOuterClass;
import com.intellij.openapi.project.Project;
-import org.jetbrains.android.dom.manifest.Manifest;
-
-import javax.annotation.Nullable;
import java.io.File;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.jetbrains.android.dom.manifest.Manifest;
-/**
- * Info about the android_binary/android_test to deploy.
- */
+/** Info about the android_binary/android_test to deploy. */
public class BlazeAndroidDeployInfo {
private final Project project;
private final File executionRoot;
private final AndroidDeployInfoOuterClass.AndroidDeployInfo deployInfo;
- public BlazeAndroidDeployInfo(Project project,
- File executionRoot,
- AndroidDeployInfoOuterClass.AndroidDeployInfo deployInfo) {
+ public BlazeAndroidDeployInfo(
+ Project project,
+ File executionRoot,
+ AndroidDeployInfoOuterClass.AndroidDeployInfo deployInfo) {
this.project = project;
this.executionRoot = executionRoot;
this.deployInfo = deployInfo;
@@ -55,16 +53,19 @@
}
public List<File> getAdditionalMergedManifestFiles() {
- return deployInfo.getAdditionalMergedManifestsList().stream()
- .map(artifact -> new File(executionRoot, artifact.getExecRootPath()))
- .collect(Collectors.toList());
+ return deployInfo
+ .getAdditionalMergedManifestsList()
+ .stream()
+ .map(artifact -> new File(executionRoot, artifact.getExecRootPath()))
+ .collect(Collectors.toList());
}
public List<Manifest> getAdditionalMergedManifests() {
- return getAdditionalMergedManifestFiles().stream()
- .map(file -> ManifestParser.getInstance(project).getManifest(file))
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
+ return getAdditionalMergedManifestFiles()
+ .stream()
+ .map(file -> ManifestParser.getInstance(project).getManifest(file))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
}
public List<File> getManifestFiles() {
@@ -74,12 +75,12 @@
return result;
}
- /**
- * Returns the full list of apks to deploy, if any.
- */
+ /** Returns the full list of apks to deploy, if any. */
public List<File> getApksToDeploy() {
- return deployInfo.getApksToDeployList().stream()
- .map(artifact -> new File(executionRoot, artifact.getExecRootPath()))
- .collect(Collectors.toList());
+ return deployInfo
+ .getApksToDeployList()
+ .stream()
+ .map(artifact -> new File(executionRoot, artifact.getExecRootPath()))
+ .collect(Collectors.toList());
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkDeployInfoProtoHelper.java b/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkDeployInfoProtoHelper.java
index 9628565..477e1f2 100644
--- a/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkDeployInfoProtoHelper.java
+++ b/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkDeployInfoProtoHelper.java
@@ -29,18 +29,15 @@
import com.google.repackaged.devtools.build.lib.rules.android.deployinfo.AndroidDeployInfoOuterClass;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
-/**
- * Reads the deploy info from a build step.
- */
+/** Reads the deploy info from a build step. */
public class BlazeApkDeployInfoProtoHelper {
private static final Logger LOG = Logger.getInstance(BlazeApkDeployInfoProtoHelper.class);
@@ -49,7 +46,7 @@
private final ImmutableList<String> buildFlags;
private final List<File> deployInfoFiles = Lists.newArrayList();
private final LineProcessingOutputStream.LineProcessor lineProcessor =
- new ExperimentalShowArtifactsLineProcessor(deployInfoFiles, ".deployinfo.pb");
+ new ExperimentalShowArtifactsLineProcessor(deployInfoFiles, ".deployinfo.pb");
public BlazeApkDeployInfoProtoHelper(Project project, ImmutableList<String> buildFlags) {
this.project = project;
@@ -78,7 +75,8 @@
if (executionRoot == null) {
return null;
}
- BlazeAndroidDeployInfo androidDeployInfo = new BlazeAndroidDeployInfo(project, new File(executionRoot), deployInfo);
+ BlazeAndroidDeployInfo androidDeployInfo =
+ new BlazeAndroidDeployInfo(project, new File(executionRoot), deployInfo);
List<File> manifestFiles = androidDeployInfo.getManifestFiles();
ManifestParser.getInstance(project).refreshManifests(manifestFiles);
@@ -88,19 +86,19 @@
@Nullable
private String getExecutionRoot(BlazeContext context) {
- ListenableFuture<String> execRootFuture = BlazeInfo.getInstance().runBlazeInfo(
- context, Blaze.getBuildSystem(project),
- workspaceRoot,
- buildFlags,
- BlazeInfo.EXECUTION_ROOT_KEY
- );
+ ListenableFuture<String> execRootFuture =
+ BlazeInfo.getInstance()
+ .runBlazeInfo(
+ context,
+ Blaze.getBuildSystem(project),
+ workspaceRoot,
+ buildFlags,
+ BlazeInfo.EXECUTION_ROOT_KEY);
try {
return execRootFuture.get();
- }
- catch (InterruptedException e) {
+ } catch (InterruptedException e) {
context.setCancelled();
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
LOG.error(e);
context.setHasError();
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkProvider.java b/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkProvider.java
index 5bf27c0..bdcc5d6 100644
--- a/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/deployinfo/BlazeApkProvider.java
@@ -25,21 +25,18 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.idea.blaze.android.run.runner.AaptUtil;
import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
import java.io.File;
import java.util.Collection;
import java.util.List;
+import org.jetbrains.annotations.NotNull;
-/**
- * Apk provider from deploy info proto
- */
+/** Apk provider from deploy info proto */
public class BlazeApkProvider implements ApkProvider {
private final Project project;
private final ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture;
- public BlazeApkProvider(Project project,
- ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture) {
+ public BlazeApkProvider(
+ Project project, ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture) {
this.project = project;
this.deployInfoFuture = deployInfoFuture;
}
@@ -49,7 +46,7 @@
public Collection<ApkInfo> getApks(@NotNull IDevice device) throws ApkProvisionException {
BlazeAndroidDeployInfo deployInfo = Futures.get(deployInfoFuture, ApkProvisionException.class);
ImmutableList.Builder<ApkInfo> apkInfos = ImmutableList.builder();
- for (File apk : deployInfo.getApksToDeploy()) {
+ for (File apk : deployInfo.getApksToDeploy()) {
apkInfos.add(new ApkInfo(apk, manifestPackageForApk(apk)));
}
return apkInfos.build();
@@ -59,12 +56,13 @@
private String manifestPackageForApk(@NotNull final File apk) throws ApkProvisionException {
try {
return AaptUtil.getApkManifestPackage(project, apk);
- }
- catch (AaptUtil.AaptUtilException e) {
+ } catch (AaptUtil.AaptUtilException e) {
throw new ApkProvisionException(
- "Could not determine manifest package for apk: " + apk.getPath()
- + "\nbecause: " + e.getMessage(),
- e);
+ "Could not determine manifest package for apk: "
+ + apk.getPath()
+ + "\nbecause: "
+ + e.getMessage(),
+ e);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/AaptUtil.java b/aswb/src/com/google/idea/blaze/android/run/runner/AaptUtil.java
index 9fc61a7..9ad2aa0 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/AaptUtil.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/AaptUtil.java
@@ -22,9 +22,6 @@
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.openapi.project.Project;
-import org.jetbrains.android.sdk.AndroidPlatform;
-
-import javax.annotation.Nullable;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
@@ -32,17 +29,18 @@
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+import org.jetbrains.android.sdk.AndroidPlatform;
-/**
- * A collection of utilities for extracting information from APKs using aapt.
- */
+/** A collection of utilities for extracting information from APKs using aapt. */
public final class AaptUtil {
private static final Pattern DEBUGGABLE_PATTERN = Pattern.compile("^application-debuggable$");
private static final Pattern PACKAGE_PATTERN = Pattern.compile("^package: .*name='([\\w\\.]+)'");
private static final Pattern LAUNCHABLE_PATTERN =
- Pattern.compile("^launchable-activity: .*name='([\\w\\.]+)'");
+ Pattern.compile("^launchable-activity: .*name='([\\w\\.]+)'");
+ /** exception thrown by this class */
public static class AaptUtilException extends Exception {
public AaptUtilException(String message) {
super(message);
@@ -53,46 +51,32 @@
}
}
- private AaptUtil() {
- }
+ private AaptUtil() {}
/**
* Determines whether the given APK is debuggable. Trying to debug a non-debuggable APK on a
* release-keys device will fail.
*/
- public static boolean isApkDebuggable(
- Project project,
- File apk
- ) throws AaptUtilException {
+ public static boolean isApkDebuggable(Project project, File apk) throws AaptUtilException {
return getAaptBadging(project, apk, DEBUGGABLE_PATTERN) != null;
}
- /**
- * Determines the manifest package name for the given APK.
- */
- public static String getApkManifestPackage(
- Project project,
- File apk
- ) throws AaptUtilException {
+ /** Determines the manifest package name for the given APK. */
+ public static String getApkManifestPackage(Project project, File apk) throws AaptUtilException {
MatchResult packageResult = getAaptBadging(project, apk, PACKAGE_PATTERN);
if (packageResult == null) {
throw new AaptUtilException(
- "No match found in `aapt dump badging` for package manifest pattern.");
+ "No match found in `aapt dump badging` for package manifest pattern.");
}
return packageResult.group(1);
}
- /**
- * Determines the default launchable activity for the given apk.
- */
- public static String getLaunchableActivity(
- Project project,
- File apk
- ) throws AaptUtilException {
+ /** Determines the default launchable activity for the given apk. */
+ public static String getLaunchableActivity(Project project, File apk) throws AaptUtilException {
MatchResult activityResult = getAaptBadging(project, apk, LAUNCHABLE_PATTERN);
if (activityResult == null) {
throw new AaptUtilException(
- "No match found in `aapt dump badging` for launchable activity pattern.");
+ "No match found in `aapt dump badging` for launchable activity pattern.");
}
return activityResult.group(1);
}
@@ -102,41 +86,34 @@
* output matching the given pattern.
*/
@Nullable
- private static MatchResult getAaptBadging(
- Project project,
- File apk,
- Pattern pattern
- ) throws AaptUtilException {
+ private static MatchResult getAaptBadging(Project project, File apk, Pattern pattern)
+ throws AaptUtilException {
if (!apk.exists()) {
throw new AaptUtilException("apk file does not exist: " + apk);
}
AndroidPlatform androidPlatform = SdkUtil.getAndroidPlatform(project);
if (androidPlatform == null) {
throw new AaptUtilException(
- "Could not find Android platform sdk for project " + project.getName());
+ "Could not find Android platform sdk for project " + project.getName());
}
BuildToolInfo toolInfo = androidPlatform.getSdkData().getLatestBuildTool();
if (toolInfo == null) {
throw new AaptUtilException(
- "Could not find Android sdk build-tools for project " + project.getName());
+ "Could not find Android sdk build-tools for project " + project.getName());
}
String aapt = toolInfo.getPath(PathId.AAPT);
- GeneralCommandLine commandLine = new GeneralCommandLine(
- aapt,
- "dump",
- "badging",
- apk.getAbsolutePath());
+ GeneralCommandLine commandLine =
+ new GeneralCommandLine(aapt, "dump", "badging", apk.getAbsolutePath());
OSProcessHandler handler;
try {
handler = new OSProcessHandler(commandLine);
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
throw new AaptUtilException("Could not execute aapt to extract apk information.", e);
}
// The wrapped stream is closed by the process handler.
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(handler.getProcess().getInputStream()));
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(handler.getProcess().getInputStream()));
try {
String line;
while ((line = reader.readLine()) != null) {
@@ -145,8 +122,7 @@
return matcher.toMatchResult();
}
}
- }
- catch (IOException e) {
+ } catch (IOException e) {
throw new AaptUtilException("Could not read aapt output.", e);
}
return null;
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidDeviceSelector.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidDeviceSelector.java
index bc6737a..a1ef71c 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidDeviceSelector.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidDeviceSelector.java
@@ -15,6 +15,8 @@
*/
package com.google.idea.blaze.android.run.runner;
+import static org.jetbrains.android.actions.RunAndroidAvdManagerAction.getName;
+
import com.android.tools.idea.run.AndroidSessionInfo;
import com.android.tools.idea.run.DeviceFutures;
import com.android.tools.idea.run.editor.DeployTarget;
@@ -27,43 +29,44 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
+import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
-import javax.annotation.Nullable;
-
-import static org.jetbrains.android.actions.RunAndroidAvdManagerAction.getName;
-
-/**
- * Selects a device.
- */
+/** Selects a device. */
public interface BlazeAndroidDeviceSelector {
+ /** A device session */
class DeviceSession {
@Nullable public final DeployTarget deployTarget;
@Nullable public final DeviceFutures deviceFutures;
@Nullable public final AndroidSessionInfo sessionInfo;
- public DeviceSession(@Nullable DeployTarget deployTarget,
- @Nullable DeviceFutures deviceFutures,
- @Nullable AndroidSessionInfo sessionInfo) {
+ public DeviceSession(
+ @Nullable DeployTarget deployTarget,
+ @Nullable DeviceFutures deviceFutures,
+ @Nullable AndroidSessionInfo sessionInfo) {
this.deployTarget = deployTarget;
this.deviceFutures = deviceFutures;
this.sessionInfo = sessionInfo;
}
}
- DeviceSession getDevice(Project project,
- AndroidFacet facet,
- BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager,
- Executor executor,
- ExecutionEnvironment env,
- AndroidSessionInfo info,
- boolean debug,
- int runConfigId) throws ExecutionException;
+ DeviceSession getDevice(
+ Project project,
+ AndroidFacet facet,
+ BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager,
+ Executor executor,
+ ExecutionEnvironment env,
+ AndroidSessionInfo info,
+ boolean debug,
+ int runConfigId)
+ throws ExecutionException;
+ /** Standard device selector */
class NormalDeviceSelector implements BlazeAndroidDeviceSelector {
- private static final DialogWrapper.DoNotAskOption ourKillLaunchOption = new KillLaunchDialogOption();
+ private static final DialogWrapper.DoNotAskOption ourKillLaunchOption =
+ new KillLaunchDialogOption();
private static final Logger LOG = Logger.getInstance(NormalDeviceSelector.class);
static class KillLaunchDialogOption implements DialogWrapper.DoNotAskOption {
@@ -96,14 +99,16 @@
}
@Override
- public DeviceSession getDevice(Project project,
- AndroidFacet facet,
- BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager,
- Executor executor,
- ExecutionEnvironment env,
- AndroidSessionInfo info,
- boolean debug,
- int runConfigId) throws ExecutionException {
+ public DeviceSession getDevice(
+ Project project,
+ AndroidFacet facet,
+ BlazeAndroidRunConfigurationDeployTargetManager deployTargetManager,
+ Executor executor,
+ ExecutionEnvironment env,
+ AndroidSessionInfo info,
+ boolean debug,
+ int runConfigId)
+ throws ExecutionException {
// If there is an existing session, then terminate those sessions
if (info != null) {
boolean continueLaunch = promptAndKillSession(executor, project, info);
@@ -120,36 +125,45 @@
DeviceFutures deviceFutures = null;
DeployTargetState deployTargetState = deployTargetManager.getCurrentDeployTargetState();
if (!deployTarget.hasCustomRunProfileState(executor)) {
- deviceFutures = deployTarget.getDevices(
- deployTargetState,
- facet,
- deployTargetManager.getDeviceCount(),
- debug,
- runConfigId
- );
+ deviceFutures =
+ deployTarget.getDevices(
+ deployTargetState, facet, deployTargetManager.getDeviceCount(), debug, runConfigId);
}
return new DeviceSession(deployTarget, deviceFutures, info);
}
- private boolean promptAndKillSession(Executor executor, Project project, AndroidSessionInfo info) {
+ private boolean promptAndKillSession(
+ Executor executor, Project project, AndroidSessionInfo info) {
String previousExecutor = info.getExecutorId();
String currentExecutor = executor.getId();
if (ourKillLaunchOption.isToBeShown()) {
String msg, noText;
if (previousExecutor.equals(currentExecutor)) {
- msg = String.format("Restart App?\nThe app is already running. Would you like to kill it and restart the session?");
+ msg =
+ String.format(
+ "Restart App?\nThe app is already running. "
+ + "Would you like to kill it and restart the session?");
noText = "Cancel";
- }
- else {
- msg = String.format("To switch from %1$s to %2$s, the app has to restart. Continue?", previousExecutor, currentExecutor);
+ } else {
+ msg =
+ String.format(
+ "To switch from %1$s to %2$s, the app has to restart. Continue?",
+ previousExecutor, currentExecutor);
noText = "Cancel " + currentExecutor;
}
String title = "Launching " + getName();
String yesText = "Restart " + getName();
- if (Messages.NO ==
- Messages.showYesNoDialog(project, msg, title, yesText, noText, AllIcons.General.QuestionDialog, ourKillLaunchOption)) {
+ if (Messages.NO
+ == Messages.showYesNoDialog(
+ project,
+ msg,
+ title,
+ yesText,
+ noText,
+ AllIcons.General.QuestionDialog,
+ ourKillLaunchOption)) {
return false;
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidLaunchTasksProvider.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidLaunchTasksProvider.java
index 79b21cd..2916688 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidLaunchTasksProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidLaunchTasksProvider.java
@@ -17,55 +17,73 @@
import com.android.ddmlib.IDevice;
import com.android.sdklib.AndroidVersion;
-import com.android.tools.idea.run.*;
+import com.android.tools.idea.run.AndroidLaunchTasksProvider;
+import com.android.tools.idea.run.ApkProvisionException;
+import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.ConsolePrinter;
+import com.android.tools.idea.run.LaunchOptions;
import com.android.tools.idea.run.editor.AndroidDebugger;
import com.android.tools.idea.run.editor.AndroidDebuggerState;
-import com.android.tools.idea.run.tasks.*;
+import com.android.tools.idea.run.tasks.ClearLogcatTask;
+import com.android.tools.idea.run.tasks.DebugConnectorTask;
+import com.android.tools.idea.run.tasks.DismissKeyguardTask;
+import com.android.tools.idea.run.tasks.LaunchTask;
+import com.android.tools.idea.run.tasks.LaunchTasksProvider;
+import com.android.tools.idea.run.tasks.ShowLogcatTask;
import com.android.tools.idea.run.util.LaunchStatus;
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import com.google.idea.blaze.android.run.binary.UserIdHelper;
import com.intellij.execution.ExecutionException;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import java.util.List;
+import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Normal launch tasks provider.
- */
+/** Normal launch tasks provider. */
public class BlazeAndroidLaunchTasksProvider implements LaunchTasksProvider {
private static final Logger LOG = Logger.getInstance(BlazeAndroidLaunchTasksProvider.class);
private final Project project;
private final BlazeAndroidRunContext runContext;
private final ApplicationIdProvider applicationIdProvider;
- private final LaunchOptions launchOptions;
+ private final LaunchOptions.Builder launchOptionsBuilder;
+ private final boolean isDebug;
private final BlazeAndroidRunConfigurationDebuggerManager debuggerManager;
- public BlazeAndroidLaunchTasksProvider(Project project,
- BlazeAndroidRunContext runContext,
- ApplicationIdProvider applicationIdProvider,
- LaunchOptions launchOptions,
- BlazeAndroidRunConfigurationDebuggerManager debuggerManager) {
+ public BlazeAndroidLaunchTasksProvider(
+ Project project,
+ BlazeAndroidRunContext runContext,
+ ApplicationIdProvider applicationIdProvider,
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidRunConfigurationDebuggerManager debuggerManager) {
this.project = project;
this.runContext = runContext;
this.applicationIdProvider = applicationIdProvider;
- this.launchOptions = launchOptions;
+ this.launchOptionsBuilder = launchOptionsBuilder;
+ this.isDebug = isDebug;
this.debuggerManager = debuggerManager;
}
@NotNull
@Override
- public List<LaunchTask> getTasks(@NotNull IDevice device,
- @NotNull LaunchStatus launchStatus,
- @NotNull ConsolePrinter consolePrinter) {
+ public List<LaunchTask> getTasks(
+ @NotNull IDevice device,
+ @NotNull LaunchStatus launchStatus,
+ @NotNull ConsolePrinter consolePrinter)
+ throws ExecutionException {
final List<LaunchTask> launchTasks = Lists.newArrayList();
+ Integer userId = runContext.getUserId(device, consolePrinter);
+ launchOptionsBuilder.setPmInstallOptions(UserIdHelper.getFlagsFromUserId(userId));
+
+ LaunchOptions launchOptions = launchOptionsBuilder.build();
+
if (launchOptions.isClearLogcatBeforeStart()) {
launchTasks.add(new ClearLogcatTask(project));
}
@@ -73,14 +91,8 @@
launchTasks.add(new DismissKeyguardTask());
if (launchOptions.isDeploy()) {
- try {
- ImmutableList<LaunchTask> deployTasks = runContext.getDeployTasks(device, launchOptions);
- launchTasks.addAll(deployTasks);
- }
- catch (ExecutionException e) {
- launchStatus.terminateLaunch(e.getMessage());
- return ImmutableList.of();
- }
+ ImmutableList<LaunchTask> deployTasks = runContext.getDeployTasks(device, launchOptions);
+ launchTasks.addAll(deployTasks);
}
if (launchStatus.isLaunchTerminated()) {
return launchTasks;
@@ -90,23 +102,23 @@
try {
packageName = applicationIdProvider.getPackageName();
- ProcessHandlerLaunchStatus processHandlerLaunchStatus = (ProcessHandlerLaunchStatus)launchStatus;
- LaunchTask appLaunchTask = runContext.getApplicationLaunchTask(
- launchOptions,
- debuggerManager.getAndroidDebugger(),
- debuggerManager.getAndroidDebuggerState(),
- processHandlerLaunchStatus
- );
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus =
+ (ProcessHandlerLaunchStatus) launchStatus;
+ LaunchTask appLaunchTask =
+ runContext.getApplicationLaunchTask(
+ launchOptions,
+ userId,
+ debuggerManager.getAndroidDebugger(),
+ debuggerManager.getAndroidDebuggerState(),
+ processHandlerLaunchStatus);
if (appLaunchTask != null) {
launchTasks.add(appLaunchTask);
}
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
LOG.error(e);
launchStatus.terminateLaunch("Unable to determine application id: " + e);
return ImmutableList.of();
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
launchStatus.terminateLaunch(e.getMessage());
return ImmutableList.of();
}
@@ -120,17 +132,16 @@
@Nullable
@Override
- public DebugConnectorTask getConnectDebuggerTask(@NotNull LaunchStatus launchStatus,
- @Nullable AndroidVersion version) {
- if (!launchOptions.isDebug()) {
+ public DebugConnectorTask getConnectDebuggerTask(
+ @NotNull LaunchStatus launchStatus, @Nullable AndroidVersion version) {
+ if (!isDebug) {
return null;
}
Set<String> packageIds = Sets.newHashSet();
try {
String packageName = applicationIdProvider.getPackageName();
packageIds.add(packageName);
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
Logger.getInstance(AndroidLaunchTasksProvider.class).error(e);
}
@@ -139,11 +150,12 @@
if (packageName != null) {
packageIds.add(packageName);
}
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
// not as severe as failing to obtain package id for main application
Logger.getInstance(AndroidLaunchTasksProvider.class)
- .warn("Unable to obtain test package name, will not connect debugger if tests don't instantiate main application");
+ .warn(
+ "Unable to obtain test package name, will not connect debugger "
+ + "if tests don't instantiate main application");
}
AndroidDebugger androidDebugger = debuggerManager.getAndroidDebugger();
@@ -154,14 +166,8 @@
}
try {
- return runContext.getDebuggerTask(
- launchOptions,
- androidDebugger,
- androidDebuggerState,
- packageIds
- );
- }
- catch (ExecutionException e) {
+ return runContext.getDebuggerTask(androidDebugger, androidDebuggerState, packageIds);
+ } catch (ExecutionException e) {
launchStatus.terminateLaunch(e.getMessage());
return null;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDebuggerManager.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDebuggerManager.java
index 3d174c9..d51f14a 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDebuggerManager.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDebuggerManager.java
@@ -29,33 +29,31 @@
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
-import org.jdom.Element;
-import org.jetbrains.android.facet.AndroidFacet;
-
-import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import javax.annotation.Nullable;
+import org.jdom.Element;
+import org.jetbrains.android.facet.AndroidFacet;
-/**
- * Manages android debugger state for the run configurations.
- */
+/** Manages android debugger state for the run configurations. */
public class BlazeAndroidRunConfigurationDebuggerManager implements JDOMExternalizable {
private final Project project;
private final Map<String, AndroidDebuggerState> androidDebuggerStates = Maps.newHashMap();
private final BlazeAndroidRunConfigurationCommonState commonState;
- BlazeAndroidRunConfigurationDebuggerManager(Project project,
- BlazeAndroidRunConfigurationCommonState commonState) {
+ BlazeAndroidRunConfigurationDebuggerManager(
+ Project project, BlazeAndroidRunConfigurationCommonState commonState) {
this.project = project;
this.commonState = commonState;
- for (AndroidDebugger androidDebugger: getAndroidDebuggers()) {
+ for (AndroidDebugger androidDebugger : getAndroidDebuggers()) {
this.androidDebuggerStates.put(androidDebugger.getId(), androidDebugger.createState());
}
}
List<ValidationError> validate(AndroidFacet facet) {
- // All of the AndroidDebuggerState classes implement a validate that either does nothing or is specific to gradle so there is no point
+ // All of the AndroidDebuggerState classes implement a validate that
+ // either does nothing or is specific to gradle so there is no point
// in calling validate on our AndroidDebuggerState.
return ImmutableList.of();
}
@@ -63,7 +61,7 @@
@Nullable
AndroidDebugger getAndroidDebugger() {
String debuggerID = getDebuggerID();
- for (AndroidDebugger androidDebugger: getAndroidDebuggers()) {
+ for (AndroidDebugger androidDebugger : getAndroidDebuggers()) {
if (androidDebugger.getId().equals(debuggerID)) {
return androidDebugger;
}
@@ -76,7 +74,7 @@
T androidDebuggerState = getAndroidDebuggerState(getDebuggerID());
// Set our working directory to our workspace root for native debugging.
if (androidDebuggerState instanceof NativeAndroidDebuggerState) {
- NativeAndroidDebuggerState nativeState = (NativeAndroidDebuggerState)androidDebuggerState;
+ NativeAndroidDebuggerState nativeState = (NativeAndroidDebuggerState) androidDebuggerState;
String workingDirPath = WorkspaceRoot.fromProject(project).directory().getPath();
nativeState.setWorkingDir(workingDirPath);
}
@@ -89,21 +87,23 @@
}
private String getDebuggerID() {
- BlazeNativeDebuggerIdProvider blazeNativeDebuggerIdProvider = BlazeNativeDebuggerIdProvider.getInstance();
+ BlazeNativeDebuggerIdProvider blazeNativeDebuggerIdProvider =
+ BlazeNativeDebuggerIdProvider.getInstance();
return (blazeNativeDebuggerIdProvider != null && commonState.isNativeDebuggingEnabled())
- ? blazeNativeDebuggerIdProvider.getDebuggerId()
- : AndroidJavaDebugger.ID;
+ ? blazeNativeDebuggerIdProvider.getDebuggerId()
+ : AndroidJavaDebugger.ID;
}
@Nullable
- private final <T extends AndroidDebuggerState> T getAndroidDebuggerState(String androidDebuggerId) {
+ private final <T extends AndroidDebuggerState> T getAndroidDebuggerState(
+ String androidDebuggerId) {
AndroidDebuggerState state = androidDebuggerStates.get(androidDebuggerId);
- return (state != null) ? (T)state : null;
+ return (state != null) ? (T) state : null;
}
@Override
public void readExternal(Element element) throws InvalidDataException {
- for (Map.Entry<String, AndroidDebuggerState> entry: androidDebuggerStates.entrySet()) {
+ for (Map.Entry<String, AndroidDebuggerState> entry : androidDebuggerStates.entrySet()) {
Element optionElement = element.getChild(entry.getKey());
if (optionElement != null) {
entry.getValue().readExternal(optionElement);
@@ -113,7 +113,7 @@
@Override
public void writeExternal(Element element) throws WriteExternalException {
- for (Map.Entry<String, AndroidDebuggerState> entry: androidDebuggerStates.entrySet()) {
+ for (Map.Entry<String, AndroidDebuggerState> entry : androidDebuggerStates.entrySet()) {
Element optionElement = new Element(entry.getKey());
element.addContent(optionElement);
entry.getValue().writeExternal(optionElement);
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDeployTargetManager.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDeployTargetManager.java
index 3b76283..306bec4 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDeployTargetManager.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationDeployTargetManager.java
@@ -30,16 +30,13 @@
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
import org.jdom.Element;
import org.jetbrains.android.facet.AndroidFacet;
-import javax.annotation.Nullable;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Manages deploy target state for run configurations.
- */
+/** Manages deploy target state for run configurations. */
public class BlazeAndroidRunConfigurationDeployTargetManager implements JDOMExternalizable {
private static final String TARGET_SELECTION_MODE = TargetSelectionMode.SHOW_DIALOG.name();
@@ -48,8 +45,7 @@
private final List<DeployTargetProvider> deployTargetProviders;
private final Map<String, DeployTargetState> deployTargetStates;
- BlazeAndroidRunConfigurationDeployTargetManager(int runConfigId,
- boolean isAndroidTest) {
+ BlazeAndroidRunConfigurationDeployTargetManager(int runConfigId, boolean isAndroidTest) {
this.runConfigId = runConfigId;
this.isAndroidTest = isAndroidTest;
this.deployTargetProviders = DeployTargetProvider.getProviders();
@@ -66,28 +62,26 @@
}
@Nullable
- DeployTarget getDeployTarget(Executor executor,
- ExecutionEnvironment env,
- AndroidFacet facet) throws ExecutionException {
+ DeployTarget getDeployTarget(Executor executor, ExecutionEnvironment env, AndroidFacet facet)
+ throws ExecutionException {
DeployTargetProvider currentTargetProvider = getCurrentDeployTargetProvider();
DeployTarget deployTarget;
if (currentTargetProvider.requiresRuntimePrompt()) {
- deployTarget = currentTargetProvider.showPrompt(
- executor,
- env,
- facet,
- getDeviceCount(),
- isAndroidTest,
- deployTargetStates,
- runConfigId,
- (device) -> LaunchCompatibility.YES
- );
+ deployTarget =
+ currentTargetProvider.showPrompt(
+ executor,
+ env,
+ facet,
+ getDeviceCount(),
+ isAndroidTest,
+ deployTargetStates,
+ runConfigId,
+ (device) -> LaunchCompatibility.YES);
if (deployTarget == null) {
return null;
}
- }
- else {
+ } else {
deployTarget = currentTargetProvider.getDeployTarget();
}
@@ -99,7 +93,8 @@
return deployTargetStates.get(currentTarget.getId());
}
- // TODO(salguarnieri) Currently the target selection mode is always SHOW_DIALOG. This code is here for future use.
+ // TODO(salguarnieri) Currently the target selection mode is always SHOW_DIALOG.
+ // This code is here for future use.
// If this code still isn't used after ASwB supports native, then we should delete this logic.
private DeployTargetProvider getCurrentDeployTargetProvider() {
DeployTargetProvider target = getDeployTargetProvider(TARGET_SELECTION_MODE);
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationRunner.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationRunner.java
index eed693e..e0cef2a 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationRunner.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunConfigurationRunner.java
@@ -16,8 +16,19 @@
package com.google.idea.blaze.android.run.runner;
+import static com.android.tools.idea.gradle.util.Projects.requiredAndroidModelMissing;
+import static org.jetbrains.android.actions.RunAndroidAvdManagerAction.getName;
+
import com.android.ddmlib.IDevice;
-import com.android.tools.idea.run.*;
+import com.android.tools.idea.run.AndroidProcessHandler;
+import com.android.tools.idea.run.AndroidSessionInfo;
+import com.android.tools.idea.run.ApkProvisionException;
+import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.DeviceFutures;
+import com.android.tools.idea.run.LaunchInfo;
+import com.android.tools.idea.run.LaunchOptions;
+import com.android.tools.idea.run.LaunchTaskRunner;
+import com.android.tools.idea.run.ValidationError;
import com.android.tools.idea.run.editor.DeployTarget;
import com.android.tools.idea.run.editor.DeployTargetState;
import com.android.tools.idea.run.tasks.LaunchTasksProvider;
@@ -26,8 +37,8 @@
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfiguration;
import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandler;
import com.google.idea.blaze.base.command.BlazeFlags;
import com.google.idea.blaze.base.experiments.ExperimentScope;
import com.google.idea.blaze.base.metrics.Action;
@@ -36,6 +47,7 @@
import com.google.idea.blaze.base.scope.Scope;
import com.google.idea.blaze.base.scope.output.IssueOutput;
import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
import com.google.idea.blaze.base.scope.scopes.IssuesScope;
import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
import com.google.idea.blaze.base.settings.BlazeUserSettings;
@@ -57,6 +69,7 @@
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.WriteExternalException;
+import java.util.List;
import org.jdom.Element;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.sdk.AndroidSdkUtils;
@@ -64,35 +77,35 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-
-import static com.android.tools.idea.gradle.util.Projects.requiredAndroidModelMissing;
-import static org.jetbrains.android.actions.RunAndroidAvdManagerAction.getName;
-
/**
* Supports the entire run configuration flow. Used by both android_binary and android_test.
*
- * Does any verification necessary, builds the APK and installs it, launches and debug tasks, etc.
+ * <p>Does any verification necessary, builds the APK and installs it, launches and debug tasks,
+ * etc.
*
- * Any indirection between android_binary/android_test, mobile-install, InstantRun etc. should
+ * <p>Any indirection between android_binary/android_test, mobile-install, InstantRun etc. should
* come via the strategy class.
*/
public final class BlazeAndroidRunConfigurationRunner implements JDOMExternalizable {
private static final Logger LOG = Logger.getInstance(BlazeAndroidRunConfigurationRunner.class);
- private static final String SYNC_FAILED_ERR_MSG = "Project state is invalid. Please sync and try your action again.";
+ private static final String SYNC_FAILED_ERR_MSG =
+ "Project state is invalid. Please sync and try your action again.";
public static final Key<BlazeAndroidRunContext> RUN_CONTEXT_KEY = Key.create("blaze.run.context");
- public static final Key<BlazeAndroidDeviceSelector.DeviceSession> DEVICE_SESSION_KEY = Key.create("blaze.device.session");
+ public static final Key<BlazeAndroidDeviceSelector.DeviceSession> DEVICE_SESSION_KEY =
+ Key.create("blaze.device.session");
- // We need to split "-c dbg" into two flags because we pass flags as a list of strings to the command line executor and we need blaze
+ // We need to split "-c dbg" into two flags because we pass flags
+ // as a list of strings to the command line executor and we need blaze
// to see -c and dbg as two separate entities, not one.
- private static final ImmutableList<String> NATIVE_DEBUG_FLAGS = ImmutableList.of("--fission=no", "-c", "dbg");
+ private static final ImmutableList<String> NATIVE_DEBUG_FLAGS =
+ ImmutableList.of("--fission=no", "-c", "dbg");
private final Project project;
- private final BlazeAndroidRunConfiguration runConfiguration;
+ private final BlazeAndroidRunConfigurationHandler runConfigurationHandler;
private final BlazeAndroidRunConfigurationCommonState commonState;
@@ -102,25 +115,27 @@
private final BlazeAndroidRunConfigurationDebuggerManager debuggerManager;
- public BlazeAndroidRunConfigurationRunner(Project project,
- BlazeAndroidRunConfiguration runConfiguration,
- BlazeAndroidRunConfigurationCommonState commonState,
- boolean isAndroidTest,
- int runConfigId) {
+ public BlazeAndroidRunConfigurationRunner(
+ Project project,
+ BlazeAndroidRunConfigurationHandler runConfigurationHandler,
+ BlazeAndroidRunConfigurationCommonState commonState,
+ boolean isAndroidTest,
+ int runConfigId) {
this.project = project;
- this.runConfiguration = runConfiguration;
+ this.runConfigurationHandler = runConfigurationHandler;
this.commonState = commonState;
this.runConfigId = runConfigId;
- this.deployTargetManager = new BlazeAndroidRunConfigurationDeployTargetManager(runConfigId, isAndroidTest);
+ this.deployTargetManager =
+ new BlazeAndroidRunConfigurationDeployTargetManager(runConfigId, isAndroidTest);
this.debuggerManager = new BlazeAndroidRunConfigurationDebuggerManager(project, commonState);
}
private ImmutableList<String> getBuildFlags(Project project, ProjectViewSet projectViewSet) {
return ImmutableList.<String>builder()
- .addAll(BlazeFlags.buildFlags(project, projectViewSet))
- .addAll(commonState.getUserFlags())
- .addAll(getNativeDebuggerFlags())
- .build();
+ .addAll(BlazeFlags.buildFlags(project, projectViewSet))
+ .addAll(commonState.getUserFlags())
+ .addAll(getNativeDebuggerFlags())
+ .build();
}
public ImmutableList<String> getNativeDebuggerFlags() {
@@ -128,17 +143,20 @@
}
/**
- * We collect errors rather than throwing to avoid missing fatal errors by exiting early for a warning.
- * We use a separate method for the collection so the compiler prevents us from accidentally throwing.
+ * We collect errors rather than throwing to avoid missing fatal errors by exiting early for a
+ * warning. We use a separate method for the collection so the compiler prevents us from
+ * accidentally throwing.
*/
public List<ValidationError> validate(@Nullable Module module) {
List<ValidationError> errors = Lists.newArrayList();
if (module == null) {
- errors.add(ValidationError.fatal("No run configuration module found"));
+ errors.add(
+ ValidationError.fatal(
+ "No run configuration module found. Have you successfully synced your project?"));
return errors;
}
- if (commonState.getTarget() == null) {
+ if (runConfigurationHandler.getLabel() == null) {
errors.add(ValidationError.fatal("No target selected"));
return errors;
}
@@ -151,7 +169,8 @@
AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet == null) {
// Can't proceed.
- return ImmutableList.of(ValidationError.fatal(AndroidBundle.message("no.facet.error", module.getName())));
+ return ImmutableList.of(
+ ValidationError.fatal(AndroidBundle.message("no.facet.error", module.getName())));
}
if (facet.getConfiguration().getAndroidPlatform() == null) {
@@ -165,9 +184,8 @@
}
@Nullable
- public final RunProfileState getState(Module module,
- final Executor executor,
- ExecutionEnvironment env) throws ExecutionException {
+ public final RunProfileState getState(
+ Module module, final Executor executor, ExecutionEnvironment env) throws ExecutionException {
assert module != null : "Enforced by fatal validation check in checkConfiguration.";
final AndroidFacet facet = AndroidFacet.getInstance(module);
@@ -180,33 +198,24 @@
}
ImmutableList<String> buildFlags = getBuildFlags(project, projectViewSet);
- BlazeAndroidRunContext runContext = runConfiguration.createRunContext(
- project,
- facet,
- env,
- buildFlags
- );
+ BlazeAndroidRunContext runContext =
+ runConfigurationHandler.createRunContext(project, facet, env, buildFlags);
runContext.augmentEnvironment(env);
- boolean debug = executor instanceof DefaultDebugExecutor;
- if (debug && !AndroidSdkUtils.activateDdmsIfNecessary(facet.getModule().getProject())) {
- throw new ExecutionException("Unable to obtain debug bridge. Please check if there is a different tool using adb that is active.");
+ boolean isDebug = executor instanceof DefaultDebugExecutor;
+ if (isDebug && !AndroidSdkUtils.activateDdmsIfNecessary(facet.getModule().getProject())) {
+ throw new ExecutionException(
+ "Unable to obtain debug bridge. "
+ + "Please check if there is a different tool using adb that is active.");
}
AndroidSessionInfo info = AndroidSessionInfo.findOldSession(project, null, runConfigId);
BlazeAndroidDeviceSelector deviceSelector = runContext.getDeviceSelector();
- BlazeAndroidDeviceSelector.DeviceSession deviceSession = deviceSelector.getDevice(
- project,
- facet,
- deployTargetManager,
- executor,
- env,
- info,
- debug,
- runConfigId
- );
+ BlazeAndroidDeviceSelector.DeviceSession deviceSession =
+ deviceSelector.getDevice(
+ project, facet, deployTargetManager, executor, env, info, isDebug, runConfigId);
if (deviceSession == null) {
return null;
}
@@ -219,7 +228,8 @@
DeviceFutures deviceFutures = deviceSession.deviceFutures;
if (deviceFutures == null) {
- // The user deliberately canceled, or some error was encountered and exposed by the chooser. Quietly exit.
+ // The user deliberately canceled, or some error was encountered and exposed by the chooser.
+ // Quietly exit.
return null;
}
@@ -227,33 +237,26 @@
throw new ExecutionException(AndroidBundle.message("deployment.target.not.found"));
}
- if (debug) {
+ if (isDebug) {
String error = canDebug(deviceFutures, facet, module.getName());
if (error != null) {
throw new ExecutionException(error);
}
}
- LaunchOptions.Builder launchOptionsBuilder = getDefaultLaunchOptions()
- .setDebug(debug);
+ LaunchOptions.Builder launchOptionsBuilder = getDefaultLaunchOptions().setDebug(isDebug);
runContext.augmentLaunchOptions(launchOptionsBuilder);
- LaunchOptions launchOptions = launchOptionsBuilder.build();
// Store the run context on the execution environment so before-run tasks can access it.
env.putCopyableUserData(RUN_CONTEXT_KEY, runContext);
env.putCopyableUserData(DEVICE_SESSION_KEY, deviceSession);
return new BlazeAndroidRunState(
- module,
- env,
- getName(),
- launchOptions,
- deviceSession,
- runContext
- );
+ module, env, getName(), launchOptionsBuilder, isDebug, deviceSession, runContext);
}
- private static String canDebug(DeviceFutures deviceFutures, AndroidFacet facet, String moduleName) {
+ private static String canDebug(
+ DeviceFutures deviceFutures, AndroidFacet facet, String moduleName) {
// If we are debugging on a device, then the app needs to be debuggable
for (ListenableFuture<IDevice> future : deviceFutures.get()) {
if (!future.isDone()) {
@@ -262,45 +265,50 @@
}
IDevice device = Futures.getUnchecked(future);
if (!LaunchUtils.canDebugAppOnDevice(facet, device)) {
- return AndroidBundle.message("android.cannot.debug.noDebugPermissions", moduleName, device.getName());
+ return AndroidBundle.message(
+ "android.cannot.debug.noDebugPermissions", moduleName, device.getName());
}
}
return null;
}
-
private static LaunchOptions.Builder getDefaultLaunchOptions() {
return LaunchOptions.builder()
- .setClearLogcatBeforeStart(false)
- .setSkipNoopApkInstallations(true)
- .setForceStopRunningApp(true);
+ .setClearLogcatBeforeStart(false)
+ .setSkipNoopApkInstallations(true)
+ .setForceStopRunningApp(true);
}
public boolean executeBuild(ExecutionEnvironment env) {
boolean suppressConsole = BlazeUserSettings.getInstance().getSuppressConsoleForRunAction();
- return Scope.root(context -> {
- context
- .push(new IssuesScope(project))
- .push(new ExperimentScope())
- .push(new BlazeConsoleScope.Builder(project).setSuppressConsole(suppressConsole).build())
- .push(new LoggedTimingScope(project, Action.APK_BUILD_AND_INSTALL))
- ;
+ return Scope.root(
+ context -> {
+ context
+ .push(new IssuesScope(project))
+ .push(new ExperimentScope())
+ .push(
+ new BlazeConsoleScope.Builder(project)
+ .setSuppressConsole(suppressConsole)
+ .build())
+ .push(new IdeaLogScope())
+ .push(new LoggedTimingScope(project, Action.APK_BUILD_AND_INSTALL));
- BlazeAndroidRunContext runContext = env.getCopyableUserData(RUN_CONTEXT_KEY);
- if (runContext == null) {
- IssueOutput.error("Could not find run context. Please try again").submit(context);
- return false;
- }
- BlazeAndroidDeviceSelector.DeviceSession deviceSession = env.getCopyableUserData(DEVICE_SESSION_KEY);
+ BlazeAndroidRunContext runContext = env.getCopyableUserData(RUN_CONTEXT_KEY);
+ if (runContext == null) {
+ IssueOutput.error("Could not find run context. Please try again").submit(context);
+ return false;
+ }
+ BlazeAndroidDeviceSelector.DeviceSession deviceSession =
+ env.getCopyableUserData(DEVICE_SESSION_KEY);
- BlazeApkBuildStep buildStep = runContext.getBuildStep();
- try {
- return buildStep.build(context, deviceSession);
- } catch (Exception e) {
- LOG.error(e);
- return false;
- }
- });
+ BlazeApkBuildStep buildStep = runContext.getBuildStep();
+ try {
+ return buildStep.build(context, deviceSession);
+ } catch (Exception e) {
+ LOG.error(e);
+ return false;
+ }
+ });
}
private final class BlazeAndroidRunState implements RunProfileState {
@@ -310,25 +318,30 @@
private final String launchConfigName;
private final BlazeAndroidDeviceSelector.DeviceSession deviceSession;
private final BlazeAndroidRunContext runContext;
- private final LaunchOptions launchOptions;
+ private final LaunchOptions.Builder launchOptionsBuilder;
+ private final boolean isDebug;
- private BlazeAndroidRunState(Module module,
- ExecutionEnvironment env,
- String launchConfigName,
- LaunchOptions launchOptions,
- BlazeAndroidDeviceSelector.DeviceSession deviceSession,
- BlazeAndroidRunContext runContext) {
+ private BlazeAndroidRunState(
+ Module module,
+ ExecutionEnvironment env,
+ String launchConfigName,
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidDeviceSelector.DeviceSession deviceSession,
+ BlazeAndroidRunContext runContext) {
this.module = module;
this.env = env;
this.launchConfigName = launchConfigName;
this.deviceSession = deviceSession;
this.runContext = runContext;
- this.launchOptions = launchOptions;
+ this.launchOptionsBuilder = launchOptionsBuilder;
+ this.isDebug = isDebug;
}
@Nullable
@Override
- public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
+ public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner)
+ throws ExecutionException {
ProcessHandler processHandler;
ConsoleView console;
@@ -337,42 +350,51 @@
String applicationId;
try {
applicationId = applicationIdProvider.getPackageName();
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
throw new ExecutionException("Unable to obtain application id", e);
}
- LaunchTasksProvider launchTasksProvider = runContext.getLaunchTasksProvider(launchOptions, debuggerManager);
+ LaunchTasksProvider launchTasksProvider =
+ runContext.getLaunchTasksProvider(launchOptionsBuilder, isDebug, debuggerManager);
DeviceFutures deviceFutures = deviceSession.deviceFutures;
assert deviceFutures != null;
- ProcessHandler previousSessionProcessHandler = deviceSession.sessionInfo != null ?
- deviceSession.sessionInfo.getProcessHandler() : null;
+ ProcessHandler previousSessionProcessHandler =
+ deviceSession.sessionInfo != null ? deviceSession.sessionInfo.getProcessHandler() : null;
if (launchTasksProvider.createsNewProcess()) {
- // In the case of cold swap, there is an existing process that is connected, but we are going to launch a new one.
- // Detach the previous process handler so that we don't end up with 2 run tabs for the same launch (the existing one
- // and the new one).
+ // In the case of cold swap, there is an existing process that is connected,
+ // but we are going to launch a new one.
+ // Detach the previous process handler so that we don't end up with
+ // 2 run tabs for the same launch (the existing one and the new one).
if (previousSessionProcessHandler != null) {
previousSessionProcessHandler.detachProcess();
}
- processHandler = new AndroidProcessHandler(applicationId, launchTasksProvider.monitorRemoteProcess());
- console = runContext.getConsoleProvider().createAndAttach(module.getProject(), processHandler, executor);
+ processHandler =
+ new AndroidProcessHandler(applicationId, launchTasksProvider.monitorRemoteProcess());
+ console =
+ runContext
+ .getConsoleProvider()
+ .createAndAttach(module.getProject(), processHandler, executor);
} else {
- assert previousSessionProcessHandler != null : "No process handler from previous session, yet current tasks don't create one";
+ assert previousSessionProcessHandler != null
+ : "No process handler from previous session, yet current tasks don't create one";
processHandler = previousSessionProcessHandler;
console = null;
}
- LaunchInfo launchInfo = new LaunchInfo(executor, runner, env, runContext.getConsoleProvider());
+ LaunchInfo launchInfo =
+ new LaunchInfo(executor, runner, env, runContext.getConsoleProvider());
- LaunchTaskRunner task = new LaunchTaskRunner(module.getProject(),
- launchConfigName,
- launchInfo,
- processHandler,
- deviceSession.deviceFutures,
- launchTasksProvider);
+ LaunchTaskRunner task =
+ new LaunchTaskRunner(
+ module.getProject(),
+ launchConfigName,
+ launchInfo,
+ processHandler,
+ deviceSession.deviceFutures,
+ launchTasksProvider);
ProgressManager.getInstance().run(task);
return console == null ? null : new DefaultExecutionResult(console, processHandler);
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunContext.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunContext.java
index ef6f94d..1778a63 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunContext.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeAndroidRunContext.java
@@ -17,6 +17,7 @@
import com.android.ddmlib.IDevice;
import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.ConsolePrinter;
import com.android.tools.idea.run.ConsoleProvider;
import com.android.tools.idea.run.LaunchOptions;
import com.android.tools.idea.run.editor.AndroidDebugger;
@@ -28,13 +29,10 @@
import com.google.common.collect.ImmutableList;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.runners.ExecutionEnvironment;
-
-import javax.annotation.Nullable;
import java.util.Set;
+import javax.annotation.Nullable;
-/**
- * Instantiated when the configuration wants to run.
- */
+/** Instantiated when the configuration wants to run. */
public interface BlazeAndroidRunContext {
BlazeAndroidDeviceSelector getDeviceSelector();
@@ -50,29 +48,33 @@
ApplicationIdProvider getApplicationIdProvider() throws ExecutionException;
LaunchTasksProvider getLaunchTasksProvider(
- LaunchOptions launchOptions,
- BlazeAndroidRunConfigurationDebuggerManager debuggerManager) throws ExecutionException;
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidRunConfigurationDebuggerManager debuggerManager)
+ throws ExecutionException;
- /**
- * Returns the tasks to deploy the application.
- */
- ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions) throws ExecutionException;
+ /** Returns the tasks to deploy the application. */
+ ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions)
+ throws ExecutionException;
- /**
- * Returns the task to launch the application.
- */
+ /** Returns the task to launch the application. */
@Nullable
- LaunchTask getApplicationLaunchTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- ProcessHandlerLaunchStatus processHandlerLaunchStatus) throws ExecutionException;
+ LaunchTask getApplicationLaunchTask(
+ LaunchOptions launchOptions,
+ @Nullable Integer userId,
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus)
+ throws ExecutionException;
- /**
- * Returns the task to connect the debugger.
- */
+ /** Returns the task to connect the debugger. */
@Nullable
- DebugConnectorTask getDebuggerTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- Set<String> packageIds) throws ExecutionException;
+ DebugConnectorTask getDebuggerTask(
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ Set<String> packageIds)
+ throws ExecutionException;
+
+ @Nullable
+ Integer getUserId(IDevice device, ConsolePrinter consolePrinter) throws ExecutionException;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStep.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStep.java
index 3667c93..b437f7f 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStep.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStep.java
@@ -17,9 +17,7 @@
import com.google.idea.blaze.base.scope.BlazeContext;
-/**
- * Builds the APK.
- */
+/** Builds the APK. */
public interface BlazeApkBuildStep {
/**
* Builds an optionally installs the APK.
diff --git a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStepNormalBuild.java b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStepNormalBuild.java
index 2da6a9a..9c18824 100644
--- a/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStepNormalBuild.java
+++ b/aswb/src/com/google/idea/blaze/android/run/runner/BlazeApkBuildStepNormalBuild.java
@@ -19,7 +19,6 @@
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.deployinfo.BlazeAndroidDeployInfo;
import com.google.idea.blaze.android.run.deployinfo.BlazeApkDeployInfoProtoHelper;
import com.google.idea.blaze.base.async.executor.BlazeExecutor;
@@ -28,8 +27,10 @@
import com.google.idea.blaze.base.command.BlazeCommand;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.ScopedTask;
@@ -39,82 +40,80 @@
import com.google.idea.blaze.base.util.SaveUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.LocalFileSystem;
+import java.util.concurrent.CancellationException;
import org.jetbrains.annotations.NotNull;
-import java.util.concurrent.CancellationException;
-
-/**
- * Builds the APK using normal blaze build.
- */
+/** Builds the APK using normal blaze build. */
public class BlazeApkBuildStepNormalBuild implements BlazeApkBuildStep {
private final Project project;
- private final BlazeAndroidRunConfigurationCommonState commonState;
+ private final Label label;
private final ImmutableList<String> buildFlags;
private final SettableFuture<BlazeAndroidDeployInfo> deployInfoFuture = SettableFuture.create();
- public BlazeApkBuildStepNormalBuild(Project project,
- BlazeAndroidRunConfigurationCommonState commonState,
- ImmutableList<String> buildFlags) {
+ public BlazeApkBuildStepNormalBuild(
+ Project project, Label label, ImmutableList<String> buildFlags) {
this.project = project;
- this.commonState = commonState;
+ this.label = label;
this.buildFlags = buildFlags;
}
@Override
- public boolean build(BlazeContext context, BlazeAndroidDeviceSelector.DeviceSession deviceSession) {
- final ScopedTask buildTask = new ScopedTask(context) {
- @Override
- protected void execute(@NotNull BlazeContext context) {
- BlazeCommand.Builder command = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD);
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ public boolean build(
+ BlazeContext context, BlazeAndroidDeviceSelector.DeviceSession deviceSession) {
+ final ScopedTask buildTask =
+ new ScopedTask(context) {
+ @Override
+ protected void execute(@NotNull BlazeContext context) {
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD);
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- command
- .addTargets(commonState.getTarget())
- .addBlazeFlags("--output_groups=+android_deploy_info")
- .addBlazeFlags(buildFlags)
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS)
- ;
+ command
+ .addTargets(label)
+ .addBlazeFlags("--output_groups=+android_deploy_info")
+ .addBlazeFlags(buildFlags)
+ .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS);
- BlazeApkDeployInfoProtoHelper deployInfoHelper = new BlazeApkDeployInfoProtoHelper(project, buildFlags);
+ BlazeApkDeployInfoProtoHelper deployInfoHelper =
+ new BlazeApkDeployInfoProtoHelper(project, buildFlags);
- SaveUtil.saveAllFiles();
- int retVal = ExternalTask.builder(workspaceRoot, command.build())
- .context(context)
- .stderr(LineProcessingOutputStream.of(
- deployInfoHelper.getLineProcessor(),
- new IssueOutputLineProcessor(project, context, workspaceRoot)
- ))
- .build()
- .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
- LocalFileSystem.getInstance().refresh(true);
+ SaveUtil.saveAllFiles();
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command.build())
+ .context(context)
+ .stderr(
+ LineProcessingOutputStream.of(
+ deployInfoHelper.getLineProcessor(),
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
+ FileCaches.refresh(project);
- if (retVal != 0) {
- context.setHasError();
- return;
- }
- BlazeAndroidDeployInfo deployInfo = deployInfoHelper.readDeployInfo(context);
- if (deployInfo == null) {
- IssueOutput.error("Could not read apk deploy info from build").submit(context);
- return;
- }
- deployInfoFuture.set(deployInfo);
- }
- };
+ if (retVal != 0) {
+ context.setHasError();
+ return;
+ }
+ BlazeAndroidDeployInfo deployInfo = deployInfoHelper.readDeployInfo(context);
+ if (deployInfo == null) {
+ IssueOutput.error("Could not read apk deploy info from build").submit(context);
+ return;
+ }
+ deployInfoFuture.set(deployInfo);
+ }
+ };
- ListenableFuture<Void> buildFuture = BlazeExecutor.submitTask(
- project,
- String.format("Executing %s apk build", Blaze.buildSystemName(project)),
- buildTask
- );
+ ListenableFuture<Void> buildFuture =
+ BlazeExecutor.submitTask(
+ project,
+ String.format("Executing %s apk build", Blaze.buildSystemName(project)),
+ buildTask);
try {
Futures.get(buildFuture, ExecutionException.class);
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
context.setHasError();
- }
- catch (CancellationException e) {
+ } catch (CancellationException e) {
context.setCancelled();
}
return context.shouldContinue();
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/AndroidTestConsoleProvider.java b/aswb/src/com/google/idea/blaze/android/run/test/AndroidTestConsoleProvider.java
index 878cf08..56ff338 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/AndroidTestConsoleProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/AndroidTestConsoleProvider.java
@@ -29,17 +29,16 @@
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
-/**
- * Console provider for android_test
- */
+/** Console provider for android_test */
class AndroidTestConsoleProvider implements ConsoleProvider {
private final Project project;
private final RunConfiguration runConfiguration;
private final BlazeAndroidTestRunConfigurationState configState;
- AndroidTestConsoleProvider(Project project,
- RunConfiguration runConfiguration,
- BlazeAndroidTestRunConfigurationState configState) {
+ AndroidTestConsoleProvider(
+ Project project,
+ RunConfiguration runConfiguration,
+ BlazeAndroidTestRunConfigurationState configState) {
this.project = project;
this.runConfiguration = runConfiguration;
this.configState = configState;
@@ -47,23 +46,24 @@
@NotNull
@Override
- public ConsoleView createAndAttach(@NotNull Disposable parent,
- @NotNull ProcessHandler handler,
- @NotNull Executor executor) throws ExecutionException {
+ public ConsoleView createAndAttach(
+ @NotNull Disposable parent, @NotNull ProcessHandler handler, @NotNull Executor executor)
+ throws ExecutionException {
if (!configState.isRunThroughBlaze()) {
return getStockConsoleProvider().createAndAttach(parent, handler, executor);
}
- ConsoleView console = TextConsoleBuilderFactory.getInstance()
- .createBuilder(project)
- .getConsole();
+ ConsoleView console =
+ TextConsoleBuilderFactory.getInstance().createBuilder(project).getConsole();
console.attachToProcess(handler);
return console;
}
private ConsoleProvider getStockConsoleProvider() {
return (parent, handler, executor) -> {
- AndroidTestConsoleProperties properties = new AndroidTestConsoleProperties(runConfiguration, executor);
- ConsoleView consoleView = SMTestRunnerConnectionUtil.createAndAttachConsole("Android", handler, properties);
+ AndroidTestConsoleProperties properties =
+ new AndroidTestConsoleProperties(runConfiguration, executor);
+ ConsoleView consoleView =
+ SMTestRunnerConnectionUtil.createAndAttachConsole("Android", handler, properties);
Disposer.register(parent, consoleView);
return consoleView;
};
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestApplicationIdProvider.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestApplicationIdProvider.java
index d7e7b86..71f37fd 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestApplicationIdProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestApplicationIdProvider.java
@@ -28,15 +28,13 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-/**
- * Application id provider for android_binary.
- */
+/** Application id provider for android_binary. */
public class BlazeAndroidTestApplicationIdProvider implements ApplicationIdProvider {
private final Project project;
private final ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture;
- public BlazeAndroidTestApplicationIdProvider(Project project,
- ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture) {
+ public BlazeAndroidTestApplicationIdProvider(
+ Project project, ListenableFuture<BlazeAndroidDeployInfo> deployInfoFuture) {
this.project = project;
this.deployInfoFuture = deployInfoFuture;
}
@@ -47,11 +45,13 @@
BlazeAndroidDeployInfo deployInfo = Futures.get(deployInfoFuture, ApkProvisionException.class);
Manifest manifest = Iterables.getFirst(deployInfo.getAdditionalMergedManifests(), null);
if (manifest == null) {
- throw new ApkProvisionException("Could not find manifest for application under test");
+ // The application may not have a separate package,
+ // and can instead be in the same package as the tests.
+ return getTestPackageName();
}
- String applicationId = ApplicationManager.getApplication().runReadAction(
- (Computable<String>)() -> manifest.getPackage().getValue()
- );
+ String applicationId =
+ ApplicationManager.getApplication()
+ .runReadAction((Computable<String>) () -> manifest.getPackage().getValue());
if (applicationId == null) {
throw new ApkProvisionException("No application id in manifest under test");
}
@@ -64,13 +64,15 @@
BlazeAndroidDeployInfo deployInfo = Futures.get(deployInfoFuture, ApkProvisionException.class);
Manifest manifest = deployInfo.getMergedManifest();
if (manifest == null) {
- throw new ApkProvisionException("Could not find merged manifest: " + deployInfo.getMergedManifestFile());
+ throw new ApkProvisionException(
+ "Could not find merged manifest: " + deployInfo.getMergedManifestFile());
}
- String applicationId = ApplicationManager.getApplication().runReadAction(
- (Computable<String>)() -> manifest.getPackage().getValue()
- );
+ String applicationId =
+ ApplicationManager.getApplication()
+ .runReadAction((Computable<String>) () -> manifest.getPackage().getValue());
if (applicationId == null) {
- throw new ApkProvisionException("No application id in merged manifest: " + deployInfo.getMergedManifestFile());
+ throw new ApkProvisionException(
+ "No application id in merged manifest: " + deployInfo.getMergedManifestFile());
}
return applicationId;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestClassRunConfigurationProducer.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestClassRunConfigurationProducer.java
index d09065c..ff1e6b7 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestClassRunConfigurationProducer.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestClassRunConfigurationProducer.java
@@ -19,8 +19,10 @@
import com.google.common.base.Strings;
import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
import com.google.idea.blaze.java.run.RunUtil;
-import com.google.idea.blaze.java.run.producers.BlazeTestRunConfigurationProducer;
import com.google.idea.blaze.java.run.producers.JUnitConfigurationUtil;
import com.google.idea.blaze.java.run.producers.ProducerUtils;
import com.intellij.execution.JavaExecutionUtil;
@@ -35,21 +37,22 @@
/**
* Producer for run configurations related to Android test classes in Blaze.
- * <p/>
- * This class is based on
- * {@link org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer}.
+ *
+ * <p>This class is based on {@link
+ * org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer}.
*/
-public class BlazeAndroidTestClassRunConfigurationProducer extends BlazeTestRunConfigurationProducer<BlazeAndroidTestRunConfiguration> {
+public class BlazeAndroidTestClassRunConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
public BlazeAndroidTestClassRunConfigurationProducer() {
- super(BlazeAndroidTestRunConfigurationType.getInstance());
+ super(BlazeCommandRunConfigurationType.getInstance());
}
@Override
protected boolean doSetupConfigFromContext(
- @NotNull BlazeAndroidTestRunConfiguration configuration,
- @NotNull ConfigurationContext context,
- @NotNull Ref<PsiElement> sourceElement) {
+ @NotNull BlazeCommandRunConfiguration configuration,
+ @NotNull ConfigurationContext context,
+ @NotNull Ref<PsiElement> sourceElement) {
final Location contextLocation = context.getLocation();
assert contextLocation != null;
@@ -76,9 +79,14 @@
return false;
}
configuration.setTarget(rule.label);
- BlazeAndroidTestRunConfigurationState configState = configuration.getConfigState();
- configState.TESTING_TYPE = AndroidTestRunConfiguration.TEST_CLASS;
- configState.CLASS_NAME = testClass.getQualifiedName();
+ BlazeAndroidTestRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeAndroidTestRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ BlazeAndroidTestRunConfigurationState configState = handler.getConfigState();
+ configState.setTestingType(AndroidTestRunConfiguration.TEST_CLASS);
+ configState.setClassName(testClass.getQualifiedName());
configuration.setGeneratedName();
return true;
@@ -86,8 +94,7 @@
@Override
protected boolean doIsConfigFromContext(
- @NotNull BlazeAndroidTestRunConfiguration configuration,
- @NotNull ConfigurationContext context) {
+ @NotNull BlazeCommandRunConfiguration configuration, @NotNull ConfigurationContext context) {
final Location contextLocation = context.getLocation();
assert contextLocation != null;
@@ -114,13 +121,18 @@
}
private static boolean checkIfAttributesAreTheSame(
- BlazeAndroidTestRunConfiguration configuration, PsiClass testClass) {
- BlazeAndroidTestRunConfigurationState configState = configuration.getConfigState();
- if (Strings.isNullOrEmpty(configState.CLASS_NAME)) {
+ BlazeCommandRunConfiguration configuration, PsiClass testClass) {
+ BlazeAndroidTestRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeAndroidTestRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ BlazeAndroidTestRunConfigurationState configState = handler.getConfigState();
+ if (Strings.isNullOrEmpty(configState.getClassName())) {
return false;
}
- return configState.TESTING_TYPE == AndroidTestRunConfiguration.TEST_CLASS
- && configState.CLASS_NAME.equals(testClass.getQualifiedName());
+ return configState.getTestingType() == AndroidTestRunConfiguration.TEST_CLASS
+ && configState.getClassName().equals(testClass.getQualifiedName());
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestFilter.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestFilter.java
index 1b9d234..c6f4a3b 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestFilter.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestFilter.java
@@ -21,12 +21,11 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-/**
- * A test filter specification for Android tests.
- */
+/** A test filter specification for Android tests. */
final class BlazeAndroidTestFilter {
// Specifies that Android tests should be filtered by name.
- private static final String TEST_FILTER_BY_NAME = BlazeFlags.TEST_ARG + "--test_filter_spec=TEST_NAME";
+ private static final String TEST_FILTER_BY_NAME =
+ BlazeFlags.TEST_ARG + "--test_filter_spec=TEST_NAME";
// As part of a name filter spec, the packages to include.
private static final String TEST_PACKAGE_NAMES = BlazeFlags.TEST_ARG + "--test_package_names=";
// As part of a name filter spec, the classes to include.
@@ -35,19 +34,15 @@
private static final String TEST_METHOD_NAMES = BlazeFlags.TEST_ARG + "--test_method_full_names=";
private final int testingType;
- @Nullable
- private final String className;
- @Nullable
- private final String methodName;
- @Nullable
- private final String packageName;
+ @Nullable private final String className;
+ @Nullable private final String methodName;
+ @Nullable private final String packageName;
public BlazeAndroidTestFilter(
- int testingType,
- @Nullable String className,
- @Nullable String methodName,
- @Nullable String packageName
- ) {
+ int testingType,
+ @Nullable String className,
+ @Nullable String methodName,
+ @Nullable String packageName) {
this.testingType = testingType;
this.className = className;
this.methodName = methodName;
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestLaunchTask.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestLaunchTask.java
index f7d0a9e..7283e53 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestLaunchTask.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestLaunchTask.java
@@ -28,6 +28,7 @@
import com.google.idea.blaze.base.command.BlazeCommand;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.projectview.ProjectViewManager;
@@ -37,26 +38,27 @@
import com.google.idea.blaze.base.scope.ScopedFunction;
import com.google.idea.blaze.base.scope.output.IssueOutput;
import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.util.SaveUtil;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.ide.PooledThreadExecutor;
-
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.ide.PooledThreadExecutor;
/**
- * An Android application launcher that invokes `blaze test` on an android_test target, and sets
- * up process handling and debugging for the test run.
+ * An Android application launcher that invokes `blaze test` on an android_test target, and sets up
+ * process handling and debugging for the test run.
*/
class BlazeAndroidTestLaunchTask implements LaunchTask {
// Uses a local device/emulator attached to adb to run an android_test.
- public static final String TEST_LOCAL_DEVICE = BlazeFlags.TEST_ARG + "--device_broker_type=LOCAL_ADB_SERVER";
+ public static final String TEST_LOCAL_DEVICE =
+ BlazeFlags.TEST_ARG + "--device_broker_type=LOCAL_ADB_SERVER";
// Uses a local device/emulator attached to adb to run an android_test.
public static final String TEST_DEBUG = BlazeFlags.TEST_ARG + "--enable_debug";
// Specifies the serial number for a local test device.
@@ -75,13 +77,12 @@
private final boolean debug;
public BlazeAndroidTestLaunchTask(
- Project project,
- Label target,
- List<String> buildFlags,
- BlazeAndroidTestFilter testFilter,
- BlazeAndroidTestRunContext runContext,
- boolean debug
- ) {
+ Project project,
+ Label target,
+ List<String> buildFlags,
+ BlazeAndroidTestFilter testFilter,
+ BlazeAndroidTestRunContext runContext,
+ boolean debug) {
this.project = project;
this.target = target;
this.buildFlags = buildFlags;
@@ -102,65 +103,83 @@
}
@Override
- public boolean perform(@NotNull IDevice device, @NotNull LaunchStatus launchStatus, @NotNull ConsolePrinter printer) {
+ public boolean perform(
+ @NotNull IDevice device,
+ @NotNull LaunchStatus launchStatus,
+ @NotNull ConsolePrinter printer) {
BlazeExecutor executor = BlazeExecutor.getInstance();
- ProcessHandlerLaunchStatus processHandlerLaunchStatus = (ProcessHandlerLaunchStatus)launchStatus;
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus =
+ (ProcessHandlerLaunchStatus) launchStatus;
final ProcessHandler processHandler = processHandlerLaunchStatus.getProcessHandler();
- blazeResult = executor.submit(new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return Scope.root(new ScopedFunction<Boolean>() {
- @Override
- public Boolean execute(@NotNull BlazeContext context) {
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- IssueOutput.error("Could not load project view. Please resync project.").submit(context);
- return false;
- }
+ blazeResult =
+ executor.submit(
+ new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return Scope.root(
+ new ScopedFunction<Boolean>() {
+ @Override
+ public Boolean execute(@NotNull BlazeContext context) {
+ ProjectViewSet projectViewSet =
+ ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ IssueOutput.error("Could not load project view. Please resync project.")
+ .submit(context);
+ return false;
+ }
- BlazeCommand.Builder commandBuilder = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.TEST)
- .addTargets(target);
- // Build flags must match BlazeBeforeRunTask.
- commandBuilder
- .addBlazeFlags(buildFlags);
- // Run the test on the selected local device/emulator.
- commandBuilder
- .addBlazeFlags(TEST_LOCAL_DEVICE, BlazeFlags.TEST_OUTPUT_STREAMED)
- .addBlazeFlags(testDeviceSerialFlags(device.getSerialNumber()))
- .addBlazeFlags(testFilter.getBlazeFlags());
- if (debug) {
- commandBuilder.addBlazeFlags(TEST_DEBUG, BlazeFlags.NO_CACHE_TEST_RESULTS);
- }
- BlazeCommand command = commandBuilder.build();
+ BlazeCommand.Builder commandBuilder =
+ BlazeCommand.builder(
+ Blaze.getBuildSystem(project), BlazeCommandName.TEST)
+ .addTargets(target);
+ // Build flags must match BlazeBeforeRunTask.
+ commandBuilder.addBlazeFlags(buildFlags);
+ // Run the test on the selected local device/emulator.
+ commandBuilder
+ .addBlazeFlags(TEST_LOCAL_DEVICE, BlazeFlags.TEST_OUTPUT_STREAMED)
+ .addBlazeFlags(testDeviceSerialFlags(device.getSerialNumber()))
+ .addBlazeFlags(testFilter.getBlazeFlags());
+ if (debug) {
+ commandBuilder.addBlazeFlags(
+ TEST_DEBUG, BlazeFlags.NO_CACHE_TEST_RESULTS);
+ }
+ BlazeCommand command = commandBuilder.build();
- printer.stdout(String.format("Starting %s test...\n", Blaze.buildSystemName(project)));
- printer.stdout(command + "\n");
- LineProcessingOutputStream.LineProcessor stdoutLineProcessor = line -> {
- printer.stdout(line);
- return true;
- };
- LineProcessingOutputStream.LineProcessor stderrLineProcessor = line -> {
- printer.stderr(line);
- return true;
- };
- int retVal = ExternalTask.builder(WorkspaceRoot.fromProject(project), command)
- .context(context)
- .stdout(LineProcessingOutputStream.of(stdoutLineProcessor))
- .stderr(LineProcessingOutputStream.of(stderrLineProcessor))
- .build()
- .run();
+ printer.stdout(
+ String.format("Starting %s test...\n", Blaze.buildSystemName(project)));
+ printer.stdout(command + "\n");
+ LineProcessingOutputStream.LineProcessor stdoutLineProcessor =
+ line -> {
+ printer.stdout(line);
+ return true;
+ };
+ LineProcessingOutputStream.LineProcessor stderrLineProcessor =
+ line -> {
+ printer.stderr(line);
+ return true;
+ };
+ SaveUtil.saveAllFiles();
+ int retVal =
+ ExternalTask.builder(WorkspaceRoot.fromProject(project))
+ .addBlazeCommand(command)
+ .context(context)
+ .stdout(LineProcessingOutputStream.of(stdoutLineProcessor))
+ .stderr(LineProcessingOutputStream.of(stderrLineProcessor))
+ .build()
+ .run();
+ FileCaches.refresh(project);
- if (retVal != 0) {
- context.setHasError();
- }
+ if (retVal != 0) {
+ context.setHasError();
+ }
- return !context.hasErrors();
- }
- });
- }
- });
+ return !context.hasErrors();
+ }
+ });
+ }
+ });
blazeResult.addListener(runContext::onLaunchTaskComplete, PooledThreadExecutor.INSTANCE);
@@ -172,36 +191,35 @@
}
/**
- * Hooks up the Blaze process to be killed if the user hits the 'Stop' button, then waits for
- * the Blaze process to stop.
- * In non-debug mode, we wait for test execution to finish before returning from launch()
- * (this matches the behavior of the stock ddmlib runner).
+ * Hooks up the Blaze process to be killed if the user hits the 'Stop' button, then waits for the
+ * Blaze process to stop. In non-debug mode, we wait for test execution to finish before returning
+ * from launch() (this matches the behavior of the stock ddmlib runner).
*/
- private void waitAndSetUpForKillingBlazeOnStop(@NotNull final ProcessHandler processHandler, @NotNull LaunchStatus launchStatus) {
- processHandler.addProcessListener(new ProcessAdapter() {
- @Override
- public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
- blazeResult.cancel(true /* mayInterruptIfRunning */);
- launchStatus.terminateLaunch("Test run stopped.\n");
- }
- });
+ private void waitAndSetUpForKillingBlazeOnStop(
+ @NotNull final ProcessHandler processHandler, @NotNull LaunchStatus launchStatus) {
+ processHandler.addProcessListener(
+ new ProcessAdapter() {
+ @Override
+ public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
+ blazeResult.cancel(true /* mayInterruptIfRunning */);
+ launchStatus.terminateLaunch("Test run stopped.\n");
+ }
+ });
try {
blazeResult.get();
launchStatus.terminateLaunch("Tests ran to completion.\n");
- }
- catch (CancellationException e) {
+ } catch (CancellationException e) {
// The user has canceled the test.
launchStatus.terminateLaunch("Test run stopped.\n");
- }
- catch (InterruptedException e) {
+ } catch (InterruptedException e) {
// We've been interrupted - cancel the underlying Blaze process.
blazeResult.cancel(true /* mayInterruptIfRunning */);
launchStatus.terminateLaunch("Test run stopped.\n");
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
LOG.error(e);
- launchStatus.terminateLaunch("Test run stopped due to internal exception. Please file a bug report.\n");
+ launchStatus.terminateLaunch(
+ "Test run stopped due to internal exception. Please file a bug report.\n");
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestMethodRunConfigurationProducer.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestMethodRunConfigurationProducer.java
index 8de6656..7f87f1b 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestMethodRunConfigurationProducer.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestMethodRunConfigurationProducer.java
@@ -19,8 +19,10 @@
import com.google.common.base.Strings;
import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
import com.google.idea.blaze.java.run.RunUtil;
-import com.google.idea.blaze.java.run.producers.BlazeTestRunConfigurationProducer;
import com.google.idea.blaze.java.run.producers.JUnitConfigurationUtil;
import com.google.idea.blaze.java.run.producers.ProducerUtils;
import com.intellij.execution.Location;
@@ -33,21 +35,22 @@
/**
* Producer for run configurations related to Android test methods in Blaze.
- * <p/>
- * This class is based on
- * {@link org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer}.
+ *
+ * <p>This class is based on {@link
+ * org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer}.
*/
-public class BlazeAndroidTestMethodRunConfigurationProducer extends BlazeTestRunConfigurationProducer<BlazeAndroidTestRunConfiguration> {
+public class BlazeAndroidTestMethodRunConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
public BlazeAndroidTestMethodRunConfigurationProducer() {
- super(BlazeAndroidTestRunConfigurationType.getInstance());
+ super(BlazeCommandRunConfigurationType.getInstance());
}
@Override
protected boolean doSetupConfigFromContext(
- @NotNull BlazeAndroidTestRunConfiguration configuration,
- @NotNull ConfigurationContext context,
- @NotNull Ref<PsiElement> sourceElement) {
+ @NotNull BlazeCommandRunConfiguration configuration,
+ @NotNull ConfigurationContext context,
+ @NotNull Ref<PsiElement> sourceElement) {
if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
return false;
@@ -76,10 +79,15 @@
return false;
}
configuration.setTarget(rule.label);
- BlazeAndroidTestRunConfigurationState configState = configuration.getConfigState();
- configState.TESTING_TYPE = AndroidTestRunConfiguration.TEST_METHOD;
- configState.CLASS_NAME = containingClass.getQualifiedName();
- configState.METHOD_NAME = psiMethod.getName();
+ BlazeAndroidTestRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeAndroidTestRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ BlazeAndroidTestRunConfigurationState configState = handler.getConfigState();
+ configState.setTestingType(AndroidTestRunConfiguration.TEST_METHOD);
+ configState.setClassName(containingClass.getQualifiedName());
+ configState.setMethodName(psiMethod.getName());
configuration.setGeneratedName();
return true;
@@ -87,8 +95,7 @@
@Override
protected boolean doIsConfigFromContext(
- @NotNull BlazeAndroidTestRunConfiguration configuration,
- @NotNull ConfigurationContext context) {
+ @NotNull BlazeCommandRunConfiguration configuration, @NotNull ConfigurationContext context) {
if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
return false;
@@ -111,16 +118,21 @@
return checkIfAttributesAreTheSame(configuration, psiMethod);
}
- private static boolean checkIfAttributesAreTheSame(BlazeAndroidTestRunConfiguration configuration,
- PsiMethod testMethod) {
- BlazeAndroidTestRunConfigurationState configState = configuration.getConfigState();
- if (Strings.isNullOrEmpty(configState.CLASS_NAME)
- || Strings.isNullOrEmpty(configState.METHOD_NAME)) {
+ private static boolean checkIfAttributesAreTheSame(
+ BlazeCommandRunConfiguration configuration, PsiMethod testMethod) {
+ BlazeAndroidTestRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeAndroidTestRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ BlazeAndroidTestRunConfigurationState configState = handler.getConfigState();
+ if (Strings.isNullOrEmpty(configState.getClassName())
+ || Strings.isNullOrEmpty(configState.getMethodName())) {
return false;
}
- return configState.TESTING_TYPE == AndroidTestRunConfiguration.TEST_METHOD
- && configState.CLASS_NAME.equals(testMethod.getContainingClass().getQualifiedName())
- && configState.METHOD_NAME.equals(testMethod.getName());
+ return configState.getTestingType() == AndroidTestRunConfiguration.TEST_METHOD
+ && configState.getClassName().equals(testMethod.getContainingClass().getQualifiedName())
+ && configState.getMethodName().equals(testMethod.getName());
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfiguration.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfiguration.java
deleted file mode 100644
index 1e01d20..0000000
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfiguration.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.android.run.test;
-
-import com.android.tools.idea.run.ValidationError;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfiguration;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationRunner;
-import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
-import com.google.idea.blaze.android.sync.projectstructure.BlazeAndroidProjectStructureSyncer;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.Executor;
-import com.intellij.execution.JavaExecutionUtil;
-import com.intellij.execution.configurations.*;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
-import org.jdom.Element;
-import org.jetbrains.android.facet.AndroidFacet;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
-/**
- * An extension of the normal Android Studio run configuration for launching Android tests,
- * adapted specifically for selecting and launching android_test targets.
- */
-public final class BlazeAndroidTestRunConfiguration extends LocatableConfigurationBase
- implements BlazeAndroidRunConfiguration, RunConfiguration {
-
- private static final Logger LOG = Logger.getInstance(BlazeAndroidTestRunConfiguration.class);
- private final Project project;
- private final BlazeAndroidRunConfigurationCommonState commonState;
- private final BlazeAndroidRunConfigurationRunner runner;
-
- @NotNull private final BlazeAndroidTestRunConfigurationState configState = new BlazeAndroidTestRunConfigurationState();
-
- public BlazeAndroidTestRunConfiguration(Project project, ConfigurationFactory factory) {
- super(project, factory, "");
- this.project = project;
-
- RuleIdeInfo rule = RuleFinder.getInstance().firstRuleOfKinds(project, Kind.ANDROID_TEST);
- this.commonState = new BlazeAndroidRunConfigurationCommonState(rule != null ? rule.label : null, ImmutableList.of());
- this.runner = new BlazeAndroidRunConfigurationRunner(project, this, commonState, true, getUniqueID());
- }
-
- @Override
- public BlazeAndroidRunConfigurationCommonState getCommonState() {
- return commonState;
- }
-
- @NotNull
- public BlazeAndroidTestRunConfigurationState getConfigState() {
- return configState;
- }
-
- @Nullable
- @Override
- public final Label getTarget() {
- return commonState.getTarget();
- }
-
- public final void setTarget(@Nullable Label target) {
- commonState.setTarget(target);
- }
-
- @Override
- public BlazeAndroidRunConfigurationRunner getRunner() {
- return runner;
- }
-
- @Override
- public BlazeAndroidRunContext createRunContext(Project project,
- AndroidFacet facet,
- ExecutionEnvironment env,
- ImmutableList<String> buildFlags) {
- return new BlazeAndroidTestRunContext(project, facet, this, env, commonState, configState, buildFlags);
- }
-
- @NotNull
- @Override
- public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
- return new BlazeAndroidTestRunConfigurationEditor(
- getProject(),
- new BlazeAndroidTestRunConfigurationStateEditor(project)
- );
- }
-
- @Override
- public final void checkConfiguration() throws RuntimeConfigurationException {
- List<ValidationError> errors = validate();
- if (errors.isEmpty()) {
- return;
- }
- ValidationError topError = Ordering.natural().max(errors);
- if (topError.isFatal()) {
- throw new RuntimeConfigurationError(topError.getMessage(), topError.getQuickfix());
- }
- throw new RuntimeConfigurationWarning(topError.getMessage(), topError.getQuickfix());
- }
-
- private List<ValidationError> validate() {
- List<ValidationError> errors = Lists.newArrayList();
- errors.addAll(runner.validate(getModule()));
- commonState.checkConfiguration(getProject(), Kind.ANDROID_TEST, errors);
- return errors;
- }
-
- @Override
- @Nullable
- public final RunProfileState getState(@NotNull final Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
- final Module module = getModule();
- return runner.getState(module, executor, env);
- }
-
- private Module getModule() {
- return BlazeAndroidProjectStructureSyncer.ensureRunConfigurationModule(project, getTarget());
- }
-
- @Override
- @Nullable
- public String suggestedName() {
- Label target = commonState.getTarget();
- if (target == null) {
- return null;
- }
- String name = target.ruleName().toString();
- if (configState.TESTING_TYPE == BlazeAndroidTestRunConfigurationState.TEST_CLASS) {
- name += ": " + configState.CLASS_NAME;
- }
- else if (configState.TESTING_TYPE == BlazeAndroidTestRunConfigurationState.TEST_METHOD) {
- name += ": " + configState.CLASS_NAME + "#" + configState.METHOD_NAME;
- }
- return String.format("%s test: %s", Blaze.buildSystemName(project), name);
- }
-
- @Override
- public boolean isGeneratedName() {
- final String name = getName();
-
- if ((configState.TESTING_TYPE == BlazeAndroidTestRunConfigurationState.TEST_CLASS || configState.TESTING_TYPE == BlazeAndroidTestRunConfigurationState.TEST_METHOD) &&
- (configState.CLASS_NAME == null || configState.CLASS_NAME.length() == 0)) {
- return JavaExecutionUtil.isNewName(name);
- }
- if (configState.TESTING_TYPE == BlazeAndroidTestRunConfigurationState.TEST_METHOD &&
- (configState.METHOD_NAME == null || configState.METHOD_NAME.length() == 0)) {
- return JavaExecutionUtil.isNewName(name);
- }
- return Comparing.equal(name, suggestedName());
- }
-
- @Override
- public void readExternal(Element element) throws InvalidDataException {
- super.readExternal(element);
-
- commonState.readExternal(element);
- runner.readExternal(element);;
- configState.readExternal(element);
- }
-
- @Override
- public void writeExternal(Element element) throws WriteExternalException {
- super.writeExternal(element);
-
- commonState.writeExternal(element);
- runner.writeExternal(element);;
- configState.writeExternal(element);
- }
-
- @Override
- public RunConfiguration clone() {
- final Element element = new Element("dummy");
- try {
- writeExternal(element);
- BlazeAndroidTestRunConfiguration clone = new BlazeAndroidTestRunConfiguration(
- getProject(), getFactory());
- clone.readExternal(element);
- return clone;
- } catch (InvalidDataException e) {
- LOG.error(e);
- return null;
- } catch (WriteExternalException e) {
- LOG.error(e);
- return null;
- }
- }
-}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationEditor.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationEditor.java
deleted file mode 100644
index 34f3fcb..0000000
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationEditor.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.android.run.test;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonStateEditor;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.List;
-
-/**
- * A simplified, Blaze-specific variant of
- * {@link org.jetbrains.android.run.AndroidRunConfigurationEditor}.
- */
-class BlazeAndroidTestRunConfigurationEditor extends SettingsEditor<BlazeAndroidTestRunConfiguration> {
-
- private final BlazeAndroidTestRunConfigurationStateEditor kindSpecificEditor;
- private final BlazeAndroidRunConfigurationCommonStateEditor commonStateEditor;
-
- public BlazeAndroidTestRunConfigurationEditor(
- Project project,
- BlazeAndroidTestRunConfigurationStateEditor kindSpecificEditor) {
- this.kindSpecificEditor = kindSpecificEditor;
- this.commonStateEditor = new BlazeAndroidRunConfigurationCommonStateEditor(project, Kind.ANDROID_TEST);
- }
-
- @Override
- protected void resetEditorFrom(BlazeAndroidTestRunConfiguration configuration) {
- commonStateEditor.resetEditorFrom(configuration.getCommonState());
- kindSpecificEditor.resetFrom(configuration);
- }
-
- @Override
- protected void applyEditorTo(@NotNull BlazeAndroidTestRunConfiguration configuration)
- throws ConfigurationException {
- commonStateEditor.applyEditorTo(configuration.getCommonState());
- kindSpecificEditor.applyTo(configuration);
- }
-
- @Override
- @NotNull
- protected JComponent createEditor() {
- List<Component> components = Lists.newArrayList();
- components.addAll(commonStateEditor.getComponents());
- components.add(kindSpecificEditor.getComponent());
- return UiUtil.createBox(components);
- }
-}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandler.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandler.java
new file mode 100644
index 0000000..885a8ae
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandler.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run.test;
+
+import com.android.tools.idea.run.ValidationError;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandler;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandlerEditor;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationRunner;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.android.sync.projectstructure.BlazeAndroidProjectStructureSyncer;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerEditor;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.JavaExecutionUtil;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationError;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.configurations.RuntimeConfigurationWarning;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import java.util.List;
+import javax.swing.Icon;
+import org.jdom.Element;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * {@link com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler} for
+ * android_test targets.
+ */
+public class BlazeAndroidTestRunConfigurationHandler
+ implements BlazeAndroidRunConfigurationHandler {
+ private static final Logger LOG =
+ Logger.getInstance(BlazeAndroidTestRunConfigurationHandler.class);
+
+ private final BlazeCommandRunConfiguration configuration;
+ private final BlazeAndroidRunConfigurationCommonState commonState;
+ private final BlazeAndroidTestRunConfigurationState configState;
+ private final BlazeAndroidRunConfigurationRunner runner;
+
+ BlazeAndroidTestRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ this.configuration = configuration;
+ commonState = new BlazeAndroidRunConfigurationCommonState(ImmutableList.of());
+ configState = new BlazeAndroidTestRunConfigurationState();
+ runner =
+ new BlazeAndroidRunConfigurationRunner(
+ configuration.getProject(), this, commonState, true, configuration.getUniqueID());
+ }
+
+ @Override
+ public BlazeAndroidRunContext createRunContext(
+ Project project,
+ AndroidFacet facet,
+ ExecutionEnvironment env,
+ ImmutableList<String> buildFlags) {
+ return new BlazeAndroidTestRunContext(
+ project, facet, configuration, env, configState, getLabel(), buildFlags);
+ }
+
+ @Override
+ @Nullable
+ public Label getLabel() {
+ TargetExpression target = configuration.getTarget();
+ if (target instanceof Label) {
+ return (Label) target;
+ }
+ return null;
+ }
+
+ @Override
+ public BlazeAndroidRunConfigurationCommonState getCommonState() {
+ return commonState;
+ }
+
+ @Override
+ public BlazeAndroidTestRunConfigurationState getConfigState() {
+ return configState;
+ }
+
+ @Nullable
+ private Module getModule() {
+ Label target = getLabel();
+ return target != null
+ ? BlazeAndroidProjectStructureSyncer.ensureRunConfigurationModule(
+ configuration.getProject(), target)
+ : null;
+ }
+
+ @Override
+ public final void checkConfiguration() throws RuntimeConfigurationException {
+ List<ValidationError> errors = validate();
+ if (errors.isEmpty()) {
+ return;
+ }
+ // TODO: Do something with the extra error information? Error count?
+ ValidationError topError = Ordering.natural().max(errors);
+ if (topError.isFatal()) {
+ throw new RuntimeConfigurationError(topError.getMessage(), topError.getQuickfix());
+ }
+ throw new RuntimeConfigurationWarning(topError.getMessage(), topError.getQuickfix());
+ }
+
+ private List<ValidationError> validate() {
+ List<ValidationError> errors = Lists.newArrayList();
+ errors.addAll(runner.validate(getModule()));
+ validateLabel(errors);
+ return errors;
+ }
+
+ private void validateLabel(List<ValidationError> errors) {
+ Project project = configuration.getProject();
+ Label target = getLabel();
+ Kind kind = Kind.ANDROID_TEST;
+ RuleIdeInfo rule =
+ target != null ? RuleFinder.getInstance().ruleForTarget(project, target) : null;
+ if (rule == null) {
+ errors.add(
+ ValidationError.fatal(
+ String.format("No existing %s rule selected.", Blaze.buildSystemName(project))));
+ } else if (!rule.kindIsOneOf(kind)) {
+ errors.add(
+ ValidationError.fatal(
+ String.format(
+ "Selected %s rule is not %s", Blaze.buildSystemName(project), kind.toString())));
+ }
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ commonState.readExternal(element);
+ runner.readExternal(element);
+ configState.readExternal(element);
+ }
+
+ @Override
+ public void writeExternal(Element element) throws WriteExternalException {
+ commonState.writeExternal(element);
+ runner.writeExternal(element);
+ configState.writeExternal(element);
+ }
+
+ @Override
+ public BlazeAndroidTestRunConfigurationHandler cloneFor(
+ BlazeCommandRunConfiguration configuration) {
+ final Element element = new Element("dummy");
+ try {
+ writeExternal(element);
+ final BlazeAndroidTestRunConfigurationHandler handler =
+ new BlazeAndroidTestRunConfigurationHandler(configuration);
+ handler.readExternal(element);
+ return handler;
+ } catch (InvalidDataException | WriteExternalException e) {
+ LOG.error(e);
+ return null;
+ }
+ }
+
+ @Override
+ @Nullable
+ public final RunProfileState getState(
+ @NotNull final Executor executor, @NotNull ExecutionEnvironment env)
+ throws ExecutionException {
+ final Module module = getModule();
+ return runner.getState(module, executor, env);
+ }
+
+ @Override
+ public boolean executeBeforeRunTask(ExecutionEnvironment environment) {
+ return runner.executeBuild(environment);
+ }
+
+ @Override
+ @Nullable
+ public String suggestedName() {
+ Label target = getLabel();
+ if (target == null) {
+ return null;
+ }
+ BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
+
+ boolean isClassTest =
+ configState.getTestingType() == BlazeAndroidTestRunConfigurationState.TEST_CLASS;
+ boolean isMethodTest =
+ configState.getTestingType() == BlazeAndroidTestRunConfigurationState.TEST_METHOD;
+ if ((isClassTest || isMethodTest) && configState.getClassName() != null) {
+ // Get the class name without the package.
+ String className = JavaExecutionUtil.getPresentableClassName(configState.getClassName());
+ if (className != null) {
+ String targetString = className;
+ if (isMethodTest) {
+ targetString += "#" + configState.getMethodName();
+ }
+ return nameBuilder.setTargetString(targetString).build();
+ }
+ }
+ return nameBuilder.build();
+ }
+
+ @Override
+ public boolean isGeneratedName(boolean hasGeneratedFlag) {
+ final String name = configuration.getName();
+
+ if ((configState.getTestingType() == BlazeAndroidTestRunConfigurationState.TEST_CLASS
+ || configState.getTestingType() == BlazeAndroidTestRunConfigurationState.TEST_METHOD)
+ && (configState.getClassName() == null || configState.getClassName().length() == 0)) {
+ return JavaExecutionUtil.isNewName(name);
+ }
+ if (configState.getTestingType() == BlazeAndroidTestRunConfigurationState.TEST_METHOD
+ && (configState.getMethodName() == null || configState.getMethodName().length() == 0)) {
+ return JavaExecutionUtil.isNewName(name);
+ }
+ return Comparing.equal(name, suggestedName());
+ }
+
+ @Override
+ @Nullable
+ public String getCommandName() {
+ return "test";
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "Android Test Handler";
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(RunConfiguration configuration, Executor executor) {
+ return null;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandlerEditor getHandlerEditor() {
+ Project project = configuration.getProject();
+ return new BlazeAndroidRunConfigurationHandlerEditor(
+ project, new BlazeAndroidTestRunConfigurationStateEditor(project));
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandlerProvider.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..bef595f
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandlerProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run.test;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+
+/** Handler provider for android_test targets. */
+public class BlazeAndroidTestRunConfigurationHandlerProvider
+ implements BlazeCommandRunConfigurationHandlerProvider {
+
+ public static BlazeAndroidTestRunConfigurationHandlerProvider getInstance() {
+ return BlazeCommandRunConfigurationHandlerProvider.EP_NAME.findExtension(
+ BlazeAndroidTestRunConfigurationHandlerProvider.class);
+ }
+
+ @Override
+ public boolean canHandleKind(Kind kind) {
+ return kind == Kind.ANDROID_TEST;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config) {
+ return new BlazeAndroidTestRunConfigurationHandler(config);
+ }
+
+ @Override
+ public String getId() {
+ return "BlazeAndroidTestRunConfigurationHandlerProvider";
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationState.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationState.java
index 91236aa..9f05bc5 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationState.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationState.java
@@ -15,17 +15,17 @@
*/
package com.google.idea.blaze.android.run.test;
-import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationState;
import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
+import java.util.Map;
import org.jdom.Element;
import org.jetbrains.annotations.Contract;
-/**
- * State specific for the android test configuration.
- */
-final class BlazeAndroidTestRunConfigurationState implements JDOMExternalizable {
+/** State specific for the android test configuration. */
+final class BlazeAndroidTestRunConfigurationState implements BlazeAndroidRunConfigurationState {
private static final String RUN_THROUGH_BLAZE_ATTR = "blaze-run-through-blaze";
@@ -34,20 +34,34 @@
public static final int TEST_CLASS = 2;
public static final int TEST_METHOD = 3;
- // We reinterpret Android Studio's test mode for running "all tests in a module" (all the tests in the installed test APK) as running all
+ // We reinterpret Android Studio's test mode for running "all tests in a module"
+ // (all the tests in the installed test APK) as running all
// the tests in a rule.
public static final int TEST_ALL_IN_TARGET = TEST_ALL_IN_MODULE;
- public int TESTING_TYPE = TEST_ALL_IN_MODULE;
- public String INSTRUMENTATION_RUNNER_CLASS = InstrumentationRunnerProvider.getDefaultInstrumentationRunnerClass();
- public String METHOD_NAME = "";
- public String CLASS_NAME = "";
- public String PACKAGE_NAME = "";
- public String EXTRA_OPTIONS = "";
+ private static final String TESTING_TYPE = "TESTING_TYPE";
+ private static final String INSTRUMENTATION_RUNNER_CLASS = "INSTRUMENTATION_RUNNER_CLASS";
+ private static final String METHOD_NAME = "METHOD_NAME";
+ private static final String CLASS_NAME = "CLASS_NAME";
+ private static final String PACKAGE_NAME = "PACKAGE_NAME";
+ private static final String EXTRA_OPTIONS = "EXTRA_OPTIONS";
+
+ private int testingType = TEST_ALL_IN_MODULE;
+ private String instrumentationRunnerClass;
+ private String methodName = "";
+ private String className = "";
+ private String packageName = "";
+ private String extraOptions = "";
// Whether to delegate to 'blaze test'.
private boolean runThroughBlaze;
+ public BlazeAndroidTestRunConfigurationState() {
+ String defaultInstrumentationRunnerClass =
+ InstrumentationRunnerProvider.getDefaultInstrumentationRunnerClass();
+ instrumentationRunnerClass = Strings.nullToEmpty(defaultInstrumentationRunnerClass);
+ }
+
@Contract(pure = true)
boolean isRunThroughBlaze() {
return runThroughBlaze;
@@ -57,17 +71,116 @@
this.runThroughBlaze = runThroughBlaze;
}
+ public int getTestingType() {
+ return testingType;
+ }
+
+ public void setTestingType(int testingType) {
+ this.testingType = testingType;
+ }
+
+ public String getInstrumentationRunnerClass() {
+ return instrumentationRunnerClass;
+ }
+
+ public void setInstrumentationRunnerClass(String instrumentationRunnerClass) {
+ this.instrumentationRunnerClass = instrumentationRunnerClass;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ public String getExtraOptions() {
+ return extraOptions;
+ }
+
+ public void setExtraOptions(String extraOptions) {
+ this.extraOptions = extraOptions;
+ }
+
@Override
public void readExternal(Element element) throws InvalidDataException {
- DefaultJDOMExternalizer.readExternal(this, element);
-
+ String testingTypeAttribute = element.getAttributeValue(TESTING_TYPE);
+ if (!Strings.isNullOrEmpty(testingTypeAttribute)) {
+ testingType = Integer.parseInt(testingTypeAttribute);
+ }
+ instrumentationRunnerClass =
+ Strings.nullToEmpty(element.getAttributeValue(INSTRUMENTATION_RUNNER_CLASS));
+ methodName = Strings.nullToEmpty(element.getAttributeValue(METHOD_NAME));
+ className = Strings.nullToEmpty(element.getAttributeValue(CLASS_NAME));
+ packageName = Strings.nullToEmpty(element.getAttributeValue(PACKAGE_NAME));
+ extraOptions = Strings.nullToEmpty(element.getAttributeValue(EXTRA_OPTIONS));
runThroughBlaze = Boolean.parseBoolean(element.getAttributeValue(RUN_THROUGH_BLAZE_ATTR));
+
+ for (Map.Entry<String, String> entry : getLegacyValues(element).entrySet()) {
+ String value = entry.getValue();
+ switch (entry.getKey()) {
+ case TESTING_TYPE:
+ if (!Strings.isNullOrEmpty(value)) {
+ testingType = Integer.parseInt(value);
+ }
+ break;
+ case INSTRUMENTATION_RUNNER_CLASS:
+ instrumentationRunnerClass = Strings.nullToEmpty(value);
+ break;
+ case METHOD_NAME:
+ methodName = Strings.nullToEmpty(value);
+ break;
+ case CLASS_NAME:
+ className = Strings.nullToEmpty(value);
+ break;
+ case PACKAGE_NAME:
+ packageName = Strings.nullToEmpty(value);
+ break;
+ case EXTRA_OPTIONS:
+ extraOptions = Strings.nullToEmpty(value);
+ break;
+ default:
+ break;
+ }
+ }
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
- DefaultJDOMExternalizer.writeExternal(this, element);
-
element.setAttribute(RUN_THROUGH_BLAZE_ATTR, Boolean.toString(runThroughBlaze));
+ element.setAttribute(TESTING_TYPE, Integer.toString(testingType));
+ element.setAttribute(INSTRUMENTATION_RUNNER_CLASS, instrumentationRunnerClass);
+ element.setAttribute(METHOD_NAME, methodName);
+ element.setAttribute(CLASS_NAME, className);
+ element.setAttribute(PACKAGE_NAME, packageName);
+ element.setAttribute(EXTRA_OPTIONS, extraOptions);
+ }
+
+ /** Imports legacy values in the old reflective JDOM externalizer manner. Can be removed ~2.0+. */
+ private static Map<String, String> getLegacyValues(Element element) {
+ Map<String, String> result = Maps.newHashMap();
+ for (Element option : element.getChildren("option")) {
+ String name = option.getAttributeValue("name");
+ String value = option.getAttributeValue("value");
+ result.put(name, value);
+ }
+ return result;
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateEditor.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateEditor.java
index 265bf2f..d03f883 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateEditor.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateEditor.java
@@ -16,7 +16,13 @@
package com.google.idea.blaze.android.run.test;
-import com.android.tools.idea.run.ConfigurationSpecificEditor;
+import static com.android.tools.idea.run.testing.AndroidTestRunConfiguration.TEST_ALL_IN_MODULE;
+import static com.android.tools.idea.run.testing.AndroidTestRunConfiguration.TEST_ALL_IN_PACKAGE;
+import static com.android.tools.idea.run.testing.AndroidTestRunConfiguration.TEST_CLASS;
+import static com.android.tools.idea.run.testing.AndroidTestRunConfiguration.TEST_METHOD;
+
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationState;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationStateEditor;
import com.google.idea.blaze.base.settings.Blaze;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.LabeledComponent;
@@ -25,23 +31,24 @@
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
+import java.awt.Component;
+import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ResourceBundle;
-
-import static com.android.tools.idea.run.testing.AndroidTestRunConfiguration.*;
-
+import javax.swing.AbstractButton;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
/**
- * The part of the Blaze Android test configuration editor that allows the user to pick an
- * android_test target and test filters.
+ * The part of the Blaze Android Test handler editor that allows the user to pick test filters.
* Forked from {@link org.jetbrains.android.run.testing.TestRunParameters}.
*/
-class BlazeAndroidTestRunConfigurationStateEditor implements ConfigurationSpecificEditor<BlazeAndroidTestRunConfiguration> {
+class BlazeAndroidTestRunConfigurationStateEditor
+ implements BlazeAndroidRunConfigurationStateEditor {
private JRadioButton allInPackageButton;
private JRadioButton classButton;
private JRadioButton testMethodButton;
@@ -55,9 +62,6 @@
private JCheckBox runThroughBlazeTestCheckBox;
private final JRadioButton[] testingType2RadioButton = new JRadioButton[4];
- @NotNull
- private JComponent anchor;
-
BlazeAndroidTestRunConfigurationStateEditor(Project project) {
setupUI(project);
@@ -73,32 +77,17 @@
addTestingType(TEST_ALL_IN_PACKAGE, allInPackageButton);
addTestingType(TEST_CLASS, classButton);
addTestingType(TEST_METHOD, testMethodButton);
-
- setAnchor(packageComponent.getLabel());
}
private void addTestingType(final int type, JRadioButton button) {
testingType2RadioButton[type] = button;
- button.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- updateLabelComponents(type);
- }
- });
- }
-
- @Override
- public JComponent getAnchor() {
- return anchor;
- }
-
- @Override
- public void setAnchor(JComponent anchor) {
- this.anchor = anchor;
- packageComponent.setAnchor(anchor);
- classComponent.setAnchor(anchor);
- methodComponent.setAnchor(anchor);
- labelTest.setAnchor(anchor);
+ button.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ updateLabelComponents(type);
+ }
+ });
}
private void updateButtonsAndLabelComponents(int type) {
@@ -115,106 +104,268 @@
methodComponent.setVisible(type == TEST_METHOD);
}
- private void setupUI(Project project)
- {
+ private void setupUI(Project project) {
try {
doSetupUI(project);
- }
- catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// Can't happen - this is from IJ generated code
}
}
- /**
- * Initially generated by IntelliJ from a .form file, then checked in.
- */
+ /** Initially generated by IntelliJ from a .form file, then checked in. */
private void doSetupUI(Project project)
- throws ClassCastException, InstantiationException, IllegalAccessException, ClassNotFoundException {
+ throws ClassCastException, InstantiationException, IllegalAccessException,
+ ClassNotFoundException {
panel = new JPanel();
panel.setLayout(new GridLayoutManager(6, 6, new Insets(0, 0, 0, 0), -1, -1));
panel.setAlignmentX(0.0f);
allInPackageButton = new JRadioButton();
- allInPackageButton
- .setActionCommand(ResourceBundle.getBundle("messages/ExecutionBundle").getString("jnit.configuration.all.tests.in.package.radio"));
- this.loadButtonText(allInPackageButton, ResourceBundle.getBundle("messages/AndroidBundle")
- .getString("android.run.configuration.all.in.package.radio"));
- panel.add(allInPackageButton,
- new GridConstraints(1, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ allInPackageButton.setActionCommand(
+ ResourceBundle.getBundle("messages/ExecutionBundle")
+ .getString("jnit.configuration.all.tests.in.package.radio"));
+ this.loadButtonText(
+ allInPackageButton,
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.all.in.package.radio"));
+ panel.add(
+ allInPackageButton,
+ new GridConstraints(
+ 1,
+ 2,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
classButton = new JRadioButton();
- classButton.setActionCommand(ResourceBundle.getBundle("messages/ExecutionBundle").getString("junit.configuration.test.class.radio"));
+ classButton.setActionCommand(
+ ResourceBundle.getBundle("messages/ExecutionBundle")
+ .getString("junit.configuration.test.class.radio"));
classButton.setEnabled(true);
classButton.setSelected(false);
- this.loadButtonText(classButton,
- ResourceBundle.getBundle("messages/AndroidBundle").getString("android.run.configuration.class.radio"));
- panel.add(classButton,
- new GridConstraints(1, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ this.loadButtonText(
+ classButton,
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.class.radio"));
+ panel.add(
+ classButton,
+ new GridConstraints(
+ 1,
+ 3,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
testMethodButton = new JRadioButton();
- testMethodButton
- .setActionCommand(ResourceBundle.getBundle("messages/ExecutionBundle").getString("junit.configuration.test.method.radio"));
+ testMethodButton.setActionCommand(
+ ResourceBundle.getBundle("messages/ExecutionBundle")
+ .getString("junit.configuration.test.method.radio"));
testMethodButton.setSelected(false);
- this.loadButtonText(testMethodButton,
- ResourceBundle.getBundle("messages/AndroidBundle").getString("android.run.configuration.method.radio"));
- panel.add(testMethodButton,
- new GridConstraints(1, 4, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ this.loadButtonText(
+ testMethodButton,
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.method.radio"));
+ panel.add(
+ testMethodButton,
+ new GridConstraints(
+ 1,
+ 4,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
labelTest = new JBLabel();
labelTest.setHorizontalAlignment(2);
labelTest.setHorizontalTextPosition(2);
labelTest.setIconTextGap(4);
- this.loadLabelText(labelTest, ResourceBundle.getBundle("messages/ExecutionBundle")
- .getString("junit.configuration.configure.junit.test.label"));
- panel.add(labelTest,
- new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ this.loadLabelText(
+ labelTest,
+ ResourceBundle.getBundle("messages/ExecutionBundle")
+ .getString("junit.configuration.configure.junit.test.label"));
+ panel.add(
+ labelTest,
+ new GridConstraints(
+ 1,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
final Spacer spacer1 = new Spacer();
- panel.add(spacer1, new GridConstraints(1, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
+ panel.add(
+ spacer1,
+ new GridConstraints(
+ 1,
+ 5,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ 1,
+ null,
+ null,
+ null,
+ 0,
+ false));
allInTargetButton = new JRadioButton();
allInTargetButton.setText("All in test target");
allInTargetButton.setMnemonic('A');
allInTargetButton.setDisplayedMnemonicIndex(0);
- panel.add(allInTargetButton, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ panel.add(
+ allInTargetButton,
+ new GridConstraints(
+ 1,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
classComponent = new LabeledComponent();
classComponent.setComponentClass("javax.swing.JPanel");
classComponent.setLabelLocation("West");
- classComponent.setText(ResourceBundle.getBundle("messages/AndroidBundle").getString("android.run.configuration.class.label"));
- panel.add(classComponent, new GridConstraints(3, 0, 1, 6, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ classComponent.setText(
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.class.label"));
+ panel.add(
+ classComponent,
+ new GridConstraints(
+ 3,
+ 0,
+ 1,
+ 6,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
methodComponent = new LabeledComponent();
- methodComponent.setComponentClass("com.intellij.openapi.ui.TextFieldWithBrowseButton$NoPathCompletion");
+ methodComponent.setComponentClass(
+ "com.intellij.openapi.ui.TextFieldWithBrowseButton$NoPathCompletion");
methodComponent.setLabelLocation("West");
- methodComponent.setText(ResourceBundle.getBundle("messages/AndroidBundle").getString("android.run.configuration.method.label"));
- panel.add(methodComponent, new GridConstraints(4, 0, 1, 6, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ methodComponent.setText(
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.method.label"));
+ panel.add(
+ methodComponent,
+ new GridConstraints(
+ 4,
+ 0,
+ 1,
+ 6,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
runnerComponent = new LabeledComponent();
runnerComponent.setComponentClass("javax.swing.JPanel");
runnerComponent.setEnabled(true);
runnerComponent.setLabelLocation("North");
- runnerComponent
- .setText(ResourceBundle.getBundle("messages/AndroidBundle").getString("android.test.run.configuration.instrumentation.label"));
- panel.add(runnerComponent, new GridConstraints(5, 0, 1, 6, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ runnerComponent.setText(
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.test.run.configuration.instrumentation.label"));
+ panel.add(
+ runnerComponent,
+ new GridConstraints(
+ 5,
+ 0,
+ 1,
+ 6,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
packageComponent = new LabeledComponent();
packageComponent.setComponentClass("javax.swing.JPanel");
packageComponent.setLabelLocation("West");
- packageComponent.setText(ResourceBundle.getBundle("messages/AndroidBundle").getString("android.run.configuration.package.label"));
- panel.add(packageComponent, new GridConstraints(2, 0, 1, 6, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+ packageComponent.setText(
+ ResourceBundle.getBundle("messages/AndroidBundle")
+ .getString("android.run.configuration.package.label"));
+ panel.add(
+ packageComponent,
+ new GridConstraints(
+ 2,
+ 0,
+ 1,
+ 6,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
runThroughBlazeTestCheckBox = new JCheckBox();
- runThroughBlazeTestCheckBox.setText(String.format("Run through '%s test'", Blaze.buildSystemName(project).toLowerCase()));
- runThroughBlazeTestCheckBox.setToolTipText(String.format("Slower, but more truthful to %s", Blaze.buildSystemName(project)));
- panel.add(runThroughBlazeTestCheckBox, new GridConstraints(0, 0, 1, 6, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK |
- GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED,
- null, null, null, 0, false));
+ runThroughBlazeTestCheckBox.setText(
+ String.format("Run through '%s test'", Blaze.buildSystemName(project).toLowerCase()));
+ runThroughBlazeTestCheckBox.setToolTipText(
+ String.format("Slower, but more truthful to %s", Blaze.buildSystemName(project)));
+ panel.add(
+ runThroughBlazeTestCheckBox,
+ new GridConstraints(
+ 0,
+ 0,
+ 1,
+ 6,
+ GridConstraints.ANCHOR_WEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
ButtonGroup buttonGroup;
buttonGroup = new ButtonGroup();
buttonGroup.add(allInPackageButton);
@@ -223,9 +374,7 @@
buttonGroup.add(allInTargetButton);
}
- /**
- * Initially generated by IntelliJ from a .form file, then checked in.
- */
+ /** Initially generated by IntelliJ from a .form file, then checked in. */
private void loadLabelText(JLabel component, String text) {
StringBuffer result = new StringBuffer();
boolean haveMnemonic = false;
@@ -234,7 +383,9 @@
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == '&') {
i++;
- if (i == text.length()) break;
+ if (i == text.length()) {
+ break;
+ }
if (!haveMnemonic && text.charAt(i) != '&') {
haveMnemonic = true;
mnemonic = text.charAt(i);
@@ -250,9 +401,7 @@
}
}
- /**
- * Initially generated by IntelliJ from a .form file and checked in.
- */
+ /** Initially generated by IntelliJ from a .form file and checked in. */
private void loadButtonText(AbstractButton component, String text) {
StringBuffer result = new StringBuffer();
boolean haveMnemonic = false;
@@ -261,7 +410,9 @@
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == '&') {
i++;
- if (i == text.length()) break;
+ if (i == text.length()) {
+ break;
+ }
if (!haveMnemonic && text.charAt(i) != '&') {
haveMnemonic = true;
mnemonic = text.charAt(i);
@@ -279,7 +430,8 @@
private int getTestingType() {
for (int i = 0, myTestingType2RadioButtonLength = testingType2RadioButton.length;
- i < myTestingType2RadioButtonLength; i++) {
+ i < myTestingType2RadioButtonLength;
+ i++) {
JRadioButton button = testingType2RadioButton[i];
if (button.isSelected()) {
return i;
@@ -289,27 +441,29 @@
}
@Override
- public void applyTo(BlazeAndroidTestRunConfiguration configuration) {
- BlazeAndroidTestRunConfigurationState configState = configuration.getConfigState();
+ public void applyEditorTo(BlazeAndroidRunConfigurationState state) {
+ BlazeAndroidTestRunConfigurationState configState =
+ (BlazeAndroidTestRunConfigurationState) state;
configState.setRunThroughBlaze(runThroughBlazeTestCheckBox.isSelected());
- configState.TESTING_TYPE = getTestingType();
- configState.CLASS_NAME = classComponent.getComponent().getText();
- configState.METHOD_NAME = methodComponent.getComponent().getText();
- configState.PACKAGE_NAME = packageComponent.getComponent().getText();
- configState.INSTRUMENTATION_RUNNER_CLASS = runnerComponent.getComponent().getText();
+ configState.setTestingType(getTestingType());
+ configState.setClassName(classComponent.getComponent().getText());
+ configState.setMethodName(methodComponent.getComponent().getText());
+ configState.setPackageName(packageComponent.getComponent().getText());
+ configState.setInstrumentationRunnerClass(runnerComponent.getComponent().getText());
}
@Override
- public void resetFrom(BlazeAndroidTestRunConfiguration configuration) {
- BlazeAndroidTestRunConfigurationState configState = configuration.getConfigState();
+ public void resetEditorFrom(BlazeAndroidRunConfigurationState state) {
+ BlazeAndroidTestRunConfigurationState configState =
+ (BlazeAndroidTestRunConfigurationState) state;
runThroughBlazeTestCheckBox.setSelected(configState.isRunThroughBlaze());
- updateButtonsAndLabelComponents(configState.TESTING_TYPE);
- packageComponent.getComponent().setText(configState.PACKAGE_NAME);
- classComponent.getComponent().setText(configState.CLASS_NAME);
- methodComponent.getComponent().setText(configState.METHOD_NAME);
- runnerComponent.getComponent().setText(configState.INSTRUMENTATION_RUNNER_CLASS);
+ updateButtonsAndLabelComponents(configState.getTestingType());
+ packageComponent.getComponent().setText(configState.getPackageName());
+ classComponent.getComponent().setText(configState.getClassName());
+ methodComponent.getComponent().setText(configState.getMethodName());
+ runnerComponent.getComponent().setText(configState.getInstrumentationRunnerClass());
}
@Override
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationType.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationType.java
index acc06d9..2104d75 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationType.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationType.java
@@ -15,31 +15,32 @@
*/
package com.google.idea.blaze.android.run.test;
-import com.google.idea.blaze.android.run.BlazeBeforeRunTaskProvider;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.intellij.execution.BeforeRunTask;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.execution.configurations.ConfigurationTypeUtil;
+import com.intellij.execution.configurations.UnknownConfigurationType;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.ui.LayeredIcon;
import icons.AndroidIcons;
+import javax.swing.Icon;
import org.jetbrains.annotations.NotNull;
-import javax.swing.*;
-
/**
* A type for Android test run configurations adapted specifically to run android_test targets.
+ *
+ * @deprecated See {@link com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType}. Retained
+ * in 1.9 for legacy purposes, to allow existing BlazeAndroidTestRunConfigurations to be updated
+ * to BlazeCommandRunConfigurations. Intended to be removed in 2.1.
*/
-public class BlazeAndroidTestRunConfigurationType implements ConfigurationType {
+// Hack: extend UnknownConfigurationType to completely hide it in the Run/Debug Configurations UI.
+@Deprecated
+public class BlazeAndroidTestRunConfigurationType extends UnknownConfigurationType {
private static final Icon ANDROID_TEST_ICON;
static {
@@ -50,31 +51,28 @@
}
private final BlazeAndroidTestRunConfigurationFactory factory =
- new BlazeAndroidTestRunConfigurationFactory(this);
+ new BlazeAndroidTestRunConfigurationFactory(this);
- public static class BlazeAndroidTestRuleConfigurationFactory implements BlazeRuleConfigurationFactory {
- @Override
- public boolean handlesRule(WorkspaceLanguageSettings workspaceLanguageSettings, @NotNull RuleIdeInfo rule) {
- return rule.kindIsOneOf(Kind.ANDROID_TEST);
- }
-
- @Override
- @NotNull
- public RunnerAndConfigurationSettings createForRule(@NotNull RunManager runManager, @NotNull RuleIdeInfo rule) {
- return getInstance().factory.createForRule(runManager, rule);
- }
- }
-
- public static class BlazeAndroidTestRunConfigurationFactory extends ConfigurationFactory {
+ static class BlazeAndroidTestRunConfigurationFactory extends ConfigurationFactory {
protected BlazeAndroidTestRunConfigurationFactory(@NotNull ConfigurationType type) {
super(type);
}
@Override
+ public String getName() {
+ // Used to look up this ConfigurationFactory.
+ // Preserve value so legacy configurations can be loaded.
+ return Blaze.defaultBuildSystemName() + " Android Test";
+ }
+
+ @Override
@NotNull
- public BlazeAndroidTestRunConfiguration createTemplateConfiguration(@NotNull Project project) {
- return new BlazeAndroidTestRunConfiguration(project, this);
+ public BlazeCommandRunConfiguration createTemplateConfiguration(@NotNull Project project) {
+ // Create a BlazeCommandRunConfiguration instead, to update legacy configurations.
+ return BlazeCommandRunConfigurationType.getInstance()
+ .getFactory()
+ .createTemplateConfiguration(project);
}
@Override
@@ -89,18 +87,8 @@
@Override
public void configureBeforeRunTaskDefaults(
- Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
- task.setEnabled(providerID.equals(BlazeBeforeRunTaskProvider.ID));
- }
-
- @NotNull
- public RunnerAndConfigurationSettings createForRule(@NotNull RunManager runManager, @NotNull RuleIdeInfo rule) {
- final RunnerAndConfigurationSettings settings =
- runManager.createRunConfiguration(rule.label.toString(), this);
- final BlazeAndroidTestRunConfiguration configuration =
- (BlazeAndroidTestRunConfiguration) settings.getConfiguration();
- configuration.setTarget(rule.label);
- return settings;
+ Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
+ // Removed BlazeAndroidBeforeRunTaskProvider; this method won't be called anymore anyhow.
}
@Override
@@ -115,12 +103,13 @@
@Override
public String getDisplayName() {
- return Blaze.defaultBuildSystemName() + " Android Test";
+ return "Legacy " + Blaze.defaultBuildSystemName() + " Android Test";
}
@Override
public String getConfigurationTypeDescription() {
- return "Launch/debug configuration for android_test rules";
+ return "Launch/debug configuration for android_test rules "
+ + "Use Blaze Command instead; this legacy configuration type is being removed.";
}
@Override
@@ -131,11 +120,13 @@
@Override
@NotNull
public String getId() {
+ // Used to look up this ConfigurationType.
+ // Preserve value so legacy configurations can be loaded.
return "BlazeAndroidTestRunConfigurationType";
}
@Override
public BlazeAndroidTestRunConfigurationFactory[] getConfigurationFactories() {
- return new BlazeAndroidTestRunConfigurationFactory[]{factory};
+ return new BlazeAndroidTestRunConfigurationFactory[] {factory};
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunContext.java b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunContext.java
index 034c7b6..a12d370 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunContext.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunContext.java
@@ -16,7 +16,13 @@
package com.google.idea.blaze.android.run.test;
import com.android.ddmlib.IDevice;
-import com.android.tools.idea.run.*;
+import com.android.tools.idea.run.ApkInfo;
+import com.android.tools.idea.run.ApkProvider;
+import com.android.tools.idea.run.ApkProvisionException;
+import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.ConsolePrinter;
+import com.android.tools.idea.run.ConsoleProvider;
+import com.android.tools.idea.run.LaunchOptions;
import com.android.tools.idea.run.editor.AndroidDebugger;
import com.android.tools.idea.run.editor.AndroidDebuggerState;
import com.android.tools.idea.run.tasks.DebugConnectorTask;
@@ -26,31 +32,33 @@
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
import com.google.idea.blaze.android.run.deployinfo.BlazeApkProvider;
-import com.google.idea.blaze.android.run.runner.*;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidDeviceSelector;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidLaunchTasksProvider;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunConfigurationDebuggerManager;
+import com.google.idea.blaze.android.run.runner.BlazeAndroidRunContext;
+import com.google.idea.blaze.android.run.runner.BlazeApkBuildStep;
+import com.google.idea.blaze.android.run.runner.BlazeApkBuildStepNormalBuild;
+import com.google.idea.blaze.base.model.primitives.Label;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.project.Project;
-import org.jetbrains.android.facet.AndroidFacet;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Set;
+import javax.annotation.Nullable;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.annotations.NotNull;
-/**
- * Run context for android_test.
- */
+/** Run context for android_test. */
class BlazeAndroidTestRunContext implements BlazeAndroidRunContext {
private final Project project;
private final AndroidFacet facet;
private final RunConfiguration runConfiguration;
private final ExecutionEnvironment env;
- private final BlazeAndroidRunConfigurationCommonState commonState;
private final BlazeAndroidTestRunConfigurationState configState;
+ private final Label label;
private final ImmutableList<String> buildFlags;
private final List<Runnable> launchTaskCompleteListeners = Lists.newArrayList();
private final ConsoleProvider consoleProvider;
@@ -58,29 +66,30 @@
private final ApplicationIdProvider applicationIdProvider;
private final ApkProvider apkProvider;
- public BlazeAndroidTestRunContext(Project project,
- AndroidFacet facet,
- RunConfiguration runConfiguration,
- ExecutionEnvironment env,
- BlazeAndroidRunConfigurationCommonState commonState,
- BlazeAndroidTestRunConfigurationState configState,
- ImmutableList<String> buildFlags) {
+ public BlazeAndroidTestRunContext(
+ Project project,
+ AndroidFacet facet,
+ RunConfiguration runConfiguration,
+ ExecutionEnvironment env,
+ BlazeAndroidTestRunConfigurationState configState,
+ Label label,
+ ImmutableList<String> buildFlags) {
this.project = project;
this.facet = facet;
this.runConfiguration = runConfiguration;
this.env = env;
- this.commonState = commonState;
+ this.label = label;
this.configState = configState;
this.buildFlags = buildFlags;
this.consoleProvider = new AndroidTestConsoleProvider(project, runConfiguration, configState);
- this.buildStep = new BlazeApkBuildStepNormalBuild(project, commonState, buildFlags);
- this.applicationIdProvider = new BlazeAndroidTestApplicationIdProvider(project, buildStep.getDeployInfo());
+ this.buildStep = new BlazeApkBuildStepNormalBuild(project, label, buildFlags);
+ this.applicationIdProvider =
+ new BlazeAndroidTestApplicationIdProvider(project, buildStep.getDeployInfo());
this.apkProvider = new BlazeApkProvider(project, buildStep.getDeployInfo());
}
@Override
- public void augmentEnvironment(ExecutionEnvironment env) {
- }
+ public void augmentEnvironment(ExecutionEnvironment env) {}
@Override
public BlazeAndroidDeviceSelector getDeviceSelector() {
@@ -110,18 +119,21 @@
@Override
public LaunchTasksProvider getLaunchTasksProvider(
- LaunchOptions launchOptions,
- BlazeAndroidRunConfigurationDebuggerManager debuggerManager) throws ExecutionException {
- return new BlazeAndroidLaunchTasksProvider(project, this, applicationIdProvider, launchOptions, debuggerManager);
+ LaunchOptions.Builder launchOptionsBuilder,
+ boolean isDebug,
+ BlazeAndroidRunConfigurationDebuggerManager debuggerManager)
+ throws ExecutionException {
+ return new BlazeAndroidLaunchTasksProvider(
+ project, this, applicationIdProvider, launchOptionsBuilder, isDebug, debuggerManager);
}
@Override
- public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions) throws ExecutionException {
+ public ImmutableList<LaunchTask> getDeployTasks(IDevice device, LaunchOptions launchOptions)
+ throws ExecutionException {
Collection<ApkInfo> apks;
try {
apks = apkProvider.getApks(device);
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
throw new ExecutionException(e);
}
return ImmutableList.of(new DeployApkTask(project, launchOptions, apks));
@@ -129,42 +141,47 @@
@Nullable
@Override
- public LaunchTask getApplicationLaunchTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- ProcessHandlerLaunchStatus processHandlerLaunchStatus) throws ExecutionException {
+ public LaunchTask getApplicationLaunchTask(
+ LaunchOptions launchOptions,
+ @Nullable Integer userId,
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ ProcessHandlerLaunchStatus processHandlerLaunchStatus)
+ throws ExecutionException {
if (configState.isRunThroughBlaze()) {
return new BlazeAndroidTestLaunchTask(
- project,
- commonState.getTarget(),
- buildFlags,
- new BlazeAndroidTestFilter(configState.TESTING_TYPE,
- configState.CLASS_NAME,
- configState.METHOD_NAME,
- configState.PACKAGE_NAME),
- this,
- launchOptions.isDebug()
- );
+ project,
+ label,
+ buildFlags,
+ new BlazeAndroidTestFilter(
+ configState.getTestingType(),
+ configState.getClassName(),
+ configState.getMethodName(),
+ configState.getPackageName()),
+ this,
+ launchOptions.isDebug());
}
return StockAndroidTestLaunchTask.getStockTestLaunchTask(
- configState,
- applicationIdProvider,
- launchOptions.isDebug(),
- facet,
- processHandlerLaunchStatus
- );
+ configState,
+ applicationIdProvider,
+ launchOptions.isDebug(),
+ facet,
+ processHandlerLaunchStatus);
}
@Override
- public DebugConnectorTask getDebuggerTask(LaunchOptions launchOptions,
- AndroidDebugger androidDebugger,
- AndroidDebuggerState androidDebuggerState,
- @NotNull Set<String> packageIds) throws ExecutionException {
+ public DebugConnectorTask getDebuggerTask(
+ AndroidDebugger androidDebugger,
+ AndroidDebuggerState androidDebuggerState,
+ @NotNull Set<String> packageIds)
+ throws ExecutionException {
if (configState.isRunThroughBlaze()) {
- return new ConnectBlazeTestDebuggerTask(env.getProject(), androidDebugger, packageIds, applicationIdProvider, this);
+ return new ConnectBlazeTestDebuggerTask(
+ env.getProject(), androidDebugger, packageIds, applicationIdProvider, this);
}
//noinspection unchecked
- return androidDebugger.getConnectDebuggerTask(env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
+ return androidDebugger.getConnectDebuggerTask(
+ env, null, packageIds, facet, androidDebuggerState, runConfiguration.getType().getId());
}
void onLaunchTaskComplete() {
@@ -176,4 +193,10 @@
void addLaunchTaskCompleteListener(Runnable runnable) {
launchTaskCompleteListeners.add(runnable);
}
+
+ @Nullable
+ @Override
+ public Integer getUserId(IDevice device, ConsolePrinter consolePrinter) {
+ return null;
+ }
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/ConnectBlazeTestDebuggerTask.java b/aswb/src/com/google/idea/blaze/android/run/test/ConnectBlazeTestDebuggerTask.java
index d15ecb6..9fe3377 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/ConnectBlazeTestDebuggerTask.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/ConnectBlazeTestDebuggerTask.java
@@ -19,7 +19,14 @@
import com.android.ddmlib.Client;
import com.android.ddmlib.ClientData;
import com.android.ddmlib.IDevice;
-import com.android.tools.idea.run.*;
+import com.android.tools.idea.run.AndroidDebugState;
+import com.android.tools.idea.run.AndroidProcessText;
+import com.android.tools.idea.run.AndroidRunConfigurationBase;
+import com.android.tools.idea.run.AndroidSessionInfo;
+import com.android.tools.idea.run.ApkProvisionException;
+import com.android.tools.idea.run.ApplicationIdProvider;
+import com.android.tools.idea.run.LaunchInfo;
+import com.android.tools.idea.run.ProcessHandlerConsolePrinter;
import com.android.tools.idea.run.editor.AndroidDebugger;
import com.android.tools.idea.run.tasks.ConnectDebuggerTask;
import com.android.tools.idea.run.tasks.ConnectJavaDebuggerTask;
@@ -36,15 +43,12 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import java.util.Locale;
+import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Connects the blaze debugger during execution.
- */
+/** Connects the blaze debugger during execution. */
class ConnectBlazeTestDebuggerTask extends ConnectDebuggerTask {
private static final Logger LOG = Logger.getInstance(ConnectBlazeTestDebuggerTask.class);
@@ -53,11 +57,11 @@
private final BlazeAndroidTestRunContext runContext;
public ConnectBlazeTestDebuggerTask(
- Project project,
- AndroidDebugger debugger,
- Set<String> applicationIds,
- ApplicationIdProvider applicationIdProvider,
- BlazeAndroidTestRunContext runContext) {
+ Project project,
+ AndroidDebugger debugger,
+ Set<String> applicationIds,
+ ApplicationIdProvider applicationIdProvider,
+ BlazeAndroidTestRunContext runContext) {
super(applicationIds, debugger, project);
this.project = project;
this.applicationIdProvider = applicationIdProvider;
@@ -66,15 +70,15 @@
@Nullable
@Override
- public ProcessHandler perform(@NotNull LaunchInfo launchInfo,
- @NotNull IDevice device,
- @NotNull ProcessHandlerLaunchStatus state,
- @NotNull ProcessHandlerConsolePrinter printer) {
+ public ProcessHandler perform(
+ @NotNull LaunchInfo launchInfo,
+ @NotNull IDevice device,
+ @NotNull ProcessHandlerLaunchStatus state,
+ @NotNull ProcessHandlerConsolePrinter printer) {
try {
String packageName = applicationIdProvider.getPackageName();
setUpForReattachingDebugger(packageName, launchInfo, state, printer);
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
LOG.error(e);
}
@@ -83,75 +87,83 @@
}
/**
- * Wires up listeners to automatically reconnect the debugger for each test method.
- * When you `blaze test` an android_test in debug mode, it kills the instrumentation process
- * between each test method, disconnecting the debugger. We listen for the start of a new
- * method waiting for a debugger, and reconnect.
- * TODO: Support stopping Blaze from the UI. This is hard because we have no way to distinguish
- * process handler termination/debug session ending initiated by the user.
+ * Wires up listeners to automatically reconnect the debugger for each test method. When you
+ * `blaze test` an android_test in debug mode, it kills the instrumentation process between each
+ * test method, disconnecting the debugger. We listen for the start of a new method waiting for a
+ * debugger, and reconnect. TODO: Support stopping Blaze from the UI. This is hard because we have
+ * no way to distinguish process handler termination/debug session ending initiated by the user.
*/
private void setUpForReattachingDebugger(
- String targetPackage,
- LaunchInfo launchInfo,
- ProcessHandlerLaunchStatus launchStatus,
- ProcessHandlerConsolePrinter printer
- ) {
+ String targetPackage,
+ LaunchInfo launchInfo,
+ ProcessHandlerLaunchStatus launchStatus,
+ ProcessHandlerConsolePrinter printer) {
final AndroidDebugBridge.IClientChangeListener reattachingListener =
- new AndroidDebugBridge.IClientChangeListener() {
- // The target application can either
- // 1. Match our target name, and become available for debugging.
- // 2. Be available for debugging, and suddenly have its name changed to match.
- static final int CHANGE_MASK = Client.CHANGE_DEBUGGER_STATUS | Client.CHANGE_NAME;
+ new AndroidDebugBridge.IClientChangeListener() {
+ // The target application can either
+ // 1. Match our target name, and become available for debugging.
+ // 2. Be available for debugging, and suddenly have its name changed to match.
+ static final int CHANGE_MASK = Client.CHANGE_DEBUGGER_STATUS | Client.CHANGE_NAME;
- @Override
- public void clientChanged(@NotNull Client client, int changeMask) {
- ClientData data = client.getClientData();
- String clientDescription = data.getClientDescription();
- if (clientDescription != null && clientDescription.equals(targetPackage)
- && (changeMask & CHANGE_MASK) != 0
- && data.getDebuggerConnectionStatus().equals(ClientData.DebuggerStatus.WAITING)) {
- reattachDebugger(launchInfo, client, launchStatus, printer);
+ @Override
+ public void clientChanged(@NotNull Client client, int changeMask) {
+ ClientData data = client.getClientData();
+ String clientDescription = data.getClientDescription();
+ if (clientDescription != null
+ && clientDescription.equals(targetPackage)
+ && (changeMask & CHANGE_MASK) != 0
+ && data.getDebuggerConnectionStatus().equals(ClientData.DebuggerStatus.WAITING)) {
+ reattachDebugger(launchInfo, client, launchStatus, printer);
+ }
}
- }
- };
+ };
AndroidDebugBridge.addClientChangeListener(reattachingListener);
- runContext.addLaunchTaskCompleteListener(() -> {
- AndroidDebugBridge.removeClientChangeListener(reattachingListener);
- launchStatus.terminateLaunch("Test run completed.\n");
- });
+ runContext.addLaunchTaskCompleteListener(
+ () -> {
+ AndroidDebugBridge.removeClientChangeListener(reattachingListener);
+ launchStatus.terminateLaunch("Test run completed.\n");
+ });
}
private void reattachDebugger(
- LaunchInfo launchInfo,
- final Client client,
- ProcessHandlerLaunchStatus launchStatus,
- ProcessHandlerConsolePrinter printer
- ) {
- ApplicationManager.getApplication().invokeLater(() -> launchDebugger(launchInfo, client, launchStatus, printer));
+ LaunchInfo launchInfo,
+ final Client client,
+ ProcessHandlerLaunchStatus launchStatus,
+ ProcessHandlerConsolePrinter printer) {
+ ApplicationManager.getApplication()
+ .invokeLater(() -> launchDebugger(launchInfo, client, launchStatus, printer));
}
/**
- * Nearly a clone of {@link ConnectJavaDebuggerTask#launchDebugger}. There are a few changes to account for null variables that could
- * occur in our implementation.
+ * Nearly a clone of {@link ConnectJavaDebuggerTask#launchDebugger}. There are a few changes to
+ * account for null variables that could occur in our implementation.
*/
@Override
- public ProcessHandler launchDebugger(@NotNull LaunchInfo currentLaunchInfo,
- @NotNull Client client,
- @NotNull ProcessHandlerLaunchStatus launchStatus,
- @NotNull ProcessHandlerConsolePrinter printer) {
+ public ProcessHandler launchDebugger(
+ @NotNull LaunchInfo currentLaunchInfo,
+ @NotNull Client client,
+ @NotNull ProcessHandlerLaunchStatus launchStatus,
+ @NotNull ProcessHandlerConsolePrinter printer) {
String debugPort = Integer.toString(client.getDebuggerListenPort());
int pid = client.getClientData().getPid();
Logger.getInstance(ConnectJavaDebuggerTask.class)
- .info(String.format(Locale.US, "Attempting to connect debugger to port %1$s [client %2$d]", debugPort, pid));
+ .info(
+ String.format(
+ Locale.US,
+ "Attempting to connect debugger to port %1$s [client %2$d]",
+ debugPort,
+ pid));
// create a new process handler
RemoteConnection connection = new RemoteConnection(true, "localhost", debugPort, false);
RemoteDebugProcessHandler debugProcessHandler = new RemoteDebugProcessHandler(project);
// switch the launch status and console printers to point to the new process handler
- // this is required, esp. for AndroidTestListener which holds a reference to the launch status and printers, and those should
- // be updated to point to the new process handlers, otherwise test results will not be forwarded appropriately
+ // this is required, esp. for AndroidTestListener which holds a
+ // reference to the launch status and printers, and those should
+ // be updated to point to the new process handlers,
+ // otherwise test results will not be forwarded appropriately
launchStatus.setProcessHandler(debugProcessHandler);
printer.setProcessHandler(debugProcessHandler);
@@ -166,29 +178,34 @@
processHandler.detachProcess();
}
- AndroidDebugState debugState = new AndroidDebugState(project, debugProcessHandler, connection, currentLaunchInfo.consoleProvider);
+ AndroidDebugState debugState =
+ new AndroidDebugState(
+ project, debugProcessHandler, connection, currentLaunchInfo.consoleProvider);
RunContentDescriptor debugDescriptor;
try {
// @formatter:off
- ExecutionEnvironment debugEnv = new ExecutionEnvironmentBuilder(currentLaunchInfo.env)
- .executor(currentLaunchInfo.executor)
- .runner(currentLaunchInfo.runner)
- .contentToReuse(processHandler == null ? null : descriptor)
- .build();
- debugDescriptor = DebuggerPanelsManager.getInstance(project).attachVirtualMachine(debugEnv, debugState, connection, false);
+ ExecutionEnvironment debugEnv =
+ new ExecutionEnvironmentBuilder(currentLaunchInfo.env)
+ .executor(currentLaunchInfo.executor)
+ .runner(currentLaunchInfo.runner)
+ .contentToReuse(processHandler == null ? null : descriptor)
+ .build();
+ debugDescriptor =
+ DebuggerPanelsManager.getInstance(project)
+ .attachVirtualMachine(debugEnv, debugState, connection, false);
// @formatter:on
- }
- catch (ExecutionException e) {
+ } catch (ExecutionException e) {
printer.stderr("ExecutionException: " + e.getMessage() + '.');
return null;
}
- // Based on the above try block, we shouldn't get here unless we have assigned to debugDescriptor
+ // Based on the above try block we shouldn't get here unless we have assigned to debugDescriptor
assert debugDescriptor != null;
// re-run the collected text from the old process handler to the new
- // TODO: is there a race between messages received once the debugger has been connected, and these messages that are printed out?
+ // TODO: is there a race between messages received once the debugger has been connected,
+ // and these messages that are printed out?
if (processHandler != null) {
final AndroidProcessText oldText = AndroidProcessText.get(processHandler);
if (oldText != null) {
@@ -197,12 +214,21 @@
}
RunProfile runProfile = currentLaunchInfo.env.getRunProfile();
- int uniqueId = runProfile instanceof AndroidRunConfigurationBase ? ((AndroidRunConfigurationBase)runProfile).getUniqueID() : -1;
+ int uniqueId =
+ runProfile instanceof AndroidRunConfigurationBase
+ ? ((AndroidRunConfigurationBase) runProfile).getUniqueID()
+ : -1;
AndroidSessionInfo value =
- new AndroidSessionInfo(debugProcessHandler, debugDescriptor, uniqueId, currentLaunchInfo.executor.getId(), false);
+ new AndroidSessionInfo(
+ debugProcessHandler,
+ debugDescriptor,
+ uniqueId,
+ currentLaunchInfo.executor.getId(),
+ false);
debugProcessHandler.putUserData(AndroidSessionInfo.KEY, value);
debugProcessHandler.putUserData(AndroidSessionInfo.ANDROID_DEBUG_CLIENT, client);
- debugProcessHandler.putUserData(AndroidSessionInfo.ANDROID_DEVICE_API_LEVEL, client.getDevice().getVersion());
+ debugProcessHandler.putUserData(
+ AndroidSessionInfo.ANDROID_DEVICE_API_LEVEL, client.getDevice().getVersion());
return debugProcessHandler;
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/InstrumentationRunnerProvider.java b/aswb/src/com/google/idea/blaze/android/run/test/InstrumentationRunnerProvider.java
index 3d7b435..3c90aba 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/InstrumentationRunnerProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/InstrumentationRunnerProvider.java
@@ -16,16 +16,13 @@
package com.google.idea.blaze.android.run.test;
import com.intellij.openapi.extensions.ExtensionPointName;
-
import javax.annotation.Nullable;
-/**
- * Provides a default instrumentation test runner class for android test configurations.
- */
+/** Provides a default instrumentation test runner class for android test configurations. */
public interface InstrumentationRunnerProvider {
ExtensionPointName<InstrumentationRunnerProvider> EP_NAME =
- ExtensionPointName.create("com.google.idea.blaze.android.InstrumentationRunnerProvider");
+ ExtensionPointName.create("com.google.idea.blaze.android.InstrumentationRunnerProvider");
@Nullable
static String getDefaultInstrumentationRunnerClass() {
@@ -40,5 +37,4 @@
@Nullable
String getInstrumentationRunnerClass();
-
}
diff --git a/aswb/src/com/google/idea/blaze/android/run/test/StockAndroidTestLaunchTask.java b/aswb/src/com/google/idea/blaze/android/run/test/StockAndroidTestLaunchTask.java
index 10c3fd1..4ec111f 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/StockAndroidTestLaunchTask.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/StockAndroidTestLaunchTask.java
@@ -44,7 +44,11 @@
@NotNull private final String testApplicationId;
private final boolean waitForDebugger;
- private StockAndroidTestLaunchTask(@NotNull BlazeAndroidTestRunConfigurationState configState, @Nullable String runner, @NotNull String testPackage, boolean waitForDebugger) {
+ private StockAndroidTestLaunchTask(
+ @NotNull BlazeAndroidTestRunConfigurationState configState,
+ @Nullable String runner,
+ @NotNull String testPackage,
+ boolean waitForDebugger) {
this.configState = configState;
this.instrumentationTestRunner = runner;
this.waitForDebugger = waitForDebugger;
@@ -52,15 +56,15 @@
}
public static LaunchTask getStockTestLaunchTask(
- @NotNull BlazeAndroidTestRunConfigurationState configState,
- @NotNull ApplicationIdProvider applicationIdProvider,
- boolean waitForDebugger,
- @NotNull AndroidFacet facet,
- @NotNull LaunchStatus launchStatus
- ) {
- String runner = StringUtil.isEmpty(configState.INSTRUMENTATION_RUNNER_CLASS)
- ? findInstrumentationRunner(facet)
- : configState.INSTRUMENTATION_RUNNER_CLASS;
+ @NotNull BlazeAndroidTestRunConfigurationState configState,
+ @NotNull ApplicationIdProvider applicationIdProvider,
+ boolean waitForDebugger,
+ @NotNull AndroidFacet facet,
+ @NotNull LaunchStatus launchStatus) {
+ String runner =
+ StringUtil.isEmpty(configState.getInstrumentationRunnerClass())
+ ? findInstrumentationRunner(facet)
+ : configState.getInstrumentationRunnerClass();
String testPackage;
try {
testPackage = applicationIdProvider.getTestPackageName();
@@ -68,8 +72,7 @@
launchStatus.terminateLaunch("Unable to determine test package name");
return null;
}
- }
- catch (ApkProvisionException e) {
+ } catch (ApkProvisionException e) {
launchStatus.terminateLaunch("Unable to determine test package name");
return null;
}
@@ -97,12 +100,14 @@
@Nullable
private static String getRunnerFromManifest(@NotNull final AndroidFacet facet) {
if (!ApplicationManager.getApplication().isReadAccessAllowed()) {
- return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
- @Override
- public String compute() {
- return getRunnerFromManifest(facet);
- }
- });
+ return ApplicationManager.getApplication()
+ .runReadAction(
+ new Computable<String>() {
+ @Override
+ public String compute() {
+ return getRunnerFromManifest(facet);
+ }
+ });
}
Manifest manifest = facet.getManifest();
@@ -119,7 +124,6 @@
return null;
}
-
@NotNull
@Override
public String getDescription() {
@@ -132,39 +136,44 @@
}
@Override
- public boolean perform(@NotNull IDevice device, @NotNull final LaunchStatus launchStatus, @NotNull final ConsolePrinter printer) {
+ public boolean perform(
+ @NotNull IDevice device,
+ @NotNull final LaunchStatus launchStatus,
+ @NotNull final ConsolePrinter printer) {
printer.stdout("Running tests\n");
- final RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(testApplicationId, instrumentationTestRunner, device);
- switch (configState.TESTING_TYPE) {
+ final RemoteAndroidTestRunner runner =
+ new RemoteAndroidTestRunner(testApplicationId, instrumentationTestRunner, device);
+ switch (configState.getTestingType()) {
case BlazeAndroidTestRunConfigurationState.TEST_ALL_IN_PACKAGE:
- runner.setTestPackageName(configState.PACKAGE_NAME);
+ runner.setTestPackageName(configState.getPackageName());
break;
case BlazeAndroidTestRunConfigurationState.TEST_CLASS:
- runner.setClassName(configState.CLASS_NAME);
+ runner.setClassName(configState.getClassName());
break;
case BlazeAndroidTestRunConfigurationState.TEST_METHOD:
- runner.setMethodName(configState.CLASS_NAME, configState.METHOD_NAME);
+ runner.setMethodName(configState.getClassName(), configState.getMethodName());
break;
}
runner.setDebug(waitForDebugger);
- runner.setRunOptions(configState.EXTRA_OPTIONS);
+ runner.setRunOptions(configState.getExtraOptions());
printer.stdout("$ adb shell " + runner.getAmInstrumentCommand());
// run in a separate thread as this will block until the tests complete
- ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
- @Override
- public void run() {
- try {
- runner.run(new AndroidTestListener(launchStatus, printer));
- }
- catch (Exception e) {
- LOG.info(e);
- printer.stderr("Error: Unexpected exception while running tests: " + e);
- }
- }
- });
+ ApplicationManager.getApplication()
+ .executeOnPooledThread(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runner.run(new AndroidTestListener(launchStatus, printer));
+ } catch (Exception e) {
+ LOG.info(e);
+ printer.stderr("Error: Unexpected exception while running tests: " + e);
+ }
+ }
+ });
return true;
}
diff --git a/aswb/src/com/google/idea/blaze/android/sdk/AndroidSdkListener.java b/aswb/src/com/google/idea/blaze/android/sdk/AndroidSdkListener.java
index b58f3f5..4a6a6d1 100644
--- a/aswb/src/com/google/idea/blaze/android/sdk/AndroidSdkListener.java
+++ b/aswb/src/com/google/idea/blaze/android/sdk/AndroidSdkListener.java
@@ -19,13 +19,10 @@
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.sync.status.BlazeSyncStatus;
import com.intellij.openapi.project.Project;
+import java.io.File;
import org.jetbrains.annotations.NotNull;
-import java.io.File;
-
-/**
- * Listens for android SDK changes, and queues up a blaze sync
- */
+/** Listens for android SDK changes, and queues up a blaze sync */
public class AndroidSdkListener implements IdeSdks.AndroidSdkEventListener {
@Override
diff --git a/aswb/src/com/google/idea/blaze/android/sdk/SdkUtil.java b/aswb/src/com/google/idea/blaze/android/sdk/SdkUtil.java
index 2c56c29..a48166a 100644
--- a/aswb/src/com/google/idea/blaze/android/sdk/SdkUtil.java
+++ b/aswb/src/com/google/idea/blaze/android/sdk/SdkUtil.java
@@ -26,17 +26,17 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-/**
- * SDK utilities.
- */
+/** SDK utilities. */
public class SdkUtil {
@Nullable
public static AndroidPlatform getAndroidPlatform(@NotNull Project project) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
if (blazeProjectData == null) {
return null;
}
- AndroidSdkPlatform androidSdkPlatform = AndroidSdkPlatformSyncer.getAndroidSdkPlatform(blazeProjectData);
+ AndroidSdkPlatform androidSdkPlatform =
+ AndroidSdkPlatformSyncer.getAndroidSdkPlatform(blazeProjectData);
if (androidSdkPlatform == null) {
return null;
}
diff --git a/aswb/src/com/google/idea/blaze/android/settings/AswbGlobalSettings.java b/aswb/src/com/google/idea/blaze/android/settings/AswbGlobalSettings.java
index 53992b0..9532859 100644
--- a/aswb/src/com/google/idea/blaze/android/settings/AswbGlobalSettings.java
+++ b/aswb/src/com/google/idea/blaze/android/settings/AswbGlobalSettings.java
@@ -15,17 +15,15 @@
*/
package com.google.idea.blaze.android.settings;
-import com.intellij.openapi.components.*;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.Nullable;
-/**
- * Stores aswb global settings.
- */
-@State(
- name = "AswbGlobalSettings",
- storages = @Storage(file = StoragePathMacros.APP_CONFIG + "/aswb.global.xml")
-)
+/** Stores aswb global settings. */
+@State(name = "AswbGlobalSettings", storages = @Storage("aswb.global.xml"))
public class AswbGlobalSettings implements PersistentStateComponent<AswbGlobalSettings> {
private String localSdkLocation;
diff --git a/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java b/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java
new file mode 100644
index 0000000..58f99de
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.sync;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.prefetch.PrefetchFileSource;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Set;
+
+/** Adds the resource directories outside our source roots to prefetch. */
+public class AndroidPrefetchFileSource implements PrefetchFileSource {
+ @Override
+ public void addFilesToPrefetch(
+ Project project, BlazeProjectData blazeProjectData, Collection<File> files) {
+ BlazeAndroidSyncData syncData = blazeProjectData.syncState.get(BlazeAndroidSyncData.class);
+ if (syncData == null) {
+ return;
+ }
+ if (syncData.importResult.resourceLibrary == null) {
+ return;
+ }
+ files.addAll(syncData.importResult.resourceLibrary.sources);
+ }
+
+ @Override
+ public Set<String> prefetchSrcFileExtensions() {
+ return ImmutableSet.of("xml");
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/AndroidSdkPlatformSyncer.java b/aswb/src/com/google/idea/blaze/android/sync/AndroidSdkPlatformSyncer.java
index 2ee6d56..c219263 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/AndroidSdkPlatformSyncer.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/AndroidSdkPlatformSyncer.java
@@ -15,7 +15,11 @@
*/
package com.google.idea.blaze.android.sync;
+import com.android.tools.idea.startup.AndroidStudioInitializer;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.idea.blaze.android.projectview.AndroidSdkPlatformSection;
import com.google.idea.blaze.android.settings.AswbGlobalSettings;
import com.google.idea.blaze.android.sync.model.AndroidSdkPlatform;
@@ -23,73 +27,95 @@
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.projectview.ProjectViewManager;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.sdk.AndroidSdkAdditionalData;
import org.jetbrains.android.sdk.AndroidSdkUtils;
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-
-/**
- * Calculates AndroidSdkPlatform.
- */
+/** Calculates AndroidSdkPlatform. */
public class AndroidSdkPlatformSyncer {
@Nullable
- static AndroidSdkPlatform getAndroidSdkPlatform(
- Project project,
- BlazeContext context,
- File androidPlatformDirectory) {
+ static AndroidSdkPlatform getAndroidSdkPlatform(Project project, BlazeContext context) {
- String androidSdk = null;
-
- String localSdkLocation = AswbGlobalSettings.getInstance().getLocalSdkLocation();
- if (localSdkLocation == null) {
- IssueOutput
- .error("Error: No android_sdk synced yet. Please sync SDK following go/aswb-sdk.")
- .submit(context);
- }
-
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet != null) {
- Collection<ScalarSection<String>> androidSdkPlatformSections =
- projectViewSet.getSections(AndroidSdkPlatformSection.KEY);
- if (!androidSdkPlatformSections.isEmpty()) {
- ScalarSection<String> androidSdkPlatformSection = Iterables.getLast(androidSdkPlatformSections);
- androidSdk = BlazeAndroidSdk.getAndroidSdkLevelFromLocalChannel(
- localSdkLocation,
- androidSdkPlatformSection.getValue());
-
- if (androidSdk == null) {
- IssueOutput
- .error("No such android_sdk_platform: " + androidSdkPlatformSection.getValue())
- .inFile(projectViewSet.getTopLevelProjectViewFile().projectViewFile)
+ final String localSdkLocation;
+ if (AndroidStudioInitializer.isAndroidSdkManagerEnabled()) {
+ Sdk sdk = Iterables.getFirst(AndroidSdkUtils.getAllAndroidSdks(), null);
+ if (sdk == null) {
+ IssueOutput.error(
+ "Error: No Android SDK configured. Please use the SDK manager to configure.")
.submit(context);
- }
+ return null;
+ }
+ localSdkLocation = sdk.getHomePath();
+ } else {
+ localSdkLocation = AswbGlobalSettings.getInstance().getLocalSdkLocation();
+ if (localSdkLocation == null) {
+ IssueOutput.error(
+ "Error: No Android SDK synced yet."
+ + (Blaze.defaultBuildSystem() == BuildSystem.Blaze
+ ? " Please sync SDK following go/aswb-sdk."
+ : ""))
+ .submit(context);
+ return null;
}
}
- if (androidSdk == null) {
- androidSdk = BlazeAndroidSdk.getAndroidSdkLevelFromBlazeRc(androidPlatformDirectory);
+ String androidSdkPlatform = null;
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet != null) {
+ androidSdkPlatform = projectViewSet.getScalarValue(AndroidSdkPlatformSection.KEY);
}
+ // This is verified in the project view verification step, but double-check here
+ if (androidSdkPlatform == null) {
+ IssueOutput.error(
+ "No android_sdk_platform set. Please ensure this is set to a platform SDK directory.")
+ .submit(context);
+ return null;
+ }
+
+ String androidSdk =
+ BlazeAndroidSdk.getAndroidSdkLevelFromLocalChannel(localSdkLocation, androidSdkPlatform);
+
if (androidSdk == null) {
- IssueOutput
- .error("Can't determine your SDK. Please sync your SDK by following go/aswb-sdk and try again.")
- .submit(context);
+ IssueOutput.error(
+ Joiner.on("\n")
+ .join(
+ "No such android_sdk_platform: " + androidSdkPlatform,
+ "Available android_sdk_platforms are: "
+ + getAvailableSdkPlatforms(localSdkLocation)))
+ .inFile(projectViewSet.getTopLevelProjectViewFile().projectViewFile)
+ .submit(context);
return null;
}
Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdk);
if (sdk == null) {
- IssueOutput
- .error("Can't find a matching SDK. Please sync your SDK by following go/aswb-sdk and try again.")
- .submit(context);
+ ImmutableList.Builder<String> error =
+ ImmutableList.<String>builder()
+ .add(
+ String.format(
+ "Can't find a matching SDK "
+ + "(was looking for '%s' in the '%s' platform directory).",
+ androidSdk, androidSdkPlatform),
+ "Available android_sdk_platforms are: "
+ + getAvailableSdkPlatforms(localSdkLocation));
+ if (Blaze.defaultBuildSystem() == BuildSystem.Blaze) {
+ error.add(
+ "If you have no SDK, please sync your SDK by following go/aswb-sdk and try again. ",
+ "If you have done everything correctly, this can be due to an SDK sync manager bug.",
+ "To workaround, please delete ~/.AndroidStudioWithBlazeXX/system and restart");
+ }
+
+ IssueOutput.error(String.join("\n", error.build())).submit(context);
return null;
}
@@ -97,8 +123,28 @@
return new AndroidSdkPlatform(androidSdk, androidSdkApiLevel);
}
+ private static String getAvailableSdkPlatforms(String localSdkDirectoryString) {
+ File localSdkDirectory = new File(localSdkDirectoryString);
+ if (localSdkDirectory.exists()) {
+ File platformDirectory = new File(localSdkDirectory, "platforms");
+ if (platformDirectory.exists()) {
+ File[] children = platformDirectory.listFiles();
+ if (children != null) {
+ List<String> names = Lists.newArrayList();
+ for (File child : children) {
+ if (child.isDirectory()) {
+ names.add('"' + child.getName() + '"');
+ }
+ }
+ return "{" + Joiner.on(", ").join(names) + "}";
+ }
+ }
+ }
+ return "<No platforms found>";
+ }
+
@Nullable
- static public AndroidSdkPlatform getAndroidSdkPlatform(BlazeProjectData blazeProjectData) {
+ public static AndroidSdkPlatform getAndroidSdkPlatform(BlazeProjectData blazeProjectData) {
BlazeAndroidSyncData syncData = blazeProjectData.syncState.get(BlazeAndroidSyncData.class);
return syncData != null ? syncData.androidSdkPlatform : null;
}
@@ -107,7 +153,8 @@
int androidSdkApiLevel = 1;
Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdk);
if (sdk != null) {
- AndroidSdkAdditionalData additionalData = (AndroidSdkAdditionalData)sdk.getSdkAdditionalData();
+ AndroidSdkAdditionalData additionalData =
+ (AndroidSdkAdditionalData) sdk.getSdkAdditionalData();
if (additionalData != null) {
AndroidPlatform androidPlatform = additionalData.getAndroidPlatform();
if (androidPlatform != null) {
diff --git a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidJavaSyncAugmenter.java b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidJavaSyncAugmenter.java
index ea02f53..96df410 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidJavaSyncAugmenter.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidJavaSyncAugmenter.java
@@ -16,26 +16,59 @@
package com.google.idea.blaze.android.sync;
import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.android.sync.importer.BlazeAndroidWorkspaceImporter;
import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-
import java.util.Collection;
-/**
- * Augments the java sync process with Android support.
- */
-public class BlazeAndroidJavaSyncAugmenter implements BlazeJavaSyncAugmenter {
- private static final BoolExperiment EXCLUDE_ANDROID_BLAZE_JAR = new BoolExperiment("exclude.android.blaze.jar", true);
+/** Augments the java sync process with Android support. */
+public class BlazeAndroidJavaSyncAugmenter extends BlazeJavaSyncAugmenter.Adapter {
+
+ @Override
+ public boolean isActive(WorkspaceLanguageSettings workspaceLanguageSettings) {
+ return workspaceLanguageSettings.isLanguageActive(LanguageClass.ANDROID);
+ }
+
+ @Override
+ public void addJarsForSourceRule(
+ RuleIdeInfo rule, Collection<BlazeJarLibrary> jars, Collection<BlazeJarLibrary> genJars) {
+ AndroidRuleIdeInfo androidRuleIdeInfo = rule.androidRuleIdeInfo;
+ if (androidRuleIdeInfo == null) {
+ return;
+ }
+ LibraryArtifact idlJar = androidRuleIdeInfo.idlJar;
+ if (idlJar != null) {
+ genJars.add(new BlazeJarLibrary(idlJar, rule.label));
+ }
+
+ if (BlazeAndroidWorkspaceImporter.shouldGenerateResources(androidRuleIdeInfo)
+ && !BlazeAndroidWorkspaceImporter.shouldGenerateResourceModule(androidRuleIdeInfo)) {
+ // Add blaze's output unless it's a top level rule.
+ // In these cases the resource jar contains the entire
+ // transitive closure of R classes. It's unlikely this is wanted to resolve in the IDE.
+ boolean discardResourceJar = rule.kindIsOneOf(Kind.ANDROID_BINARY, Kind.ANDROID_TEST);
+ if (!discardResourceJar) {
+ LibraryArtifact resourceJar = androidRuleIdeInfo.resourceJar;
+ if (resourceJar != null) {
+ jars.add(new BlazeJarLibrary(resourceJar, rule.label));
+ }
+ }
+ }
+ }
@Override
public void addLibraryFilter(Glob.GlobSet excludedLibraries) {
- if (EXCLUDE_ANDROID_BLAZE_JAR.getValue()) {
- excludedLibraries.add(new Glob("*/android_blaze.jar")); // This is supplied via the SDK
- }
+ excludedLibraries.add(new Glob("*/android_blaze.jar")); // This is supplied via the SDK
}
@Override
@@ -44,11 +77,10 @@
if (syncData == null) {
return ImmutableList.of();
}
- return syncData.importResult.libraries;
- }
-
- @Override
- public Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData) {
- return ImmutableList.of();
+ ImmutableList.Builder<BlazeLibrary> libraries = ImmutableList.builder();
+ if (syncData.importResult.resourceLibrary != null) {
+ libraries.add(syncData.importResult.resourceLibrary);
+ }
+ return libraries.build();
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSdk.java b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSdk.java
index 826e1c4..e9e838e 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSdk.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSdk.java
@@ -19,53 +19,29 @@
import com.android.sdklib.AndroidTargetHash;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.AndroidVersionHelper;
-import com.android.tools.idea.sdk.IdeSdks;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
-
import javax.annotation.Nullable;
-/**
- * Utility methods for handling the android sdk.
- */
+/** Utility methods for handling the android sdk. */
public final class BlazeAndroidSdk {
private static final Logger LOG = Logger.getInstance(BlazeAndroidSdk.class);
- private BlazeAndroidSdk() {
- }
+ private BlazeAndroidSdk() {}
- /**
- * Reads the android sdk level from your local SDK directory.
- */
- public static String getAndroidSdkLevelFromLocalChannel(String localSdkLocation,
- String androidSdkPlatform) {
- File androidSdkPlatformsDir = new File(new File(new File(localSdkLocation), "platforms"), androidSdkPlatform);
+ /** Reads the android sdk level from your local SDK directory. */
+ public static String getAndroidSdkLevelFromLocalChannel(
+ String localSdkLocation, String androidSdkPlatform) {
+ File androidSdkPlatformsDir =
+ new File(new File(new File(localSdkLocation), "platforms"), androidSdkPlatform);
File sourcePropertiesFile = new File(androidSdkPlatformsDir, SdkConstants.FN_SOURCE_PROP);
return getAndroidSdkLevelFromSourceProperties(sourcePropertiesFile);
}
- /**
- * The user's blazerc is read to discover the --android_sdk configuration. The resulting
- * label can be an indirection (eg. "latest" or "prerelease"), so blaze query is used to
- * query for "android_blaze.jar", which marks the actual android sdk directory.
- * <p/>
- * <p>This directory should have a source.properties file. This is read to discover the
- * platform API level (eg. "21"). This is hashed according to ADT standards to return
- * a unique SDK key, eg "android-21".
- */
- @Nullable
- public static String getAndroidSdkLevelFromBlazeRc(
- File androidPlatformDir) {
- File sourcePropertiesFile = new File(androidPlatformDir, SdkConstants.FN_SOURCE_PROP);
- return getAndroidSdkLevelFromSourceProperties(sourcePropertiesFile);
- }
-
@Nullable
public static String getAndroidSdkLevelFromSourceProperties(File sourcePropertiesFile) {
if (!sourcePropertiesFile.exists()) {
@@ -73,7 +49,7 @@
}
AndroidVersion androidVersion =
- readAndroidVersionFromSourcePropertiesFile(sourcePropertiesFile);
+ readAndroidVersionFromSourcePropertiesFile(sourcePropertiesFile);
if (androidVersion == null) {
LOG.warn("Could not read source.properties from: " + sourcePropertiesFile);
return null;
@@ -82,7 +58,8 @@
}
@Nullable
- private static AndroidVersion readAndroidVersionFromSourcePropertiesFile(File sourcePropertiesFile) {
+ private static AndroidVersion readAndroidVersionFromSourcePropertiesFile(
+ File sourcePropertiesFile) {
Properties props = parseProperties(sourcePropertiesFile);
if (props == null) {
return null;
@@ -95,8 +72,8 @@
}
/**
- * Parses the given file as properties file if it exists.
- * Returns null if the file does not exist, cannot be parsed or has no properties.
+ * Parses the given file as properties file if it exists. Returns null if the file does not exist,
+ * cannot be parsed or has no properties.
*/
@Nullable
private static Properties parseProperties(File propsFile) {
@@ -116,5 +93,4 @@
}
return null;
}
-
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncListener.java b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncListener.java
index 6fa349a..91d6b57 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncListener.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncListener.java
@@ -16,31 +16,15 @@
package com.google.idea.blaze.android.sync;
import com.android.tools.idea.res.ResourceFolderRegistry;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.sync.SyncListener;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
-/**
- * Android-specific hooks to run after a blaze sync.
- */
-public class BlazeAndroidSyncListener implements SyncListener {
+/** Android-specific hooks to run after a blaze sync. */
+public class BlazeAndroidSyncListener extends SyncListener.Adapter {
@Override
- public void onSyncStart(Project project) {
- }
-
- @Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- }
-
- @Override
- public void afterSync(Project project, boolean successful) {
- if (successful) {
+ public void afterSync(Project project, SyncResult syncResult) {
+ if (syncResult == SyncResult.SUCCESS || syncResult == SyncResult.PARTIAL_SUCCESS) {
DumbService dumbService = DumbService.getInstance(project);
dumbService.queueTask(new ResourceFolderRegistry.PopulateCachesTask(project));
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncPlugin.java b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncPlugin.java
index 2760980..03d8f1b 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncPlugin.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncPlugin.java
@@ -16,8 +16,8 @@
package com.google.idea.blaze.android.sync;
import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.idea.blaze.android.cppapi.NdkSupport;
import com.google.idea.blaze.android.projectview.AndroidSdkPlatformSection;
@@ -26,15 +26,13 @@
import com.google.idea.blaze.android.sync.model.BlazeAndroidImportResult;
import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
import com.google.idea.blaze.android.sync.projectstructure.BlazeAndroidProjectStructureSyncer;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.model.primitives.WorkspaceType;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
import com.google.idea.blaze.base.projectview.section.SectionParser;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.Scope;
@@ -58,17 +56,13 @@
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.ui.UIUtil;
+import java.util.Collection;
+import java.util.Set;
+import javax.annotation.Nullable;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.sdk.AndroidSdkUtils;
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * ASwB sync plugin.
- */
+/** ASwB sync plugin. */
public class BlazeAndroidSyncPlugin extends BlazeSyncPlugin.Adapter {
@Nullable
@@ -94,8 +88,7 @@
case ANDROID_NDK:
if (NdkSupport.NDK_SUPPORT.getValue()) {
return ImmutableSet.of(LanguageClass.ANDROID, LanguageClass.JAVA, LanguageClass.C);
- }
- else {
+ } else {
return ImmutableSet.of(LanguageClass.ANDROID, LanguageClass.JAVA);
}
default:
@@ -104,43 +97,43 @@
}
@Override
- public void updateSyncState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
+ public void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {
if (!isAndroidWorkspace(workspaceLanguageSettings)) {
return;
}
- AndroidSdkPlatform androidSdkPlatform = AndroidSdkPlatformSyncer.getAndroidSdkPlatform(project, context, androidPlatformDirectory);
- BlazeAndroidWorkspaceImporter workspaceImporter = new BlazeAndroidWorkspaceImporter(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- ruleMap
- );
- BlazeAndroidImportResult importResult = Scope.push(context, (childContext) -> {
- childContext.push(new TimingScope("AndroidWorkspaceImporter"));
- return workspaceImporter.importWorkspace();
- });
+ AndroidSdkPlatform androidSdkPlatform =
+ AndroidSdkPlatformSyncer.getAndroidSdkPlatform(project, context);
+ BlazeAndroidWorkspaceImporter workspaceImporter =
+ new BlazeAndroidWorkspaceImporter(project, context, workspaceRoot, projectViewSet, ruleMap);
+ BlazeAndroidImportResult importResult =
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("AndroidWorkspaceImporter"));
+ return workspaceImporter.importWorkspace();
+ });
BlazeAndroidSyncData syncData = new BlazeAndroidSyncData(importResult, androidSdkPlatform);
syncStateBuilder.put(BlazeAndroidSyncData.class, syncData);
}
@Override
- public void updateSdk(Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
+ public void updateSdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData) {
if (!isAndroidWorkspace(blazeProjectData.workspaceLanguageSettings)) {
return;
}
@@ -154,53 +147,52 @@
}
Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdkPlatform.androidSdk);
if (sdk == null) {
- IssueOutput
- .error(String.format("Android platform '%s' not found.", androidSdkPlatform.androidSdk))
- .submit(context);
+ IssueOutput.error(
+ String.format("Android platform '%s' not found.", androidSdkPlatform.androidSdk))
+ .submit(context);
return;
}
- LanguageLevel javaLanguageLevel = JavaLanguageLevelSection.getLanguageLevel(projectViewSet, LanguageLevel.JDK_1_7);
+ LanguageLevel javaLanguageLevel =
+ JavaLanguageLevelSection.getLanguageLevel(projectViewSet, LanguageLevel.JDK_1_7);
setProjectSdkAndLanguageLevel(project, sdk, javaLanguageLevel);
}
@Override
- public void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel) {
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
BlazeAndroidProjectStructureSyncer.updateProjectStructure(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- blazeProjectData,
- moduleEditor,
- workspaceModule,
- workspaceModifiableModel,
- isAndroidWorkspace(blazeProjectData.workspaceLanguageSettings)
- );
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ blazeProjectData,
+ moduleEditor,
+ workspaceModule,
+ workspaceModifiableModel,
+ isAndroidWorkspace(blazeProjectData.workspaceLanguageSettings));
}
@Override
- public boolean validate(Project project,
- BlazeContext context,
- BlazeProjectData blazeProjectData) {
+ public boolean validate(
+ Project project, BlazeContext context, BlazeProjectData blazeProjectData) {
if (!isAndroidWorkspace(blazeProjectData.workspaceLanguageSettings)) {
return true;
}
-
+
boolean valid = true;
for (Module module : ModuleManager.getInstance(project).getModules()) {
AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet != null && facet.requiresAndroidModel() && facet.getAndroidModel() == null) {
- IssueOutput.error("Android model missing for module: " + module.getName())
- .submit(context);
+ IssueOutput.error("Android model missing for module: " + module.getName()).submit(context);
valid = false;
}
}
@@ -208,70 +200,61 @@
}
@Override
- public boolean validateProjectView(BlazeContext context,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings) {
+ public boolean validateProjectView(
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!isAndroidWorkspace(workspaceLanguageSettings)) {
return true;
}
- if (workspaceLanguageSettings.isWorkspaceType(WorkspaceType.ANDROID_NDK) && !NdkSupport.NDK_SUPPORT.getValue()) {
- IssueOutput
- .error("Android NDK is not supported yet.")
- .submit(context);
+ if (workspaceLanguageSettings.isWorkspaceType(WorkspaceType.ANDROID_NDK)
+ && !NdkSupport.NDK_SUPPORT.getValue()) {
+ IssueOutput.error("Android NDK is not supported yet.").submit(context);
return false;
}
- Collection<ScalarSection<String>> androidSdkPlatformSections =
- projectViewSet.getSections(AndroidSdkPlatformSection.KEY);
- if (androidSdkPlatformSections.isEmpty()) {
- String error = Joiner.on('\n').join(
- "You should specify the android SDK platform in your '.asproject' file.",
- "To set this, first ensure your SDK is up-to-date (go/aswb-sdk)",
- "Then add an 'android_sdk_platform' line to your .asproject file,",
- "e.g. 'android_sdk_platform: \"android-N\"', where 'android-N' is a",
- "platform directory name in your local SDK directory.",
- "",
- "NOTE: This will become an error starting from the next release."
- );
- IssueOutput
- .warn(error)
- .inFile(projectViewSet.getTopLevelProjectViewFile().projectViewFile)
- .submit(context);
+ String androidSdkPlatform = projectViewSet.getScalarValue(AndroidSdkPlatformSection.KEY);
+ if (Strings.isNullOrEmpty(androidSdkPlatform)) {
+ String error =
+ Joiner.on('\n')
+ .join(
+ "No android_sdk_platform set.",
+ "You should specify the android SDK platform in your '.blazeproject' file.",
+ "To set this add an 'android_sdk_platform' line to your .blazeproject file,",
+ "e.g. 'android_sdk_platform: \"android-N\"', where 'android-N' is a",
+ "platform directory name in your local SDK directory.");
+ IssueOutput.error(error)
+ .inFile(projectViewSet.getTopLevelProjectViewFile().projectViewFile)
+ .submit(context);
}
return true;
}
private static void setProjectSdkAndLanguageLevel(
- final Project project,
- final Sdk sdk,
- final LanguageLevel javaLanguageLevel) {
- UIUtil.invokeAndWaitIfNeeded((Runnable)() -> ApplicationManager.getApplication().runWriteAction(() -> {
- ProjectRootManagerEx rootManager = ProjectRootManagerEx.getInstanceEx(project);
- rootManager.setProjectSdk(sdk);
- LanguageLevelProjectExtension ext = LanguageLevelProjectExtension.getInstance(project);
- ext.setLanguageLevel(javaLanguageLevel);
- }));
+ final Project project, final Sdk sdk, final LanguageLevel javaLanguageLevel) {
+ UIUtil.invokeAndWaitIfNeeded(
+ (Runnable)
+ () ->
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ ProjectRootManagerEx rootManager =
+ ProjectRootManagerEx.getInstanceEx(project);
+ rootManager.setProjectSdk(sdk);
+ LanguageLevelProjectExtension ext =
+ LanguageLevelProjectExtension.getInstance(project);
+ ext.setLanguageLevel(javaLanguageLevel);
+ }));
}
@Override
public Collection<SectionParser> getSections() {
- return ImmutableList.of(
- AndroidSdkPlatformSection.PARSER
- );
- }
-
- @Override
- public boolean requiresAndroidSdk(WorkspaceLanguageSettings workspaceLanguageSettings) {
- return isAndroidWorkspace(workspaceLanguageSettings);
+ return ImmutableList.of(AndroidSdkPlatformSection.PARSER);
}
private static boolean isAndroidWorkspace(WorkspaceLanguageSettings workspaceLanguageSettings) {
- return workspaceLanguageSettings.isWorkspaceType(WorkspaceType.ANDROID, WorkspaceType.ANDROID_NDK);
- }
-
- @Override
- public Set<String> prefetchSrcFileExtensions() {
- return ImmutableSet.of("xml");
+ return workspaceLanguageSettings.isWorkspaceType(
+ WorkspaceType.ANDROID, WorkspaceType.ANDROID_NDK);
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporter.java b/aswb/src/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporter.java
index c67da3c..0439e9b 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporter.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporter.java
@@ -15,16 +15,20 @@
*/
package com.google.idea.blaze.android.sync.importer;
-import com.google.common.collect.*;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
import com.google.idea.blaze.android.sync.importer.aggregators.TransitiveResourceMap;
import com.google.idea.blaze.android.sync.model.AndroidResourceModule;
import com.google.idea.blaze.android.sync.model.BlazeAndroidImportResult;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
+import com.google.idea.blaze.android.sync.model.BlazeResourceLibrary;
import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
@@ -33,13 +37,8 @@
import com.google.idea.blaze.base.scope.output.IssueOutput;
import com.google.idea.blaze.base.scope.output.PerformanceWarning;
import com.google.idea.blaze.base.sync.projectview.ProjectViewRuleImportFilter;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
import java.io.File;
import java.util.Collection;
import java.util.Collections;
@@ -47,130 +46,123 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
-/**
- * Builds a BlazeWorkspace.
- */
+/** Builds a BlazeWorkspace. */
public final class BlazeAndroidWorkspaceImporter {
private static final Logger LOG = Logger.getInstance(BlazeAndroidWorkspaceImporter.class);
- private static final BoolExperiment DISCARD_ANDROID_BINARY_RESOURCE_JAR = new BoolExperiment("discard.android.binary.resource.jar", true);
private final Project project;
private final BlazeContext context;
private final WorkspaceRoot workspaceRoot;
- private final ImmutableMap<Label, RuleIdeInfo> ruleMap;
+ private final RuleMap ruleMap;
private final ProjectViewRuleImportFilter importFilter;
- private final boolean discardAndroidBinaryResourceJar;
public BlazeAndroidWorkspaceImporter(
- Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- ImmutableMap<Label, RuleIdeInfo> ruleMap) {
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ RuleMap ruleMap) {
this.project = project;
this.context = context;
this.workspaceRoot = workspaceRoot;
this.ruleMap = ruleMap;
this.importFilter = new ProjectViewRuleImportFilter(project, workspaceRoot, projectViewSet);
- this.discardAndroidBinaryResourceJar = DISCARD_ANDROID_BINARY_RESOURCE_JAR.getValue();
}
public BlazeAndroidImportResult importWorkspace() {
- List<RuleIdeInfo> rules = ruleMap.values()
- .stream()
- .filter(rule -> rule.kind.getLanguageClass() == LanguageClass.ANDROID)
- .filter(importFilter::isSourceRule)
- .filter(rule -> !importFilter.excludeTarget(rule))
- .collect(Collectors.toList());
+ List<RuleIdeInfo> rules =
+ ruleMap
+ .rules()
+ .stream()
+ .filter(rule -> rule.kind.getLanguageClass() == LanguageClass.ANDROID)
+ .filter(rule -> rule.androidRuleIdeInfo != null)
+ .filter(importFilter::isSourceRule)
+ .filter(rule -> !importFilter.excludeTarget(rule))
+ .collect(Collectors.toList());
TransitiveResourceMap transitiveResourceMap = new TransitiveResourceMap(ruleMap);
WorkspaceBuilder workspaceBuilder = new WorkspaceBuilder();
for (RuleIdeInfo rule : rules) {
- addRule(
- workspaceBuilder,
- transitiveResourceMap,
- rule
- );
+ addSourceRule(workspaceBuilder, transitiveResourceMap, rule);
}
- ImmutableList<AndroidResourceModule> androidResourceModules = buildAndroidResourceModules(workspaceBuilder);
- BlazeLibrary resourceLibrary = createResourceLibrary(androidResourceModules);
- if (resourceLibrary != null) {
- workspaceBuilder.libraries.add(resourceLibrary);
- }
+ warnAboutGeneratedResources(workspaceBuilder.generatedResourceLocations);
- return new BlazeAndroidImportResult(
- androidResourceModules,
- workspaceBuilder.libraries.build()
- );
+ ImmutableList<AndroidResourceModule> androidResourceModules =
+ buildAndroidResourceModules(workspaceBuilder);
+ BlazeResourceLibrary resourceLibrary = createResourceLibrary(androidResourceModules);
+
+ return new BlazeAndroidImportResult(androidResourceModules, resourceLibrary);
}
- private void addRule(
- WorkspaceBuilder workspaceBuilder,
- TransitiveResourceMap transitiveResourceMap,
- RuleIdeInfo rule) {
-
+ private void addSourceRule(
+ WorkspaceBuilder workspaceBuilder,
+ TransitiveResourceMap transitiveResourceMap,
+ RuleIdeInfo rule) {
AndroidRuleIdeInfo androidRuleIdeInfo = rule.androidRuleIdeInfo;
- if (androidRuleIdeInfo != null) {
- // Generate an android resource module if this rule defines resources
- // We don't want to generate one if this depends on a legacy resource rule through :resources
- // In this case, the resource information is redundantly forwarded to this class for
- // backwards compatibility, but the android_resource rule itself is already generating
- // the android resource module
- if (androidRuleIdeInfo.generateResourceClass && androidRuleIdeInfo.legacyResources == null) {
- List<ArtifactLocation> nonGeneratedResources = Lists.newArrayList();
- for (ArtifactLocation artifactLocation : androidRuleIdeInfo.resources) {
- if (!artifactLocation.isGenerated()) {
- nonGeneratedResources.add(artifactLocation);
- }
- }
+ assert androidRuleIdeInfo != null;
+ if (shouldGenerateResources(androidRuleIdeInfo)
+ && shouldGenerateResourceModule(androidRuleIdeInfo)) {
+ AndroidResourceModule.Builder builder = new AndroidResourceModule.Builder(rule.label);
+ workspaceBuilder.androidResourceModules.add(builder);
- // Only create a resource module if there are any non-generated resources
- // Empty R classes or ones with only generated sources are added as jars
- if (!nonGeneratedResources.isEmpty()) {
- AndroidResourceModule.Builder builder = new AndroidResourceModule.Builder(rule.label);
- workspaceBuilder.androidResourceModules.add(builder);
-
- builder.addAllResources(nonGeneratedResources);
-
- TransitiveResourceMap.TransitiveResourceInfo transitiveResourceInfo = transitiveResourceMap.get(rule.label);
- for (ArtifactLocation artifactLocation : transitiveResourceInfo.transitiveResources) {
- if (!artifactLocation.isGenerated()) {
- builder.addTransitiveResource(artifactLocation);
- }
- }
- for (Label resourceDependency : transitiveResourceInfo.transitiveResourceRules) {
- if (!resourceDependency.equals(rule.label)) {
- builder.addTransitiveResourceDependency(resourceDependency);
- }
- }
+ for (ArtifactLocation artifactLocation : androidRuleIdeInfo.resources) {
+ if (artifactLocation.isSource()) {
+ builder.addResource(artifactLocation);
} else {
- // Add blaze's output unless it's a top level rule. In these cases the resource jar contains the entire
- // transitive closure of R classes. It's unlikely this is wanted to resolve in the IDE.
- boolean discardResourceJar = discardAndroidBinaryResourceJar && rule.kindIsOneOf(Kind.ANDROID_BINARY, Kind.ANDROID_TEST);
- if (!discardResourceJar) {
- LibraryArtifact resourceJar = androidRuleIdeInfo.resourceJar;
- if (resourceJar != null) {
- BlazeLibrary library = new BlazeLibrary(LibraryKey.fromJarFile(resourceJar.jar.getFile()), resourceJar);
- workspaceBuilder.libraries.add(library);
- }
- }
+ workspaceBuilder.generatedResourceLocations.add(artifactLocation);
}
}
- LibraryArtifact idlJar = androidRuleIdeInfo.idlJar;
- if (idlJar != null) {
- BlazeLibrary library = new BlazeLibrary(LibraryKey.fromJarFile(idlJar.jar.getFile()), idlJar);
- workspaceBuilder.libraries.add(library);
+ TransitiveResourceMap.TransitiveResourceInfo transitiveResourceInfo =
+ transitiveResourceMap.get(rule.label);
+ for (ArtifactLocation artifactLocation : transitiveResourceInfo.transitiveResources) {
+ if (artifactLocation.isSource()) {
+ builder.addTransitiveResource(artifactLocation);
+ } else {
+ workspaceBuilder.generatedResourceLocations.add(artifactLocation);
+ }
}
+ for (Label resourceDependency : transitiveResourceInfo.transitiveResourceRules) {
+ if (!resourceDependency.equals(rule.label)) {
+ builder.addTransitiveResourceDependency(resourceDependency);
+ }
+ }
+ }
+ }
+
+ public static boolean shouldGenerateResources(AndroidRuleIdeInfo androidRuleIdeInfo) {
+ // Generate an android resource module if this rule defines resources
+ // We don't want to generate one if this depends on a legacy resource rule through :resources
+ // In this case, the resource information is redundantly forwarded to this class for
+ // backwards compatibility, but the android_resource rule itself is already generating
+ // the android resource module
+ return androidRuleIdeInfo.generateResourceClass && androidRuleIdeInfo.legacyResources == null;
+ }
+
+ public static boolean shouldGenerateResourceModule(AndroidRuleIdeInfo androidRuleIdeInfo) {
+ return androidRuleIdeInfo.resources.stream().anyMatch(ArtifactLocation::isSource);
+ }
+
+ private void warnAboutGeneratedResources(Set<ArtifactLocation> generatedResourceLocations) {
+ for (ArtifactLocation artifactLocation : generatedResourceLocations) {
+ IssueOutput.warn(
+ String.format(
+ "Dropping generated resource directory '%s', "
+ + "R classes will not contain resources from this directory",
+ artifactLocation.getExecutionRootRelativePath()))
+ .submit(context);
}
}
@Nullable
- private BlazeLibrary createResourceLibrary(Collection<AndroidResourceModule> androidResourceModules) {
+ private BlazeResourceLibrary createResourceLibrary(
+ Collection<AndroidResourceModule> androidResourceModules) {
Set<File> result = Sets.newHashSet();
for (AndroidResourceModule androidResourceModule : androidResourceModules) {
result.addAll(androidResourceModule.transitiveResources);
@@ -179,50 +171,57 @@
result.removeAll(androidResourceModule.resources);
}
if (!result.isEmpty()) {
- return new BlazeLibrary(LibraryKey.forResourceLibrary(),
- ImmutableList.copyOf(result.stream().sorted().collect(Collectors.toList())));
+ return new BlazeResourceLibrary(
+ ImmutableList.copyOf(result.stream().sorted().collect(Collectors.toList())));
}
return null;
}
@NotNull
- private ImmutableList<AndroidResourceModule> buildAndroidResourceModules(WorkspaceBuilder workspaceBuilder) {
+ private ImmutableList<AndroidResourceModule> buildAndroidResourceModules(
+ WorkspaceBuilder workspaceBuilder) {
// Filter empty resource modules
- Stream<AndroidResourceModule> androidResourceModuleStream = workspaceBuilder.androidResourceModules
- .stream()
- .map(AndroidResourceModule.Builder::build)
- .filter(androidResourceModule -> !androidResourceModule.isEmpty())
- .filter(androidResourceModule -> !androidResourceModule.resources.isEmpty());
- List<AndroidResourceModule> androidResourceModules = androidResourceModuleStream.collect(Collectors.toList());
+ Stream<AndroidResourceModule> androidResourceModuleStream =
+ workspaceBuilder
+ .androidResourceModules
+ .stream()
+ .map(AndroidResourceModule.Builder::build)
+ .filter(androidResourceModule -> !androidResourceModule.isEmpty())
+ .filter(androidResourceModule -> !androidResourceModule.resources.isEmpty());
+ List<AndroidResourceModule> androidResourceModules =
+ androidResourceModuleStream.collect(Collectors.toList());
// Detect, filter, and warn about multiple R classes
- Multimap<String, AndroidResourceModule> javaPackageToResourceModule = ArrayListMultimap.create();
+ Multimap<String, AndroidResourceModule> javaPackageToResourceModule =
+ ArrayListMultimap.create();
for (AndroidResourceModule androidResourceModule : androidResourceModules) {
RuleIdeInfo rule = ruleMap.get(androidResourceModule.label);
AndroidRuleIdeInfo androidRuleIdeInfo = rule.androidRuleIdeInfo;
assert androidRuleIdeInfo != null;
- javaPackageToResourceModule.put(androidRuleIdeInfo.resourceJavaPackage, androidResourceModule);
+ javaPackageToResourceModule.put(
+ androidRuleIdeInfo.resourceJavaPackage, androidResourceModule);
}
List<AndroidResourceModule> result = Lists.newArrayList();
for (String resourceJavaPackage : javaPackageToResourceModule.keySet()) {
- Collection<AndroidResourceModule> androidResourceModulesWithJavaPackage = javaPackageToResourceModule.get(resourceJavaPackage);
+ Collection<AndroidResourceModule> androidResourceModulesWithJavaPackage =
+ javaPackageToResourceModule.get(resourceJavaPackage);
if (androidResourceModulesWithJavaPackage.size() == 1) {
result.addAll(androidResourceModulesWithJavaPackage);
- }
- else {
+ } else {
StringBuilder messageBuilder = new StringBuilder();
- messageBuilder.append("Multiple R classes generated with the same java package ").append(resourceJavaPackage).append(".R: ");
+ messageBuilder
+ .append("Multiple R classes generated with the same java package ")
+ .append(resourceJavaPackage)
+ .append(".R: ");
messageBuilder.append('\n');
for (AndroidResourceModule androidResourceModule : androidResourceModulesWithJavaPackage) {
messageBuilder.append(" ").append(androidResourceModule.label).append('\n');
}
String message = messageBuilder.toString();
context.output(new PerformanceWarning(message));
- IssueOutput
- .warn(message)
- .submit(context);
+ IssueOutput.warn(message).submit(context);
result.add(selectBestAndroidResourceModule(androidResourceModulesWithJavaPackage));
}
@@ -232,19 +231,28 @@
return ImmutableList.copyOf(result);
}
- private AndroidResourceModule selectBestAndroidResourceModule(Collection<AndroidResourceModule> androidResourceModulesWithJavaPackage) {
+ private AndroidResourceModule selectBestAndroidResourceModule(
+ Collection<AndroidResourceModule> androidResourceModulesWithJavaPackage) {
return androidResourceModulesWithJavaPackage
- .stream()
- .max((lhs, rhs) -> ComparisonChain.start()
- .compare(lhs.resources.size(), rhs.resources.size()) // Most resources wins
- .compare(lhs.transitiveResources.size(), rhs.transitiveResources.size()) // Most transitive resources wins
- .compare(rhs.label.toString().length(), lhs.label.toString().length()) // Shortest label wins - note lhs, rhs are flipped
- .result())
- .get();
+ .stream()
+ .max(
+ (lhs, rhs) ->
+ ComparisonChain.start()
+ .compare(lhs.resources.size(), rhs.resources.size()) // Most resources wins
+ .compare(
+ lhs.transitiveResources.size(),
+ rhs.transitiveResources.size()) // Most transitive resources wins
+ .compare(
+ rhs.label.toString().length(),
+ lhs.label
+ .toString()
+ .length()) // Shortest label wins - note lhs, rhs are flipped
+ .result())
+ .get();
}
static class WorkspaceBuilder {
List<AndroidResourceModule.Builder> androidResourceModules = Lists.newArrayList();
- ImmutableList.Builder<BlazeLibrary> libraries = ImmutableList.builder();
+ Set<ArtifactLocation> generatedResourceLocations = Sets.newHashSet();
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/RuleIdeInfoTransitiveAggregator.java b/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/RuleIdeInfoTransitiveAggregator.java
index fd2d4d5..3a7b95c 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/RuleIdeInfoTransitiveAggregator.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/RuleIdeInfoTransitiveAggregator.java
@@ -15,21 +15,18 @@
*/
package com.google.idea.blaze.android.sync.importer.aggregators;
-import com.google.common.collect.ImmutableMap;
import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.NotNull;
-/**
- * Transitive aggregator for RuleIdeInfo.
- */
-public abstract class RuleIdeInfoTransitiveAggregator<T> extends TransitiveAggregator<RuleIdeInfo, T> {
- protected RuleIdeInfoTransitiveAggregator(@NotNull ImmutableMap<Label, RuleIdeInfo> ruleMap) {
+/** Transitive aggregator for RuleIdeInfo. */
+public abstract class RuleIdeInfoTransitiveAggregator<T> extends TransitiveAggregator<T> {
+ protected RuleIdeInfoTransitiveAggregator(RuleMap ruleMap) {
super(ruleMap);
}
@Override
- protected Iterable<Label> getDependencies(@NotNull RuleIdeInfo ruleIdeInfo) {
+ protected Iterable<Label> getDependencies(RuleIdeInfo ruleIdeInfo) {
return ruleIdeInfo.dependencies;
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveAggregator.java b/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveAggregator.java
index 526a6b7..5048910 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveAggregator.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveAggregator.java
@@ -16,41 +16,37 @@
package com.google.idea.blaze.android.sync.importer.aggregators;
import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.NotNull;
+import java.util.Map;
import org.jetbrains.annotations.Nullable;
-import java.util.Map;
-
-/**
- * Peforms a transitive reduction on the rule
- */
-public abstract class TransitiveAggregator<Rule, T> {
+/** Peforms a transitive reduction on the rule */
+public abstract class TransitiveAggregator<T> {
private Map<Label, T> labelToResult;
- protected TransitiveAggregator(@NotNull Map<Label, Rule> ruleMap) {
+ protected TransitiveAggregator(RuleMap ruleMap) {
this.labelToResult = Maps.newHashMap();
- for (Label label : ruleMap.keySet()) {
+ for (RuleIdeInfo rule : ruleMap.rules()) {
+ Label label = rule.label;
aggregate(label, ruleMap);
}
}
- @NotNull
- protected T getOrDefault(@NotNull Label key, @NotNull T defaultValue) {
+ protected T getOrDefault(Label key, T defaultValue) {
T result = labelToResult.get(key);
return result != null ? result : defaultValue;
}
@Nullable
- private T aggregate(
- @NotNull Label label,
- @NotNull Map<Label, Rule> ruleMap) {
+ private T aggregate(Label label, RuleMap ruleMap) {
T result = labelToResult.get(label);
if (result != null) {
return result;
}
- Rule rule = ruleMap.get(label);
+ RuleIdeInfo rule = ruleMap.get(label);
if (rule == null) {
return null;
}
@@ -68,17 +64,11 @@
return result;
}
- protected abstract Iterable<Label> getDependencies(@NotNull Rule rule);
+ protected abstract Iterable<Label> getDependencies(RuleIdeInfo rule);
- /**
- * Creates the initial value for a given rule.
- */
- @NotNull
- protected abstract T createForRule(@NotNull Rule rule);
+ /** Creates the initial value for a given rule. */
+ protected abstract T createForRule(RuleIdeInfo rule);
- /**
- * Reduces two values, sum + new value. May mutate value in place.
- */
- @NotNull
- protected abstract T reduce(@NotNull T value, @NotNull T dependencyValue);
+ /** Reduces two values, sum + new value. May mutate value in place. */
+ protected abstract T reduce(T value, T dependencyValue);
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveResourceMap.java b/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveResourceMap.java
index 9bdd852..f49029d 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveResourceMap.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/importer/aggregators/TransitiveResourceMap.java
@@ -15,34 +15,32 @@
*/
package com.google.idea.blaze.android.sync.importer.aggregators;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.NotNull;
-
import java.util.List;
import java.util.Set;
-/**
- * Computes transitive resources.
- */
-public class TransitiveResourceMap extends RuleIdeInfoTransitiveAggregator<TransitiveResourceMap.TransitiveResourceInfo> {
+/** Computes transitive resources. */
+public class TransitiveResourceMap
+ extends RuleIdeInfoTransitiveAggregator<TransitiveResourceMap.TransitiveResourceInfo> {
+ /** The transitive info computed per-rule */
public static class TransitiveResourceInfo {
public static final TransitiveResourceInfo NO_RESOURCES = new TransitiveResourceInfo();
public final Set<ArtifactLocation> transitiveResources = Sets.newHashSet();
public final Set<Label> transitiveResourceRules = Sets.newHashSet();
}
- public TransitiveResourceMap(@NotNull ImmutableMap<Label, RuleIdeInfo> ruleMap) {
+ public TransitiveResourceMap(RuleMap ruleMap) {
super(ruleMap);
}
@Override
- protected Iterable<Label> getDependencies(@NotNull RuleIdeInfo ruleIdeInfo) {
+ protected Iterable<Label> getDependencies(RuleIdeInfo ruleIdeInfo) {
AndroidRuleIdeInfo androidRuleIdeInfo = ruleIdeInfo.androidRuleIdeInfo;
if (androidRuleIdeInfo != null && androidRuleIdeInfo.legacyResources != null) {
List<Label> result = Lists.newArrayList(super.getDependencies(ruleIdeInfo));
@@ -52,14 +50,12 @@
return super.getDependencies(ruleIdeInfo);
}
- @NotNull
- public TransitiveResourceInfo get(@NotNull Label label) {
+ public TransitiveResourceInfo get(Label label) {
return getOrDefault(label, TransitiveResourceInfo.NO_RESOURCES);
}
- @NotNull
@Override
- protected TransitiveResourceInfo createForRule(@NotNull RuleIdeInfo ruleIdeInfo) {
+ protected TransitiveResourceInfo createForRule(RuleIdeInfo ruleIdeInfo) {
TransitiveResourceInfo result = new TransitiveResourceInfo();
AndroidRuleIdeInfo androidRuleIdeInfo = ruleIdeInfo.androidRuleIdeInfo;
if (androidRuleIdeInfo == null) {
@@ -73,9 +69,9 @@
return result;
}
- @NotNull
@Override
- protected TransitiveResourceInfo reduce(@NotNull TransitiveResourceInfo value, @NotNull TransitiveResourceInfo dependencyValue) {
+ protected TransitiveResourceInfo reduce(
+ TransitiveResourceInfo value, TransitiveResourceInfo dependencyValue) {
value.transitiveResources.addAll(dependencyValue.transitiveResources);
value.transitiveResourceRules.addAll(dependencyValue.transitiveResourceRules);
return value;
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/AndroidResourceModule.java b/aswb/src/com/google/idea/blaze/android/sync/model/AndroidResourceModule.java
index e8c61ff..e4807a9 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/AndroidResourceModule.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/AndroidResourceModule.java
@@ -21,15 +21,18 @@
import com.google.common.collect.Sets;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.concurrent.Immutable;
import java.io.File;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.annotation.concurrent.Immutable;
+import org.jetbrains.annotations.NotNull;
+/**
+ * An android resource module. Maps from an android_library's resources to an Android Studio
+ * module/facet.
+ */
@Immutable
public final class AndroidResourceModule implements Serializable {
private static final long serialVersionUID = 5L;
@@ -39,10 +42,11 @@
public final ImmutableCollection<File> transitiveResources;
public final ImmutableCollection<Label> transitiveResourceDependencies;
- public AndroidResourceModule(Label label,
- ImmutableCollection<File> resources,
- ImmutableCollection<File> transitiveResources,
- ImmutableCollection<Label> transitiveResourceDependencies) {
+ public AndroidResourceModule(
+ Label label,
+ ImmutableCollection<File> resources,
+ ImmutableCollection<File> transitiveResources,
+ ImmutableCollection<Label> transitiveResourceDependencies) {
this.label = label;
this.resources = resources;
this.transitiveResources = transitiveResources;
@@ -52,11 +56,12 @@
@Override
public boolean equals(Object o) {
if (o instanceof AndroidResourceModule) {
- AndroidResourceModule that = (AndroidResourceModule)o;
+ AndroidResourceModule that = (AndroidResourceModule) o;
return Objects.equal(this.label, that.label)
- && Objects.equal(this.resources, that.resources)
- && Objects.equal(this.transitiveResources, that.transitiveResources)
- && Objects.equal(this.transitiveResourceDependencies, that.transitiveResourceDependencies);
+ && Objects.equal(this.resources, that.resources)
+ && Objects.equal(this.transitiveResources, that.transitiveResources)
+ && Objects.equal(
+ this.transitiveResourceDependencies, that.transitiveResourceDependencies);
}
return false;
}
@@ -64,21 +69,26 @@
@Override
public int hashCode() {
return Objects.hashCode(
- this.label,
- this.resources,
- this.transitiveResources,
- this.transitiveResourceDependencies
- );
+ this.label, this.resources, this.transitiveResources, this.transitiveResourceDependencies);
}
@Override
public String toString() {
- return "AndroidResourceModule{" + "\n"
- + " label: " + label + "\n"
- + " resources: " + resources + "\n"
- + " transitiveResources: " + transitiveResources + "\n"
- + " transitiveResourceDependencies: " + transitiveResourceDependencies + "\n"
- + '}';
+ return "AndroidResourceModule{"
+ + "\n"
+ + " label: "
+ + label
+ + "\n"
+ + " resources: "
+ + resources
+ + "\n"
+ + " transitiveResources: "
+ + transitiveResources
+ + "\n"
+ + " transitiveResourceDependencies: "
+ + transitiveResourceDependencies
+ + "\n"
+ + '}';
}
public static Builder builder(Label label) {
@@ -89,6 +99,7 @@
return resources.isEmpty() && transitiveResources.isEmpty();
}
+ /** Builder for the resource module */
public static class Builder {
private final Label label;
private final Set<ArtifactLocation> resources = Sets.newHashSet();
@@ -132,25 +143,21 @@
@NotNull
public AndroidResourceModule build() {
return new AndroidResourceModule(
- label,
- ImmutableList.copyOf(
- resources
- .stream()
- .map(ArtifactLocation::getFile)
- .sorted()
- .collect(Collectors.toList())),
- ImmutableList.copyOf(
- transitiveResources
- .stream()
- .map(ArtifactLocation::getFile)
- .sorted()
- .collect(Collectors.toList())),
- ImmutableList.copyOf(
- transitiveResourceDependencies
- .stream()
- .sorted()
- .collect(Collectors.toList()))
- );
+ label,
+ ImmutableList.copyOf(
+ resources
+ .stream()
+ .map(ArtifactLocation::getFile)
+ .sorted()
+ .collect(Collectors.toList())),
+ ImmutableList.copyOf(
+ transitiveResources
+ .stream()
+ .map(ArtifactLocation::getFile)
+ .sorted()
+ .collect(Collectors.toList())),
+ ImmutableList.copyOf(
+ transitiveResourceDependencies.stream().sorted().collect(Collectors.toList())));
}
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/AndroidSdkPlatform.java b/aswb/src/com/google/idea/blaze/android/sync/model/AndroidSdkPlatform.java
index f38c80d..644d749 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/AndroidSdkPlatform.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/AndroidSdkPlatform.java
@@ -15,12 +15,10 @@
*/
package com.google.idea.blaze.android.sync.model;
-import javax.annotation.concurrent.Immutable;
import java.io.Serializable;
+import javax.annotation.concurrent.Immutable;
-/**
- * Information about the android platform selected at sync time.
- */
+/** Information about the android platform selected at sync time. */
@Immutable
public class AndroidSdkPlatform implements Serializable {
public final String androidSdk;
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidImportResult.java b/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidImportResult.java
index e134399..b4750a2 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidImportResult.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidImportResult.java
@@ -16,25 +16,22 @@
package com.google.idea.blaze.android.sync.model;
import com.google.common.collect.ImmutableCollection;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-
-import javax.annotation.concurrent.Immutable;
import java.io.Serializable;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
-/**
- * The result of a blaze import operation.
- */
+/** The result of a blaze import operation. */
@Immutable
public class BlazeAndroidImportResult implements Serializable {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 3L;
public final ImmutableCollection<AndroidResourceModule> androidResourceModules;
- public final ImmutableCollection<BlazeLibrary> libraries;
+ @Nullable public final BlazeResourceLibrary resourceLibrary;
public BlazeAndroidImportResult(
- ImmutableCollection<AndroidResourceModule> androidResourceModules,
- ImmutableCollection<BlazeLibrary> libraries) {
+ ImmutableCollection<AndroidResourceModule> androidResourceModules,
+ @Nullable BlazeResourceLibrary resourceLibrary) {
this.androidResourceModules = androidResourceModules;
- this.libraries = libraries;
+ this.resourceLibrary = resourceLibrary;
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidSyncData.java b/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidSyncData.java
index c0f529b..6881b71 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidSyncData.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/BlazeAndroidSyncData.java
@@ -15,13 +15,11 @@
*/
package com.google.idea.blaze.android.sync.model;
+import java.io.Serializable;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
-import java.io.Serializable;
-/**
- * Sync data for the Android plugin.
- */
+/** Sync data for the Android plugin. */
@Immutable
public class BlazeAndroidSyncData implements Serializable {
private static final long serialVersionUID = 1L;
@@ -29,8 +27,8 @@
public final BlazeAndroidImportResult importResult;
@Nullable public final AndroidSdkPlatform androidSdkPlatform;
- public BlazeAndroidSyncData(BlazeAndroidImportResult importResult,
- @Nullable AndroidSdkPlatform androidSdkPlatform) {
+ public BlazeAndroidSyncData(
+ BlazeAndroidImportResult importResult, @Nullable AndroidSdkPlatform androidSdkPlatform) {
this.importResult = importResult;
this.androidSdkPlatform = androidSdkPlatform;
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/BlazeResourceLibrary.java b/aswb/src/com/google/idea/blaze/android/sync/model/BlazeResourceLibrary.java
new file mode 100644
index 0000000..240424e
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/BlazeResourceLibrary.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.sync.model;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.libraries.Library;
+import java.io.File;
+import javax.annotation.concurrent.Immutable;
+
+/** A library that contains sources. */
+@Immutable
+public final class BlazeResourceLibrary extends BlazeLibrary {
+ private static final long serialVersionUID = 1L;
+
+ public final ImmutableList<File> sources;
+
+ public BlazeResourceLibrary(ImmutableList<File> sources) {
+ super(LibraryKey.forResourceLibrary());
+ this.sources = sources;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), sources);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof BlazeResourceLibrary)) {
+ return false;
+ }
+
+ BlazeResourceLibrary that = (BlazeResourceLibrary) other;
+
+ return super.equals(other) && Objects.equal(sources, that.sources);
+ }
+
+ @Override
+ public void modifyLibraryModel(Project project, Library.ModifiableModel libraryModel) {
+ for (File file : sources) {
+ libraryModel.addRoot(pathToUrl(file), OrderRootType.SOURCES);
+ }
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeAndroidModel.java b/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeAndroidModel.java
index 48b4dcc..7a13e1e 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeAndroidModel.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeAndroidModel.java
@@ -27,13 +27,12 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.android.dom.manifest.Manifest;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
import java.io.File;
import java.util.List;
import java.util.Set;
+import org.jetbrains.android.dom.manifest.Manifest;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* Contains Android-Blaze related state necessary for configuring an IDEA project based on a
@@ -51,17 +50,15 @@
private final String resourceJavaPackage;
private final int androidSdkApiLevel;
- /**
- * Creates a new {@link BlazeAndroidModel}.
- */
+ /** Creates a new {@link BlazeAndroidModel}. */
public BlazeAndroidModel(
- Project project,
- Module module,
- File rootDirPath,
- SourceProvider sourceProvider,
- File moduleManifest,
- String resourceJavaPackage,
- int androidSdkApiLevel) {
+ Project project,
+ Module module,
+ File rootDirPath,
+ SourceProvider sourceProvider,
+ File moduleManifest,
+ String resourceJavaPackage,
+ int androidSdkApiLevel) {
this.project = project;
this.module = module;
this.rootDirPath = rootDirPath;
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java b/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
index 7719c95..f6372ed 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
@@ -21,32 +21,32 @@
import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.OrderedSet;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
import java.io.File;
import java.util.List;
+import org.jetbrains.annotations.Nullable;
+/** Collects class jars from the user's build. */
public class BlazeClassJarProvider extends ClassJarProvider {
- private @NotNull final Project project;
+ private final Project project;
- public BlazeClassJarProvider(@NotNull final Project project){
+ public BlazeClassJarProvider(final Project project) {
this.project = project;
}
@Override
@Nullable
- public VirtualFile findModuleClassFile(@NotNull String className, @NotNull Module module) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ public VirtualFile findModuleClassFile(String className, Module module) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
if (blazeProjectData == null) {
return null;
}
@@ -56,12 +56,12 @@
if (syncData == null) {
return null;
}
- for (File runtimeJar : syncData.importResult.buildOutputJars) {
- VirtualFile runtimeJarVF = localVfs.findFileByIoFile(runtimeJar);
- if (runtimeJarVF == null) {
+ for (File classJar : syncData.importResult.buildOutputJars) {
+ VirtualFile classJarVF = localVfs.findFileByIoFile(classJar);
+ if (classJarVF == null) {
continue;
}
- VirtualFile classFile = findClassInJar(runtimeJarVF, classNamePath);
+ VirtualFile classFile = findClassInJar(classJarVF, classNamePath);
if (classFile != null) {
return classFile;
}
@@ -70,9 +70,8 @@
}
@Nullable
- private static VirtualFile findClassInJar(@NotNull final VirtualFile runtimeJar,
- @NotNull String classNamePath) {
- VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(runtimeJar);
+ private static VirtualFile findClassInJar(final VirtualFile classJar, String classNamePath) {
+ VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(classJar);
if (jarRoot == null) {
return null;
}
@@ -80,10 +79,10 @@
}
@Override
- @NotNull
- public List<VirtualFile> getModuleExternalLibraries(@NotNull Module module) {
+ public List<VirtualFile> getModuleExternalLibraries(Module module) {
OrderedSet<VirtualFile> results = new OrderedSet<VirtualFile>();
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
if (blazeProjectData == null) {
return results;
}
@@ -92,16 +91,13 @@
return null;
}
LocalFileSystem localVfs = LocalFileSystem.getInstance();
- for (BlazeLibrary blazeLibrary : syncData.importResult.libraries.values()) {
- LibraryArtifact libraryArtifact = blazeLibrary.getLibraryArtifact();
- if (libraryArtifact == null) {
+ for (BlazeJarLibrary blazeLibrary : syncData.importResult.libraries.values()) {
+ LibraryArtifact libraryArtifact = blazeLibrary.libraryArtifact;
+ ArtifactLocation classJar = libraryArtifact.classJar;
+ if (classJar == null) {
continue;
}
- ArtifactLocation runtimeJar = libraryArtifact.runtimeJar;
- if (runtimeJar == null) {
- continue;
- }
- VirtualFile libVF = localVfs.findFileByIoFile(runtimeJar.getFile());
+ VirtualFile libVF = localVfs.findFileByIoFile(classJar.getFile());
if (libVF == null) {
continue;
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/idea/NullClassJarProvider.java b/aswb/src/com/google/idea/blaze/android/sync/model/idea/NullClassJarProvider.java
index 969428f..037f4fa 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/idea/NullClassJarProvider.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/idea/NullClassJarProvider.java
@@ -19,15 +19,11 @@
import com.google.common.collect.ImmutableList;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.VirtualFile;
+import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-
-/**
- * Returns no class jars. Used to disable the layout editor
- * loading jars.
- */
+/** Returns no class jars. Used to disable the layout editor loading jars. */
public class NullClassJarProvider extends ClassJarProvider {
@Nullable
@Override
diff --git a/aswb/src/com/google/idea/blaze/android/sync/model/idea/SourceProviderImpl.java b/aswb/src/com/google/idea/blaze/android/sync/model/idea/SourceProviderImpl.java
index 427f0fa..2bf8e82 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/model/idea/SourceProviderImpl.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/model/idea/SourceProviderImpl.java
@@ -18,8 +18,6 @@
import com.android.builder.model.SourceProvider;
import com.google.common.collect.ImmutableList;
-import com.intellij.openapi.diagnostic.Logger;
-
import java.io.File;
import java.io.Serializable;
import java.util.Collection;
@@ -36,9 +34,7 @@
private final File manifestFile;
private final Collection<File> resDirs;
- public SourceProviderImpl(String name,
- File manifestFile,
- Collection<File> resDirs) {
+ public SourceProviderImpl(String name, File manifestFile, Collection<File> resDirs) {
this.name = name;
this.manifestFile = manifestFile;
this.resDirs = resDirs;
diff --git a/aswb/src/com/google/idea/blaze/android/sync/projectstructure/AndroidFacetModuleCustomizer.java b/aswb/src/com/google/idea/blaze/android/sync/projectstructure/AndroidFacetModuleCustomizer.java
index bae295d..62a06a2 100755
--- a/aswb/src/com/google/idea/blaze/android/sync/projectstructure/AndroidFacetModuleCustomizer.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/projectstructure/AndroidFacetModuleCustomizer.java
@@ -22,17 +22,14 @@
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.jps.android.model.impl.JpsAndroidModuleProperties;
-/**
- * Adds the Android facet to modules imported from {@link AndroidProject}s.
- */
+/** Adds the Android facet to modules imported from {@link AndroidProject}s. */
public class AndroidFacetModuleCustomizer {
public static void createAndroidFacet(Module module) {
AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet != null) {
configureFacet(facet);
- }
- else {
+ } else {
// Module does not have Android facet. Create one and add it.
FacetManager facetManager = FacetManager.getInstance(module);
ModifiableFacetModel model = facetManager.createModifiableModel();
@@ -40,8 +37,7 @@
facet = facetManager.createFacet(AndroidFacet.getFacetType(), AndroidFacet.NAME, null);
model.addFacet(facet);
configureFacet(facet);
- }
- finally {
+ } finally {
model.commit();
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/projectstructure/BlazeAndroidProjectStructureSyncer.java b/aswb/src/com/google/idea/blaze/android/sync/projectstructure/BlazeAndroidProjectStructureSyncer.java
index d411447..5fc8793 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/projectstructure/BlazeAndroidProjectStructureSyncer.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/projectstructure/BlazeAndroidProjectStructureSyncer.java
@@ -21,7 +21,7 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.idea.blaze.android.resources.LightResourceClassService;
-import com.google.idea.blaze.android.run.BlazeAndroidRunConfiguration;
+import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationHandler;
import com.google.idea.blaze.android.sync.AndroidSdkPlatformSyncer;
import com.google.idea.blaze.android.sync.model.AndroidResourceModule;
import com.google.idea.blaze.android.sync.model.AndroidSdkPlatform;
@@ -50,28 +50,27 @@
import com.intellij.openapi.module.StdModuleTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
-import org.jetbrains.android.facet.AndroidFacet;
-
-import javax.annotation.Nullable;
import java.io.File;
import java.util.Map;
import java.util.Set;
+import javax.annotation.Nullable;
+import org.jetbrains.android.facet.AndroidFacet;
-/**
- * Updates the IDE's project structure.
- */
+/** Updates the IDE's project structure. */
public class BlazeAndroidProjectStructureSyncer {
- public static void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- BlazeSyncPlugin.ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel,
- boolean isAndroidWorkspace) {
- LightResourceClassService.Builder rClassBuilder = new LightResourceClassService.Builder(project);
+ public static void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ BlazeSyncPlugin.ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel,
+ boolean isAndroidWorkspace) {
+ LightResourceClassService.Builder rClassBuilder =
+ new LightResourceClassService.Builder(project);
if (isAndroidWorkspace) {
BlazeAndroidSyncData syncData = blazeProjectData.syncState.get(BlazeAndroidSyncData.class);
@@ -84,17 +83,13 @@
int totalOrderEntries = 0;
// Create the workspace module
- updateWorkspaceModule(
- project,
- workspaceRoot,
- workspaceModule,
- androidSdkPlatform
- );
+ updateWorkspaceModule(project, workspaceRoot, workspaceModule, androidSdkPlatform);
// Create android resource modules
// Because we're setting up dependencies, the modules have to exist before we configure them
Map<Label, AndroidResourceModule> labelToAndroidResourceModule = Maps.newHashMap();
- for (AndroidResourceModule androidResourceModule : syncData.importResult.androidResourceModules) {
+ for (AndroidResourceModule androidResourceModule :
+ syncData.importResult.androidResourceModules) {
labelToAndroidResourceModule.put(androidResourceModule.label, androidResourceModule);
String moduleName = moduleNameForAndroidModule(androidResourceModule.label);
moduleEditor.createModule(moduleName, StdModuleTypes.JAVA);
@@ -112,14 +107,13 @@
ModifiableRootModel modifiableRootModel = moduleEditor.editModule(module);
updateAndroidRuleModule(
- project,
- workspaceRoot,
- androidSdkPlatform,
- rule,
- module,
- modifiableRootModel,
- androidResourceModule
- );
+ project,
+ workspaceRoot,
+ androidSdkPlatform,
+ rule,
+ module,
+ modifiableRootModel,
+ androidResourceModule);
for (Label resourceDependency : androidResourceModule.transitiveResourceDependencies) {
if (!labelToAndroidResourceModule.containsKey(resourceDependency)) {
@@ -147,16 +141,18 @@
if (!(targetExpression instanceof Label)) {
continue;
}
- Label label = (Label)targetExpression;
+ Label label = (Label) targetExpression;
runConfigurationModuleTargets.add(label);
}
// Get any pre-existing targets
- for (RunConfiguration runConfiguration : RunManager.getInstance(project).getAllConfigurationsList()) {
- if (!(runConfiguration instanceof BlazeAndroidRunConfiguration)) {
+ for (RunConfiguration runConfiguration :
+ RunManager.getInstance(project).getAllConfigurationsList()) {
+ BlazeAndroidRunConfigurationHandler handler =
+ BlazeAndroidRunConfigurationHandler.getHandlerFrom(runConfiguration);
+ if (handler == null) {
continue;
}
- BlazeAndroidRunConfiguration blazeAndroidRunConfiguration = (BlazeAndroidRunConfiguration)runConfiguration;
- runConfigurationModuleTargets.add(blazeAndroidRunConfiguration.getTarget());
+ runConfigurationModuleTargets.add(handler.getLabel());
}
int totalRunConfigurationModules = 0;
@@ -178,23 +174,17 @@
Module module = moduleEditor.createModule(moduleName, StdModuleTypes.JAVA);
ModifiableRootModel modifiableRootModel = moduleEditor.editModule(module);
updateAndroidRuleModule(
- project,
- workspaceRoot,
- androidSdkPlatform,
- rule,
- module,
- modifiableRootModel,
- null
- );
+ project, workspaceRoot, androidSdkPlatform, rule, module, modifiableRootModel, null);
++totalRunConfigurationModules;
}
- context.output(new PrintOutput(String.format(
- "Android resource module count: %d, run config modules: %d, order entries: %d",
- syncData.importResult.androidResourceModules.size(),
- totalRunConfigurationModules,
- totalOrderEntries
- )));
+ context.output(
+ PrintOutput.log(
+ String.format(
+ "Android resource module count: %d, run config modules: %d, order entries: %d",
+ syncData.importResult.androidResourceModules.size(),
+ totalRunConfigurationModules,
+ totalOrderEntries)));
}
} else {
AndroidFacetModuleCustomizer.removeAndroidFacet(workspaceModule);
@@ -203,9 +193,7 @@
LightResourceClassService.getInstance(project).installRClasses(rClassBuilder);
}
- /**
- * Ensures a suitable module exists for the given android target.
- */
+ /** Ensures a suitable module exists for the given android target. */
@Nullable
public static Module ensureRunConfigurationModule(Project project, Label target) {
String moduleName = moduleNameForAndroidModule(target);
@@ -215,11 +203,13 @@
}
WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
if (blazeProjectData == null) {
return null;
}
- AndroidSdkPlatform androidSdkPlatform = AndroidSdkPlatformSyncer.getAndroidSdkPlatform(blazeProjectData);
+ AndroidSdkPlatform androidSdkPlatform =
+ AndroidSdkPlatformSyncer.getAndroidSdkPlatform(blazeProjectData);
if (androidSdkPlatform == null) {
return null;
}
@@ -230,118 +220,121 @@
if (rule.androidRuleIdeInfo == null) {
return null;
}
+ // We can't run a write action outside the dispatch thread, and can't
+ // invokeAndWait it because the caller may have a read action.
+ if (!ApplicationManager.getApplication().isDispatchThread()) {
+ return null;
+ }
- BlazeSyncPlugin.ModuleEditor moduleEditor = BlazeProjectDataManager.getInstance(project).editModules();
+ BlazeSyncPlugin.ModuleEditor moduleEditor =
+ BlazeProjectDataManager.getInstance(project).editModules();
Module newModule = moduleEditor.createModule(moduleName, StdModuleTypes.JAVA);
ModifiableRootModel modifiableRootModel = moduleEditor.editModule(newModule);
- ApplicationManager.getApplication().runWriteAction(() -> {
- updateAndroidRuleModule(
- project,
- workspaceRoot,
- androidSdkPlatform,
- rule,
- newModule,
- modifiableRootModel,
- null
- );
- moduleEditor.commit();
- });
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ updateAndroidRuleModule(
+ project,
+ workspaceRoot,
+ androidSdkPlatform,
+ rule,
+ newModule,
+ modifiableRootModel,
+ null);
+ moduleEditor.commit();
+ });
return newModule;
}
public static String moduleNameForAndroidModule(Label label) {
- return label.toString()
- .substring(2) // Skip initial "//"
- .replace('/', '.')
- .replace(':', '.');
+ return label
+ .toString()
+ .substring(2) // Skip initial "//"
+ .replace('/', '.')
+ .replace(':', '.');
}
- /**
- * Updates the shared workspace module with android info.
- */
- private static void updateWorkspaceModule(Project project,
- WorkspaceRoot workspaceRoot,
- Module workspaceModule,
- AndroidSdkPlatform androidSdkPlatform) {
+ /** Updates the shared workspace module with android info. */
+ private static void updateWorkspaceModule(
+ Project project,
+ WorkspaceRoot workspaceRoot,
+ Module workspaceModule,
+ AndroidSdkPlatform androidSdkPlatform) {
File moduleDirectory = workspaceRoot.directory();
File manifest = new File(workspaceRoot.directory(), "AndroidManifest.xml");
String resourceJavaPackage = ":workspace";
ImmutableList<File> transitiveResources = ImmutableList.of();
createAndroidModel(
- project,
- androidSdkPlatform,
- workspaceModule,
- moduleDirectory,
- manifest,
- resourceJavaPackage,
- transitiveResources
- );
+ project,
+ androidSdkPlatform,
+ workspaceModule,
+ moduleDirectory,
+ manifest,
+ resourceJavaPackage,
+ transitiveResources);
}
- /**
- * Updates a module from an android rule.
- */
- private static void updateAndroidRuleModule(Project project,
- WorkspaceRoot workspaceRoot,
- AndroidSdkPlatform androidSdkPlatform,
- RuleIdeInfo rule,
- Module module,
- ModifiableRootModel modifiableRootModel,
- @Nullable AndroidResourceModule androidResourceModule) {
+ /** Updates a module from an android rule. */
+ private static void updateAndroidRuleModule(
+ Project project,
+ WorkspaceRoot workspaceRoot,
+ AndroidSdkPlatform androidSdkPlatform,
+ RuleIdeInfo rule,
+ Module module,
+ ModifiableRootModel modifiableRootModel,
+ @Nullable AndroidResourceModule androidResourceModule) {
- ImmutableCollection<File> resources = androidResourceModule != null
- ? androidResourceModule.resources
- : ImmutableList.of();
- ImmutableCollection<File> transitiveResources = androidResourceModule != null
- ? androidResourceModule.transitiveResources
- : ImmutableList.of();
+ ImmutableCollection<File> resources =
+ androidResourceModule != null ? androidResourceModule.resources : ImmutableList.of();
+ ImmutableCollection<File> transitiveResources =
+ androidResourceModule != null
+ ? androidResourceModule.transitiveResources
+ : ImmutableList.of();
AndroidRuleIdeInfo androidRuleIdeInfo = rule.androidRuleIdeInfo;
assert androidRuleIdeInfo != null;
File moduleDirectory = workspaceRoot.fileForPath(rule.label.blazePackage());
ArtifactLocation manifestArtifactLocation = androidRuleIdeInfo.manifest;
- File manifest = manifestArtifactLocation != null
- ? manifestArtifactLocation.getFile()
- : new File(moduleDirectory, "AndroidManifest.xml");
+ File manifest =
+ manifestArtifactLocation != null
+ ? manifestArtifactLocation.getFile()
+ : new File(moduleDirectory, "AndroidManifest.xml");
String resourceJavaPackage = androidRuleIdeInfo.resourceJavaPackage;
ResourceModuleContentRootCustomizer.setupContentRoots(modifiableRootModel, resources);
createAndroidModel(
- project,
- androidSdkPlatform,
- module,
- moduleDirectory,
- manifest,
- resourceJavaPackage,
- transitiveResources
- );
+ project,
+ androidSdkPlatform,
+ module,
+ moduleDirectory,
+ manifest,
+ resourceJavaPackage,
+ transitiveResources);
}
- private static void createAndroidModel(Project project,
- AndroidSdkPlatform androidSdkPlatform,
- Module module,
- File moduleDirectory,
- File manifest,
- String resourceJavaPackage,
- ImmutableCollection<File> transitiveResources) {
+ private static void createAndroidModel(
+ Project project,
+ AndroidSdkPlatform androidSdkPlatform,
+ Module module,
+ File moduleDirectory,
+ File manifest,
+ String resourceJavaPackage,
+ ImmutableCollection<File> transitiveResources) {
AndroidFacetModuleCustomizer.createAndroidFacet(module);
- SourceProvider sourceProvider = new SourceProviderImpl(
- module.getName(),
- manifest,
- transitiveResources
- );
- BlazeAndroidModel androidModel = new BlazeAndroidModel(
- project,
- module,
- moduleDirectory,
- sourceProvider,
- manifest,
- resourceJavaPackage,
- androidSdkPlatform.androidSdkLevel
- );
+ SourceProvider sourceProvider =
+ new SourceProviderImpl(module.getName(), manifest, transitiveResources);
+ BlazeAndroidModel androidModel =
+ new BlazeAndroidModel(
+ project,
+ module,
+ moduleDirectory,
+ sourceProvider,
+ manifest,
+ resourceJavaPackage,
+ androidSdkPlatform.androidSdkLevel);
AndroidFacet facet = AndroidFacet.getInstance(module);
if (facet != null) {
facet.setAndroidModel(androidModel);
diff --git a/aswb/src/com/google/idea/blaze/android/sync/projectstructure/ResourceModuleContentRootCustomizer.java b/aswb/src/com/google/idea/blaze/android/sync/projectstructure/ResourceModuleContentRootCustomizer.java
index adf17ff..ea8db29 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/projectstructure/ResourceModuleContentRootCustomizer.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/projectstructure/ResourceModuleContentRootCustomizer.java
@@ -20,17 +20,15 @@
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.util.io.URLUtil;
+import java.io.File;
+import java.util.Collection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.java.JavaResourceRootType;
-import java.io.File;
-import java.util.Collection;
-
-public class ResourceModuleContentRootCustomizer {
+class ResourceModuleContentRootCustomizer {
public static void setupContentRoots(
- @NotNull ModifiableRootModel model,
- @NotNull Collection<File> resources) {
+ @NotNull ModifiableRootModel model, @NotNull Collection<File> resources) {
for (ContentEntry contentEntry : model.getContentEntries()) {
model.removeContentEntry(contentEntry);
}
@@ -45,14 +43,10 @@
private static String pathToUrl(@NotNull String filePath) {
filePath = FileUtil.toSystemIndependentName(filePath);
if (filePath.endsWith(".srcjar") || filePath.endsWith(".jar")) {
- return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR +
- filePath + URLUtil.JAR_SEPARATOR;
- }
- else if (filePath.contains("src.jar!")) {
- return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR +
- filePath;
- }
- else {
+ return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR + filePath + URLUtil.JAR_SEPARATOR;
+ } else if (filePath.contains("src.jar!")) {
+ return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR + filePath;
+ } else {
return VfsUtilCore.pathToUrl(filePath);
}
}
diff --git a/aswb/src/icons/BlazeAndroidIcons.java b/aswb/src/icons/BlazeAndroidIcons.java
index 7f14ec5..957358f 100644
--- a/aswb/src/icons/BlazeAndroidIcons.java
+++ b/aswb/src/icons/BlazeAndroidIcons.java
@@ -16,20 +16,22 @@
package icons;
import com.intellij.openapi.util.IconLoader;
+import javax.swing.Icon;
-import javax.swing.*;
-
-/**
- * Class to manage icons used by the Blaze plugin.
- */
+/** Class to manage icons used by the Blaze plugin. */
public class BlazeAndroidIcons {
- public static final Icon MobileInstallRun = load("/aswb/resources/icons/mobileInstallRun.png"); // 16x16
- public static final Icon MobileInstallDebug = load("/aswb/resources/icons/mobileInstallDebug.png"); // 16x16
- public static final Icon Crow = load("/aswb/resources/icons/crow.png"); // 16x16
- public static final Icon CrowToolWindow = load("/aswb/resources/icons/crowToolWindow.png"); // 13x13
+ private static final String BASE = "/";
+
+ public static final Icon MobileInstallRun =
+ load("aswb/resources/icons/mobileInstallRun.png"); // 16x16
+ public static final Icon MobileInstallDebug =
+ load("aswb/resources/icons/mobileInstallDebug.png"); // 16x16
+ public static final Icon Crow = load("aswb/resources/icons/crow.png"); // 16x16
+ public static final Icon CrowToolWindow =
+ load("aswb/resources/icons/crowToolWindow.png"); // 13x13
private static Icon load(String path) {
- return IconLoader.getIcon(path, BlazeAndroidIcons.class);
+ return IconLoader.getIcon(BASE + path, BlazeAndroidIcons.class);
}
}
diff --git a/aswb/tests/unittests/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtilsTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtilsTest.java
index d2490ed..7341666 100644
--- a/aswb/tests/unittests/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtilsTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/resources/actions/BlazeCreateResourceUtilsTest.java
@@ -15,6 +15,8 @@
*/
package com.google.idea.blaze.android.resources.actions;
+import static com.google.common.truth.Truth.assertThat;
+
import com.google.idea.blaze.base.BlazeTestCase;
import com.intellij.mock.MockVirtualFile;
import com.intellij.openapi.vfs.VirtualFile;
@@ -23,11 +25,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for BlazeCreateResourceUtils.
- */
+/** Tests for BlazeCreateResourceUtils. */
@RunWith(JUnit4.class)
public class BlazeCreateResourceUtilsTest extends BlazeTestCase {
@@ -78,8 +76,9 @@
@Test
public void getDirectoryFromContextJavaFile() {
- // This is just the first cut, where it isn't obvious that the A.java file is associated with the
- // neighboring res directory. We'll have a second pass that looks at the rule map for possible choices.
+ // This is just the first cut, where it isn't obvious that the A.java
+ // file is associated with the neighboring res directory.
+ // We'll have a second pass that looks at the rule map for possible choices.
VirtualFile dir = BlazeCreateResourceUtils.getResDirFromDataContext(javaFile);
assertThat(dir).isNull();
}
diff --git a/aswb/tests/unittests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java
new file mode 100644
index 0000000..761643d
--- /dev/null
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.android.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.android.cppapi.NdkSupport;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeAndroidRunConfigurationCommonState}. */
+@RunWith(JUnit4.class)
+public class BlazeAndroidRunConfigurationCommonStateTest extends BlazeTestCase {
+ private BlazeAndroidRunConfigurationCommonState commonState;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ MockExperimentService experimentService = new MockExperimentService();
+ applicationServices.register(ExperimentService.class, experimentService);
+ // BlazeAndroidRunConfigurationCommonState.isNativeDebuggingEnabled() always
+ // returns false if this experiment is false.
+ experimentService.setExperiment(NdkSupport.NDK_SUPPORT, true);
+
+ commonState = new BlazeAndroidRunConfigurationCommonState(ImmutableList.of());
+ }
+
+ @Test
+ public void readAndWriteShouldMatch() throws InvalidDataException, WriteExternalException {
+ commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.setNativeDebuggingEnabled(true);
+
+ Element element = new Element("test");
+ commonState.writeExternal(element);
+ BlazeAndroidRunConfigurationCommonState readCommonState =
+ new BlazeAndroidRunConfigurationCommonState(ImmutableList.of());
+ readCommonState.readExternal(element);
+
+ assertThat(readCommonState.getUserFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readCommonState.isNativeDebuggingEnabled()).isTrue();
+ }
+
+ @Test
+ public void readAndWriteShouldHandleNulls() throws InvalidDataException, WriteExternalException {
+ Element element = new Element("test");
+ commonState.writeExternal(element);
+ BlazeAndroidRunConfigurationCommonState readCommonState =
+ new BlazeAndroidRunConfigurationCommonState(ImmutableList.of());
+ readCommonState.readExternal(element);
+
+ assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.isNativeDebuggingEnabled())
+ .isEqualTo(commonState.isNativeDebuggingEnabled());
+ }
+
+ @Test
+ public void readShouldOmitEmptyFlags() throws InvalidDataException, WriteExternalException {
+ commonState.setUserFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
+
+ Element element = new Element("test");
+ commonState.writeExternal(element);
+ BlazeAndroidRunConfigurationCommonState readCommonState =
+ new BlazeAndroidRunConfigurationCommonState(ImmutableList.of());
+ readCommonState.readExternal(element);
+
+ assertThat(readCommonState.getUserFlags()).containsExactly("hi", "I'm", "Josh").inOrder();
+ }
+}
diff --git a/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporterTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporterTest.java
index 107ab27..dddf2f5 100644
--- a/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporterTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/BlazeAndroidWorkspaceImporterTest.java
@@ -15,14 +15,23 @@
*/
package com.google.idea.blaze.android.sync.importer;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.android.sync.BlazeAndroidJavaSyncAugmenter;
import com.google.idea.blaze.android.sync.model.AndroidResourceModule;
import com.google.idea.blaze.android.sync.model.BlazeAndroidImportResult;
+import com.google.idea.blaze.android.sync.model.BlazeResourceLibrary;
import com.google.idea.blaze.base.BlazeTestCase;
import com.google.idea.blaze.base.async.executor.BlazeExecutor;
import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.ideinfo.*;
+import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
@@ -37,45 +46,49 @@
import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import java.io.File;
+import java.util.List;
+import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
-import java.io.File;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests for BlazeAndroidWorkspaceImporter
- */
+/** Tests for BlazeAndroidWorkspaceImporter */
+@RunWith(JUnit4.class)
public class BlazeAndroidWorkspaceImporterTest extends BlazeTestCase {
- private String FAKE_ROOT = "/root";
+ private static final String FAKE_ROOT = "/root";
private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File(FAKE_ROOT));
private static final String FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT =
- "blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin";
+ "blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin";
private static final String FAKE_GEN_ROOT =
- "/abs_root/_blaze_user/8093958afcfde6c33d08b621dfaa4e09/root/"
- + FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT;
+ "/abs_root/_blaze_user/8093958afcfde6c33d08b621dfaa4e09/root/"
+ + FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT;
- private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS = new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+ private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
+ new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
private BlazeContext context;
private ErrorCollector errorCollector = new ErrorCollector();
@Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
MockExperimentService mockExperimentService = new MockExperimentService();
applicationServices.register(ExperimentService.class, mockExperimentService);
BlazeExecutor blazeExecutor = new MockBlazeExecutor();
applicationServices.register(BlazeExecutor.class, blazeExecutor);
- projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ projectServices.register(
+ BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
context = new BlazeContext();
@@ -83,455 +96,509 @@
}
BlazeAndroidImportResult importWorkspace(
- WorkspaceRoot workspaceRoot,
- RuleMapBuilder ruleMapBuilder,
- ProjectView projectView) {
+ WorkspaceRoot workspaceRoot, RuleMapBuilder ruleMapBuilder, ProjectView projectView) {
ProjectViewSet projectViewSet = ProjectViewSet.builder().add(projectView).build();
- BlazeAndroidWorkspaceImporter workspaceImporter = new BlazeAndroidWorkspaceImporter(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- ruleMapBuilder.build()
- );
+ BlazeAndroidWorkspaceImporter workspaceImporter =
+ new BlazeAndroidWorkspaceImporter(
+ project, context, workspaceRoot, projectViewSet, ruleMapBuilder.build());
return workspaceImporter.importWorkspace();
}
- /**
- * Test that a two packages use the same un-imported android_library
- */
+ /** Test that a two packages use the same un-imported android_library */
@Test
public void testResourceInheritance() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .build();
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .build();
- /**
- * Deps are project -> lib0 -> lib1 -> shared
- * project -> shared
- */
-
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example/lib0:lib0")
- .setKind("android_library")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/lib0/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/lib0/SharedActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/lib0/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/lib0/res"))
+ /** Deps are project -> lib0 -> lib1 -> shared project -> shared */
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example/lib0:lib0")
+ .setKind("android_library")
+ .setBuildFile(source("java/apps/example/lib0/BUILD"))
+ .addSource(source("java/apps/example/lib0/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/lib0/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/lib0/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.apps.example.lib0"))
- .addDependency("//java/com/google/android/apps/example/lib1:lib1")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib0/lib0.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib0/lib0.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example/lib1:lib1")
- .setKind("android_library")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/lib1/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/lib1/SharedActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/lib1/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
+ .addDependency("//java/apps/example/lib1:lib1")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/lib0/lib0.jar"))
+ .setClassJar(gen("java/apps/example/lib0/lib0.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example/lib1:lib1")
+ .setKind("android_library")
+ .setBuildFile(source("java/apps/example/lib1/BUILD"))
+ .addSource(source("java/apps/example/lib1/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/lib1/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/lib1/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.apps.example.lib1"))
- .addDependency("//java/com/google/android/libraries/shared:shared")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib1/lib1.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib1/lib1.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setKind("android_binary")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
+ .addDependency("//java/libraries/shared:shared")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/lib1/lib1.jar"))
+ .setClassJar(gen("java/apps/example/lib1/lib1.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setKind("android_binary")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/android/apps/example/lib0:lib0")
- .addDependency("//java/com/google/android/libraries/shared:shared")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/libraries/shared:shared")
- .setBuildFile(sourceRoot("java/com/google/android/libraries/shared/BUILD"))
- .setKind("android_library")
- .addSource(sourceRoot("java/com/google/android/libraries/shared/SharedActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/libraries/shared/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/libraries/shared/res"))
+ .addDependency("//java/apps/example/lib0:lib0")
+ .addDependency("//java/libraries/shared:shared")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/example_debug.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/libraries/shared:shared")
+ .setBuildFile(source("java/libraries/shared/BUILD"))
+ .setKind("android_library")
+ .addSource(source("java/libraries/shared/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/libraries/shared/AndroidManifest.xml"))
+ .addResource(source("java/libraries/shared/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.libraries.shared"))
- .setBuildFile(sourceRoot("java/com/google/android/libraries/shared/BUILD"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/libraries/shared.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/libraries/shared.jar")))));
+ .setBuildFile(source("java/libraries/shared/BUILD"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/libraries/shared.jar"))
+ .setClassJar(gen("java/libraries/shared.jar")))));
- BlazeAndroidImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
+ BlazeAndroidImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
errorCollector.assertNoIssues();
- assertThat(result.androidResourceModules).containsExactly(
- AndroidResourceModule.builder(new Label("//java/com/google/android/apps/example:example_debug"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/apps/example/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib0/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/libraries/shared/res"))
- .addTransitiveResourceDependency("//java/com/google/android/apps/example/lib0:lib0")
- .addTransitiveResourceDependency("//java/com/google/android/apps/example/lib1:lib1")
- .addTransitiveResourceDependency("//java/com/google/android/libraries/shared:shared")
- .build(),
- AndroidResourceModule.builder(new Label("//java/com/google/android/apps/example/lib0:lib0"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib0/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/libraries/shared/res"))
- .addTransitiveResourceDependency("//java/com/google/android/apps/example/lib1:lib1")
- .addTransitiveResourceDependency("//java/com/google/android/libraries/shared:shared")
- .build(),
- AndroidResourceModule.builder(new Label("//java/com/google/android/apps/example/lib1:lib1"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/libraries/shared/res"))
- .addTransitiveResourceDependency("//java/com/google/android/libraries/shared:shared")
- .build()
- );
+ assertThat(result.androidResourceModules)
+ .containsExactly(
+ AndroidResourceModule.builder(new Label("//java/apps/example:example_debug"))
+ .addResourceAndTransitiveResource(source("java/apps/example/res"))
+ .addTransitiveResource(source("java/apps/example/lib0/res"))
+ .addTransitiveResource(source("java/apps/example/lib1/res"))
+ .addTransitiveResource(source("java/libraries/shared/res"))
+ .addTransitiveResourceDependency("//java/apps/example/lib0:lib0")
+ .addTransitiveResourceDependency("//java/apps/example/lib1:lib1")
+ .addTransitiveResourceDependency("//java/libraries/shared:shared")
+ .build(),
+ AndroidResourceModule.builder(new Label("//java/apps/example/lib0:lib0"))
+ .addResourceAndTransitiveResource(source("java/apps/example/lib0/res"))
+ .addTransitiveResource(source("java/apps/example/lib1/res"))
+ .addTransitiveResource(source("java/libraries/shared/res"))
+ .addTransitiveResourceDependency("//java/apps/example/lib1:lib1")
+ .addTransitiveResourceDependency("//java/libraries/shared:shared")
+ .build(),
+ AndroidResourceModule.builder(new Label("//java/apps/example/lib1:lib1"))
+ .addResourceAndTransitiveResource(source("java/apps/example/lib1/res"))
+ .addTransitiveResource(source("java/libraries/shared/res"))
+ .addTransitiveResourceDependency("//java/libraries/shared:shared")
+ .build());
}
- /**
- * Test adding empty resource modules as jars.
- */
+ /** Test adding empty resource modules as jars. */
@Test
public void testEmptyResourceModuleIsAddedAsJar() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .build();
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .build();
- /**
- * Deps are project -> lib0 (no res) -> lib1 (has res)
- * \
- * -> lib2 (has res)
- */
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example/lib0:lib0")
- .setKind("android_library")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/lib0/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/lib0/SharedActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/lib0/AndroidManifest.xml"))
+ /** Deps are project -> lib0 (no res) -> lib1 (has res) \ -> lib2 (has res) */
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example/lib0:lib0")
+ .setKind("android_library")
+ .setBuildFile(source("java/apps/example/lib0/BUILD"))
+ .addSource(source("java/apps/example/lib0/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/lib0/AndroidManifest.xml"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.apps.example.lib0")
- .setResourceJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib0/lib0_resources.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib0/lib0_resources.jar"))))
- .addDependency("//java/com/google/android/apps/example/lib1:lib1")
- .addDependency("//java/com/google/android/apps/example/lib2:lib2")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib0/lib0.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib0/lib0.jar")))
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib0/lib0_resources.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib0/lib0_resources.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example/lib1:lib1")
- .setKind("android_library")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/lib1/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/lib1/SharedActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/lib1/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
+ .setResourceJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/lib0/lib0_resources.jar"))
+ .setClassJar(gen("java/apps/example/lib0/lib0_resources.jar"))))
+ .addDependency("//java/apps/example/lib1:lib1")
+ .addDependency("//java/apps/example/lib2:lib2")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/lib0/lib0.jar"))
+ .setClassJar(gen("java/apps/example/lib0/lib0.jar")))
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/lib0/lib0_resources.jar"))
+ .setClassJar(
+ gen("java/apps/example/lib0/lib0_resources.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example/lib1:lib1")
+ .setKind("android_library")
+ .setBuildFile(source("java/apps/example/lib1/BUILD"))
+ .addSource(source("java/apps/example/lib1/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/lib1/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/lib1/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.apps.example.lib1")
- .setResourceJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib1/li11_resources.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib1/lib1_resources.jar"))))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib1/lib1.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib1/lib1.jar")))
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib1/lib1_resources.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib1/lib1_resources.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example/lib2:lib2")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/lib2/BUILD"))
- .setKind("android_library")
- .addSource(sourceRoot("java/com/google/android/apps/example/lib2/SharedActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/lib2/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/lib2/res"))
+ .setResourceJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/lib1/li11_resources.jar"))
+ .setClassJar(gen("java/apps/example/lib1/lib1_resources.jar"))))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/lib1/lib1.jar"))
+ .setClassJar(gen("java/apps/example/lib1/lib1.jar")))
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/lib1/lib1_resources.jar"))
+ .setClassJar(
+ gen("java/apps/example/lib1/lib1_resources.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example/lib2:lib2")
+ .setBuildFile(source("java/apps/example/lib2/BUILD"))
+ .setKind("android_library")
+ .addSource(source("java/apps/example/lib2/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/lib2/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/lib2/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.libraries.example.lib2")
- .setResourceJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib2/lib2_resources.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib2/lib2_resources.jar"))))
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/lib2/BUILD"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib2/lib2.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib2/lib2.jar")))
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/lib2/lib2_resources.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/lib2/lib2_resources.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setKind("android_binary")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
+ .setResourceJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/lib2/lib2_resources.jar"))
+ .setClassJar(gen("java/apps/example/lib2/lib2_resources.jar"))))
+ .setBuildFile(source("java/apps/example/lib2/BUILD"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/lib2/lib2.jar"))
+ .setClassJar(gen("java/apps/example/lib2/lib2.jar")))
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/lib2/lib2_resources.jar"))
+ .setClassJar(
+ gen("java/apps/example/lib2/lib2_resources.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setKind("android_binary")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/android/apps/example/lib0:lib0")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))));
+ .addDependency("//java/apps/example/lib0:lib0")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/example_debug.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))));
- BlazeAndroidImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
- errorCollector.assertNoIssues();
+ RuleMap ruleMap = response.build();
+ BlazeAndroidJavaSyncAugmenter syncAugmenter = new BlazeAndroidJavaSyncAugmenter();
+ List<BlazeJarLibrary> jars = Lists.newArrayList();
+ List<BlazeJarLibrary> genJars = Lists.newArrayList();
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(ProjectViewSet.builder().add(projectView).build())
+ .build();
+ for (RuleIdeInfo rule : ruleMap.rules()) {
+ if (importRoots.importAsSource(rule.label)) {
+ syncAugmenter.addJarsForSourceRule(rule, jars, genJars);
+ }
+ }
- assertThat(result.androidResourceModules).containsExactly(
- AndroidResourceModule.builder(new Label("//java/com/google/android/apps/example:example_debug"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/apps/example/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
- .addTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib2/res"))
- .addTransitiveResourceDependency("//java/com/google/android/apps/example/lib0:lib0")
- .addTransitiveResourceDependency("//java/com/google/android/apps/example/lib1:lib1")
- .addTransitiveResourceDependency("//java/com/google/android/apps/example/lib2:lib2")
- .build(),
- AndroidResourceModule.builder(new Label("//java/com/google/android/apps/example/lib1:lib1"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib1/res"))
- .build(),
- AndroidResourceModule.builder(new Label("//java/com/google/android/apps/example/lib2:lib2"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/apps/example/lib2/res"))
- .build()
- );
-
- assertEquals(1, result.libraries.size());
- BlazeLibrary library = result.libraries.iterator().next();
- assertEquals("lib0_resources.jar", library.getLibraryArtifact().jar.getFile().getName());
+ assertThat(
+ jars.stream()
+ .map(library -> library.libraryArtifact.interfaceJar.getFile().getName())
+ .collect(Collectors.toList()))
+ .containsExactly("lib0_resources.jar");
}
@Test
public void testIdlClassJarIsAddedAsLibrary() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("example"))))
- .build();
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("example"))))
+ .build();
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//example:lib")
- .setBuildFile(sourceRoot("example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("example/MainActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//example:lib")
+ .setBuildFile(source("example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("example/MainActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
.setResourceJavaPackage("example")
- .setIdlJar(LibraryArtifact.builder()
- .setJar(genRoot("example/libidl.jar"))
- .setSourceJar(genRoot("example/libidl.srcjar"))
- .build())
+ .setIdlJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("example/libidl.jar"))
+ .setSourceJar(gen("example/libidl.srcjar"))
+ .build())
.setHasIdlSources(true)));
- BlazeAndroidImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertEquals(1, result.libraries.size());
-
- BlazeLibrary library = result.libraries.iterator().next();
- assertEquals("libidl.jar", library.getLibraryArtifact().jar.getFile().getName());
- assertEquals("libidl.srcjar", library.getLibraryArtifact().sourceJar.getFile().getName());
+ RuleMap ruleMap = ruleMapBuilder.build();
+ BlazeAndroidJavaSyncAugmenter syncAugmenter = new BlazeAndroidJavaSyncAugmenter();
+ List<BlazeJarLibrary> jars = Lists.newArrayList();
+ List<BlazeJarLibrary> genJars = Lists.newArrayList();
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(ProjectViewSet.builder().add(projectView).build())
+ .build();
+ for (RuleIdeInfo rule : ruleMap.rules()) {
+ if (importRoots.importAsSource(rule.label)) {
+ syncAugmenter.addJarsForSourceRule(rule, jars, genJars);
+ }
+ }
+ assertThat(
+ genJars
+ .stream()
+ .map(library -> library.libraryArtifact.interfaceJar.getFile().getName())
+ .collect(Collectors.toList()))
+ .containsExactly("libidl.jar");
}
@Test
public void testAndroidResourceImport() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/example"))))
- .build();
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/example:lib")
- .setBuildFile(sourceRoot("java/com/google/android/example/BUILD"))
- .setKind("android_library")
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setLegacyResources(new Label("//java/com/google/android/example:resources"))
- .setManifestFile(sourceRoot("java/com/google/android/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/example/res"))
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:lib")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setLegacyResources(new Label("//java/example:resources"))
+ .setManifestFile(source("java/example/AndroidManifest.xml"))
+ .addResource(source("java/example/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.example"))
- .build())
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/example:resources")
- .setBuildFile(sourceRoot("java/com/google/android/example/BUILD"))
- .setKind("android_resources")
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/example/res"))
+ .build())
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:resources")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("android_resources")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/example/AndroidManifest.xml"))
+ .addResource(source("java/example/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.example"))
- .build());
+ .build());
- BlazeAndroidImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
+ BlazeAndroidImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
errorCollector.assertNoIssues();
- assertThat(result.androidResourceModules).containsExactly(
- AndroidResourceModule.builder(new Label("//java/com/google/android/example:resources"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/example/res"))
- .build()
- );
+ assertThat(result.androidResourceModules)
+ .containsExactly(
+ AndroidResourceModule.builder(new Label("//java/example:resources"))
+ .addResourceAndTransitiveResource(source("java/example/res"))
+ .build());
}
@Test
public void testResourceImportOutsideSourceFilterIsAddedToResourceLibrary() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/example"))))
- .build();
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/example:lib")
- .setBuildFile(sourceRoot("java/com/google/android/example/BUILD"))
- .setKind("android_library")
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/example/res"))
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:lib")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/example/AndroidManifest.xml"))
+ .addResource(source("java/example/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.example"))
- .addDependency("//java/com/google/android/example2:resources")
- .build())
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/example2:resources")
- .setBuildFile(sourceRoot("java/com/google/android/example2/BUILD"))
- .setKind("android_library")
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/example2/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/example2/res"))
+ .addDependency("//java/example2:resources")
+ .build())
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example2:resources")
+ .setBuildFile(source("java/example2/BUILD"))
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/example2/AndroidManifest.xml"))
+ .addResource(source("java/example2/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.example2"))
- .build());
+ .build());
- BlazeAndroidImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
+ BlazeAndroidImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
errorCollector.assertNoIssues();
- BlazeLibrary library = result.libraries.stream()
- .filter(item -> item.getKey().equals(LibraryKey.forResourceLibrary()))
- .findAny()
- .orElse(null);
+ BlazeResourceLibrary library = result.resourceLibrary;
assertThat(library).isNotNull();
- assertThat(library.getSources()).containsExactly(
- new File("/root/java/com/google/android/example2/res")
- );
+ assertThat(library.sources).containsExactly(new File("/root/java/example2/res"));
}
@Test
public void testConflictingResourceRClasses() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/example"))))
- .build();
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/example:lib")
- .setBuildFile(sourceRoot("java/com/google/android/example/BUILD"))
- .setKind("android_library")
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/example/res"))
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:lib")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/example/AndroidManifest.xml"))
+ .addResource(source("java/example/res"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.example"))
- .addDependency("//java/com/google/android/example2:resources")
- .build())
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/example:lib2")
- .setBuildFile(sourceRoot("java/com/google/android/example2/BUILD"))
- .setKind("android_library")
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/example2/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/example/res2"))
+ .addDependency("//java/example2:resources")
+ .build())
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:lib2")
+ .setBuildFile(source("java/example2/BUILD"))
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/example2/AndroidManifest.xml"))
+ .addResource(source("java/example/res2"))
.setGenerateResourceClass(true)
.setResourceJavaPackage("com.google.android.example"))
- .build());
+ .build());
- BlazeAndroidImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
+ BlazeAndroidImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
errorCollector.assertIssueContaining("Multiple R classes generated");
- assertThat(result.androidResourceModules).containsExactly(
- AndroidResourceModule.builder(new Label("//java/com/google/android/example:lib"))
- .addResourceAndTransitiveResource(sourceRoot("java/com/google/android/example/res"))
- .build()
- );
+ assertThat(result.androidResourceModules)
+ .containsExactly(
+ AndroidResourceModule.builder(new Label("//java/example:lib"))
+ .addResourceAndTransitiveResource(source("java/example/res"))
+ .build());
}
- private ArtifactLocation sourceRoot(String relativePath) {
- return ArtifactLocation.builder()
- .setRootPath(FAKE_ROOT)
- .setRelativePath(relativePath)
- .setIsSource(true)
- .build();
+ @Test
+ public void testMixingGeneratedAndNonGeneratedSourcesGeneratesIssue() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:lib")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/example/AndroidManifest.xml"))
+ .addResource(source("java/example/res"))
+ .addResource(gen("java/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.example"))
+ .build());
+
+ importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertIssueContaining("Dropping generated resource");
}
- private static ArtifactLocation genRoot(String relativePath) {
+ private ArtifactLocation source(String relativePath) {
return ArtifactLocation.builder()
- .setRootPath(FAKE_GEN_ROOT)
- .setRootExecutionPathFragment(FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT)
- .setRelativePath(relativePath)
- .setIsSource(false)
- .build();
+ .setRootPath(FAKE_ROOT)
+ .setRelativePath(relativePath)
+ .setIsSource(true)
+ .build();
+ }
+
+ private static ArtifactLocation gen(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootPath(FAKE_GEN_ROOT)
+ .setRootExecutionPathFragment(FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT)
+ .setRelativePath(relativePath)
+ .setIsSource(false)
+ .build();
}
}
diff --git a/base/BUILD b/base/BUILD
new file mode 100644
index 0000000..add4fdb
--- /dev/null
+++ b/base/BUILD
@@ -0,0 +1,110 @@
+licenses(["notice"]) # Apache 2.0
+
+java_library(
+ name = "base",
+ srcs = glob(["src/**/*.java"]),
+ resources = glob(["resources/**/*"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//common/experiments",
+ "//intellij_platform_sdk:plugin_api",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+filegroup(
+ name = "plugin_xml",
+ srcs = ["src/META-INF/blaze-base.xml"],
+ visibility = ["//visibility:public"],
+)
+
+java_library(
+ name = "unit_test_utils",
+ testonly = 1,
+ srcs = glob(["tests/utils/unit/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
+
+java_library(
+ name = "integration_test_utils",
+ testonly = 1,
+ srcs = glob(["tests/utils/integration/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ ":unit_test_utils",
+ "//base",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+load(
+ "//build_defs:build_defs.bzl",
+ "stamped_plugin_xml",
+ "intellij_plugin",
+)
+
+stamped_plugin_xml(
+ name = "base_plugin_xml",
+ plugin_id = "com.google.idea.blaze.base",
+ plugin_name = "com.google.idea.blaze.base",
+ plugin_xml = "plugin_xml",
+)
+
+intellij_plugin(
+ name = "base_integration_test_plugin",
+ testonly = 1,
+ plugin_xml = ":base_plugin_xml",
+ deps = [
+ ":base",
+ ],
+)
+
+load(
+ "//intellij_test:test_defs.bzl",
+ "intellij_integration_test_suite",
+ "intellij_unit_test_suite",
+)
+
+intellij_unit_test_suite(
+ name = "unit_tests",
+ srcs = glob(["tests/unittests/**/*.java"]),
+ test_package_root = "com.google.idea.blaze.base",
+ deps = [
+ ":base",
+ ":unit_test_utils",
+ "//common/experiments",
+ "//common/experiments:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
+
+intellij_integration_test_suite(
+ name = "integration_tests",
+ srcs = glob(["tests/integrationtests/**/*.java"]),
+ required_plugins = "com.google.idea.blaze.base",
+ test_package_root = "com.google.idea.blaze.base",
+ runtime_deps = [
+ ":base_integration_test_plugin",
+ ],
+ deps = [
+ ":base",
+ ":integration_test_utils",
+ ":unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
diff --git a/base/lib/proto_deps.jar b/base/lib/proto_deps.jar
new file mode 100755
index 0000000..4943ed3
--- /dev/null
+++ b/base/lib/proto_deps.jar
Binary files differ
diff --git a/blaze-base/resources/binaries/README b/base/resources/binaries/README
similarity index 100%
rename from blaze-base/resources/binaries/README
rename to base/resources/binaries/README
diff --git a/blaze-base/resources/icons/bazel_leaf.png b/base/resources/icons/bazel_leaf.png
similarity index 100%
rename from blaze-base/resources/icons/bazel_leaf.png
rename to base/resources/icons/bazel_leaf.png
Binary files differ
diff --git a/blaze-base/resources/icons/blaze.png b/base/resources/icons/blaze.png
similarity index 100%
rename from blaze-base/resources/icons/blaze.png
rename to base/resources/icons/blaze.png
Binary files differ
diff --git a/blaze-base/resources/icons/blazeToolWindow.png b/base/resources/icons/blazeToolWindow.png
similarity index 100%
rename from blaze-base/resources/icons/blazeToolWindow.png
rename to base/resources/icons/blazeToolWindow.png
Binary files differ
diff --git a/blaze-base/resources/icons/blaze_clean.png b/base/resources/icons/blaze_clean.png
similarity index 100%
rename from blaze-base/resources/icons/blaze_clean.png
rename to base/resources/icons/blaze_clean.png
Binary files differ
diff --git a/blaze-base/resources/icons/blaze_dirty.png b/base/resources/icons/blaze_dirty.png
similarity index 100%
rename from blaze-base/resources/icons/blaze_dirty.png
rename to base/resources/icons/blaze_dirty.png
Binary files differ
diff --git a/blaze-base/resources/icons/blaze_failed.png b/base/resources/icons/blaze_failed.png
similarity index 100%
rename from blaze-base/resources/icons/blaze_failed.png
rename to base/resources/icons/blaze_failed.png
Binary files differ
diff --git a/blaze-base/resources/icons/blaze_slow.png b/base/resources/icons/blaze_slow.png
similarity index 100%
rename from blaze-base/resources/icons/blaze_slow.png
rename to base/resources/icons/blaze_slow.png
Binary files differ
diff --git a/blaze-base/resources/icons/build_editor.png b/base/resources/icons/build_editor.png
similarity index 100%
rename from blaze-base/resources/icons/build_editor.png
rename to base/resources/icons/build_editor.png
Binary files differ
diff --git a/blaze-base/resources/icons/build_file.png b/base/resources/icons/build_file.png
similarity index 100%
rename from blaze-base/resources/icons/build_file.png
rename to base/resources/icons/build_file.png
Binary files differ
diff --git a/blaze-base/resources/icons/build_rule.png b/base/resources/icons/build_rule.png
similarity index 100%
rename from blaze-base/resources/icons/build_rule.png
rename to base/resources/icons/build_rule.png
Binary files differ
diff --git a/blaze-base/scripts/create_bugreport.sh b/base/scripts/create_bugreport.sh
similarity index 100%
rename from blaze-base/scripts/create_bugreport.sh
rename to base/scripts/create_bugreport.sh
diff --git a/base/src/META-INF/blaze-base.xml b/base/src/META-INF/blaze-base.xml
new file mode 100644
index 0000000..606ea98
--- /dev/null
+++ b/base/src/META-INF/blaze-base.xml
@@ -0,0 +1,281 @@
+<!--
+ ~ Copyright 2016 The Bazel Authors. All rights reserved.
+ ~
+ ~ 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.
+ -->
+<idea-plugin>
+ <actions>
+ <action id="MakeBlazeProject" class="com.google.idea.blaze.base.actions.BlazeMakeProjectAction" use-shortcut-of="CompileDirty" icon="AllIcons.Actions.Compile">
+ </action>
+ <action id="MakeBlazeModule" class="com.google.idea.blaze.base.actions.BlazeCompileFileAction">
+ </action>
+ <action id="Blaze.IncrementalSyncProject" class="com.google.idea.blaze.base.sync.actions.IncrementalSyncProjectAction" icon="BlazeIcons.Blaze">
+ </action>
+ <action id="Blaze.FullSyncProject" class="com.google.idea.blaze.base.sync.actions.FullSyncProjectAction" icon="BlazeIcons.BlazeSlow">
+ </action>
+ <action id="Blaze.SyncWorkingSet" class="com.google.idea.blaze.base.sync.actions.SyncWorkingSetAction" icon="BlazeIcons.Blaze" text="Sync Working Set">
+ </action>
+ <action id="Blaze.ExpandSyncToWorkingSet" class="com.google.idea.blaze.base.sync.actions.ExpandSyncToWorkingSetAction" text="Expand Sync to Working Set">
+ </action>
+ <action id="Blaze.ShowPerformanceWarnings" class="com.google.idea.blaze.base.sync.actions.ShowPerformanceWarningsToggleAction" text="Show Performance Warnings">
+ </action>
+ <action id="Blaze.EditProjectView" class="com.google.idea.blaze.base.settings.ui.EditProjectViewAction" text="Edit Project View..." icon="BlazeIcons.Blaze">
+ </action>
+
+ <action class="com.google.idea.blaze.base.buildmap.OpenCorrespondingBuildFile"
+ id="Blaze.OpenCorrespondingBuildFile"
+ icon="BlazeIcons.Blaze"
+ text="Open Corresponding BUILD File">
+ </action>
+ <action class="com.google.idea.blaze.base.sync.actions.PartialSyncAction"
+ id="Blaze.PartialSync"
+ icon="BlazeIcons.Blaze">
+ </action>
+
+ <group id="Blaze.MainMenuActionGroup" class="com.google.idea.blaze.base.actions.BlazeMenuGroup">
+ <add-to-group group-id="MainMenu" anchor="before" relative-to-action="HelpMenu"/>
+ <reference id="MakeBlazeProject"/>
+ <reference id="MakeBlazeModule"/>
+ <separator/>
+ <reference id="Blaze.EditProjectView"/>
+ <separator/>
+ <reference id="Blaze.IncrementalSyncProject"/>
+ <reference id="Blaze.FullSyncProject"/>
+ <reference id="Blaze.SyncWorkingSet"/>
+ <reference id="Blaze.PartialSync"/>
+ <reference id="Blaze.ExpandSyncToWorkingSet"/>
+ <reference id="Blaze.ShowPerformanceWarnings"/>
+ </group>
+
+ <group id="Blaze.MainToolBarActionGroup">
+ <add-to-group group-id="MainToolBar" anchor="before" relative-to-action="HelpTopics" />
+ <add-to-group group-id="NavBarToolBarOthers" anchor="last"/>
+ <reference id="Blaze.IncrementalSyncProject"/>
+ </group>
+
+ <group id="Blaze.NewActions" text="Edit Blaze structure" description="Create new Blaze packages, rules, etc.">
+ <add-to-group group-id="NewGroup" anchor="first"/>
+ <action id="Blaze.NewPackageAction" class="com.google.idea.blaze.base.ide.NewBlazePackageAction" popup="true"/>
+ <action id="Blaze.NewRuleAction" class="com.google.idea.blaze.base.ide.NewBlazeRuleAction" popup="true"/>
+ <separator/>
+ </group>
+
+ <group id="Blaze.ProjectViewPopupMenu">
+ <add-to-group anchor="after" group-id="ProjectViewPopupMenu" relative-to-action="EditSource"/>
+ <separator/>
+ <reference ref="Blaze.PartialSync"/>
+ <reference ref="Blaze.OpenCorrespondingBuildFile"/>
+ </group>
+
+ <group id="Blaze.EditorTabPopupMenu">
+ <add-to-group anchor="after" group-id="EditorTabPopupMenu" relative-to-action="CopyReference"/>
+ <separator/>
+ <reference ref="Blaze.PartialSync"/>
+ <reference ref="Blaze.OpenCorrespondingBuildFile"/>
+ </group>
+ </actions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <postStartupActivity implementation="com.google.idea.blaze.base.sync.BlazeSyncStartupActivity"/>
+
+ <toolWindow id="Blaze Console"
+ anchor="bottom"
+ secondary="true"
+ conditionClass="com.google.idea.blaze.base.settings.IsBlazeProjectCondition"
+ icon="BlazeIcons.BlazeToolWindow"
+ factoryClass="com.google.idea.blaze.base.console.BlazeConsoleToolWindowFactory"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.console.BlazeConsoleView"/>
+ <fileTypeFactory implementation="com.google.idea.blaze.base.plugin.BlazeFileTypeFactory" />
+
+ <projectConfigurable instance="com.google.idea.blaze.base.settings.ui.BlazeUserSettingsConfigurable"
+ id ="blaze.view" displayName="Blaze Settings"/>
+
+ <projectService serviceInterface="com.google.idea.blaze.base.sync.data.BlazeProjectDataManager"
+ serviceImplementation="com.google.idea.blaze.base.sync.data.BlazeProjectDataManagerImpl"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.sync.BlazeSyncManager"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.sync.status.BlazeSyncStatus"
+ serviceImplementation="com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl"/>
+
+ <applicationService serviceInterface="com.google.idea.blaze.base.async.executor.BlazeExecutor"
+ serviceImplementation="com.google.idea.blaze.base.async.executor.BlazeExecutorImpl"/>
+ <fileDocumentManagerListener implementation="com.google.idea.blaze.base.buildmodifier.FileSaveHandler" order="first"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.io.InputStreamProvider"
+ serviceImplementation="com.google.idea.blaze.base.io.InputStreamProviderImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.io.FileAttributeProvider"
+ serviceImplementation="com.google.idea.blaze.base.io.FileAttributeProvider"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.io.WorkspaceScanner"
+ serviceImplementation="com.google.idea.blaze.base.io.VfsWorkspaceScanner"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.buildmodifier.BuildFileModifier"
+ serviceImplementation="com.google.idea.blaze.base.lang.buildfile.actions.BuildFileModifierImpl"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.buildmodifier.FileSystemModifier"
+ serviceImplementation="com.google.idea.blaze.base.buildmodifier.FileSystemModifierImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.run.rulefinder.RuleFinder"
+ serviceImplementation="com.google.idea.blaze.base.run.rulefinder.RuleFinderImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.command.info.BlazeInfo"
+ serviceImplementation="com.google.idea.blaze.base.command.info.BlazeInfoImpl"/>
+
+ <treeStructureProvider implementation="com.google.idea.blaze.base.treeview.BlazeTreeStructureProvider" id="blaze"/>
+
+ <applicationService serviceInterface="com.google.idea.blaze.base.projectview.ProjectViewStorageManager"
+ serviceImplementation="com.google.idea.blaze.base.projectview.ProjectViewStorageManagerImpl"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.projectview.ProjectViewManager"
+ serviceImplementation="com.google.idea.blaze.base.projectview.ProjectViewManagerImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface"
+ serviceImplementation="com.google.idea.blaze.base.sync.aspects.BlazeIdeInterfaceAspectsImpl"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.run.TestRuleFinder"
+ serviceImplementation="com.google.idea.blaze.base.run.testmap.TestRuleFinderImpl"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.console.BlazeConsoleService"
+ serviceImplementation="com.google.idea.blaze.base.console.BlazeConsoleServiceImpl"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.buildmap.FileToBuildMap"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.rulemaps.SourceToRuleMap"
+ serviceImplementation="com.google.idea.blaze.base.rulemaps.SourceToRuleMapImpl"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.settings.BlazeImportSettingsManager"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.settings.BlazeImportSettingsManagerLegacy"/>
+ <applicationService serviceImplementation="com.google.idea.blaze.base.settings.BlazeUserSettings"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider"
+ serviceImplementation="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProviderImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider"
+ serviceImplementation="com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProviderImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.prefetch.PrefetchService"
+ serviceImplementation="com.google.idea.blaze.base.prefetch.PrefetchServiceImpl"/>
+ <applicationService serviceImplementation="com.google.idea.blaze.base.wizard2.BlazeWizardUserSettingsStorage"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider"
+ serviceImplementation="com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProviderImpl"/>
+ <configurationType implementation="com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType"/>
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.base.run.producers.AllInPackageBlazeConfigurationProducer"
+ order="first"/>
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.base.run.producers.BlazeBuildFileRunConfigurationProducer"
+ order="first"/>
+ <stepsBeforeRunProvider implementation="com.google.idea.blaze.base.run.BlazeBeforeRunTaskProvider"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.help.BlazeHelpHandler"
+ serviceImplementation="com.google.idea.blaze.base.help.BlazeHelpHandlerImpl"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <fileTypeFactory implementation="com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileTypeFactory"/>
+ <lang.parserDefinition language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.parser.ProjectViewParserDefinition"/>
+ <lang.commenter language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.formatting.ProjectViewCommenter"/>
+ <lang.syntaxHighlighterFactory language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.highlighting.ProjectViewSyntaxHighlighterFactory"/>
+ <completion.contributor language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.completion.ProjectViewKeywordCompletionContributor"/>
+ <completion.contributor language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.completion.WorkspaceTypeCompletionContributor"/>
+ <completion.contributor language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.completion.AdditionalLanguagesCompletionContributor"/>
+ <enterHandlerDelegate implementation="com.google.idea.blaze.base.lang.projectview.formatting.ProjectViewEnterHandler"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <fileTypeFactory implementation="com.google.idea.blaze.base.lang.buildfile.language.BuildFileTypeFactory"/>
+ <annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.HighlightingAnnotator"/>
+ <!--<annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.ErrorAnnotator"/>-->
+ <annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.GlobErrorAnnotator"/>
+ <colorSettingsPage implementation="com.google.idea.blaze.base.lang.buildfile.highlighting.BuildColorsPage"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.lang.buildfile.psi.util.BuildElementGenerator"/>
+ <projectService serviceImplementation="com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager"/>
+ <referencesSearch implementation="com.google.idea.blaze.base.lang.buildfile.search.BuildLabelReferenceSearcher"/>
+ <referencesSearch implementation="com.google.idea.blaze.base.lang.buildfile.search.GlobReferenceSearcher"/>
+ <readWriteAccessDetector implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildReadWriteAccessDetector"/>
+ <elementDescriptionProvider implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildElementDescriptionProvider"/>
+ <usageGroupingRuleProvider implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildUsageGroupingRuleProvider"/>
+ <useScopeOptimizer implementation="com.google.idea.blaze.base.lang.buildfile.search.ExcludeBuildFilesScope"/>
+ <targetElementEvaluator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.findusages.BuildTargetElementEvaluator"/>
+ <quoteHandler fileType="BUILD" className="com.google.idea.blaze.base.lang.buildfile.editor.BuildQuoteHandler"/>
+ <enterHandlerDelegate implementation="com.google.idea.blaze.base.lang.buildfile.editor.BuildEnterBetweenBracketsHandler" order="before EnterBetweenBracesHandler"/>
+ <enterHandlerDelegate implementation="com.google.idea.blaze.base.lang.buildfile.editor.BuildEnterHandler" order="after EnterBetweenBracesHandler"/>
+ <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.ParameterCompletionContributor"/>
+ <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.BuiltInFunctionCompletionContributor"/>
+ <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.BuiltInFunctionAttributeCompletionContributor"/>
+ <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.ArgumentCompletionContributor"/>
+ <langCodeStyleSettingsProvider implementation="com.google.idea.blaze.base.lang.buildfile.formatting.BuildLanguageCodeStyleSettingsProvider"/>
+ <codeStyleSettingsProvider implementation="com.google.idea.blaze.base.lang.buildfile.formatting.BuildCodeStyleSettingsProvider"/>
+ <editor.backspaceModeOverride language="BUILD" implementationClass="com.intellij.codeInsight.editorActions.SmartBackspaceDisabler"/>
+ <filetype.stubBuilder filetype="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.stubs.BuildFileStubBuilder"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij.lang">
+ <syntaxHighlighterFactory language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.highlighting.BuildSyntaxHighlighterFactory"/>
+ <parserDefinition language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.parser.BuildParserDefinition"/>
+ <namesValidator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.refactor.BuildNamesValidator"/>
+ <braceMatcher language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.formatting.BuildBraceMatcher"/>
+ <commenter language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.formatting.BuildCommenter"/>
+ <foldingBuilder language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.formatting.BuildFileFoldingBuilder"/>
+ <psiStructureViewFactory language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.views.BuildStructureViewFactory"/>
+ <findUsagesProvider language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.findusages.BuildFindUsagesProvider"/>
+ <refactoringSupport language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.refactor.BuildRefactoringSupportProvider"/>
+ <documentationProvider language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.documentation.BuildDocumentationProvider"/>
+ </extensions>
+
+ <extensionPoints>
+ <extensionPoint qualifiedName="com.google.idea.blaze.base.lang.buildfile.DumbAnnotator" interface="com.google.idea.blaze.base.lang.buildfile.validation.BuildAnnotator"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.base.lang.buildfile.Annotator" interface="com.google.idea.blaze.base.lang.buildfile.validation.BuildAnnotator"/>
+ </extensionPoints>
+
+ <application-components>
+ <component>
+ <implementation-class>com.google.idea.blaze.base.plugin.BlazeSpecificInitializer</implementation-class>
+ </component>
+ <component>
+ <implementation-class>com.google.idea.blaze.base.plugin.dependency.ProjectDependencyMigration</implementation-class>
+ </component>
+ <component>
+ <interface-class>com.google.idea.common.experiments.ExperimentService</interface-class>
+ <implementation-class>com.google.idea.blaze.base.experiments.BlazeExperimentService</implementation-class>
+ </component>
+ </application-components>
+
+ <extensionPoints>
+ <extensionPoint qualifiedName="com.google.idea.blaze.SyncListener" interface="com.google.idea.blaze.base.sync.SyncListener"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.SyncPlugin" interface="com.google.idea.blaze.base.sync.BlazeSyncPlugin"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.RuleConfigurationFactory" interface="com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.Prefetcher"
+ interface="com.google.idea.blaze.base.prefetch.Prefetcher"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.PrefetchFileSource"
+ interface="com.google.idea.blaze.base.prefetch.PrefetchFileSource"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.PsiFileProvider" interface="com.google.idea.blaze.base.lang.buildfile.search.PsiFileProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.VcsHandler"
+ interface="com.google.idea.blaze.base.vcs.BlazeVcsHandler"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazeWizardOptionProvider"
+ interface="com.google.idea.blaze.base.wizard2.BlazeWizardOptionProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.DefaultSdkProvider"
+ interface="com.google.idea.blaze.base.sync.sdk.DefaultSdkProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BuildFlagsProvider" interface="com.google.idea.blaze.base.command.BuildFlagsProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BuildSystemProvider" interface="com.google.idea.blaze.base.bazel.BuildSystemProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BuildifierBinaryProvider" interface="com.google.idea.blaze.base.buildmodifier.BuildifierBinaryProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.LoggingService" interface="com.google.idea.blaze.base.metrics.LoggingService"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazeCommandRunConfigurationHandlerProvider" interface="com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazeUserSettingsContributor" interface="com.google.idea.blaze.base.settings.ui.BlazeUserSettingsContributor$Provider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazePsiDirectoryRootNodeNameModifier" interface="com.google.idea.blaze.base.treeview.BlazePsiDirectoryRootNodeNameModifier"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.FileCache" interface="com.google.idea.blaze.base.filecache.FileCache"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.TestRuleHeuristic" interface="com.google.idea.blaze.base.run.TestRuleHeuristic"/>
+ </extensionPoints>
+
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncListener implementation="com.google.idea.blaze.base.run.BlazeRunConfigurationSyncListener"/>
+ <SyncListener implementation="com.google.idea.blaze.base.sync.status.BlazeSyncStatusListener"/>
+ <SyncListener implementation="com.google.idea.blaze.base.run.testmap.TestRuleFinderImpl$ClearTestMap"/>
+ <SyncListener implementation="com.google.idea.blaze.base.rulemaps.SourceToRuleMapImpl$ClearSourceToTargetMap"/>
+ <SyncListener implementation="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProviderImpl"/>
+ <SyncListener implementation="com.google.idea.blaze.base.run.BlazeCommandRunConfigurationUpdater"/>
+ <SyncPlugin implementation="com.google.idea.blaze.base.lang.buildfile.sync.BuildLangSyncPlugin"/>
+ <BlazeWizardOptionProvider implementation="com.google.idea.blaze.base.wizard2.BazelWizardOptionProvider"/>
+ <BuildFlagsProvider implementation="com.google.idea.blaze.base.command.BuildFlagsProviderImpl"/>
+ <VcsHandler implementation="com.google.idea.blaze.base.vcs.git.GitBlazeVcsHandler"/>
+ <VcsHandler implementation="com.google.idea.blaze.base.vcs.FallbackBlazeVcsHandler" order="last" id="fallback"/>
+ <BuildSystemProvider implementation="com.google.idea.blaze.base.bazel.BazelBuildSystemProvider" order="last"/>
+ <BuildifierBinaryProvider implementation="com.google.idea.blaze.base.buildmodifier.BazelBuildifierBinaryProvider"/>
+ <BlazeCommandRunConfigurationHandlerProvider implementation="com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandlerProvider" order="last"/>
+ <TestRuleHeuristic implementation="com.google.idea.blaze.base.run.RuleNameHeuristic" order="first"/>
+ <TestRuleHeuristic implementation="com.google.idea.blaze.base.run.TestSizeHeuristic" order="last" id="TestSizeHeuristic"/>
+ </extensions>
+
+</idea-plugin>
diff --git a/base/src/com/google/idea/blaze/base/actions/BlazeAction.java b/base/src/com/google/idea/blaze/base/actions/BlazeAction.java
new file mode 100644
index 0000000..ed31396
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeAction.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.actions;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import javax.swing.Icon;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Base class action that hides for non-blaze projects. */
+public abstract class BlazeAction extends AnAction {
+ protected BlazeAction() {}
+
+ protected BlazeAction(Icon icon) {
+ super(icon);
+ }
+
+ protected BlazeAction(@Nullable String text) {
+ super(text);
+ }
+
+ protected BlazeAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
+ super(text, description, icon);
+ }
+
+ @Override
+ public final void update(AnActionEvent e) {
+ if (!isBlazeProject(e)) {
+ e.getPresentation().setEnabledAndVisible(false);
+ return;
+ }
+
+ e.getPresentation().setEnabledAndVisible(true);
+ doUpdate(e);
+ }
+
+ protected void doUpdate(@NotNull AnActionEvent e) {}
+
+ private static boolean isBlazeProject(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ return project != null && Blaze.isBlazeProject(project);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/actions/BlazeCompileFileAction.java b/base/src/com/google/idea/blaze/base/actions/BlazeCompileFileAction.java
new file mode 100644
index 0000000..7a94e64
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeCompileFileAction.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.actions;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.experiments.ExperimentScope;
+import com.google.idea.blaze.base.filecache.FileCaches;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ScopedTask;
+import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.scope.scopes.NotificationScope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface.BuildResult;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.util.SaveUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+class BlazeCompileFileAction extends BlazeAction {
+ private static final Logger LOG = Logger.getInstance(BlazeCompileFileAction.class);
+
+ public BlazeCompileFileAction() {
+ super("Compile file");
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent e) {
+ // IntelliJ uses different logic for 1 vs many module selection. When many modules are selected
+ // modules with more than 1 content root are ignored
+ // (ProjectViewImpl#moduleBySingleContentRoot).
+ if (getTargets(e).isEmpty()) {
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabled(false);
+ }
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ ImmutableCollection<Label> targets = getTargets(e);
+ buildSourceFile(project, targets);
+ }
+ }
+
+ private ImmutableCollection<Label> getTargets(AnActionEvent e) {
+ Project project = e.getProject();
+ VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
+ if (project != null && virtualFile != null) {
+ return SourceToRuleMap.getInstance(project)
+ .getTargetsForSourceFile(new File(virtualFile.getPath()));
+ }
+ return ImmutableList.of();
+ }
+
+ private static void buildSourceFile(
+ @NotNull Project project, @NotNull ImmutableCollection<Label> targets) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null || targets.isEmpty()) {
+ return;
+ }
+ final ProjectViewSet projectViewSet =
+ ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return;
+ }
+ BlazeExecutor.submitTask(
+ project,
+ new ScopedTask() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ context
+ .push(new ExperimentScope())
+ .push(new BlazeConsoleScope.Builder(project).build())
+ .push(new IssuesScope(project))
+ .push(new IdeaLogScope())
+ .push(new TimingScope("Make"))
+ .push(new LoggedTimingScope(project, Action.MAKE_MODULE_TOTAL_TIME))
+ .push(
+ new NotificationScope(
+ project,
+ "Make",
+ "Make module",
+ "Make module completed successfully",
+ "Make module failed"));
+
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+
+ BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
+ List<TargetExpression> targetExpressions = Lists.newArrayList(targets);
+
+ SaveUtil.saveAllFiles();
+ BuildResult buildResult =
+ blazeIdeInterface.resolveIdeArtifacts(
+ project, context, workspaceRoot, projectViewSet, targetExpressions);
+ FileCaches.refresh(project);
+
+ if (buildResult != BuildResult.SUCCESS) {
+ context.setHasError();
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java b/base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java
new file mode 100644
index 0000000..64964c5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.actions;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.experiments.ExperimentScope;
+import com.google.idea.blaze.base.filecache.FileCaches;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ScopedTask;
+import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.scope.scopes.NotificationScope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface.BuildResult;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.util.SaveUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+class BlazeMakeProjectAction extends BlazeAction {
+
+ public BlazeMakeProjectAction() {
+ super("Make Project");
+ }
+
+ @Override
+ public final void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null && Blaze.isBlazeProject(project)) {
+ buildBlazeProject(project);
+ }
+ }
+
+ protected void buildBlazeProject(@NotNull final Project project) {
+
+ BlazeExecutor.submitTask(
+ project,
+ new ScopedTask() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ context
+ .push(new ExperimentScope())
+ .push(new BlazeConsoleScope.Builder(project).build())
+ .push(new IssuesScope(project))
+ .push(new IdeaLogScope())
+ .push(new TimingScope("Make"))
+ .push(new LoggedTimingScope(project, Action.MAKE_PROJECT_TOTAL_TIME))
+ .push(
+ new NotificationScope(
+ project,
+ "Make",
+ "Make project",
+ "Make project completed successfully",
+ "Make project failed"));
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return;
+ }
+ SaveUtil.saveAllFiles();
+
+ ProjectViewSet projectViewSet =
+ ProjectViewManager.getInstance(project)
+ .reloadProjectView(context, blazeProjectData.workspacePathResolver);
+ if (projectViewSet == null) {
+ return;
+ }
+
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+
+ List<TargetExpression> targets = Lists.newArrayList();
+ targets.addAll(projectViewSet.listItems(TargetSection.KEY));
+
+ BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
+
+ BuildResult buildResult =
+ blazeIdeInterface.resolveIdeArtifacts(
+ project, context, workspaceRoot, projectViewSet, targets);
+ FileCaches.refresh(project);
+
+ if (buildResult != BuildResult.SUCCESS) {
+ context.setHasError();
+ ;
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/actions/BlazeMenuGroup.java b/base/src/com/google/idea/blaze/base/actions/BlazeMenuGroup.java
new file mode 100644
index 0000000..dc10b88
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeMenuGroup.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.actions;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+
+/** The "Blaze" menu group, only visible in blaze mode */
+public class BlazeMenuGroup extends DefaultActionGroup {
+ @Override
+ public final void update(AnActionEvent e) {
+ if (!isBlazeProject(e)) {
+ e.getPresentation().setEnabledAndVisible(false);
+ return;
+ }
+
+ e.getPresentation().setEnabledAndVisible(true);
+ e.getPresentation().setText(Blaze.buildSystemName(e.getProject()));
+ }
+
+ @Override
+ public boolean isDumbAware() {
+ return true;
+ }
+
+ private static boolean isBlazeProject(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ return project != null && Blaze.isBlazeProject(project);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/actions/BlazeToggleAction.java b/base/src/com/google/idea/blaze/base/actions/BlazeToggleAction.java
new file mode 100644
index 0000000..0413761
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeToggleAction.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.actions;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.ToggleAction;
+import com.intellij.openapi.project.Project;
+import javax.swing.Icon;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Base class toggle action that hides for non-blaze projects. */
+public abstract class BlazeToggleAction extends ToggleAction {
+ protected BlazeToggleAction() {}
+
+ protected BlazeToggleAction(@Nullable String text) {
+ super(text);
+ }
+
+ protected BlazeToggleAction(
+ @Nullable String text, @Nullable String description, @Nullable Icon icon) {
+ super(text, description, icon);
+ }
+
+ @Override
+ public final void update(AnActionEvent e) {
+ if (!isBlazeProject(e)) {
+ e.getPresentation().setEnabledAndVisible(false);
+ return;
+ }
+
+ e.getPresentation().setEnabledAndVisible(true);
+ super.update(e);
+ doUpdate(e);
+ }
+
+ protected void doUpdate(@NotNull AnActionEvent e) {}
+
+ private static boolean isBlazeProject(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ return project != null && Blaze.isBlazeProject(project);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/AsyncUtil.java b/base/src/com/google/idea/blaze/base/async/AsyncUtil.java
new file mode 100644
index 0000000..153f995
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/AsyncUtil.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+
+/** Async utilities. */
+public class AsyncUtil {
+ public static void executeProjectChangeAction(@NotNull final Runnable task) throws Throwable {
+ final ValueHolder<Throwable> error = new ValueHolder<Throwable>();
+
+ executeOnEdt(
+ new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ task.run();
+ } catch (Throwable t) {
+ error.value = t;
+ }
+ }
+ });
+ }
+ });
+
+ if (error.value != null) {
+ throw error.value;
+ }
+ }
+
+ private static void executeOnEdt(@NotNull Runnable task) {
+ if (ApplicationManager.getApplication().isDispatchThread()) {
+ task.run();
+ } else {
+ UIUtil.invokeAndWaitIfNeeded(task);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/FutureUtil.java b/base/src/com/google/idea/blaze/base/async/FutureUtil.java
new file mode 100644
index 0000000..07f3e4e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/FutureUtil.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.intellij.openapi.diagnostic.Logger;
+import java.util.concurrent.ExecutionException;
+
+/** Utilities operating on futures. */
+public class FutureUtil {
+ /** The result of the future operation */
+ public static class FutureResult<T> {
+ private final T result;
+ private final boolean success;
+
+ FutureResult(T result) {
+ this.result = result;
+ this.success = true;
+ }
+
+ FutureResult() {
+ this.result = null;
+ this.success = false;
+ }
+
+ public T result() {
+ return result;
+ }
+
+ public boolean success() {
+ return success;
+ }
+ }
+
+ /** Builder for the future */
+ public static class Builder<T> {
+ private static final Logger LOG = Logger.getInstance(FutureUtil.class);
+ private final BlazeContext context;
+ private final ListenableFuture<T> future;
+ private String timingCategory;
+ private String errorMessage;
+ private String progressMessage;
+
+ Builder(BlazeContext context, ListenableFuture<T> future) {
+ this.context = context;
+ this.future = future;
+ }
+
+ public Builder<T> timed(String timingCategory) {
+ this.timingCategory = timingCategory;
+ return this;
+ }
+
+ public Builder<T> withProgressMessage(String message) {
+ this.progressMessage = message;
+ return this;
+ }
+
+ public Builder<T> onError(String errorMessage) {
+ this.errorMessage = errorMessage;
+ return this;
+ }
+
+ public FutureResult<T> run() {
+ return Scope.push(
+ context,
+ (childContext) -> {
+ if (timingCategory != null) {
+ childContext.push(new TimingScope(timingCategory));
+ }
+ if (progressMessage != null) {
+ childContext.output(new StatusOutput(progressMessage));
+ }
+ try {
+ return new FutureResult<>(future.get());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ context.setCancelled();
+ } catch (ExecutionException e) {
+ LOG.error(e);
+ if (errorMessage != null) {
+ IssueOutput.error(errorMessage).submit(childContext);
+ }
+ context.setHasError();
+ }
+ return new FutureResult<>();
+ });
+ }
+ }
+
+ public static <T> Builder<T> waitForFuture(BlazeContext context, ListenableFuture<T> future) {
+ return new Builder<>(context, future);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/ValueHolder.java b/base/src/com/google/idea/blaze/base/async/ValueHolder.java
new file mode 100644
index 0000000..6b73217
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/ValueHolder.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async;
+
+/** Simple wrapper to work around Java's final limitation. */
+public class ValueHolder<T> {
+ public T value;
+}
diff --git a/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java b/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java
new file mode 100644
index 0000000..f9eed17
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.executor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.progress.PerformInBackgroundOption;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Progressive;
+import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
+import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase;
+import com.intellij.openapi.progress.util.ProgressWindow;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.util.ui.UIUtil;
+import java.util.concurrent.Callable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Shared thread pool for blaze tasks. */
+public abstract class BlazeExecutor {
+ /** The type of modality used to launch tasks */
+ public enum Modality {
+ MODAL, // This task must start in the foreground and stay there.
+ BACKGROUNDABLE, // This task will start in the foreground, but can be sent to the background.
+ ALWAYS_BACKGROUND // This task will start in the background and stay there.
+ }
+
+ @NotNull
+ public static BlazeExecutor getInstance() {
+ return ServiceManager.getService(BlazeExecutor.class);
+ }
+
+ public abstract <T> ListenableFuture<T> submit(Callable<T> callable);
+
+ public abstract ListeningExecutorService getExecutor();
+
+ public static ListenableFuture<Void> submitTask(
+ @Nullable final Project project, @NotNull final Progressive progressive) {
+ return submitTask(project, "", progressive);
+ }
+
+ public static ListenableFuture<Void> submitTask(
+ @Nullable final Project project,
+ @NotNull final String title,
+ @NotNull final Progressive progressive) {
+ return submitTask(
+ project, title, true /* cancelable */, Modality.ALWAYS_BACKGROUND, progressive);
+ }
+
+ public static ListenableFuture<Void> submitTask(
+ @Nullable final Project project,
+ @NotNull final String title,
+ final boolean cancelable,
+ final Modality modality,
+ @NotNull final Progressive progressive) {
+
+ // The progress indicator must be created on the UI thread.
+ final ProgressWindow indicator =
+ UIUtil.invokeAndWaitIfNeeded(
+ new Computable<ProgressWindow>() {
+ @Override
+ public ProgressWindow compute() {
+ if (modality == Modality.MODAL) {
+ ProgressWindow indicator = new ProgressWindow(cancelable, project);
+ indicator.setTitle(title);
+ return indicator;
+ } else {
+ PerformInBackgroundOption backgroundOption =
+ modality == Modality.BACKGROUNDABLE
+ ? PerformInBackgroundOption.DEAF
+ : PerformInBackgroundOption.ALWAYS_BACKGROUND;
+ return new BackgroundableProcessIndicator(
+ project, title, backgroundOption, "Cancel", "Cancel", cancelable);
+ }
+ }
+ });
+
+ indicator.setIndeterminate(true);
+ indicator.start();
+ final Runnable process =
+ new Runnable() {
+ @Override
+ public void run() {
+ progressive.run(indicator);
+ }
+ };
+ final ListenableFuture<Void> future =
+ getInstance()
+ .submit(
+ new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ ProgressManager.getInstance().runProcess(process, indicator);
+ return null;
+ }
+ });
+ if (cancelable) {
+ indicator.addStateDelegate(
+ new AbstractProgressIndicatorExBase() {
+ @Override
+ public void cancel() {
+ super.cancel();
+ future.cancel(true);
+ }
+ });
+ }
+ return future;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutorImpl.java b/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutorImpl.java
new file mode 100644
index 0000000..92b0223
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutorImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.executor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+
+/** Executes blaze tasks on the an executor. */
+public class BlazeExecutorImpl extends BlazeExecutor {
+
+ private final ListeningExecutorService executorService =
+ MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(16));
+
+ @Override
+ public <T> ListenableFuture<T> submit(Callable<T> callable) {
+ return executorService.submit(callable);
+ }
+
+ @Override
+ public ListeningExecutorService getExecutor() {
+ return executorService;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/executor/TransientExecutor.java b/base/src/com/google/idea/blaze/base/async/executor/TransientExecutor.java
new file mode 100644
index 0000000..027b325
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/executor/TransientExecutor.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.executor;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/** An executor that grows to a finite number of threads and times them out quickly. */
+public class TransientExecutor extends ThreadPoolExecutor {
+ public TransientExecutor(int maxThreads) {
+ super(maxThreads, maxThreads, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+ allowCoreThreadTimeOut(true);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/process/ExternalTask.java b/base/src/com/google/idea/blaze/base/async/process/ExternalTask.java
new file mode 100644
index 0000000..86b7d50
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/process/ExternalTask.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.process;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.common.io.ByteStreams;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.util.SystemProperties;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import javax.annotation.Nullable;
+
+/** Invokes an external process */
+public class ExternalTask {
+ private static final Logger LOG = Logger.getInstance(ExternalTask.class);
+
+ static final OutputStream NULL_STREAM = ByteStreams.nullOutputStream();
+
+ /** Builder for an external task */
+ public static class Builder {
+ private final ImmutableList.Builder<String> command = ImmutableList.builder();
+ private final File workingDirectory;
+ private final Map<String, String> environmentVariables = Maps.newHashMap();
+ @Nullable private BlazeContext context;
+ @Nullable private OutputStream stdout;
+ @Nullable private OutputStream stderr;
+ boolean redirectErrorStream = false;
+
+ private Builder(WorkspaceRoot workspaceRoot) {
+ this(workspaceRoot.directory());
+ }
+
+ private Builder(File workingDirectory) {
+ this.workingDirectory = workingDirectory;
+ }
+
+ public Builder arg(String arg) {
+ command.add(arg);
+ return this;
+ }
+
+ public Builder args(String... args) {
+ command.add(args);
+ return this;
+ }
+
+ public Builder args(Collection<String> args) {
+ command.addAll(args);
+ return this;
+ }
+
+ public Builder args(Stream<String> args) {
+ command.addAll(args.iterator());
+ return this;
+ }
+
+ public Builder addBlazeCommand(BlazeCommand command) {
+ this.command.addAll(command.toList());
+ return this;
+ }
+
+ public Builder maybeArg(boolean b, String arg) {
+ if (b) {
+ command.add(arg);
+ }
+ return this;
+ }
+
+ public Builder context(@Nullable BlazeContext context) {
+ this.context = context;
+ return this;
+ }
+
+ public Builder redirectStderr(boolean redirectStderr) {
+ this.redirectErrorStream = redirectStderr;
+ return this;
+ }
+
+ public Builder stdout(@Nullable OutputStream stdout) {
+ this.stdout = stdout;
+ return this;
+ }
+
+ public Builder stderr(@Nullable OutputStream stderr) {
+ this.stderr = stderr;
+ return this;
+ }
+
+ public Builder environmentVar(String key, String value) {
+ environmentVariables.put(key, value);
+ return this;
+ }
+
+ public Builder environmentVars(Map<String, String> values) {
+ environmentVariables.putAll(values);
+ return this;
+ }
+
+ public ExternalTask build() {
+ return new ExternalTask(
+ context,
+ workingDirectory,
+ command.build(),
+ environmentVariables,
+ stdout,
+ stderr,
+ redirectErrorStream);
+ }
+ }
+
+ private final File workingDirectory;
+
+ private final List<String> command;
+
+ private final Map<String, String> environmentVariables;
+
+ @Nullable private final BlazeContext parentContext;
+
+ private final boolean redirectErrorStream;
+
+ private final OutputStream stdout;
+
+ private final OutputStream stderr;
+
+ private ExternalTask(
+ @Nullable BlazeContext context,
+ File workingDirectory,
+ List<String> command,
+ Map<String, String> environmentVariables,
+ @Nullable OutputStream stdout,
+ @Nullable OutputStream stderr,
+ boolean redirectErrorStream) {
+ this.workingDirectory = workingDirectory;
+ this.command = command;
+ this.environmentVariables = environmentVariables;
+ this.parentContext = context;
+ this.redirectErrorStream = redirectErrorStream;
+ this.stdout = stdout != null ? stdout : NULL_STREAM;
+ this.stderr = stderr != null ? stderr : NULL_STREAM;
+ }
+
+ public int run(BlazeScope... scopes) {
+ Integer returnValue =
+ Scope.push(
+ parentContext,
+ context -> {
+ for (BlazeScope scope : scopes) {
+ context.push(scope);
+ }
+ try {
+ return invokeCommand(context);
+ } catch (ProcessCanceledException e) {
+ // Logging a ProcessCanceledException is an IJ error - mark context canceled instead
+ context.setCancelled();
+ }
+ return -1;
+ });
+ return returnValue != null ? returnValue : -1;
+ }
+
+ private static void closeQuietly(OutputStream stream) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ Throwables.propagate(e);
+ }
+ }
+
+ private int invokeCommand(BlazeContext context) {
+ String executingTasksText =
+ "Command: "
+ + Joiner.on(" ").join(command)
+ + SystemProperties.getLineSeparator()
+ + SystemProperties.getLineSeparator();
+
+ context.output(PrintOutput.log(executingTasksText));
+
+ try {
+ if (context.isEnding()) {
+ return -1;
+ }
+ ProcessBuilder builder =
+ new ProcessBuilder()
+ .command(command)
+ .redirectErrorStream(redirectErrorStream)
+ .directory(workingDirectory);
+ for (Map.Entry<String, String> entry : environmentVariables.entrySet()) {
+ builder.environment().put(entry.getKey(), entry.getValue());
+ }
+
+ try {
+ final Process process = builder.start();
+ Thread shutdownHook = new Thread(process::destroy);
+ try {
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+ Thread stdoutThread = ProcessUtil.forwardAsync(process.getInputStream(), stdout);
+ Thread stderrThread = null;
+ if (!redirectErrorStream) {
+ stderrThread = ProcessUtil.forwardAsync(process.getErrorStream(), stderr);
+ }
+ process.waitFor();
+ stdoutThread.join();
+ if (!redirectErrorStream) {
+ stderrThread.join();
+ }
+ int exitValue = process.exitValue();
+ if (exitValue != 0) {
+ context.setHasError();
+ }
+ return exitValue;
+ } catch (InterruptedException e) {
+ process.destroy();
+ throw new ProcessCanceledException();
+ } finally {
+ try {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ } catch (IllegalStateException e) {
+ // we can't remove a shutdown hook if we are shutting down, do nothing about it
+ }
+ }
+ } catch (IOException e) {
+ LOG.warn(e);
+ IssueOutput.error(e.getMessage()).submit(context);
+ }
+ } finally {
+ closeQuietly(stdout);
+ closeQuietly(stderr);
+ }
+ return -1;
+ }
+
+ public static Builder builder() {
+ return new Builder(new File("/"));
+ }
+
+ public static Builder builder(List<String> command) {
+ return builder().args(command);
+ }
+
+ public static Builder builder(File workingDirectory) {
+ return new Builder(workingDirectory);
+ }
+
+ public static Builder builder(WorkspaceRoot workspaceRoot) {
+ return new Builder(workspaceRoot);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java b/base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java
new file mode 100644
index 0000000..8aa44a8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.process;
+
+import com.google.common.collect.Lists;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** An base output stream which marshals output into newline-delimited segments for processing. */
+public final class LineProcessingOutputStream extends OutputStream {
+
+ /** A line processor */
+ public interface LineProcessor {
+ /**
+ * Process a single, complete line of output.
+ *
+ * @return Whether line processing should continue
+ */
+ boolean processLine(@NotNull String line);
+ }
+
+ @NotNull private final StringBuffer stringBuffer = new StringBuffer();
+ private volatile boolean closed;
+ @NotNull private final List<LineProcessor> lineProcessors;
+
+ LineProcessingOutputStream(@NotNull LineProcessor... lineProcessors) {
+ this.lineProcessors = Lists.newArrayList(lineProcessors);
+ }
+
+ public static LineProcessingOutputStream of(@NotNull LineProcessor... lineProcessors) {
+ return new LineProcessingOutputStream(lineProcessors);
+ }
+
+ @Override
+ public synchronized void write(byte[] b, int off, int len) {
+ if (!closed) {
+ String text = new String(b, off, len);
+ stringBuffer.append(text);
+
+ while (true) {
+ int lineBreakIndex = -1;
+ int lineBreakLength = 0;
+ for (int i = 0; i < stringBuffer.length(); ++i) {
+ char c = stringBuffer.charAt(i);
+ if (c == '\r' || c == '\n') {
+ lineBreakIndex = i;
+ lineBreakLength = 1;
+ if (c == '\r'
+ && (i + 1) < stringBuffer.length()
+ && stringBuffer.charAt(i + 1) == '\n') {
+ ++lineBreakLength;
+ }
+ break;
+ }
+ }
+
+ if (lineBreakIndex == -1) {
+ return;
+ }
+
+ String line = stringBuffer.substring(0, lineBreakIndex);
+
+ stringBuffer.delete(0, lineBreakIndex + lineBreakLength);
+
+ for (LineProcessor lineProcessor : lineProcessors) {
+ if (!lineProcessor.processLine(line)) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ write(new byte[] {(byte) b}, 0, 1);
+ }
+
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ super.close();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/process/PrintOutputLineProcessor.java b/base/src/com/google/idea/blaze/base/async/process/PrintOutputLineProcessor.java
new file mode 100644
index 0000000..30b3dd2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/process/PrintOutputLineProcessor.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.process;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import org.jetbrains.annotations.NotNull;
+
+/** Simple adapter between stdout and context print output. */
+public class PrintOutputLineProcessor implements LineProcessingOutputStream.LineProcessor {
+ private final BlazeContext context;
+
+ public PrintOutputLineProcessor(BlazeContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public boolean processLine(@NotNull String line) {
+ context.output(PrintOutput.output(line));
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/async/process/ProcessUtil.java b/base/src/com/google/idea/blaze/base/async/process/ProcessUtil.java
new file mode 100644
index 0000000..01b02b7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/async/process/ProcessUtil.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.process;
+
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+class ProcessUtil {
+ private static final Logger LOG = Logger.getInstance(ProcessUtil.class);
+
+ public static Thread forwardAsync(final InputStream input, final OutputStream output) {
+ Thread thread =
+ new Thread(
+ new Runnable() {
+ @Override
+ public void run() {
+ int bufferSize = 4096;
+ byte[] buffer = new byte[bufferSize];
+
+ int read = 0;
+ try {
+ read = input.read(buffer);
+ while (read != -1) {
+ output.write(buffer, 0, read);
+ read = input.read(buffer);
+ }
+ } catch (IOException e) {
+ LOG.warn("Error redirecting output", e);
+ }
+ }
+ });
+ thread.start();
+ return thread;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java b/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
new file mode 100644
index 0000000..a3cee43
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.bazel;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import javax.annotation.Nullable;
+
+/** Provides the bazel build system name string. */
+public class BazelBuildSystemProvider implements BuildSystemProvider {
+ @Override
+ public BuildSystem buildSystem() {
+ return BuildSystem.Bazel;
+ }
+
+ @Override
+ public WorkspaceRootProvider getWorkspaceRootProvider() {
+ return BazelWorkspaceRootProvider.INSTANCE;
+ }
+
+ @Override
+ public ImmutableList<String> buildArtifactDirectories(WorkspaceRoot root) {
+ String rootDir = root.directory().getName();
+ return ImmutableList.of(
+ "bazel-bin", "bazel-genfiles", "bazel-out", "bazel-testlogs", "bazel-" + rootDir);
+ }
+
+ @Nullable
+ @Override
+ public String getRuleDocumentationUrl(RuleDefinition rule) {
+ // TODO: URL pointing to specific BUILD rule.
+ return "http://www.bazel.io/docs/be/overview.html";
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/bazel/BazelWorkspaceRootProvider.java b/base/src/com/google/idea/blaze/base/bazel/BazelWorkspaceRootProvider.java
new file mode 100644
index 0000000..5167721
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/bazel/BazelWorkspaceRootProvider.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.bazel;
+
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Implementation of WorkspaceHelper. */
+public class BazelWorkspaceRootProvider implements WorkspaceRootProvider {
+
+ public static final BazelWorkspaceRootProvider INSTANCE = new BazelWorkspaceRootProvider();
+
+ private BazelWorkspaceRootProvider() {}
+
+ /** Checks for the existence of a WORKSPACE file in the given directory. */
+ @Override
+ public boolean isWorkspaceRoot(File file) {
+ return FileAttributeProvider.getInstance().isFile(new File(file, "WORKSPACE"));
+ }
+
+ @Nullable
+ @Override
+ public WorkspaceRoot findWorkspaceRoot(File file) {
+ while (file != null) {
+ if (isWorkspaceRoot(file)) {
+ return new WorkspaceRoot(file);
+ }
+ file = file.getParentFile();
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java b/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
new file mode 100644
index 0000000..42bd43b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.bazel;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import javax.annotation.Nullable;
+
+/**
+ * Extension points specify the build systems supported by this plugin.<br>
+ * The order of the extension points establishes a priority (highest priority first), for situations
+ * where we don't have an existing project to use for context (e.g. the 'import project' action).
+ */
+public interface BuildSystemProvider {
+
+ ExtensionPointName<BuildSystemProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BuildSystemProvider");
+
+ static BuildSystemProvider defaultBuildSystem() {
+ return EP_NAME.getExtensions()[0];
+ }
+
+ @Nullable
+ static BuildSystemProvider getBuildSystemProvider(BuildSystem buildSystem) {
+ for (BuildSystemProvider provider : EP_NAME.getExtensions()) {
+ if (provider.buildSystem() == buildSystem) {
+ return provider;
+ }
+ }
+ return null;
+ }
+
+ static boolean isBuildSystemAvailable(BuildSystem buildSystem) {
+ return getBuildSystemProvider(buildSystem) != null;
+ }
+
+ static WorkspaceRootProvider getWorkspaceRootProvider(BuildSystem buildSystem) {
+ BuildSystemProvider provider = getBuildSystemProvider(buildSystem);
+ if (provider == null) {
+ throw new RuntimeException(
+ String.format("Build system '%s' not supported by this plugin", buildSystem));
+ }
+ return provider.getWorkspaceRootProvider();
+ }
+
+ static BuildSystemProvider getInstance() {
+ return ServiceManager.getService(BuildSystemProvider.class);
+ }
+
+ /**
+ * Returns the default build system for this application. This should only be called in situations
+ * where it doesn't make sense to use the current project.<br>
+ * Otherwise, use {@link com.google.idea.blaze.base.settings.Blaze#getBuildSystem}
+ */
+ BuildSystem buildSystem();
+
+ WorkspaceRootProvider getWorkspaceRootProvider();
+
+ /** Directories containing artifacts produced during the build process. */
+ ImmutableList<String> buildArtifactDirectories(WorkspaceRoot root);
+
+ /** The URL providing the built-in BUILD rule's documentation, if one can be found. */
+ @Nullable
+ String getRuleDocumentationUrl(RuleDefinition rule);
+}
diff --git a/base/src/com/google/idea/blaze/base/bazel/WorkspaceRootProvider.java b/base/src/com/google/idea/blaze/base/bazel/WorkspaceRootProvider.java
new file mode 100644
index 0000000..d0604a1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/bazel/WorkspaceRootProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.bazel;
+
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Utility methods for working with workspace paths. */
+public interface WorkspaceRootProvider {
+
+ /** Checks whether the given directory is a valid workspace root. */
+ boolean isWorkspaceRoot(File file);
+
+ /**
+ * Checks whether the file or one of its ancestors is a valid workspace root.<br>
+ * This should only be called when no Project is available. Otherwise, use
+ * WorkspaceRoot.isInWorkspace.
+ */
+ default boolean isInWorkspace(File file) {
+ return findWorkspaceRoot(file) != null;
+ }
+
+ /**
+ * If the given file is inside a workspace, returns the workspace root. Otherwise returns null.
+ */
+ @Nullable
+ WorkspaceRoot findWorkspaceRoot(File file);
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmap/FileToBuildMap.java b/base/src/com/google/idea/blaze/base/buildmap/FileToBuildMap.java
new file mode 100644
index 0000000..55020f8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmap/FileToBuildMap.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmap;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/** Map of file -> BUILD files. */
+public class FileToBuildMap {
+ private final Project project;
+
+ public static FileToBuildMap getInstance(Project project) {
+ return ServiceManager.getService(project, FileToBuildMap.class);
+ }
+
+ public FileToBuildMap(Project project) {
+ this.project = project;
+ }
+
+ public Collection<File> getBuildFilesForFile(File file) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return ImmutableList.of();
+ }
+ return SourceToRuleMap.getInstance(project)
+ .getTargetsForSourceFile(file)
+ .stream()
+ .map(blazeProjectData.ruleMap::get)
+ .filter(Objects::nonNull)
+ .map((ruleIdeInfo) -> ruleIdeInfo.buildFile)
+ .filter(Objects::nonNull)
+ .map(ArtifactLocation::getFile)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmap/OpenCorrespondingBuildFile.java b/base/src/com/google/idea/blaze/base/buildmap/OpenCorrespondingBuildFile.java
new file mode 100644
index 0000000..2754da2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmap/OpenCorrespondingBuildFile.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmap;
+
+import com.google.common.collect.Iterables;
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.metrics.LoggingService;
+import com.intellij.ide.actions.OpenFileAction;
+import com.intellij.openapi.actionSystem.ActionPlaces;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+import java.util.Collection;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class OpenCorrespondingBuildFile extends BlazeAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
+ File file = getBuildFile(project, virtualFile);
+ if (file == null) {
+ return;
+ }
+ OpenFileAction.openFile(file.getPath(), project);
+ LoggingService.reportEvent(project, Action.OPEN_CORRESPONDING_BUILD_FILE);
+ }
+
+ @Nullable
+ private File getBuildFile(@Nullable Project project, @Nullable VirtualFile virtualFile) {
+ if (project == null) {
+ return null;
+ }
+ if (virtualFile == null) {
+ return null;
+ }
+ File file = new File(virtualFile.getPath());
+ Collection<File> fileInfoList = FileToBuildMap.getInstance(project).getBuildFilesForFile(file);
+ return Iterables.getFirst(fileInfoList, null);
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ DataContext dataContext = e.getDataContext();
+ VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ boolean visible = (project != null && virtualFile != null);
+ boolean enabled = getBuildFile(project, virtualFile) != null;
+ presentation.setVisible(visible || ActionPlaces.isMainMenuOrActionSearch(e.getPlace()));
+ presentation.setEnabled(enabled);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/BazelBuildifierBinaryProvider.java b/base/src/com/google/idea/blaze/base/buildmodifier/BazelBuildifierBinaryProvider.java
new file mode 100644
index 0000000..25079b2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/BazelBuildifierBinaryProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import com.google.idea.blaze.base.util.BlazeHelperBinaryUtil;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Provides the bazel buildifier binary. */
+public class BazelBuildifierBinaryProvider implements BuildifierBinaryProvider {
+
+ private static final String BASE = "/";
+ private static final String BUILDIFIER_BINARY_PATH =
+ BASE + "base/resources/binaries/bazel-buildifier";
+
+ @Nullable
+ @Override
+ public File getBuildifierBinary() {
+ return BlazeHelperBinaryUtil.getBlazeHelperBinary(BUILDIFIER_BINARY_PATH);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/BuildFileFormatter.java b/base/src/com/google/idea/blaze/base/buildmodifier/BuildFileFormatter.java
new file mode 100644
index 0000000..5875466
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/BuildFileFormatter.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import javax.annotation.Nullable;
+
+/** Formats BUILD files using 'buildifier' */
+public class BuildFileFormatter {
+
+ @Nullable
+ private static File getBuildifierBinary() {
+ for (BuildifierBinaryProvider provider : BuildifierBinaryProvider.EP_NAME.getExtensions()) {
+ File file = provider.getBuildifierBinary();
+ if (file != null) {
+ return file;
+ }
+ }
+ return null;
+ }
+
+ static String formatText(String text) {
+ try {
+ File buildifierBinary = getBuildifierBinary();
+ if (buildifierBinary == null) {
+ return null;
+ }
+ File file = createTempFile(text);
+ formatFile(file, buildifierBinary.getPath());
+ String formattedFile = readFile(file);
+ file.delete();
+ return formattedFile;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return text;
+ }
+
+ private static void formatFile(File file, String buildifierBinaryPath) throws IOException {
+ ProcessBuilder builder = new ProcessBuilder(buildifierBinaryPath, file.getAbsolutePath());
+ try {
+ builder.start().waitFor();
+ } catch (InterruptedException e) {
+ throw new IOException("buildifier execution failed", e);
+ }
+ }
+
+ private static String readFile(File file) throws IOException {
+ try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+ StringBuilder formattedFile = new StringBuilder();
+ char[] buf = new char[1024];
+ int numRead;
+ while ((numRead = reader.read(buf)) >= 0) {
+ formattedFile.append(buf, 0, numRead);
+ }
+ return formattedFile.toString();
+ }
+ }
+
+ private static File createTempFile(String text) throws IOException {
+ File file = File.createTempFile("ijwb", ".tmp");
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ writer.write(text);
+ }
+ return file;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/BuildFileModifier.java b/base/src/com/google/idea/blaze/base/buildmodifier/BuildFileModifier.java
new file mode 100644
index 0000000..ff20220
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/BuildFileModifier.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+
+/** Abstraction to modify build files, eg. using buildifier */
+public interface BuildFileModifier {
+
+ static BuildFileModifier getInstance() {
+ return ServiceManager.getService(BuildFileModifier.class);
+ }
+
+ /**
+ * Add a new rule to a build file. The rule name and rule kind must be validated before this
+ * method, but no guarantees are made about actually being able to add this rule to the build
+ * file. An example of why it might fail is the build file might already have a rule with the
+ * requested name.
+ *
+ * @param context Blaze context to operate in
+ * @param newRule new rule to create
+ * @param ruleKind valid kind of rule (android_library, java_library, etc.)
+ * @return true if rule is added to file, false otherwise
+ */
+ boolean addRule(
+ Project project, final BlazeContext context, final Label newRule, final Kind ruleKind);
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierBinaryProvider.java b/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierBinaryProvider.java
new file mode 100644
index 0000000..cb37261
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierBinaryProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Provides a buildifier binary. */
+public interface BuildifierBinaryProvider {
+
+ ExtensionPointName<BuildifierBinaryProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BuildifierBinaryProvider");
+
+ @Nullable
+ File getBuildifierBinary();
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/FileSaveHandler.java b/base/src/com/google/idea/blaze/base/buildmodifier/FileSaveHandler.java
new file mode 100644
index 0000000..02aa3f2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/FileSaveHandler.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.DocumentRunnable;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Runs the buildifier command on file save. */
+public class FileSaveHandler extends FileDocumentManagerAdapter {
+
+ @Override
+ public void beforeDocumentSaving(final Document document) {
+ if (!document.isWritable()) {
+ return;
+ }
+ FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+ VirtualFile file = fileDocumentManager.getFile(document);
+ if (file == null || !file.isValid()) {
+ return;
+ }
+
+ if (!isBuildFile(file)) {
+ return;
+ }
+ int lines = document.getLineCount();
+ if (lines > 0) {
+ String text = document.getText();
+ String formattedText = BuildFileFormatter.formatText(text);
+ updateDocument(document, formattedText);
+ }
+ }
+
+ private void updateDocument(final Document document, final String formattedContent) {
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ new DocumentRunnable(document, null) {
+ @Override
+ public void run() {
+ CommandProcessor.getInstance()
+ .runUndoTransparentAction(() -> document.setText(formattedContent));
+ }
+ });
+ }
+
+ private static boolean isBuildFile(VirtualFile file) {
+ return file.getName().equals("BUILD");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
new file mode 100644
index 0000000..f3586a2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Modifies the file system. Interface so we can mock it in tests */
+public abstract class FileSystemModifier {
+
+ public static FileSystemModifier getInstance(@NotNull Project project) {
+ return ServiceManager.getService(project, FileSystemModifier.class);
+ }
+
+ @Nullable
+ public abstract File makeWorkspacePathDirs(@NotNull WorkspacePath workspacePath);
+
+ @Nullable
+ public abstract File createFile(@NotNull WorkspacePath parentDir, @NotNull String name);
+}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
new file mode 100644
index 0000000..0d398f9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.buildmodifier;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.io.IOException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class FileSystemModifierImpl extends FileSystemModifier {
+
+ private final Project project;
+
+ public FileSystemModifierImpl(@NotNull Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public File makeWorkspacePathDirs(@NotNull WorkspacePath workspacePath) {
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ File dir = workspaceRoot.fileForPath(workspacePath);
+ boolean success = dir.mkdirs();
+ return success ? dir : null;
+ }
+
+ @Nullable
+ @Override
+ public File createFile(@NotNull WorkspacePath parentDirectory, @NotNull String name) {
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ File dir = workspaceRoot.fileForPath(parentDirectory);
+ File f = new File(dir, name);
+ boolean success;
+ try {
+ success = f.createNewFile();
+ } catch (IOException e) {
+ success = false;
+ }
+ return success ? f : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/BlazeCommand.java b/base/src/com/google/idea/blaze/base/command/BlazeCommand.java
new file mode 100644
index 0000000..a337472
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/BlazeCommand.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/** A command to issue to Blaze/Bazel on the command line. */
+@Immutable
+public final class BlazeCommand {
+
+ private final BuildSystem buildSystem;
+ private final BlazeCommandName name;
+ @Nullable private final String blazeBinary;
+ private final ImmutableList<String> arguments;
+
+ private BlazeCommand(
+ BuildSystem buildSystem,
+ BlazeCommandName name,
+ @Nullable String blazeBinary,
+ ImmutableList<String> arguments) {
+ this.buildSystem = buildSystem;
+ this.name = name;
+ this.blazeBinary = blazeBinary;
+ this.arguments = arguments;
+ }
+
+ public BlazeCommandName getName() {
+ return name;
+ }
+
+ public ImmutableList<String> toList() {
+ String blazeBinary = this.blazeBinary;
+ if (blazeBinary == null) {
+ blazeBinary = getBinaryPath(buildSystem);
+ }
+
+ ImmutableList.Builder<String> commandLine = ImmutableList.builder();
+ commandLine.add(blazeBinary, name.toString());
+ commandLine.addAll(arguments);
+ return commandLine.build();
+ }
+
+ private static String getBinaryPath(BuildSystem buildSystem) {
+ BlazeUserSettings settings = BlazeUserSettings.getInstance();
+ switch (buildSystem) {
+ case Blaze:
+ return settings.getBlazeBinaryPath();
+ case Bazel:
+ return settings.getBazelBinaryPath();
+ default:
+ throw new RuntimeException("Unrecognized build system type: " + buildSystem);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Joiner.on(' ').join(toList());
+ }
+
+ public static Builder builder(BuildSystem buildSystem, BlazeCommandName name) {
+ return new Builder(buildSystem, name);
+ }
+
+ /** Builder for a blaze command */
+ public static class Builder {
+ private final BuildSystem buildSystem;
+ private final BlazeCommandName name;
+ @Nullable private String blazeBinary;
+ private final ImmutableList.Builder<TargetExpression> targets = ImmutableList.builder();
+ private final ImmutableList.Builder<String> blazeFlags = ImmutableList.builder();
+ private final ImmutableList.Builder<String> exeFlags = ImmutableList.builder();
+
+ public Builder(BuildSystem buildSystem, BlazeCommandName name) {
+ this.buildSystem = buildSystem;
+ this.name = name;
+ // Tell forge what tool we used to call blaze so we can track usage.
+ addBlazeFlags(BlazeFlags.getToolTagFlag());
+ }
+
+ public BlazeCommand build() {
+ ImmutableList.Builder<String> arguments = ImmutableList.builder();
+ arguments.addAll(blazeFlags.build());
+ arguments.add("--");
+
+ // Trust the user's ordering of the targets since order matters to blaze
+ for (TargetExpression targetExpression : targets.build()) {
+ arguments.add(targetExpression.toString());
+ }
+
+ arguments.addAll(exeFlags.build());
+ return new BlazeCommand(buildSystem, name, blazeBinary, arguments.build());
+ }
+
+ public Builder setBlazeBinary(@Nullable String blazeBinary) {
+ this.blazeBinary = blazeBinary;
+ return this;
+ }
+
+ public Builder addTargets(TargetExpression... targets) {
+ return this.addTargets(Arrays.asList(targets));
+ }
+
+ public Builder addTargets(List<? extends TargetExpression> targets) {
+ this.targets.addAll(targets);
+ return this;
+ }
+
+ public Builder addExeFlags(String... flags) {
+ return addExeFlags(Arrays.asList(flags));
+ }
+
+ public Builder addExeFlags(List<String> flags) {
+ this.exeFlags.addAll(flags);
+ return this;
+ }
+
+ public Builder addBlazeFlags(String... flags) {
+ return addBlazeFlags(Arrays.asList(flags));
+ }
+
+ public Builder addBlazeFlags(List<String> flags) {
+ this.blazeFlags.addAll(flags);
+ return this;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/BlazeCommandName.java b/base/src/com/google/idea/blaze/base/command/BlazeCommandName.java
new file mode 100644
index 0000000..f753198
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/BlazeCommandName.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentMap;
+import javax.annotation.concurrent.Immutable;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A class for Blaze/Bazel command names. We enumerate the commands we use (and that we expect users
+ * to be interested in), but do NOT use an enum because we want to allow users to specify arbitrary
+ * commands.
+ */
+@Immutable
+public final class BlazeCommandName {
+ @NotNull
+ private static final ConcurrentMap<String, BlazeCommandName> knownCommands =
+ Maps.newConcurrentMap();
+
+ public static final BlazeCommandName BUILD = fromString("build");
+ public static final BlazeCommandName TEST = fromString("test");
+ public static final BlazeCommandName MOBILE_INSTALL = fromString("mobile-install");
+ public static final BlazeCommandName RUN = fromString("run");
+ public static final BlazeCommandName QUERY = fromString("query");
+ public static final BlazeCommandName INFO = fromString("info");
+
+ public static BlazeCommandName fromString(@NotNull String name) {
+ knownCommands.putIfAbsent(name, new BlazeCommandName(name));
+ return knownCommands.get(name);
+ }
+
+ private final String name;
+
+ private BlazeCommandName(@NotNull String name) {
+ Preconditions.checkArgument(!name.isEmpty(), "Command should be non-empty.");
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof BlazeCommandName)) {
+ return false;
+ }
+ BlazeCommandName that = (BlazeCommandName) o;
+ return name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ /**
+ * @return An unmodifiable view of the Blaze commands we know about (including those that the user
+ * has specified, in addition to those we have hard-coded).
+ */
+ @NotNull
+ public static Collection<BlazeCommandName> knownCommands() {
+ return ImmutableList.copyOf(knownCommands.values());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/BlazeFlags.java b/base/src/com/google/idea/blaze/base/command/BlazeFlags.java
new file mode 100644
index 0000000..f4a84d8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/BlazeFlags.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.sections.BuildFlagsSection;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.PlatformUtils;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** The collection of all the Bazel flag strings we use. */
+public final class BlazeFlags {
+
+ // Build the maximum number of possible dependencies of the project and to show all the build
+ // errors in single go.
+ public static final String KEEP_GOING = "--keep_going";
+ // Tells Blaze to open a debug port and wait for a connection while running tests
+ // It expands to: --test_arg=--wrapper_script_flag=--debug --test_output=streamed
+ // --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
+ public static final String JAVA_TEST_DEBUG = "--java_debug";
+ // Tells the Java wrapper stub to launch JVM in remote debugging mode, waiting for a connection
+ public static final String JAVA_BINARY_DEBUG = "--debug";
+ // Runs tests locally, in sequence (rather than parallel), and streams their results to stdout.
+ public static final String TEST_OUTPUT_STREAMED = "--test_output=streamed";
+ // Filters the unit tests that are run (used with regexp for Java/Robolectric tests).
+ public static final String TEST_FILTER = "--test_filter";
+ // Skips checking for output file modifications (reduced statting -> faster).
+ public static final String NO_CHECK_OUTPUTS = "--noexperimental_check_output_files";
+ // Ignores implicit dependencies (e.g. java_library rules depending implicitly on
+ // "//transconsole/tools:aggregate_messages" in order to support translations).
+ public static final String NO_IMPLICIT_DEPS = "--noimplicit_deps";
+ // Ignores host dependencies.
+ public static final String NO_HOST_DEPS = "--nohost_deps";
+ // When used with mobile-install, deploys the an app incrementally.
+ public static final String INCREMENTAL = "--incremental";
+ // When used with mobile-install, deploys the an app incrementally
+ // can be used for API 23 or higher, for which it is preferred to --incremental
+ public static final String SPLIT_APKS = "--split_apks";
+ // Re-run the test even if the results are cached.
+ public static final String NO_CACHE_TEST_RESULTS = "--nocache_test_results";
+ // Avoids node GC between ide_build_info and blaze build
+ public static final String VERSION_WINDOW_FOR_DIRTY_NODE_GC =
+ "--version_window_for_dirty_node_gc=-1";
+
+ public static final String EXPERIMENTAL_SHOW_ARTIFACTS = "--experimental_show_artifacts";
+
+ public static List<String> buildFlags(Project project, ProjectViewSet projectViewSet) {
+ BuildSystem buildSystem = Blaze.getBuildSystem(project);
+ List<String> flags = Lists.newArrayList();
+ for (BuildFlagsProvider buildFlagsProvider : BuildFlagsProvider.EP_NAME.getExtensions()) {
+ buildFlagsProvider.addBuildFlags(buildSystem, projectViewSet, flags);
+ }
+ flags.addAll(projectViewSet.listItems(BuildFlagsSection.KEY));
+ return flags;
+ }
+
+ // Pass-through arg for sending adb options during mobile-install.
+ public static final String ADB_ARG = "--adb_arg=";
+
+ public static ImmutableList<String> adbSerialFlags(String serial) {
+ return ImmutableList.of(ADB_ARG + "-s ", ADB_ARG + serial);
+ }
+
+ // Pass-through arg for sending test arguments.
+ public static final String TEST_ARG = "--test_arg=";
+
+ private static final String TOOL_TAG = "--tool_tag=ijwb:";
+
+ // We add this to every single BlazeCommand instance. It's for tracking usage.
+ public static String getToolTagFlag() {
+ String platformPrefix = PlatformUtils.getPlatformPrefix();
+
+ // IDEA Community Edition is "Idea", whereas IDEA Ultimate Edition is "idea".
+ // That's dumb. Let's make them more useful.
+ if (PlatformUtils.isIdeaCommunity()) {
+ platformPrefix = "IDEA:community";
+ } else if (PlatformUtils.isIdeaUltimate()) {
+ platformPrefix = "IDEA:ultimate";
+ }
+ return TOOL_TAG + platformPrefix;
+ }
+
+ public static String testFilterFlagForClass(String className) {
+ return testFilterFlagForClassAndMethod(className, null);
+ }
+
+ public static String testFilterFlagForClassAndMethod(
+ String className, @Nullable String methodName) {
+ StringBuilder output = new StringBuilder(TEST_FILTER);
+ output.append('=');
+ output.append(className);
+
+ if (!Strings.isNullOrEmpty(methodName)) {
+ output.append('#');
+ output.append(methodName);
+ }
+
+ return output.toString();
+ }
+
+ public static String testFilterFlagForClassAndMethods(
+ String className, Collection<String> methodNames, boolean isJUnit3Class) {
+ if (methodNames.size() == 0) {
+ return testFilterFlagForClass(className);
+ } else if (methodNames.size() == 1) {
+ return testFilterFlagForClassAndMethod(className, methodNames.iterator().next());
+ }
+ String methodNamePattern;
+ if (isJUnit3Class) {
+ methodNamePattern = String.join(",", methodNames);
+ } else {
+ methodNamePattern = String.format("(%s)", String.join("|", methodNames));
+ }
+ return testFilterFlagForClassAndMethod(className, methodNamePattern);
+ }
+
+ private BlazeFlags() {}
+}
diff --git a/base/src/com/google/idea/blaze/base/command/BuildFlagsProvider.java b/base/src/com/google/idea/blaze/base/command/BuildFlagsProvider.java
new file mode 100644
index 0000000..469d663
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/BuildFlagsProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.util.List;
+
+/** Provides additional build flags for bazel/blaze commands. */
+public interface BuildFlagsProvider {
+
+ ExtensionPointName<BuildFlagsProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BuildFlagsProvider");
+
+ void addBuildFlags(BuildSystem buildSystem, ProjectViewSet projectViewSet, List<String> flags);
+}
diff --git a/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java b/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
new file mode 100644
index 0000000..eb4b510
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import static com.google.idea.blaze.base.command.BlazeFlags.NO_CHECK_OUTPUTS;
+import static com.google.idea.blaze.base.command.BlazeFlags.VERSION_WINDOW_FOR_DIRTY_NODE_GC;
+
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.common.experiments.BoolExperiment;
+import java.util.List;
+
+/** Flags added to blaze/bazel build commands. */
+public class BuildFlagsProviderImpl implements BuildFlagsProvider {
+
+ private static final BoolExperiment EXPERIMENT_USE_VERSION_WINDOW_FOR_DIRTY_NODE_GC =
+ new BoolExperiment("ide_build_info.use_version_window_for_dirty_node_gc", false);
+ private static final BoolExperiment EXPERIMENT_NO_EXPERIMENTAL_CHECK_OUTPUT_FILES =
+ new BoolExperiment("build.noexperimental_check_output_files", false);
+
+ @Override
+ public void addBuildFlags(
+ BuildSystem buildSystem, ProjectViewSet projectViewSet, List<String> flags) {
+ if (EXPERIMENT_USE_VERSION_WINDOW_FOR_DIRTY_NODE_GC.getValue()) {
+ flags.add(VERSION_WINDOW_FOR_DIRTY_NODE_GC);
+ }
+ if (EXPERIMENT_NO_EXPERIMENTAL_CHECK_OUTPUT_FILES.getValue()) {
+ flags.add(NO_CHECK_OUTPUTS);
+ }
+ flags.add("--curses=no");
+ flags.add("--color=no");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java b/base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java
new file mode 100644
index 0000000..22c8c6a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import java.io.File;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** Collects the output of --experimental_show_artifacts */
+public class ExperimentalShowArtifactsLineProcessor
+ implements LineProcessingOutputStream.LineProcessor {
+ private static final String OUTPUT_START = "Build artifacts:";
+ private static final String OUTPUT_MARKER = ">>>";
+
+ final List<File> fileList;
+ private final String fileType;
+ boolean insideBuildResult = false;
+
+ public ExperimentalShowArtifactsLineProcessor(List<File> fileList, String fileType) {
+ this.fileList = fileList;
+ this.fileType = fileType;
+ }
+
+ @Override
+ public boolean processLine(@NotNull String line) {
+ if (insideBuildResult) {
+ // Workaround for --experimental_ui: Extra newlines are inserted
+ if (line.isEmpty()) {
+ return false;
+ }
+
+ insideBuildResult = line.startsWith(OUTPUT_MARKER);
+ if (insideBuildResult) {
+ String fileName = line.substring(OUTPUT_MARKER.length());
+ if (fileName.endsWith(fileType)) {
+ fileList.add(new File(fileName));
+ }
+ }
+ }
+ if (!insideBuildResult) {
+ insideBuildResult = line.equals(OUTPUT_START);
+ }
+ return !insideBuildResult;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java b/base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java
new file mode 100644
index 0000000..89530b7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command.info;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.components.ServiceManager;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Runs the blaze info command. The results may be cached in the workspace. */
+public abstract class BlazeInfo {
+ public static final String EXECUTION_ROOT_KEY = "execution_root";
+ public static final String PACKAGE_PATH_KEY = "package_path";
+ public static final String BUILD_LANGUAGE = "build-language";
+
+ public static String blazeBinKey(BuildSystem buildSystem) {
+ switch (buildSystem) {
+ case Blaze:
+ return "blaze-bin";
+ case Bazel:
+ return "bazel-bin";
+ default:
+ throw new IllegalArgumentException("Unrecognized build system: " + buildSystem);
+ }
+ }
+
+ public static String blazeGenfilesKey(BuildSystem buildSystem) {
+ switch (buildSystem) {
+ case Blaze:
+ return "blaze-genfiles";
+ case Bazel:
+ return "bazel-genfiles";
+ default:
+ throw new IllegalArgumentException("Unrecognized build system: " + buildSystem);
+ }
+ }
+
+ public static BlazeInfo getInstance() {
+ return ServiceManager.getService(BlazeInfo.class);
+ }
+
+ /**
+ * @param blazeFlags The blaze flags that will be passed to Blaze.
+ * @param key The key passed to blaze info
+ * @return The blaze info value associated with the specified key
+ */
+ public abstract ListenableFuture<String> runBlazeInfo(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags,
+ String key);
+
+ /**
+ * @param blazeFlags The blaze flags that will be passed to Blaze.
+ * @param key The key passed to blaze info
+ * @return The blaze info value associated with the specified key
+ */
+ public abstract ListenableFuture<byte[]> runBlazeInfoGetBytes(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags,
+ String key);
+
+ /**
+ * This calls blaze info without any specific key so blaze info will return all keys and values
+ * that it has. There could be a performance cost for doing this, so the user should verify that
+ * calling this method is actually faster than calling {@link #runBlazeInfo(WorkspaceRoot, List,
+ * String)}.
+ *
+ * @param blazeFlags The blaze flags that will be passed to Blaze.
+ * @return The blaze info data fields.
+ */
+ public abstract ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags);
+}
diff --git a/base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java
new file mode 100644
index 0000000..39294c3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command.info;
+
+import javax.annotation.concurrent.Immutable;
+
+/** Exception occuring during blaze infoy */
+@Immutable
+public final class BlazeInfoException extends Exception {
+ private final int exitCode;
+ private final String stdout;
+ private final String stderr;
+
+ public BlazeInfoException(int exitCode, String stdout, String stderr) {
+ this.exitCode = exitCode;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ }
+
+ @Override
+ public String getMessage() {
+ return "blaze info failed with exit code: " + exitCode + " and error stream: " + stderr;
+ }
+
+ public int getExitCode() {
+ return exitCode;
+ }
+
+ public String getStdout() {
+ return stdout;
+ }
+
+ public String getStderr() {
+ return stderr;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java
new file mode 100644
index 0000000..cf82fdd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command.info;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.async.process.ExternalTask;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+import javax.annotation.Nullable;
+
+class BlazeInfoImpl extends BlazeInfo {
+ private static final Logger LOG = Logger.getInstance(BlazeInfoImpl.class);
+
+ @Override
+ public ListenableFuture<String> runBlazeInfo(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags,
+ String key) {
+ return BlazeExecutor.getInstance()
+ .submit(
+ () ->
+ runBlazeInfo(buildSystem, workspaceRoot, key, blazeFlags, context)
+ .toString()
+ .trim());
+ }
+
+ @Override
+ public ListenableFuture<byte[]> runBlazeInfoGetBytes(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags,
+ String key) {
+ return BlazeExecutor.getInstance()
+ .submit(
+ () -> runBlazeInfo(buildSystem, workspaceRoot, key, blazeFlags, context).toByteArray());
+ }
+
+ @Override
+ public ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags) {
+ return BlazeExecutor.getInstance()
+ .submit(
+ () -> {
+ String blazeInfoString =
+ runBlazeInfo(buildSystem, workspaceRoot, null /* key */, blazeFlags, context)
+ .toString()
+ .trim();
+ return parseBlazeInfoResult(blazeInfoString);
+ });
+ }
+
+ private static ByteArrayOutputStream runBlazeInfo(
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ @Nullable String key,
+ List<String> blazeFlags,
+ @Nullable BlazeContext context)
+ throws BlazeInfoException {
+ BlazeCommand.Builder builder = BlazeCommand.builder(buildSystem, BlazeCommandName.INFO);
+ if (key != null) {
+ builder.addBlazeFlags(key);
+ }
+ BlazeCommand command = builder.addBlazeFlags(blazeFlags).build();
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ int exitCode =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command)
+ .context(context)
+ .stdout(stdout)
+ .stderr(stderr)
+ .build()
+ .run();
+ if (exitCode != 0) {
+ throw new BlazeInfoException(exitCode, stdout.toString(), stderr.toString());
+ }
+ return stdout;
+ }
+
+ private static ImmutableMap<String, String> parseBlazeInfoResult(String blazeInfoString) {
+ ImmutableMap.Builder<String, String> blazeInfoMapBuilder = ImmutableMap.builder();
+ String[] blazeInfoLines = blazeInfoString.split("\n");
+ for (String blazeInfoLine : blazeInfoLines) {
+ // Just split on the first ":".
+ String[] keyValue = blazeInfoLine.split(":", 2);
+ LOG.assertTrue(keyValue.length == 2, blazeInfoLine);
+ String key = keyValue[0].trim();
+ String value = keyValue[1].trim();
+ blazeInfoMapBuilder.put(key, value);
+ }
+ return blazeInfoMapBuilder.build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
new file mode 100644
index 0000000..2bd7d57
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.console;
+
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Prints text to the blaze console. */
+public interface BlazeConsoleService {
+ static BlazeConsoleService getInstance(@NotNull Project project) {
+ return ServiceManager.getService(project, BlazeConsoleService.class);
+ }
+
+ void print(@NotNull String text, @NotNull ConsoleViewContentType contentType);
+
+ void clear();
+
+ void setStopHandler(@Nullable Runnable runnable);
+
+ void activateConsoleWindow();
+}
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
new file mode 100644
index 0000000..ba5e3a6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.console;
+
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Implementation for BlazeConsoleService */
+public class BlazeConsoleServiceImpl implements BlazeConsoleService {
+ @NotNull private final Project project;
+ @NotNull private final BlazeConsoleView blazeConsoleView;
+
+ BlazeConsoleServiceImpl(@NotNull Project project) {
+ this.project = project;
+ blazeConsoleView = BlazeConsoleView.getInstance(project);
+ }
+
+ @Override
+ public void print(@NotNull String text, @NotNull ConsoleViewContentType contentType) {
+ blazeConsoleView.print(text, contentType);
+ }
+
+ @Override
+ public void clear() {
+ blazeConsoleView.clear();
+ }
+
+ @Override
+ public void setStopHandler(@Nullable Runnable runnable) {
+ blazeConsoleView.setStopHandler(runnable);
+ }
+
+ @Override
+ public void activateConsoleWindow() {
+ ToolWindow toolWindow =
+ ToolWindowManager.getInstance(project).getToolWindow(BlazeConsoleToolWindowFactory.ID);
+ if (toolWindow != null) {
+ toolWindow.activate(null);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleToolWindowFactory.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleToolWindowFactory.java
new file mode 100644
index 0000000..76c1966
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleToolWindowFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.console;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowFactory;
+import org.jetbrains.annotations.NotNull;
+
+/** Factory for console window. */
+public class BlazeConsoleToolWindowFactory implements DumbAware, ToolWindowFactory {
+
+ public static final String ID = "Blaze Console";
+
+ @Override
+ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
+ String title = Blaze.buildSystemName(project) + " Console";
+ toolWindow.setTitle(title);
+ toolWindow.setStripeTitle(title);
+ BlazeConsoleView.getInstance(project).createToolWindowContent(toolWindow);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
new file mode 100644
index 0000000..f507a52
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.console;
+
+import com.intellij.codeEditor.printing.PrintAction;
+import com.intellij.execution.impl.ConsoleViewImpl;
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.execution.ui.RunnerLayoutUi;
+import com.intellij.execution.ui.layout.PlaceInGrid;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.IdeBundle;
+import com.intellij.ide.actions.NextOccurenceToolbarAction;
+import com.intellij.ide.actions.PreviousOccurenceToolbarAction;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.ActionPlaces;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.ui.content.Content;
+import com.intellij.ui.content.ContentFactory;
+import java.awt.BorderLayout;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class BlazeConsoleView implements Disposable {
+
+ private static final Class<?>[] IGNORED_CONSOLE_ACTION_TYPES = {
+ PreviousOccurenceToolbarAction.class,
+ NextOccurenceToolbarAction.class,
+ ConsoleViewImpl.ClearAllAction.class,
+ PrintAction.class
+ };
+
+ @NotNull private final Project myProject;
+ @NotNull private final ConsoleViewImpl myConsoleView;
+
+ private JPanel myConsolePanel;
+ private volatile Runnable myStopHandler;
+
+ public BlazeConsoleView(@NotNull Project project) {
+ myProject = project;
+ myConsoleView = new ConsoleViewImpl(myProject, false);
+ Disposer.register(this, myConsoleView);
+ setupUI();
+ }
+
+ public static BlazeConsoleView getInstance(@NotNull Project project) {
+ return ServiceManager.getService(project, BlazeConsoleView.class);
+ }
+
+ public void setStopHandler(@Nullable Runnable stopHandler) {
+ myStopHandler = stopHandler;
+ }
+
+ private static boolean shouldIgnoreAction(@NotNull AnAction action) {
+ for (Class<?> actionType : IGNORED_CONSOLE_ACTION_TYPES) {
+ if (actionType.isInstance(action)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void createToolWindowContent(@NotNull ToolWindow toolWindow) {
+ //Create runner UI layout
+ RunnerLayoutUi.Factory factory = RunnerLayoutUi.Factory.getInstance(myProject);
+ RunnerLayoutUi layoutUi = factory.create("", "", "session", myProject);
+
+ Content console =
+ layoutUi.createContent(
+ BlazeConsoleToolWindowFactory.ID, myConsoleView.getComponent(), "", null, null);
+ layoutUi.addContent(console, 0, PlaceInGrid.right, false);
+
+ // Adding actions
+ DefaultActionGroup group = new DefaultActionGroup();
+ layoutUi.getOptions().setLeftToolbar(group, ActionPlaces.UNKNOWN);
+
+ AnAction[] consoleActions = myConsoleView.createConsoleActions();
+ for (AnAction action : consoleActions) {
+ if (!shouldIgnoreAction(action)) {
+ group.add(action);
+ }
+ }
+ group.add(new StopAction());
+
+ JComponent layoutComponent = layoutUi.getComponent();
+ myConsolePanel.add(layoutComponent, BorderLayout.CENTER);
+
+ //noinspection ConstantConditions
+ Content content =
+ ContentFactory.SERVICE.getInstance().createContent(layoutComponent, null, true);
+ toolWindow.getContentManager().addContent(content);
+ }
+
+ public void clear() {
+ myConsoleView.clear();
+ }
+
+ public void print(@NotNull String text, @NotNull ConsoleViewContentType contentType) {
+ myConsoleView.print(text, contentType);
+ }
+
+ @Override
+ public void dispose() {}
+
+ private void setupUI() {
+ myConsolePanel = new JPanel();
+ myConsolePanel.setLayout(new BorderLayout(0, 0));
+ }
+
+ private class StopAction extends DumbAwareAction {
+ public StopAction() {
+ super(IdeBundle.message("action.stop"), null, AllIcons.Actions.Suspend);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Runnable handler = myStopHandler;
+ if (handler != null) {
+ handler.run();
+ myStopHandler = null;
+ }
+ }
+
+ @Override
+ public void update(AnActionEvent event) {
+ Presentation presentation = event.getPresentation();
+ boolean isNowVisible = myStopHandler != null;
+ if (presentation.isEnabled() != isNowVisible) {
+ presentation.setEnabled(isNowVisible);
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/experiments/BlazeExperimentService.java b/base/src/com/google/idea/blaze/base/experiments/BlazeExperimentService.java
new file mode 100644
index 0000000..2b9f1cc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/experiments/BlazeExperimentService.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.experiments;
+
+import com.google.idea.common.experiments.ExperimentServiceImpl;
+
+final class BlazeExperimentService extends ExperimentServiceImpl {
+
+ public BlazeExperimentService() {
+ super("ijwb");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/experiments/ExperimentScope.java b/base/src/com/google/idea/blaze/base/experiments/ExperimentScope.java
new file mode 100644
index 0000000..5415bf9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/experiments/ExperimentScope.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.experiments;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.common.experiments.ExperimentService;
+import org.jetbrains.annotations.NotNull;
+
+/** Reloads experiments at the start of the scope. */
+public class ExperimentScope implements BlazeScope {
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ ExperimentService.getInstance().startExperimentScope();
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ ExperimentService.getInstance().endExperimentScope();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/filecache/FileCache.java b/base/src/com/google/idea/blaze/base/filecache/FileCache.java
new file mode 100644
index 0000000..3878916
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/filecache/FileCache.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.filecache;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+
+/** A cache of files from the build output. */
+public interface FileCache {
+ ExtensionPointName<FileCache> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.FileCache");
+
+ /** Name of cache. Used for status messages. */
+ String getName();
+
+ /** Called on sync to fully refresh the file cache. */
+ void onSync(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData projectData,
+ BlazeSyncParams.SyncMode syncMode);
+
+ /** Called after a build operation to refresh any updated files. */
+ void refreshFiles(Project project);
+}
diff --git a/base/src/com/google/idea/blaze/base/filecache/FileCaches.java b/base/src/com/google/idea/blaze/base/filecache/FileCaches.java
new file mode 100644
index 0000000..f4c66c1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/filecache/FileCaches.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.filecache;
+
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.LocalFileSystem;
+
+/** Static helper methods to update file caches. */
+public class FileCaches {
+ /** Call on sync. Updates the file cache and deletes any old files. */
+ public static void onSync(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ BlazeSyncParams.SyncMode syncMode) {
+ for (FileCache fileCache : FileCache.EP_NAME.getExtensions()) {
+ Scope.push(
+ context,
+ childContext -> {
+ childContext.push(new TimingScope(fileCache.getName()));
+ childContext.output(new StatusOutput("Updating " + fileCache.getName() + "..."));
+ fileCache.onSync(project, context, projectViewSet, blazeProjectData, syncMode);
+ });
+ }
+ LocalFileSystem.getInstance().refresh(true);
+ }
+
+ /** Call at the end of build when you want the IDE to pick up any changes. */
+ public static void refresh(Project project) {
+ BlazeExecutor.submitTask(
+ project,
+ indicator -> {
+ indicator.setIndeterminate(true);
+ for (FileCache fileCache : FileCache.EP_NAME.getExtensions()) {
+ indicator.setText("Updating " + fileCache.getName() + "...");
+ fileCache.refreshFiles(project);
+ }
+ LocalFileSystem.getInstance().refresh(true);
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java b/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java
new file mode 100644
index 0000000..a76fa8d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.filecache;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.io.ModifiedTimeScanner;
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.jetbrains.annotations.Nullable;
+
+/** Provides a diffing service for a collection of files. */
+public final class FileDiffer {
+ private static Logger LOG = Logger.getInstance(FileDiffer.class);
+
+ private FileDiffer() {}
+
+ @Nullable
+ public static ImmutableMap<File, Long> updateFiles(
+ @Nullable ImmutableMap<File, Long> oldState,
+ Iterable<File> files,
+ List<File> updatedFiles,
+ List<File> removedFiles) {
+ ImmutableMap<File, Long> newState = readFileState(files);
+ if (newState == null) {
+ return null;
+ }
+ diffState(oldState, newState, updatedFiles, removedFiles);
+ return newState;
+ }
+
+ @Nullable
+ public static ImmutableMap<File, Long> readFileState(Iterable<File> files) {
+ try {
+ return ModifiedTimeScanner.readTimestamps(files);
+ } catch (Exception e) {
+ LOG.error(e);
+ return null;
+ }
+ }
+
+ public static <K, V> void diffState(
+ @Nullable Map<K, V> oldState, Map<K, V> newState, List<K> updated, List<K> removed) {
+ oldState = oldState != null ? oldState : ImmutableMap.of();
+
+ // Find changed/new
+ for (Map.Entry<K, V> entry : newState.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ V oldValue = oldState.get(key);
+
+ final boolean isUpdated = oldValue == null || !value.equals(oldValue);
+ if (isUpdated) {
+ updated.add(key);
+ }
+ }
+
+ // Find removed
+ Set<K> removedSet = Sets.newHashSet();
+ removedSet.addAll(oldState.keySet());
+ removedSet.removeAll(newState.keySet());
+ removed.addAll(removedSet);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/help/BlazeHelpHandler.java b/base/src/com/google/idea/blaze/base/help/BlazeHelpHandler.java
new file mode 100644
index 0000000..9397a89
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/help/BlazeHelpHandler.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.help;
+
+import com.intellij.openapi.components.ServiceManager;
+
+/** Handles help requests. */
+public interface BlazeHelpHandler {
+ static BlazeHelpHandler getInstance() {
+ return ServiceManager.getService(BlazeHelpHandler.class);
+ }
+
+ void handleHelp(String urlFragment);
+}
diff --git a/base/src/com/google/idea/blaze/base/help/BlazeHelpHandlerImpl.java b/base/src/com/google/idea/blaze/base/help/BlazeHelpHandlerImpl.java
new file mode 100644
index 0000000..e9a23b6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/help/BlazeHelpHandlerImpl.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.help;
+
+import com.intellij.ide.BrowserUtil;
+
+class BlazeHelpHandlerImpl implements BlazeHelpHandler {
+ private static final String URL_BASE = "https://ij.bazel.io/";
+
+ @Override
+ public void handleHelp(String urlFragment) {
+ BrowserUtil.browse(URL_BASE + urlFragment + ".html");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ide/NewBlazePackageAction.java b/base/src/com/google/idea/blaze/base/ide/NewBlazePackageAction.java
new file mode 100644
index 0000000..3780bf1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ide/NewBlazePackageAction.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ide;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.buildmodifier.BuildFileModifier;
+import com.google.idea.blaze.base.buildmodifier.FileSystemModifier;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.ScopedOperation;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.intellij.history.LocalHistory;
+import com.intellij.history.LocalHistoryAction;
+import com.intellij.ide.IdeView;
+import com.intellij.ide.util.DirectoryChooserUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.util.PlatformIcons;
+import java.io.File;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+class NewBlazePackageAction extends BlazeAction implements DumbAware {
+ private static final Logger LOG = Logger.getInstance(NewBlazePackageAction.class);
+
+ private static final String BUILD_FILE_NAME = "BUILD";
+
+ public NewBlazePackageAction() {
+ super();
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent event) {
+ final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
+ final Project project = event.getData(CommonDataKeys.PROJECT);
+ Scope.root(
+ new ScopedOperation() {
+ @Override
+ public void execute(@NotNull final BlazeContext context) {
+ context.push(new LoggedTimingScope(project, Action.CREATE_BLAZE_PACKAGE));
+
+ if (view == null || project == null) {
+ return;
+ }
+ PsiDirectory directory = getOrChooseDirectory(project, view);
+
+ if (directory == null) {
+ return;
+ }
+
+ NewBlazePackageDialog newBlazePackageDialog =
+ new NewBlazePackageDialog(project, directory);
+ boolean isOk = newBlazePackageDialog.showAndGet();
+ if (!isOk) {
+ return;
+ }
+
+ final Label newRule = newBlazePackageDialog.getNewRule();
+ final Kind newRuleKind = newBlazePackageDialog.getNewRuleKind();
+ // If we returned OK, we should have a non null result
+ LOG.assertTrue(newRule != null);
+ LOG.assertTrue(newRuleKind != null);
+
+ context.output(
+ new StatusOutput(
+ String.format("Setting up a new %s package", Blaze.buildSystemName(project))));
+
+ boolean success = createPackageOnDisk(project, context, newRule, newRuleKind);
+
+ if (!success) {
+ return;
+ }
+
+ File newDirectory =
+ WorkspaceRoot.fromProject(project).fileForPath(newRule.blazePackage());
+ VirtualFile virtualFile = VfsUtil.findFileByIoFile(newDirectory, true);
+ // We just created this file, it should exist
+ LOG.assertTrue(virtualFile != null);
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
+ view.selectElement(psiFile);
+ }
+ });
+ }
+
+ private static Boolean createPackageOnDisk(
+ @NotNull Project project,
+ @NotNull BlazeContext context,
+ @NotNull Label newRule,
+ @NotNull Kind ruleKind) {
+ LocalHistoryAction action;
+
+ String actionName =
+ String.format(
+ "Creating %s package: %s", Blaze.buildSystemName(project), newRule.toString());
+ LocalHistory localHistory = LocalHistory.getInstance();
+ action = localHistory.startAction(actionName);
+
+ // Create the package + BUILD file + rule
+ FileSystemModifier fileSystemModifier = FileSystemModifier.getInstance(project);
+ WorkspacePath newWorkspacePath = newRule.blazePackage();
+ File newDirectory = fileSystemModifier.makeWorkspacePathDirs(newWorkspacePath);
+ if (newDirectory == null) {
+ String errorMessage =
+ "Could not create new package directory: " + newWorkspacePath.toString();
+ context.output(PrintOutput.error(errorMessage));
+ return false;
+ }
+ File buildFile = fileSystemModifier.createFile(newWorkspacePath, BUILD_FILE_NAME);
+ if (buildFile == null) {
+ String errorMessage =
+ "Could not create new BUILD file in package: " + newWorkspacePath.toString();
+ context.output(PrintOutput.error(errorMessage));
+ return false;
+ }
+ BuildFileModifier buildFileModifier = BuildFileModifier.getInstance();
+ buildFileModifier.addRule(project, context, newRule, ruleKind);
+ action.finish();
+
+ return true;
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent event) {
+ Presentation presentation = event.getPresentation();
+ if (isEnabled(event)) {
+ String text = String.format("New %s Package", Blaze.buildSystemName(event.getProject()));
+ presentation.setEnabledAndVisible(true);
+ presentation.setText(text);
+ presentation.setDescription(text);
+ presentation.setIcon(PlatformIcons.PACKAGE_ICON);
+ } else {
+ presentation.setEnabledAndVisible(false);
+ }
+ }
+
+ private boolean isEnabled(AnActionEvent event) {
+ Project project = event.getProject();
+ IdeView view = event.getData(LangDataKeys.IDE_VIEW);
+ if (project == null || view == null) {
+ return false;
+ }
+
+ List<PsiDirectory> directories = filterDirectories(project, view.getDirectories());
+ if (directories.isEmpty()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /** Filter out directories that do not live under the project's directories. */
+ private static List<PsiDirectory> filterDirectories(Project project, PsiDirectory[] directories) {
+ if (directories.length == 0) {
+ return ImmutableList.of();
+ }
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return ImmutableList.of();
+ }
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
+ .add(projectViewSet)
+ .build();
+ return Lists.newArrayList(directories)
+ .stream()
+ .filter(directory -> isUnderProjectViewDirectory(workspaceRoot, importRoots, directory))
+ .collect(Collectors.toList());
+ }
+
+ private static boolean isUnderProjectViewDirectory(
+ WorkspaceRoot workspaceRoot, ImportRoots importRoots, PsiDirectory directory) {
+ VirtualFile virtualFile = directory.getVirtualFile();
+ // Ignore jars, etc. and their contents, which are in an ArchiveFileSystem.
+ if (!(virtualFile.isInLocalFileSystem())) {
+ return false;
+ }
+ if (!workspaceRoot.isInWorkspace(virtualFile)) {
+ return false;
+ }
+ WorkspacePath workspacePath = workspaceRoot.workspacePathFor(virtualFile);
+ return importRoots
+ .rootDirectories()
+ .stream()
+ .anyMatch(
+ importRoot ->
+ FileUtil.isAncestor(
+ importRoot.relativePath(), workspacePath.relativePath(), false));
+ }
+
+ @Nullable
+ private static PsiDirectory getOrChooseDirectory(Project project, IdeView view) {
+ List<PsiDirectory> dirs = filterDirectories(project, view.getDirectories());
+ if (dirs.size() == 0) {
+ return null;
+ }
+ if (dirs.size() == 1) {
+ return dirs.get(0);
+ } else {
+ return DirectoryChooserUtil.selectDirectory(
+ project, dirs.toArray(new PsiDirectory[dirs.size()]), null, "");
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java b/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
new file mode 100644
index 0000000..14e02d4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ide;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.RuleName;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.CommonBundle;
+import com.intellij.ide.IdeBundle;
+import com.intellij.ide.actions.CreateElementActionBase;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.components.JBTextField;
+import com.intellij.util.IncorrectOperationException;
+import java.awt.GridBagLayout;
+import java.io.File;
+import java.util.List;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class NewBlazePackageDialog extends DialogWrapper {
+ private static final Logger LOG = Logger.getInstance(NewBlazePackageDialog.class);
+
+ @NotNull private final Project project;
+ @NotNull private final PsiDirectory parentDirectory;
+
+ @Nullable private Label newRule;
+ @Nullable private Kind newRuleKind;
+
+ private static final int UI_INDENT_LEVEL = 0;
+ private static final int TEXT_FIELD_LENGTH = 40;
+ @NotNull private final JPanel component = new JPanel(new GridBagLayout());
+ @NotNull private final JBLabel packageLabel = new JBLabel("Package name:");
+ @NotNull private final JBTextField packageNameField = new JBTextField(TEXT_FIELD_LENGTH);
+ @NotNull private final NewRuleUI newRuleUI = new NewRuleUI(TEXT_FIELD_LENGTH);
+
+ public NewBlazePackageDialog(@NotNull Project project, @NotNull PsiDirectory currentDirectory) {
+ super(project);
+ this.project = project;
+ this.parentDirectory = currentDirectory;
+
+ initializeUI();
+ }
+
+ private void initializeUI() {
+ component.add(packageLabel);
+ component.add(packageNameField, UiUtil.getFillLineConstraints(UI_INDENT_LEVEL));
+ newRuleUI.fillUI(component, UI_INDENT_LEVEL);
+ UiUtil.fillBottom(component);
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return component;
+ }
+
+ @Nullable
+ @Override
+ protected ValidationInfo doValidate() {
+ String packageName = packageNameField.getText();
+ if (packageName == null) {
+ return new ValidationInfo("Internal error, package was null");
+ }
+ if (packageName.length() == 0) {
+ return new ValidationInfo(
+ IdeBundle.message("error.name.should.be.specified"), packageNameField);
+ }
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!Label.validatePackagePath(packageName, errors)) {
+ BlazeValidationError validationResult = errors.get(0);
+ return new ValidationInfo(validationResult.getError(), packageNameField);
+ }
+
+ return newRuleUI.validate();
+ }
+
+ @Override
+ protected void doOKAction() {
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ LOG.assertTrue(parentDirectory.getVirtualFile().isInLocalFileSystem());
+ File parentDirectoryFile = new File(parentDirectory.getVirtualFile().getPath());
+ String newPackageName = packageNameField.getText();
+ File newPackageDirectory = new File(parentDirectoryFile, newPackageName);
+ WorkspacePath newPackagePath = workspaceRoot.workspacePathFor(newPackageDirectory);
+
+ RuleName newRuleName = newRuleUI.getRuleName();
+ Label newRule = new Label(newPackagePath, newRuleName);
+ Kind ruleKind = newRuleUI.getSelectedRuleKind();
+ try {
+ parentDirectory.checkCreateSubdirectory(newPackageName);
+ } catch (IncorrectOperationException ex) {
+ showErrorDialog(CreateElementActionBase.filterMessage(ex.getMessage()));
+ // do not close the dialog
+ return;
+ }
+ this.newRule = newRule;
+ this.newRuleKind = ruleKind;
+ super.doOKAction();
+ }
+
+ private void showErrorDialog(@NotNull String message) {
+ String title = CommonBundle.getErrorTitle();
+ Icon icon = Messages.getErrorIcon();
+ Messages.showMessageDialog(component, message, title, icon);
+ }
+
+ @Nullable
+ public Label getNewRule() {
+ return newRule;
+ }
+
+ @Nullable
+ public Kind getNewRuleKind() {
+ return newRuleKind;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleAction.java b/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleAction.java
new file mode 100644
index 0000000..a8aaee8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleAction.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ide;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.experiments.ExperimentScope;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.ScopedOperation;
+import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.actionSystem.ActionPlaces;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+class NewBlazeRuleAction extends BlazeAction implements DumbAware {
+
+ public NewBlazeRuleAction() {
+ super();
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent event) {
+ final Project project = event.getData(CommonDataKeys.PROJECT);
+ if (project == null) {
+ return;
+ }
+ final VirtualFile virtualFile = event.getData(CommonDataKeys.VIRTUAL_FILE);
+ if (virtualFile == null) {
+ return;
+ }
+
+ Scope.root(
+ new ScopedOperation() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ context
+ .push(new ExperimentScope())
+ .push(new BlazeConsoleScope.Builder(project).build())
+ .push(new IssuesScope(project))
+ .push(new IdeaLogScope())
+ .push(new LoggedTimingScope(project, Action.CREATE_BLAZE_RULE));
+ NewBlazeRuleDialog newBlazeRuleDialog =
+ new NewBlazeRuleDialog(context, project, virtualFile);
+ newBlazeRuleDialog.show();
+ }
+ });
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent event) {
+ Presentation presentation = event.getPresentation();
+ DataContext dataContext = event.getDataContext();
+ VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ boolean enabled = (project != null && file != null && file.getName().equals("BUILD"));
+ presentation.setVisible(enabled || ActionPlaces.isMainMenuOrActionSearch(event.getPlace()));
+ presentation.setEnabled(enabled);
+ presentation.setText(getText(project));
+ }
+
+ private static String getText(@Nullable Project project) {
+ String buildSystem = Blaze.buildSystemName(project);
+ return String.format("New %s Rule", buildSystem);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java b/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
new file mode 100644
index 0000000..64dcd3d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ide;
+
+import com.google.idea.blaze.base.buildmodifier.BuildFileModifier;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.RuleName;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.io.File;
+import javax.annotation.Nullable;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+class NewBlazeRuleDialog extends DialogWrapper {
+ private static final Logger LOG = Logger.getInstance(NewBlazeRuleDialog.class);
+
+ private static final int UI_INDENT = 0;
+ private static final int TEXT_BOX_WIDTH = 40;
+
+ private final BlazeContext context;
+ private final Project project;
+ private final VirtualFile buildFile;
+ private final String buildSystemName;
+
+ private JPanel component = new JPanel(new GridBagLayout());
+ private final NewRuleUI newRuleUI = new NewRuleUI(TEXT_BOX_WIDTH);
+ private static final Dimension componentSize = new Dimension(500, 500);
+
+ public NewBlazeRuleDialog(BlazeContext context, Project project, VirtualFile buildFile) {
+ super(project);
+ this.context = context;
+ this.project = project;
+ this.buildFile = buildFile;
+ this.buildSystemName = Blaze.buildSystemName(project);
+ initComponent();
+ }
+
+ private void initComponent() {
+ setTitle(String.format("Create a New %s Rule", buildSystemName));
+ setOKButtonText("Create");
+ setCancelButtonText("Cancel");
+
+ component.setPreferredSize(componentSize);
+ component.setMinimumSize(componentSize);
+
+ newRuleUI.fillUI(component, UI_INDENT);
+ UiUtil.fillBottom(component);
+
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return component;
+ }
+
+ @Nullable
+ @Override
+ protected ValidationInfo doValidate() {
+ return newRuleUI.validate();
+ }
+
+ @Override
+ protected void doOKAction() {
+ RuleName ruleName = newRuleUI.getRuleName();
+ Kind ruleKind = newRuleUI.getSelectedRuleKind();
+
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ WorkspacePath workspacePath =
+ workspaceRoot.workspacePathFor(new File(buildFile.getParent().getPath()));
+ Label newRule = new Label(workspacePath, ruleName);
+ BuildFileModifier buildFileModifier = BuildFileModifier.getInstance();
+ boolean success = buildFileModifier.addRule(project, context, newRule, ruleKind);
+
+ if (success) {
+ super.doOKAction();
+ } else {
+ super.setErrorText(
+ String.format("Could not create new rule, see %s Console for details", buildSystemName));
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java b/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
new file mode 100644
index 0000000..f602bc2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ide;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.RuleName;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.ide.IdeBundle;
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.components.JBTextField;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+final class NewRuleUI {
+
+ private static final String[] POSSIBLE_RULES = {
+ "android_library", "java_library", "cc_library", "cc_binary", "proto_library"
+ };
+
+ @NotNull private final ComboBox ruleComboBox = new ComboBox(POSSIBLE_RULES);
+ @NotNull private final JBLabel ruleNameLabel = new JBLabel("Rule name:");
+ @NotNull private final JBTextField ruleNameField;
+
+ public NewRuleUI(int textFieldLength) {
+ this.ruleNameField = new JBTextField(textFieldLength);
+ }
+
+ public void fillUI(@NotNull JPanel component, int indentLevel) {
+ component.add(ruleNameLabel);
+ component.add(ruleNameField, UiUtil.getFillLineConstraints(indentLevel));
+ component.add(ruleComboBox, UiUtil.getFillLineConstraints(indentLevel));
+ }
+
+ @NotNull
+ public Kind getSelectedRuleKind() {
+ return Kind.fromString((String) ruleComboBox.getSelectedItem());
+ }
+
+ @NotNull
+ public RuleName getRuleName() {
+ return RuleName.create(ruleNameField.getText());
+ }
+
+ @Nullable
+ public ValidationInfo validate() {
+ String ruleName = ruleNameField.getText();
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!validateRuleName(ruleName, errors)) {
+ BlazeValidationError issue = errors.get(0);
+ return new ValidationInfo(issue.getError(), ruleNameField);
+ }
+ return null;
+ }
+
+ private static boolean validateRuleName(
+ @NotNull String inputString, @Nullable Collection<BlazeValidationError> errors) {
+ if (inputString.length() == 0) {
+ BlazeValidationError.collect(
+ errors, new BlazeValidationError(IdeBundle.message("error.name.should.be.specified")));
+ return false;
+ }
+
+ return RuleName.validate(inputString, errors);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/AndroidRuleIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/AndroidRuleIdeInfo.java
new file mode 100644
index 0000000..31d7d60
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/AndroidRuleIdeInfo.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.io.Serializable;
+import java.util.Collection;
+import org.jetbrains.annotations.Nullable;
+
+/** Ide info specific to android rules. */
+public final class AndroidRuleIdeInfo implements Serializable {
+ private static final long serialVersionUID = 5L;
+
+ public final Collection<ArtifactLocation> resources;
+ @Nullable public final ArtifactLocation manifest;
+ @Nullable public final LibraryArtifact idlJar;
+ @Nullable public final LibraryArtifact resourceJar;
+ public final boolean hasIdlSources;
+ @Nullable public final String resourceJavaPackage;
+ public boolean generateResourceClass;
+ @Nullable public Label legacyResources;
+
+ public AndroidRuleIdeInfo(
+ Collection<ArtifactLocation> resources,
+ @Nullable String resourceJavaPackage,
+ boolean generateResourceClass,
+ @Nullable ArtifactLocation manifest,
+ @Nullable LibraryArtifact idlJar,
+ @Nullable LibraryArtifact resourceJar,
+ boolean hasIdlSources,
+ @Nullable Label legacyResources) {
+ this.resources = resources;
+ this.resourceJavaPackage = resourceJavaPackage;
+ this.generateResourceClass = generateResourceClass;
+ this.manifest = manifest;
+ this.idlJar = idlJar;
+ this.resourceJar = resourceJar;
+ this.hasIdlSources = hasIdlSources;
+ this.legacyResources = legacyResources;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for android rule */
+ public static class Builder {
+ private Collection<ArtifactLocation> resources = Lists.newArrayList();
+ private ArtifactLocation manifest;
+ private LibraryArtifact idlJar;
+ private LibraryArtifact resourceJar;
+ private boolean hasIdlSources;
+ private String resourceJavaPackage;
+ private boolean generateResourceClass;
+ private Label legacyResources;
+
+ public Builder setManifestFile(ArtifactLocation artifactLocation) {
+ this.manifest = artifactLocation;
+ return this;
+ }
+
+ public Builder addResource(ArtifactLocation artifactLocation) {
+ this.resources.add(artifactLocation);
+ return this;
+ }
+
+ public Builder setIdlJar(LibraryArtifact idlJar) {
+ this.idlJar = idlJar;
+ return this;
+ }
+
+ public Builder setHasIdlSources(boolean hasIdlSources) {
+ this.hasIdlSources = hasIdlSources;
+ return this;
+ }
+
+ public Builder setResourceJar(LibraryArtifact.Builder resourceJar) {
+ this.resourceJar = resourceJar.build();
+ return this;
+ }
+
+ public Builder setResourceJavaPackage(@Nullable String resourceJavaPackage) {
+ this.resourceJavaPackage = resourceJavaPackage;
+ return this;
+ }
+
+ public Builder setGenerateResourceClass(boolean generateResourceClass) {
+ this.generateResourceClass = generateResourceClass;
+ return this;
+ }
+
+ public Builder setLegacyResources(@Nullable Label legacyResources) {
+ this.legacyResources = legacyResources;
+ return this;
+ }
+
+ public AndroidRuleIdeInfo build() {
+ if (!resources.isEmpty() || manifest != null) {
+ if (!generateResourceClass) {
+ throw new IllegalStateException(
+ "Must set generateResourceClass if manifest or resources set");
+ }
+ }
+
+ return new AndroidRuleIdeInfo(
+ resources,
+ resourceJavaPackage,
+ generateResourceClass,
+ manifest,
+ idlJar,
+ resourceJar,
+ hasIdlSources,
+ legacyResources);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java b/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
new file mode 100644
index 0000000..ac2c392
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.base.Objects;
+import java.io.File;
+import java.io.Serializable;
+import java.nio.file.Paths;
+
+/** Represents a blaze-produced artifact. */
+public final class ArtifactLocation implements Serializable {
+ private static final long serialVersionUID = 2L;
+
+ public final String rootPath;
+ public final String rootExecutionPathFragment;
+ public final String relativePath;
+ public final boolean isSource;
+
+ private ArtifactLocation(
+ String rootPath, String rootExecutionPathFragment, String relativePath, boolean isSource) {
+ this.rootPath = rootPath;
+ this.rootExecutionPathFragment = rootExecutionPathFragment;
+ this.relativePath = relativePath;
+ this.isSource = isSource;
+ }
+
+ /** Returns the root path of the artifact, eg. blaze-out */
+ public String getRootPath() {
+ return rootPath;
+ }
+
+ /** Gets the path relative to the root path. */
+ public String getRelativePath() {
+ return relativePath;
+ }
+
+ public boolean isSource() {
+ return isSource;
+ }
+
+ public boolean isGenerated() {
+ return !isSource;
+ }
+
+ public File getFile() {
+ return new File(getRootPath(), getRelativePath());
+ }
+
+ /**
+ * Returns rootExecutionPathFragment + relativePath. For source artifacts, this is simply
+ * relativePath
+ */
+ public String getExecutionRootRelativePath() {
+ return Paths.get(rootExecutionPathFragment, relativePath).toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for an artifact location */
+ public static class Builder {
+ String rootPath;
+ String relativePath;
+ String rootExecutionPathFragment = "";
+ boolean isSource;
+
+ public Builder setRootPath(String rootPath) {
+ this.rootPath = rootPath;
+ return this;
+ }
+
+ public Builder setRelativePath(String relativePath) {
+ this.relativePath = relativePath;
+ return this;
+ }
+
+ public Builder setRootExecutionPathFragment(String rootExecutionPathFragment) {
+ this.rootExecutionPathFragment = rootExecutionPathFragment;
+ return this;
+ }
+
+ public Builder setIsSource(boolean isSource) {
+ this.isSource = isSource;
+ return this;
+ }
+
+ public ArtifactLocation build() {
+ return new ArtifactLocation(rootPath, rootExecutionPathFragment, relativePath, isSource);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ArtifactLocation that = (ArtifactLocation) o;
+ return Objects.equal(rootPath, that.rootPath)
+ && Objects.equal(rootExecutionPathFragment, that.rootExecutionPathFragment)
+ && Objects.equal(relativePath, that.relativePath)
+ && Objects.equal(isSource, that.isSource);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(rootPath, rootExecutionPathFragment, relativePath, isSource);
+ }
+
+ @Override
+ public String toString() {
+ return getFile().toString();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/CRuleIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/CRuleIdeInfo.java
new file mode 100644
index 0000000..954ab66
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/CRuleIdeInfo.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import java.io.Serializable;
+
+/** Sister class to {@link JavaRuleIdeInfo} */
+public class CRuleIdeInfo implements Serializable {
+ private static final long serialVersionUID = 6L;
+
+ public final ImmutableList<ArtifactLocation> sources;
+
+ // From the cpp compilation context provider.
+ // These should all be for the entire transitive closure.
+ public final ImmutableList<ExecutionRootPath> transitiveIncludeDirectories;
+ public final ImmutableList<ExecutionRootPath> transitiveQuoteIncludeDirectories;
+ public final ImmutableList<String> transitiveDefines;
+ public final ImmutableList<ExecutionRootPath> transitiveSystemIncludeDirectories;
+
+ public CRuleIdeInfo(
+ ImmutableList<ArtifactLocation> sources,
+ ImmutableList<ExecutionRootPath> transitiveIncludeDirectories,
+ ImmutableList<ExecutionRootPath> transitiveQuoteIncludeDirectories,
+ ImmutableList<String> transitiveDefines,
+ ImmutableList<ExecutionRootPath> transitiveSystemIncludeDirectories) {
+ this.sources = sources;
+ this.transitiveIncludeDirectories = transitiveIncludeDirectories;
+ this.transitiveQuoteIncludeDirectories = transitiveQuoteIncludeDirectories;
+ this.transitiveDefines = transitiveDefines;
+ this.transitiveSystemIncludeDirectories = transitiveSystemIncludeDirectories;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for c rule info */
+ public static class Builder {
+ private final ImmutableList.Builder<ArtifactLocation> sources = ImmutableList.builder();
+
+ private final ImmutableList.Builder<ExecutionRootPath> transitiveIncludeDirectories =
+ ImmutableList.builder();
+ private final ImmutableList.Builder<ExecutionRootPath> transitiveQuoteIncludeDirectories =
+ ImmutableList.builder();
+ private final ImmutableList.Builder<String> transitiveDefines = ImmutableList.builder();
+ private final ImmutableList.Builder<ExecutionRootPath> transitiveSystemIncludeDirectories =
+ ImmutableList.builder();
+
+ public Builder addSources(Iterable<ArtifactLocation> sources) {
+ this.sources.addAll(sources);
+ return this;
+ }
+
+ public Builder addTransitiveIncludeDirectories(
+ Iterable<ExecutionRootPath> transitiveIncludeDirectories) {
+ this.transitiveIncludeDirectories.addAll(transitiveIncludeDirectories);
+ return this;
+ }
+
+ public Builder addTransitiveQuoteIncludeDirectories(
+ Iterable<ExecutionRootPath> transitiveQuoteIncludeDirectories) {
+ this.transitiveQuoteIncludeDirectories.addAll(transitiveQuoteIncludeDirectories);
+ return this;
+ }
+
+ public Builder addTransitiveDefines(Iterable<String> transitiveDefines) {
+ this.transitiveDefines.addAll(transitiveDefines);
+ return this;
+ }
+
+ public Builder addTransitiveSystemIncludeDirectories(
+ Iterable<ExecutionRootPath> transitiveSystemIncludeDirectories) {
+ this.transitiveSystemIncludeDirectories.addAll(transitiveSystemIncludeDirectories);
+ return this;
+ }
+
+ public CRuleIdeInfo build() {
+ return new CRuleIdeInfo(
+ sources.build(),
+ transitiveIncludeDirectories.build(),
+ transitiveQuoteIncludeDirectories.build(),
+ transitiveDefines.build(),
+ transitiveSystemIncludeDirectories.build());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CRuleIdeInfo{"
+ + "\n"
+ + " sources="
+ + sources
+ + "\n"
+ + " transitiveIncludeDirectories="
+ + transitiveIncludeDirectories
+ + "\n"
+ + " transitiveQuoteIncludeDirectories="
+ + transitiveQuoteIncludeDirectories
+ + "\n"
+ + " transitiveDefines="
+ + transitiveDefines
+ + "\n"
+ + " transitiveSystemIncludeDirectories="
+ + transitiveSystemIncludeDirectories
+ + "\n"
+ + '}';
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java
new file mode 100644
index 0000000..867b1fe
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import java.io.Serializable;
+
+/** Sister class to {@link JavaRuleIdeInfo} */
+public class CToolchainIdeInfo implements Serializable {
+ private static final long serialVersionUID = 3L;
+
+ public final ImmutableList<String> baseCompilerOptions;
+ public final ImmutableList<String> cCompilerOptions;
+ public final ImmutableList<String> cppCompilerOptions;
+ public final ImmutableList<String> linkOptions;
+ public final ImmutableList<ExecutionRootPath> builtInIncludeDirectories;
+ public final ExecutionRootPath cppExecutable;
+ public final ExecutionRootPath preprocessorExecutable;
+ public final String targetName;
+
+ public final ImmutableList<String> unfilteredCompilerOptions;
+ public final ImmutableList<ExecutionRootPath> unfilteredToolchainSystemIncludes;
+
+ public CToolchainIdeInfo(
+ ImmutableList<String> baseCompilerOptions,
+ ImmutableList<String> cCompilerOptions,
+ ImmutableList<String> cppCompilerOptions,
+ ImmutableList<String> linkOptions,
+ ImmutableList<ExecutionRootPath> builtInIncludeDirectories,
+ ExecutionRootPath cppExecutable,
+ ExecutionRootPath preprocessorExecutable,
+ String targetName,
+ ImmutableList<String> unfilteredCompilerOptions,
+ ImmutableList<ExecutionRootPath> unfilteredToolchainSystemIncludes) {
+ this.baseCompilerOptions = baseCompilerOptions;
+ this.cCompilerOptions = cCompilerOptions;
+ this.cppCompilerOptions = cppCompilerOptions;
+ this.linkOptions = linkOptions;
+ this.builtInIncludeDirectories = builtInIncludeDirectories;
+ this.cppExecutable = cppExecutable;
+ this.preprocessorExecutable = preprocessorExecutable;
+ this.targetName = targetName;
+ this.unfilteredCompilerOptions = unfilteredCompilerOptions;
+ this.unfilteredToolchainSystemIncludes = unfilteredToolchainSystemIncludes;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for c toolchain */
+ public static class Builder {
+ private final ImmutableList.Builder<String> baseCompilerOptions = ImmutableList.builder();
+ private final ImmutableList.Builder<String> cCompilerOptions = ImmutableList.builder();
+ private final ImmutableList.Builder<String> cppCompilerOptions = ImmutableList.builder();
+ private final ImmutableList.Builder<String> linkOptions = ImmutableList.builder();
+
+ private final ImmutableList.Builder<ExecutionRootPath> builtInIncludeDirectories =
+ ImmutableList.builder();
+
+ ExecutionRootPath cppExecutable;
+ ExecutionRootPath preprocessorExecutable;
+
+ String targetName = "";
+
+ private final ImmutableList.Builder<String> unfilteredCompilerOptions = ImmutableList.builder();
+ private final ImmutableList.Builder<ExecutionRootPath> unfilteredToolchainSystemIncludes =
+ ImmutableList.builder();
+
+ public Builder addBaseCompilerOptions(Iterable<String> baseCompilerOptions) {
+ this.baseCompilerOptions.addAll(baseCompilerOptions);
+ return this;
+ }
+
+ public Builder addCCompilerOptions(Iterable<String> cCompilerOptions) {
+ this.cCompilerOptions.addAll(cCompilerOptions);
+ return this;
+ }
+
+ public Builder addCppCompilerOptions(Iterable<String> cppCompilerOptions) {
+ this.cppCompilerOptions.addAll(cppCompilerOptions);
+ return this;
+ }
+
+ public Builder addLinkOptions(Iterable<String> linkOptions) {
+ this.linkOptions.addAll(linkOptions);
+ return this;
+ }
+
+ public Builder addBuiltInIncludeDirectories(
+ Iterable<ExecutionRootPath> builtInIncludeDirectories) {
+ this.builtInIncludeDirectories.addAll(builtInIncludeDirectories);
+ return this;
+ }
+
+ public Builder setCppExecutable(ExecutionRootPath cppExecutable) {
+ this.cppExecutable = cppExecutable;
+ return this;
+ }
+
+ public Builder setPreprocessorExecutable(ExecutionRootPath preprocessorExecutable) {
+ this.preprocessorExecutable = preprocessorExecutable;
+ return this;
+ }
+
+ public Builder setTargetName(String targetName) {
+ this.targetName = targetName;
+ return this;
+ }
+
+ public Builder addUnfilteredCompilerOptions(Iterable<String> unfilteredCompilerOptions) {
+ this.unfilteredCompilerOptions.addAll(unfilteredCompilerOptions);
+ return this;
+ }
+
+ public Builder addUnfilteredToolchainSystemIncludes(
+ Iterable<ExecutionRootPath> unfilteredToolchainSystemIncludes) {
+ this.unfilteredToolchainSystemIncludes.addAll(unfilteredToolchainSystemIncludes);
+ return this;
+ }
+
+ public CToolchainIdeInfo build() {
+ return new CToolchainIdeInfo(
+ baseCompilerOptions.build(),
+ cCompilerOptions.build(),
+ cppCompilerOptions.build(),
+ linkOptions.build(),
+ builtInIncludeDirectories.build(),
+ cppExecutable,
+ preprocessorExecutable,
+ targetName,
+ unfilteredCompilerOptions.build(),
+ unfilteredToolchainSystemIncludes.build());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CToolchainIdeInfo{"
+ + "\n"
+ + " baseCompilerOptions="
+ + baseCompilerOptions
+ + "\n"
+ + " cCompilerOptions="
+ + cCompilerOptions
+ + "\n"
+ + " cppCompilerOptions="
+ + cppCompilerOptions
+ + "\n"
+ + " linkOptions="
+ + linkOptions
+ + "\n"
+ + " builtInIncludeDirectories="
+ + builtInIncludeDirectories
+ + "\n"
+ + " cppExecutable='"
+ + cppExecutable
+ + '\''
+ + "\n"
+ + " preprocessorExecutable='"
+ + preprocessorExecutable
+ + '\''
+ + "\n"
+ + " targetName='"
+ + targetName
+ + '\''
+ + "\n"
+ + " unfilteredCompilerOptions="
+ + unfilteredCompilerOptions
+ + "\n"
+ + " unfilteredToolchainSystemIncludes="
+ + unfilteredToolchainSystemIncludes
+ + "\n"
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CToolchainIdeInfo that = (CToolchainIdeInfo) o;
+ return Objects.equal(baseCompilerOptions, that.baseCompilerOptions)
+ && Objects.equal(cCompilerOptions, that.cCompilerOptions)
+ && Objects.equal(cppCompilerOptions, that.cppCompilerOptions)
+ && Objects.equal(linkOptions, that.linkOptions)
+ && Objects.equal(builtInIncludeDirectories, that.builtInIncludeDirectories)
+ && Objects.equal(cppExecutable, that.cppExecutable)
+ && Objects.equal(preprocessorExecutable, that.preprocessorExecutable)
+ && Objects.equal(targetName, that.targetName)
+ && Objects.equal(unfilteredCompilerOptions, that.unfilteredCompilerOptions)
+ && Objects.equal(unfilteredToolchainSystemIncludes, that.unfilteredToolchainSystemIncludes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(
+ baseCompilerOptions,
+ cCompilerOptions,
+ cppCompilerOptions,
+ linkOptions,
+ builtInIncludeDirectories,
+ cppExecutable,
+ preprocessorExecutable,
+ targetName,
+ unfilteredCompilerOptions,
+ unfilteredToolchainSystemIncludes);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/JavaRuleIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/JavaRuleIdeInfo.java
new file mode 100644
index 0000000..35f5a15
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/JavaRuleIdeInfo.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.collect.ImmutableList;
+import java.io.Serializable;
+import java.util.Collection;
+import org.jetbrains.annotations.Nullable;
+
+/** Ide info specific to java rules. */
+public final class JavaRuleIdeInfo implements Serializable {
+ private static final long serialVersionUID = 2L;
+
+ /**
+ * The main jar(s) produced by this java rule.
+ *
+ * <p>Usually this will be a single jar, but java_imports support importing multiple jars.
+ */
+ public final Collection<LibraryArtifact> jars;
+
+ /** A jar containing annotation processing. */
+ public final Collection<LibraryArtifact> generatedJars;
+
+ /**
+ * A jar containing code from *only* generated sources, iff the rule contains both generated and
+ * non-generated sources.
+ */
+ @Nullable public final LibraryArtifact filteredGenJar;
+
+ /** File containing a map from .java files to their corresponding package. */
+ @Nullable public final ArtifactLocation packageManifest;
+
+ /** File containing dependencies. */
+ @Nullable public final ArtifactLocation jdepsFile;
+
+ public JavaRuleIdeInfo(
+ Collection<LibraryArtifact> jars,
+ Collection<LibraryArtifact> generatedJars,
+ @Nullable LibraryArtifact filteredGenJar,
+ @Nullable ArtifactLocation packageManifest,
+ @Nullable ArtifactLocation jdepsFile) {
+ this.jars = jars;
+ this.generatedJars = generatedJars;
+ this.packageManifest = packageManifest;
+ this.jdepsFile = jdepsFile;
+ this.filteredGenJar = filteredGenJar;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for java info */
+ public static class Builder {
+ ImmutableList.Builder<LibraryArtifact> jars = ImmutableList.builder();
+ ImmutableList.Builder<LibraryArtifact> generatedJars = ImmutableList.builder();
+ LibraryArtifact filteredGenJar;
+
+ public Builder addJar(LibraryArtifact.Builder jar) {
+ jars.add(jar.build());
+ return this;
+ }
+
+ public Builder addGeneratedJar(LibraryArtifact.Builder jar) {
+ generatedJars.add(jar.build());
+ return this;
+ }
+
+ public Builder setFilteredGenJar(LibraryArtifact.Builder jar) {
+ this.filteredGenJar = jar.build();
+ return this;
+ }
+
+ public JavaRuleIdeInfo build() {
+ return new JavaRuleIdeInfo(jars.build(), generatedJars.build(), filteredGenJar, null, null);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/JavaToolchainIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/JavaToolchainIdeInfo.java
new file mode 100644
index 0000000..b9a9dca
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/JavaToolchainIdeInfo.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import java.io.Serializable;
+
+/** Represents the java_toolchain class */
+public class JavaToolchainIdeInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final String sourceVersion;
+ public final String targetVersion;
+
+ public JavaToolchainIdeInfo(String sourceVersion, String targetVersion) {
+ this.sourceVersion = sourceVersion;
+ this.targetVersion = targetVersion;
+ }
+
+ @Override
+ public String toString() {
+ return "JavaToolchainIdeInfo{"
+ + "\n"
+ + " sourceVersion="
+ + sourceVersion
+ + "\n"
+ + " targetVersion="
+ + targetVersion
+ + "\n"
+ + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for java toolchain info */
+ public static class Builder {
+ String sourceVersion;
+ String targetVersion;
+
+ public Builder setSourceVersion(String sourceVersion) {
+ this.sourceVersion = sourceVersion;
+ return this;
+ }
+
+ public Builder setTargetVersion(String targetVersion) {
+ this.targetVersion = targetVersion;
+ return this;
+ }
+
+ public JavaToolchainIdeInfo build() {
+ return new JavaToolchainIdeInfo(sourceVersion, targetVersion);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java b/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
new file mode 100644
index 0000000..f661e5a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.base.Objects;
+import java.io.Serializable;
+import org.jetbrains.annotations.Nullable;
+
+/** Represents a jar artifact. */
+public class LibraryArtifact implements Serializable {
+ private static final long serialVersionUID = 2L;
+
+ @Nullable public final ArtifactLocation interfaceJar;
+ @Nullable public final ArtifactLocation classJar;
+ @Nullable public final ArtifactLocation sourceJar;
+
+ public LibraryArtifact(
+ @Nullable ArtifactLocation interfaceJar,
+ @Nullable ArtifactLocation classJar,
+ @Nullable ArtifactLocation sourceJar) {
+ if (interfaceJar == null && classJar == null) {
+ throw new IllegalArgumentException("Interface and class jars cannot both be null.");
+ }
+
+ this.interfaceJar = interfaceJar;
+ this.classJar = classJar;
+ this.sourceJar = sourceJar;
+ }
+
+ /**
+ * Returns the best jar to add to IntelliJ.
+ *
+ * <p>We prefer the interface jar if one exists, otherwise the class jar.
+ */
+ public ArtifactLocation jarForIntellijLibrary() {
+ if (interfaceJar != null) {
+ return interfaceJar;
+ }
+ return classJar;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("jar=%s, ijar=%s, srcjar=%s", classJar, interfaceJar, sourceJar);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ LibraryArtifact that = (LibraryArtifact) o;
+ return Objects.equal(interfaceJar, that.interfaceJar)
+ && Objects.equal(classJar, that.classJar)
+ && Objects.equal(sourceJar, that.sourceJar);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(interfaceJar, classJar, sourceJar);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for library artifacts */
+ public static class Builder {
+ private ArtifactLocation interfaceJar;
+ private ArtifactLocation classJar;
+ private ArtifactLocation sourceJar;
+
+ public Builder setInterfaceJar(ArtifactLocation artifactLocation) {
+ this.interfaceJar = artifactLocation;
+ return this;
+ }
+
+ public Builder setClassJar(@Nullable ArtifactLocation artifactLocation) {
+ this.classJar = artifactLocation;
+ return this;
+ }
+
+ public Builder setSourceJar(@Nullable ArtifactLocation artifactLocation) {
+ this.sourceJar = artifactLocation;
+ return this;
+ }
+
+ public LibraryArtifact build() {
+ return new LibraryArtifact(interfaceJar, classJar, sourceJar);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/ProtoLibraryLegacyInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/ProtoLibraryLegacyInfo.java
new file mode 100644
index 0000000..464ba20
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/ProtoLibraryLegacyInfo.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.collect.ImmutableList;
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ * Proto library info for legacy proto libraries.
+ *
+ * <p>Replicates blaze semantics.
+ */
+public class ProtoLibraryLegacyInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** The api flavour used by the proto_library rule */
+ public enum ApiFlavor {
+ VERSION_1,
+ MUTABLE,
+ IMMUTABLE,
+ BOTH,
+ NONE,
+ }
+
+ public final ApiFlavor apiFlavor;
+
+ public final Collection<LibraryArtifact> jarsV1;
+ public final Collection<LibraryArtifact> jarsMutable;
+ public final Collection<LibraryArtifact> jarsImmutable;
+
+ public ProtoLibraryLegacyInfo(
+ ApiFlavor apiFlavor,
+ Collection<LibraryArtifact> jarsV1,
+ Collection<LibraryArtifact> jarsMutable,
+ Collection<LibraryArtifact> jarsImmutable) {
+ this.apiFlavor = apiFlavor;
+ this.jarsV1 = jarsV1;
+ this.jarsMutable = jarsMutable;
+ this.jarsImmutable = jarsImmutable;
+ }
+
+ public static Builder builder(ApiFlavor apiFlavor) {
+ return new Builder(apiFlavor);
+ }
+
+ /** Builder for proto library legacy info */
+ public static class Builder {
+ private final ApiFlavor apiFlavor;
+ private ImmutableList.Builder<LibraryArtifact> jarsV1 = ImmutableList.builder();
+ private ImmutableList.Builder<LibraryArtifact> jarsMutable = ImmutableList.builder();
+ private ImmutableList.Builder<LibraryArtifact> jarsImmutable = ImmutableList.builder();
+
+ Builder(ApiFlavor apiFlavor) {
+ this.apiFlavor = apiFlavor;
+ }
+
+ public Builder addJarV1(LibraryArtifact.Builder library) {
+ jarsV1.add(library.build());
+ return this;
+ }
+
+ public Builder addJarMutable(LibraryArtifact.Builder library) {
+ jarsMutable.add(library.build());
+ return this;
+ }
+
+ public Builder addJarImmutable(LibraryArtifact.Builder library) {
+ jarsImmutable.add(library.build());
+ return this;
+ }
+
+ public ProtoLibraryLegacyInfo build() {
+ return new ProtoLibraryLegacyInfo(
+ apiFlavor, jarsV1.build(), jarsMutable.build(), jarsImmutable.build());
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/RuleIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/RuleIdeInfo.java
new file mode 100644
index 0000000..a791efc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/RuleIdeInfo.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Simple implementation of RuleIdeInfo. */
+public final class RuleIdeInfo implements Serializable {
+ private static final long serialVersionUID = 10L;
+
+ public final Label label;
+ public final Kind kind;
+ @Nullable public final ArtifactLocation buildFile;
+ public final Collection<Label> dependencies;
+ public final Collection<Label> runtimeDeps;
+ public final Collection<String> tags;
+ public final Collection<ArtifactLocation> sources;
+ @Nullable public final CRuleIdeInfo cRuleIdeInfo;
+ @Nullable public final CToolchainIdeInfo cToolchainIdeInfo;
+ @Nullable public final JavaRuleIdeInfo javaRuleIdeInfo;
+ @Nullable public final AndroidRuleIdeInfo androidRuleIdeInfo;
+ @Nullable public final TestIdeInfo testIdeInfo;
+ @Nullable public final ProtoLibraryLegacyInfo protoLibraryLegacyInfo;
+ @Nullable public final JavaToolchainIdeInfo javaToolchainIdeInfo;
+
+ public RuleIdeInfo(
+ Label label,
+ Kind kind,
+ @Nullable ArtifactLocation buildFile,
+ Collection<Label> dependencies,
+ Collection<Label> runtimeDeps,
+ Collection<String> tags,
+ Collection<ArtifactLocation> sources,
+ @Nullable CRuleIdeInfo cRuleIdeInfo,
+ @Nullable CToolchainIdeInfo cToolchainIdeInfo,
+ @Nullable JavaRuleIdeInfo javaRuleIdeInfo,
+ @Nullable AndroidRuleIdeInfo androidRuleIdeInfo,
+ @Nullable TestIdeInfo testIdeInfo,
+ @Nullable ProtoLibraryLegacyInfo protoLibraryLegacyInfo,
+ @Nullable JavaToolchainIdeInfo javaToolchainIdeInfo) {
+ this.label = label;
+ this.kind = kind;
+ this.buildFile = buildFile;
+ this.dependencies = dependencies;
+ this.runtimeDeps = runtimeDeps;
+ this.tags = tags;
+ this.sources = sources;
+ this.cRuleIdeInfo = cRuleIdeInfo;
+ this.cToolchainIdeInfo = cToolchainIdeInfo;
+ this.javaRuleIdeInfo = javaRuleIdeInfo;
+ this.androidRuleIdeInfo = androidRuleIdeInfo;
+ this.testIdeInfo = testIdeInfo;
+ this.protoLibraryLegacyInfo = protoLibraryLegacyInfo;
+ this.javaToolchainIdeInfo = javaToolchainIdeInfo;
+ }
+
+ @Override
+ public String toString() {
+ return label.toString();
+ }
+
+ /** Returns whether this rule is one of the kinds. */
+ public boolean kindIsOneOf(Kind... kinds) {
+ return kindIsOneOf(Arrays.asList(kinds));
+ }
+
+ /** Returns whether this rule is one of the kinds. */
+ public boolean kindIsOneOf(List<Kind> kinds) {
+ if (kind != null) {
+ return kind.isOneOf(kinds);
+ }
+ return false;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for rule ide info */
+ public static class Builder {
+ private Label label;
+ private Kind kind;
+ private ArtifactLocation buildFile;
+ private final List<Label> dependencies = Lists.newArrayList();
+ private final List<Label> runtimeDeps = Lists.newArrayList();
+ private final List<String> tags = Lists.newArrayList();
+ private final List<ArtifactLocation> sources = Lists.newArrayList();
+ private final List<LibraryArtifact> libraries = Lists.newArrayList();
+ private CRuleIdeInfo cRuleIdeInfo;
+ private CToolchainIdeInfo cToolchainIdeInfo;
+ private JavaRuleIdeInfo javaRuleIdeInfo;
+ private AndroidRuleIdeInfo androidRuleIdeInfo;
+ private TestIdeInfo testIdeInfo;
+ private ProtoLibraryLegacyInfo protoLibraryLegacyInfo;
+ private JavaToolchainIdeInfo javaToolchainIdeInfo;
+
+ public Builder setLabel(String label) {
+ return setLabel(new Label(label));
+ }
+
+ public Builder setLabel(Label label) {
+ this.label = label;
+ return this;
+ }
+
+ public Builder setBuildFile(ArtifactLocation buildFile) {
+ this.buildFile = buildFile;
+ return this;
+ }
+
+ public Builder setKind(String kind) {
+ return setKind(Kind.fromString(kind));
+ }
+
+ public Builder setKind(Kind kind) {
+ this.kind = kind;
+ return this;
+ }
+
+ public Builder addSource(ArtifactLocation source) {
+ this.sources.add(source);
+ return this;
+ }
+
+ public Builder addSource(ArtifactLocation.Builder source) {
+ return addSource(source.build());
+ }
+
+ public Builder setJavaInfo(JavaRuleIdeInfo.Builder builder) {
+ javaRuleIdeInfo = builder.build();
+ return this;
+ }
+
+ public Builder setCInfo(CRuleIdeInfo cInfo) {
+ this.cRuleIdeInfo = cInfo;
+ return this;
+ }
+
+ public Builder setCInfo(CRuleIdeInfo.Builder cInfo) {
+ return setCInfo(cInfo.build());
+ }
+
+ public Builder setCToolchainInfo(CToolchainIdeInfo info) {
+ this.cToolchainIdeInfo = info;
+ return this;
+ }
+
+ public Builder setCToolchainInfo(CToolchainIdeInfo.Builder info) {
+ return setCToolchainInfo(info.build());
+ }
+
+ public Builder setAndroidInfo(AndroidRuleIdeInfo androidInfo) {
+ this.androidRuleIdeInfo = androidInfo;
+ return this;
+ }
+
+ public Builder setAndroidInfo(AndroidRuleIdeInfo.Builder androidInfo) {
+ return setAndroidInfo(androidInfo.build());
+ }
+
+ public Builder setTestInfo(TestIdeInfo.Builder testInfo) {
+ this.testIdeInfo = testInfo.build();
+ return this;
+ }
+
+ public Builder setProtoLibraryLegacyInfo(
+ ProtoLibraryLegacyInfo.Builder protoLibraryLegacyInfo) {
+ this.protoLibraryLegacyInfo = protoLibraryLegacyInfo.build();
+ return this;
+ }
+
+ public Builder setJavaToolchainIdeInfo(JavaToolchainIdeInfo.Builder javaToolchainIdeInfo) {
+ this.javaToolchainIdeInfo = javaToolchainIdeInfo.build();
+ return this;
+ }
+
+ public Builder addTag(String s) {
+ this.tags.add(s);
+ return this;
+ }
+
+ public Builder addDependency(String s) {
+ return addDependency(new Label(s));
+ }
+
+ public Builder addDependency(Label label) {
+ this.dependencies.add(label);
+ return this;
+ }
+
+ public Builder addRuntimeDep(String s) {
+ return addRuntimeDep(new Label(s));
+ }
+
+ public Builder addRuntimeDep(Label label) {
+ this.runtimeDeps.add(label);
+ return this;
+ }
+
+ public RuleIdeInfo build() {
+ return new RuleIdeInfo(
+ label,
+ kind,
+ buildFile,
+ dependencies,
+ runtimeDeps,
+ tags,
+ sources,
+ cRuleIdeInfo,
+ cToolchainIdeInfo,
+ javaRuleIdeInfo,
+ androidRuleIdeInfo,
+ testIdeInfo,
+ protoLibraryLegacyInfo,
+ javaToolchainIdeInfo);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/Tags.java b/base/src/com/google/idea/blaze/base/ideinfo/Tags.java
new file mode 100644
index 0000000..6f07e33
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/Tags.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+/** Tag constants used by our rules. */
+public class Tags {
+ /** Forces import of the target output. */
+ public static final String RULE_TAG_IMPORT_TARGET_OUTPUT = "intellij-import-target-output";
+
+ public static final String RULE_TAG_IMPORT_AS_LIBRARY_LEGACY = "aswb-import-as-library";
+
+ /**
+ * Signals to the import process that the output of this rule will be provided by the IntelliJ
+ * SDK.
+ */
+ public static final String RULE_TAG_PROVIDED_BY_SDK = "intellij-provided-by-sdk";
+
+ /** Ignores the target. */
+ public static final String RULE_TAG_EXCLUDE_TARGET = "intellij-exclude-target";
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/TestIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/TestIdeInfo.java
new file mode 100644
index 0000000..9257344
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ideinfo/TestIdeInfo.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Test info. */
+public class TestIdeInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** The "size" attribute from test rules */
+ public enum TestSize {
+ SMALL,
+ MEDIUM,
+ LARGE,
+ ENORMOUS
+ }
+
+ // Rules are "medium" test size by default
+ public static final TestSize DEFAULT_RULE_TEST_SIZE = TestSize.MEDIUM;
+
+ // Non-annotated methods and classes are "small" by default
+ public static final TestSize DEFAULT_NON_ANNOTATED_TEST_SIZE = TestSize.SMALL;
+
+ public final TestSize testSize;
+
+ public TestIdeInfo(TestSize testSize) {
+ this.testSize = testSize;
+ }
+
+ @Nullable
+ public static TestSize getTestSize(RuleIdeInfo rule) {
+ TestIdeInfo testIdeInfo = rule.testIdeInfo;
+ if (testIdeInfo == null) {
+ return null;
+ }
+ return testIdeInfo.testSize;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for test info */
+ public static class Builder {
+ private TestSize testSize = DEFAULT_RULE_TEST_SIZE;
+
+ public Builder setTestSize(TestSize testSize) {
+ this.testSize = testSize;
+ return this;
+ }
+
+ public TestIdeInfo build() {
+ return new TestIdeInfo(testSize);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/FileAttributeProvider.java b/base/src/com/google/idea/blaze/base/io/FileAttributeProvider.java
new file mode 100644
index 0000000..69f8465
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/FileAttributeProvider.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.intellij.openapi.components.ServiceManager;
+import java.io.File;
+
+/** Simple file system checks (existence, isDirectory) */
+public class FileAttributeProvider {
+
+ public static FileAttributeProvider getInstance() {
+ return ServiceManager.getService(FileAttributeProvider.class);
+ }
+
+ public boolean exists(File file) {
+ return file.exists();
+ }
+
+ public boolean isDirectory(File file) {
+ return file.isDirectory();
+ }
+
+ public boolean isFile(File file) {
+ return file.isFile();
+ }
+
+ public long getFileModifiedTime(File file) {
+ return file.lastModified();
+ }
+
+ public long getFileSize(File file) {
+ return file.length();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/FileAttributeScanner.java b/base/src/com/google/idea/blaze/base/io/FileAttributeScanner.java
new file mode 100644
index 0000000..bcb30aa
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/FileAttributeScanner.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import java.io.File;
+import java.util.List;
+
+/** Reads file attributes from a list files in parallel. */
+public class FileAttributeScanner {
+
+ interface AttributeReader<T> {
+ T getAttribute(File file);
+
+ boolean isValid(T attribute);
+ }
+
+ public static <T> ImmutableMap<File, T> readAttributes(
+ Iterable<File> fileList, AttributeReader<T> attributeReader, BlazeExecutor executor)
+ throws Exception {
+ List<ListenableFuture<FilePair<T>>> futures = Lists.newArrayList();
+ for (File file : fileList) {
+ futures.add(
+ executor.submit(
+ () -> {
+ T attribute = attributeReader.getAttribute(file);
+ if (attributeReader.isValid(attribute)) {
+ return new FilePair<>(file, attribute);
+ }
+ return null;
+ }));
+ }
+
+ ImmutableMap.Builder<File, T> result = ImmutableMap.builder();
+ for (FilePair<T> filePair : Futures.allAsList(futures).get()) {
+ if (filePair != null) {
+ result.put(filePair.file, filePair.attribute);
+ }
+ }
+ return result.build();
+ }
+
+ private static class FilePair<T> {
+ public final File file;
+ public final T attribute;
+
+ public FilePair(File file, T attribute) {
+ this.file = file;
+ this.attribute = attribute;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/FileSizeScanner.java b/base/src/com/google/idea/blaze/base/io/FileSizeScanner.java
new file mode 100644
index 0000000..6930825
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/FileSizeScanner.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import java.io.File;
+
+/** Reads the file sizes from a list of files. */
+public class FileSizeScanner {
+
+ private static final class FileSizeReader implements FileAttributeScanner.AttributeReader<Long> {
+
+ private final FileAttributeProvider attributeProvider;
+
+ FileSizeReader(FileAttributeProvider attributeProvider) {
+ this.attributeProvider = attributeProvider;
+ }
+
+ @Override
+ public Long getAttribute(File file) {
+ return attributeProvider.getFileSize(file);
+ }
+
+ @Override
+ public boolean isValid(Long timestamp) {
+ return timestamp != 0;
+ }
+ }
+
+ public static ImmutableMap<File, Long> readFilesizes(Iterable<File> fileList) throws Exception {
+ final FileSizeReader fileSizeReader = new FileSizeReader(FileAttributeProvider.getInstance());
+ return FileAttributeScanner.readAttributes(
+ fileList, fileSizeReader, BlazeExecutor.getInstance());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/InputStreamProvider.java b/base/src/com/google/idea/blaze/base/io/InputStreamProvider.java
new file mode 100644
index 0000000..24607f9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/InputStreamProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.intellij.openapi.components.ServiceManager;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Provides input streams for files. */
+public interface InputStreamProvider {
+
+ static InputStreamProvider getInstance() {
+ return ServiceManager.getService(InputStreamProvider.class);
+ }
+
+ InputStream getFile(File file) throws IOException;
+}
diff --git a/base/src/com/google/idea/blaze/base/io/InputStreamProviderImpl.java b/base/src/com/google/idea/blaze/base/io/InputStreamProviderImpl.java
new file mode 100644
index 0000000..1d5507a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/InputStreamProviderImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import org.jetbrains.annotations.NotNull;
+
+/** Default implementation of InputStreamProvider. */
+final class InputStreamProviderImpl implements InputStreamProvider {
+
+ @Override
+ public InputStream getFile(@NotNull File file) throws FileNotFoundException {
+ return new FileInputStream(file);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/ModifiedTimeScanner.java b/base/src/com/google/idea/blaze/base/io/ModifiedTimeScanner.java
new file mode 100644
index 0000000..d7c66db
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/ModifiedTimeScanner.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import java.io.File;
+
+/** Reads the last modified times from a list of files. */
+public class ModifiedTimeScanner {
+
+ private static final class TimestampReader implements FileAttributeScanner.AttributeReader<Long> {
+
+ private final FileAttributeProvider attributeProvider;
+
+ TimestampReader(FileAttributeProvider attributeProvider) {
+ this.attributeProvider = attributeProvider;
+ }
+
+ @Override
+ public Long getAttribute(File file) {
+ return attributeProvider.getFileModifiedTime(file);
+ }
+
+ @Override
+ public boolean isValid(Long timestamp) {
+ return timestamp != 0;
+ }
+ }
+
+ public static ImmutableMap<File, Long> readTimestamps(Iterable<File> fileList) throws Exception {
+ final TimestampReader timestampReader =
+ new TimestampReader(FileAttributeProvider.getInstance());
+ return FileAttributeScanner.readAttributes(
+ fileList, timestampReader, BlazeExecutor.getInstance());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/VfsWorkspaceScanner.java b/base/src/com/google/idea/blaze/base/io/VfsWorkspaceScanner.java
new file mode 100644
index 0000000..de12e98
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/VfsWorkspaceScanner.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Checks the workspace using the VFS. */
+class VfsWorkspaceScanner implements WorkspaceScanner {
+ private final LocalFileSystem localFileSystem;
+
+ public VfsWorkspaceScanner() {
+ this.localFileSystem = LocalFileSystem.getInstance();
+ }
+
+ @Override
+ public boolean exists(WorkspaceRoot workspaceRoot, WorkspacePath workspacePath) {
+ VirtualFile virtualFile =
+ localFileSystem.refreshAndFindFileByPath(
+ workspaceRoot.fileForPath(workspacePath).getPath());
+ return virtualFile != null && virtualFile.exists();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/io/WorkspaceScanner.java b/base/src/com/google/idea/blaze/base/io/WorkspaceScanner.java
new file mode 100644
index 0000000..4fdc691
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/io/WorkspaceScanner.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.openapi.components.ServiceManager;
+
+/** Used to scan the file system */
+public interface WorkspaceScanner {
+ static WorkspaceScanner getInstance() {
+ return ServiceManager.getService(WorkspaceScanner.class);
+ }
+
+ boolean exists(WorkspaceRoot workspaceRoot, WorkspacePath workspacePath);
+}
diff --git a/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java b/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
new file mode 100644
index 0000000..57fcbbd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.issueparser;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.Section;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Parses blaze output for compile errors. */
+public class BlazeIssueParser {
+
+ private static class ParseResult {
+
+ public static final ParseResult NEEDS_MORE_INPUT = new ParseResult(true, null);
+
+ public static final ParseResult NO_RESULT = new ParseResult(false, null);
+
+ private boolean needsMoreInput;
+ @Nullable private IssueOutput output;
+
+ private ParseResult(boolean needsMoreInput, IssueOutput output) {
+ this.needsMoreInput = needsMoreInput;
+ this.output = output;
+ }
+
+ public static ParseResult needsMoreInput() {
+ return NEEDS_MORE_INPUT;
+ }
+
+ public static ParseResult output(IssueOutput output) {
+ return new ParseResult(false, output);
+ }
+
+ public static ParseResult noResult() {
+ return NO_RESULT;
+ }
+ }
+
+ interface Parser {
+ @NotNull
+ ParseResult parse(@NotNull String currentLine, @NotNull List<String> previousLines);
+ }
+
+ abstract static class SingleLineParser implements Parser {
+ @NotNull Pattern pattern;
+
+ SingleLineParser(@NotNull String regex) {
+ pattern = Pattern.compile(regex);
+ }
+
+ @Override
+ public ParseResult parse(
+ @NotNull String currentLine, @NotNull List<String> multilineMatchResult) {
+ checkState(
+ multilineMatchResult.isEmpty(), "SingleLineParser recieved multiple lines of input");
+ return parse(currentLine);
+ }
+
+ ParseResult parse(@NotNull String line) {
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.find()) {
+ return ParseResult.output(createIssue(matcher));
+ }
+ return ParseResult.noResult();
+ }
+
+ @Nullable
+ protected abstract IssueOutput createIssue(@NotNull Matcher matcher);
+ }
+
+ static class CompileParser extends SingleLineParser {
+ @NotNull private final WorkspaceRoot workspaceRoot;
+
+ public CompileParser(@NotNull WorkspaceRoot workspaceRoot) {
+ super("(.*?):([0-9]+):([0-9]+:)? (error|warning): (.*)");
+ this.workspaceRoot = workspaceRoot;
+ }
+
+ @Override
+ protected IssueOutput createIssue(@NotNull Matcher matcher) {
+ final File file;
+ try {
+ String fileName = matcher.group(1);
+ final WorkspacePath workspacePath;
+ if (fileName.startsWith("//depot/google3/")) {
+ workspacePath = new WorkspacePath(fileName.substring("//depot/google3/".length()));
+ } else if (fileName.startsWith("/")) {
+ workspacePath = workspaceRoot.workspacePathFor(new File(fileName));
+ } else {
+ workspacePath = new WorkspacePath(fileName);
+ }
+ file = workspaceRoot.fileForPath(workspacePath);
+ } catch (IllegalArgumentException e) {
+ // Ignore -- malformed error message
+ return null;
+ }
+
+ IssueOutput.Category type =
+ matcher.group(4).equals("error")
+ ? IssueOutput.Category.ERROR
+ : IssueOutput.Category.WARNING;
+ return IssueOutput.issue(type, matcher.group(5))
+ .inFile(file)
+ .onLine(Integer.parseInt(matcher.group(2)))
+ .build();
+ }
+ }
+
+ static class TracebackParser implements Parser {
+ private static final Pattern PATTERN =
+ Pattern.compile(
+ "(ERROR): (.*?):([0-9]+):([0-9]+): (Traceback \\(most recent call last\\):)");
+
+ @NotNull
+ @Override
+ public ParseResult parse(@NotNull String currentLine, @NotNull List<String> previousLines) {
+ if (previousLines.isEmpty()) {
+ if (PATTERN.matcher(currentLine).find()) {
+ return ParseResult.needsMoreInput();
+ } else {
+ return ParseResult.noResult();
+ }
+ }
+
+ if (currentLine.startsWith("\t")) {
+ return ParseResult.needsMoreInput();
+ } else {
+ Matcher matcher = PATTERN.matcher(previousLines.get(0));
+ checkState(
+ matcher.find(), "Found a match in the first line previously, but now it isn't there.");
+ StringBuilder message = new StringBuilder(matcher.group(5));
+ for (int i = 1; i < previousLines.size(); ++i) {
+ message.append(System.lineSeparator()).append(previousLines.get(i));
+ }
+ message.append(System.lineSeparator()).append(currentLine);
+ return ParseResult.output(
+ IssueOutput.error(message.toString())
+ .inFile(new File(matcher.group(2)))
+ .onLine(Integer.parseInt(matcher.group(3)))
+ .build());
+ }
+ }
+ }
+
+ static class BuildParser extends SingleLineParser {
+ BuildParser() {
+ super("(ERROR): (.*?):([0-9]+):([0-9]+): (.*)");
+ }
+
+ @Override
+ protected IssueOutput createIssue(@NotNull Matcher matcher) {
+ return IssueOutput.error(matcher.group(5))
+ .inFile(new File(matcher.group(2)))
+ .onLine(Integer.parseInt(matcher.group(3)))
+ .build();
+ }
+ }
+
+ static class LinelessBuildParser extends SingleLineParser {
+ LinelessBuildParser() {
+ super("(ERROR): (.*?):char offsets [0-9]+--[0-9]+: (.*)");
+ }
+
+ @Override
+ protected IssueOutput createIssue(@NotNull Matcher matcher) {
+ return IssueOutput.error(matcher.group(3)).inFile(new File(matcher.group(2))).build();
+ }
+ }
+
+ static class ProjectViewLabelParser extends SingleLineParser {
+
+ @Nullable private final ProjectViewSet projectViewSet;
+
+ ProjectViewLabelParser(@Nullable ProjectViewSet projectViewSet) {
+ super("no such target '(.*)': target .*? not declared in package .*? defined by");
+ this.projectViewSet = projectViewSet;
+ }
+
+ @Override
+ protected IssueOutput createIssue(@NotNull Matcher matcher) {
+ File file = null;
+ if (projectViewSet != null) {
+ String targetString = matcher.group(1);
+ final TargetExpression targetExpression = TargetExpression.fromString(targetString);
+ file =
+ projectViewFileWithSection(
+ projectViewSet,
+ TargetSection.KEY,
+ new Predicate<ListSection<TargetExpression>>() {
+ @Override
+ public boolean apply(@NotNull ListSection<TargetExpression> targetSection) {
+ return targetSection.items().contains(targetExpression);
+ }
+ });
+ }
+
+ return IssueOutput.error(matcher.group(0)).inFile(file).build();
+ }
+ }
+
+ static class InvalidTargetProjectViewPackageParser extends SingleLineParser {
+ @Nullable private final ProjectViewSet projectViewSet;
+
+ InvalidTargetProjectViewPackageParser(@Nullable ProjectViewSet projectViewSet, String regex) {
+ super(regex);
+ this.projectViewSet = projectViewSet;
+ }
+
+ @Override
+ protected IssueOutput createIssue(@NotNull Matcher matcher) {
+ File file = null;
+ if (projectViewSet != null) {
+ final String packageString = matcher.group(1);
+ file =
+ projectViewFileWithSection(
+ projectViewSet,
+ TargetSection.KEY,
+ targetSection -> {
+ for (TargetExpression targetExpression : targetSection.items()) {
+ if (targetExpression.toString().startsWith("//" + packageString + ":")) {
+ return true;
+ }
+ }
+ return false;
+ });
+ }
+
+ return IssueOutput.error(matcher.group(0)).inFile(file).build();
+ }
+ }
+
+ @Nullable
+ private static <T, SectionType extends Section<T>> File projectViewFileWithSection(
+ @NotNull ProjectViewSet projectViewSet,
+ @NotNull SectionKey<T, SectionType> key,
+ @NotNull Predicate<SectionType> predicate) {
+ for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
+ ImmutableList<SectionType> sections = projectViewFile.projectView.getSectionsOfType(key);
+ for (SectionType section : sections) {
+ if (predicate.apply(section)) {
+ return projectViewFile.projectViewFile;
+ }
+ }
+ }
+ return null;
+ }
+
+ @NotNull private List<Parser> parsers = Lists.newArrayList();
+ /**
+ * The parser that requested more lines of input during the last call to {@link
+ * #parseIssue(String)}.
+ */
+ @Nullable private Parser multilineMatchingParser;
+
+ @NotNull private List<String> multilineMatchResult = new ArrayList<>();
+
+ public BlazeIssueParser(@Nullable Project project, @NotNull WorkspaceRoot workspaceRoot) {
+
+ ProjectViewSet projectViewSet =
+ project != null ? ProjectViewManager.getInstance(project).getProjectViewSet() : null;
+
+ parsers.add(new CompileParser(workspaceRoot));
+ parsers.add(new TracebackParser());
+ parsers.add(new BuildParser());
+ parsers.add(new LinelessBuildParser());
+ parsers.add(new ProjectViewLabelParser(projectViewSet));
+ parsers.add(
+ new InvalidTargetProjectViewPackageParser(
+ projectViewSet, "no such package '(.*)': BUILD file not found on package path"));
+ parsers.add(
+ new InvalidTargetProjectViewPackageParser(
+ projectViewSet, "no targets found beneath '(.*)'"));
+ parsers.add(
+ new InvalidTargetProjectViewPackageParser(
+ projectViewSet, "ERROR: invalid target format '(.*)'"));
+ }
+
+ @Nullable
+ public IssueOutput parseIssue(String line) {
+
+ List<Parser> parsers = this.parsers;
+ if (multilineMatchingParser != null) {
+ parsers = Lists.newArrayList(multilineMatchingParser);
+ }
+
+ for (Parser parser : parsers) {
+ ParseResult issue = parser.parse(line, multilineMatchResult);
+ if (issue.needsMoreInput) {
+ multilineMatchingParser = parser;
+ multilineMatchResult.add(line);
+ return null;
+ } else {
+ multilineMatchingParser = null;
+ multilineMatchResult = new ArrayList<>();
+ }
+
+ if (issue.output != null) {
+ return issue.output;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java b/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
new file mode 100644
index 0000000..dbb313e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.issueparser;
+
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.PrintOutput.OutputType;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Forwards output to PrintOutputs, colored by whether or not an issue is found per-line.
+ *
+ * <p>Also creates IssueOutput if issues are found.
+ */
+public class IssueOutputLineProcessor implements LineProcessingOutputStream.LineProcessor {
+
+ @NotNull private final BlazeContext context;
+
+ @NotNull private final BlazeIssueParser blazeIssueParser;
+
+ public IssueOutputLineProcessor(
+ @Nullable Project project,
+ @NotNull BlazeContext context,
+ @NotNull WorkspaceRoot workspaceRoot) {
+ this.context = context;
+ this.blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ }
+
+ @Override
+ public boolean processLine(@NotNull String line) {
+ IssueOutput issue = blazeIssueParser.parseIssue(line);
+ if (issue != null) {
+ if (issue.getCategory() == IssueOutput.Category.ERROR) {
+ context.setHasError();
+ }
+ context.output(issue);
+ }
+
+ OutputType outputType = issue == null ? OutputType.NORMAL : OutputType.ERROR;
+
+ context.output(new PrintOutput(line, outputType));
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierImpl.java b/base/src/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierImpl.java
new file mode 100644
index 0000000..561bf04
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.actions;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.buildmodifier.BuildFileModifier;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.BuildElementGenerator;
+import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.psi.PsiElement;
+import java.io.File;
+
+/** Implementation of BuildFileModifier. Modifies the PSI tree directly. */
+public class BuildFileModifierImpl implements BuildFileModifier {
+
+ private static final Logger LOG = Logger.getInstance(BuildFileModifierImpl.class);
+
+ @Override
+ public boolean addRule(Project project, BlazeContext context, Label newRule, Kind ruleKind) {
+ return WriteCommandAction.runWriteCommandAction(
+ project,
+ (Computable<Boolean>)
+ () -> {
+ BuildReferenceManager manager = BuildReferenceManager.getInstance(project);
+ File file = manager.resolvePackage(newRule.blazePackage());
+ if (file == null) {
+ return null;
+ }
+ LocalFileSystem.getInstance().refreshIoFiles(ImmutableList.of(file));
+ BuildFile buildFile = manager.resolveBlazePackage(newRule.blazePackage());
+ if (buildFile == null) {
+ LOG.error("No BUILD file found at location: " + newRule.blazePackage());
+ return false;
+ }
+ buildFile.add(createRule(project, ruleKind, newRule.ruleName().toString()));
+ return true;
+ });
+ }
+
+ private PsiElement createRule(Project project, Kind ruleKind, String ruleName) {
+ String text =
+ Joiner.on("\n").join(ruleKind.toString() + "(", " name = \"" + ruleName + "\"", ")");
+ Expression expr = BuildElementGenerator.getInstance(project).createExpressionFromText(text);
+ assert (expr instanceof FuncallExpression);
+ return expr;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributor.java
new file mode 100644
index 0000000..f4e420f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributor.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiComment;
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.intellij.codeInsight.completion.AutoCompletionContext;
+import com.intellij.codeInsight.completion.AutoCompletionDecision;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.ProcessingContext;
+
+/**
+ * We can't rely solely keyword arg references, because as the user is typing a new keyword arg, the
+ * PsiElement will be a ReferenceExpression (with different completion results not relevant to
+ * keyword args).
+ */
+public class ArgumentCompletionContributor extends CompletionContributor {
+
+ @Override
+ public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ // auto-insert the obvious only case; else show other cases.
+ final LookupElement[] items = context.getItems();
+ if (items.length == 1) {
+ return AutoCompletionDecision.insertItem(items[0]);
+ }
+ return AutoCompletionDecision.SHOW_LOOKUP;
+ }
+
+ public ArgumentCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement()
+ .withLanguage(BuildFileLanguage.INSTANCE)
+ .withElementType(BuildToken.fromKind(TokenKind.IDENTIFIER))
+ .withParents(ReferenceExpression.class, Argument.Positional.class)
+ .andNot(psiComment())
+ .andNot(psiElement().afterLeaf("="))
+ .andNot(psiElement().afterLeaf(psiElement(BuildToken.fromKind(TokenKind.IDENTIFIER)))),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters,
+ ProcessingContext context,
+ CompletionResultSet result) {
+ Argument.Positional arg =
+ PsiTreeUtil.getParentOfType(parameters.getPosition(), Argument.Positional.class);
+ if (arg != null) {
+ Object[] lookups = arg.getReference().getVariants();
+ for (Object lookup : lookups) {
+ if (lookup instanceof LookupElement) {
+ result.addElement((LookupElement) lookup);
+ }
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java
new file mode 100644
index 0000000..cc05ea4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.codeInsight.completion.InsertionContext;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
+import com.intellij.openapi.editor.Document;
+import com.intellij.psi.PsiElement;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * Handles some boilerplate, and allows lazy calculation of some expensive components, which aren't
+ * required if the element is filtered out by IJ.
+ */
+public abstract class BuildLookupElement extends LookupElement {
+
+ public static final BuildLookupElement[] EMPTY_ARRAY = new BuildLookupElement[0];
+
+ protected final String baseName;
+ protected final QuoteType quoteWrapping;
+ protected final boolean wrapWithQuotes;
+
+ public BuildLookupElement(String baseName, QuoteType quoteWrapping) {
+ this.baseName = baseName;
+ this.quoteWrapping = quoteWrapping;
+ this.wrapWithQuotes = quoteWrapping != QuoteType.NoQuotes;
+ }
+
+ @Override
+ public String getLookupString() {
+ return quoteWrapping.wrap(baseName);
+ }
+
+ @Nullable
+ public abstract Icon getIcon();
+
+ protected String getItemText() {
+ return baseName;
+ }
+
+ @Nullable
+ protected String getTypeText() {
+ return null;
+ }
+
+ @Nullable
+ protected String getTailText() {
+ return null;
+ }
+
+ @Override
+ public void renderElement(LookupElementPresentation presentation) {
+ presentation.setItemText(getItemText());
+ presentation.setTailText(getTailText());
+ presentation.setTypeText(getTypeText());
+ presentation.setIcon(getIcon());
+ }
+
+ /**
+ * If we're wrapping with quotes, handle the (very common) case where we have a closing quote
+ * after the caret -- we want to remove this quote.
+ *
+ * @param context
+ */
+ @Override
+ public void handleInsert(InsertionContext context) {
+ if (!wrapWithQuotes) {
+ super.handleInsert(context);
+ return;
+ }
+ Document document = context.getDocument();
+ context.commitDocument();
+ PsiElement suffix = context.getFile().findElementAt(context.getTailOffset());
+ if (suffix.getText().startsWith(quoteWrapping.quoteString)) {
+ int offset = suffix.getTextOffset();
+ document.deleteString(offset, offset + 1);
+ context.commitDocument();
+ }
+ if (caretInsideQuotes()) {
+ context.getEditor().getCaretModel().moveCaretRelatively(-1, 0, false, false, true);
+ }
+ }
+
+ /**
+ * If true, and we're wrapping with quotes, the caret is moved inside the closing quote after the
+ * insert operation is performed.
+ */
+ protected boolean caretInsideQuotes() {
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributor.java
new file mode 100644
index 0000000..1b16003
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributor.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiComment;
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.codeInsight.completion.AutoCompletionContext;
+import com.intellij.codeInsight.completion.AutoCompletionDecision;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.icons.AllIcons;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.ProcessingContext;
+import javax.annotation.Nullable;
+
+/** Known attributes for built-in blaze functions. */
+public class BuiltInFunctionAttributeCompletionContributor extends CompletionContributor {
+
+ @Override
+ public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ // auto-insert the obvious only case; else show other cases.
+ final LookupElement[] items = context.getItems();
+ if (items.length == 1) {
+ return AutoCompletionDecision.insertItem(items[0]);
+ }
+ return AutoCompletionDecision.SHOW_LOOKUP;
+ }
+
+ public BuiltInFunctionAttributeCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement()
+ .withLanguage(BuildFileLanguage.INSTANCE)
+ .inside(psiElement(FuncallExpression.class))
+ .andNot(psiComment())
+ .andNot(psiElement().afterLeaf("."))
+ .andOr(
+ psiElement().withSuperParent(2, FuncallExpression.class),
+ psiElement()
+ .withSuperParent(2, Argument.class)
+ .andNot(psiElement().afterLeaf("="))
+ .andNot(
+ psiElement()
+ .afterLeaf(psiElement(BuildToken.fromKind(TokenKind.IDENTIFIER))))),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters,
+ ProcessingContext context,
+ CompletionResultSet result) {
+ BuildLanguageSpec spec =
+ BuildLanguageSpecProvider.getInstance()
+ .getLanguageSpec(parameters.getPosition().getProject());
+ if (spec == null) {
+ return;
+ }
+ RuleDefinition rule = spec.getRule(getEnclosingFuncallName(parameters.getPosition()));
+ if (rule == null) {
+ return;
+ }
+ for (String attributeName : rule.getKnownAttributeNames()) {
+ result.addElement(
+ LookupElementBuilder.create(attributeName).withIcon(AllIcons.Nodes.Parameter));
+ }
+ }
+ });
+ }
+
+ @Nullable
+ private static String getEnclosingFuncallName(PsiElement element) {
+ FuncallExpression funcall = PsiUtils.getParentOfType(element, FuncallExpression.class);
+ return funcall != null ? funcall.getFunctionName() : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributor.java
new file mode 100644
index 0000000..bf37676
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributor.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiComment;
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.StatementList;
+import com.intellij.codeInsight.completion.AutoCompletionContext;
+import com.intellij.codeInsight.completion.AutoCompletionDecision;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.util.ProcessingContext;
+import icons.BlazeIcons;
+
+/** Completes built-in blaze function names. */
+public class BuiltInFunctionCompletionContributor extends CompletionContributor {
+
+ @Override
+ public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ // auto-insert the obvious only case; else show other cases.
+ final LookupElement[] items = context.getItems();
+ if (items.length == 1) {
+ return AutoCompletionDecision.insertItem(items[0]);
+ }
+ return AutoCompletionDecision.SHOW_LOOKUP;
+ }
+
+ public BuiltInFunctionCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement()
+ .withLanguage(BuildFileLanguage.INSTANCE)
+ .andNot(psiComment())
+ .andOr(
+ // Handles only top-level rules, and rules inside a function statement.
+ // There are several other possibilities (e.g. inside top-level list comprehension),
+ // but leaving out less common cases to avoid cluttering the autocomplete
+ // suggestions when it's not valid to enter a rule.
+ psiElement()
+ .withParents(
+ ReferenceExpression.class,
+ BuildFile.class), // leaf node => BuildReference => BuildFile
+ psiElement()
+ .inside(
+ psiElement(StatementList.class).inside(psiElement(FunctionStatement.class)))
+ .afterLeaf(
+ psiElement().withText(".").afterLeaf(psiElement().withText("native")))),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters,
+ ProcessingContext context,
+ CompletionResultSet result) {
+ BuildLanguageSpec spec =
+ BuildLanguageSpecProvider.getInstance()
+ .getLanguageSpec(parameters.getPosition().getProject());
+ if (spec == null) {
+ return;
+ }
+ for (String ruleName : spec.getKnownRuleNames()) {
+ result.addElement(
+ LookupElementBuilder.create(ruleName)
+ .withIcon(BlazeIcons.BuildRule)
+ .withInsertHandler(ParenthesesInsertHandler.getInstance(true)));
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/CompletionResultsProcessor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/CompletionResultsProcessor.java
new file mode 100644
index 0000000..ba6364d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/CompletionResultsProcessor.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.util.Processor;
+import java.util.Collection;
+import java.util.Map;
+
+/** Collects completion results, removing duplicate entries. */
+public class CompletionResultsProcessor implements Processor<BuildElement> {
+
+ private final Map<String, LookupElement> results = Maps.newHashMap();
+ private final PsiElement originalElement;
+ private final QuoteType quoteType;
+
+ public CompletionResultsProcessor(PsiElement originalElement, QuoteType quoteType) {
+ this.originalElement = originalElement;
+ this.quoteType = quoteType;
+ }
+
+ @Override
+ public boolean process(BuildElement buildElement) {
+ if (buildElement == originalElement) {
+ return true;
+ }
+ if (buildElement instanceof StringLiteral) {
+ StringLiteral literal = (StringLiteral) buildElement;
+ results.put(
+ literal.getStringContents(),
+ new StringLiteralReferenceLookupElement((StringLiteral) buildElement, quoteType));
+ } else if (buildElement instanceof PsiNamedElement) {
+ PsiNamedElement namedElement = (PsiNamedElement) buildElement;
+ results.put(
+ namedElement.getName(),
+ new NamedBuildLookupElement((PsiNamedElement) buildElement, quoteType));
+ }
+ return true;
+ }
+
+ public Collection<LookupElement> getResults() {
+ return results.values();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java
new file mode 100644
index 0000000..61d40e9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.openapi.util.NullableLazyValue;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Code completion support for package paths. */
+public class FilePathLookupElement extends BuildLookupElement {
+
+ private final String itemText;
+ private final NullableLazyValue<Icon> icon;
+
+ public FilePathLookupElement(
+ String fullLabel, String itemText, QuoteType quoteWrapping, NullableLazyValue<Icon> icon) {
+ super(fullLabel, quoteWrapping);
+ this.itemText = itemText;
+ this.icon = icon;
+ }
+
+ @Override
+ protected String getItemText() {
+ return itemText;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return icon.getValue();
+ }
+
+ @Override
+ protected boolean caretInsideQuotes() {
+ // after completing, leave the caret inside the closing quote, so the user can
+ // continue typing the path.
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.java
new file mode 100644
index 0000000..d888efb
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.intellij.patterns.ElementPattern;
+import com.intellij.patterns.PatternCondition;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.ProcessingContext;
+import org.jetbrains.annotations.NotNull;
+
+/** Filter patterns used by completion contributors. */
+public class FilterPatterns {
+
+ public static final ElementPattern<PsiElement> indexInParentsChildren(final int childIndex) {
+ return psiElement()
+ .with(
+ new PatternCondition<PsiElement>("isIndexInParentsChildren") {
+ @Override
+ public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext context) {
+ final PsiElement parent = psiElement.getParent();
+ if (parent != null) {
+ final PsiElement[] children = parent.getChildren();
+ if (childIndex < children.length && psiElement.equals(children[childIndex])) {
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java
new file mode 100644
index 0000000..dc7dc46
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * Given a label fragment containing a (possibly implicit) package path, provides a lookup element
+ * to a rule target in that package.
+ */
+public class LabelRuleLookupElement extends BuildLookupElement {
+
+ public static BuildLookupElement[] collectAllRules(
+ BuildFile file,
+ String originalString,
+ String packagePrefix,
+ @Nullable String excluded,
+ QuoteType quoteType) {
+ if (packagePrefix.startsWith("//") || originalString.startsWith(":")) {
+ packagePrefix += ":";
+ }
+
+ String ruleFragment = LabelUtils.getRuleComponent(originalString);
+ List<BuildLookupElement> lookups = Lists.newArrayList();
+ // TODO: Handle rules generated via functions? (e.g. via blaze sync)
+ BuildLanguageSpec spec =
+ BuildLanguageSpecProvider.getInstance().getLanguageSpec(file.getProject());
+ for (FuncallExpression target : file.findChildrenByClass(FuncallExpression.class)) {
+ String targetName = target.getName();
+ if (targetName == null
+ || Objects.equals(target.getName(), excluded)
+ || !targetName.startsWith(ruleFragment)) {
+ continue;
+ }
+ String ruleType = target.getFunctionName();
+ if (ruleType == null || (spec != null && !spec.hasRule(ruleType))) {
+ continue;
+ }
+ lookups.add(
+ new LabelRuleLookupElement(packagePrefix, target, targetName, ruleType, quoteType));
+ }
+ return lookups.isEmpty()
+ ? BuildLookupElement.EMPTY_ARRAY
+ : lookups.toArray(new BuildLookupElement[lookups.size()]);
+ }
+
+ private final FuncallExpression target;
+ private final String targetName;
+ private final String ruleType;
+
+ private LabelRuleLookupElement(
+ String packagePrefix,
+ FuncallExpression target,
+ String targetName,
+ String ruleType,
+ QuoteType quoteType) {
+ super(packagePrefix + targetName, quoteType);
+ this.target = target;
+ this.targetName = targetName;
+ this.ruleType = ruleType;
+
+ assert (packagePrefix.isEmpty() || packagePrefix.endsWith(":"));
+ }
+
+ @Override
+ public Icon getIcon() {
+ return target.getIcon(0);
+ }
+
+ @Override
+ protected String getTypeText() {
+ return ruleType;
+ }
+
+ @Override
+ protected String getItemText() {
+ return targetName;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/NamedBuildLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/NamedBuildLookupElement.java
new file mode 100644
index 0000000..4b7c656
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/NamedBuildLookupElement.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.psi.PsiNamedElement;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Generic implementation for {@link com.intellij.psi.PsiNamedElement}s */
+public class NamedBuildLookupElement extends BuildLookupElement {
+
+ private final PsiNamedElement element;
+
+ public NamedBuildLookupElement(PsiNamedElement element, QuoteType quoteType) {
+ super(element.getName(), quoteType);
+ this.element = element;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return element.getIcon(0);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributor.java
new file mode 100644
index 0000000..7f92201
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributor.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.icons.AllIcons;
+import com.intellij.util.ProcessingContext;
+
+/** {@link CompletionContributor} for starred function parameters. */
+public class ParameterCompletionContributor extends CompletionContributor {
+
+ public ParameterCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement().inside(ParameterList.class).afterLeaf("*"),
+ new ParameterCompletionProvider("args"));
+ extend(
+ CompletionType.BASIC,
+ psiElement().inside(ParameterList.class).afterLeaf("**"),
+ new ParameterCompletionProvider("kwargs"));
+ }
+
+ private static class ParameterCompletionProvider
+ extends CompletionProvider<CompletionParameters> {
+ private String myName;
+
+ private ParameterCompletionProvider(String name) {
+ myName = name;
+ }
+
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
+ result.addElement(LookupElementBuilder.create(myName).withIcon(AllIcons.Nodes.Parameter));
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/StringLiteralReferenceLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/StringLiteralReferenceLookupElement.java
new file mode 100644
index 0000000..af85c1c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/StringLiteralReferenceLookupElement.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.openapi.util.NullableLazyValue;
+import com.intellij.psi.PsiElement;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * We calculate the referenced element lazily, as it often won't be needed (e.g. when the string
+ * doesn't match the string fragment being completed.
+ */
+public class StringLiteralReferenceLookupElement extends BuildLookupElement {
+
+ private final StringLiteral literal;
+ private NullableLazyValue<PsiElement> referencedElement =
+ new NullableLazyValue<PsiElement>() {
+ @Nullable
+ @Override
+ protected PsiElement compute() {
+ return literal.getReferencedElement();
+ }
+ };
+
+ public StringLiteralReferenceLookupElement(StringLiteral literal, QuoteType quoteType) {
+ super(literal.getStringContents(), quoteType);
+ this.literal = literal;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ PsiElement ref = referencedElement.getValue();
+ return ref != null ? ref.getIcon(0) : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/documentation/BuildDocumentationProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/documentation/BuildDocumentationProvider.java
new file mode 100644
index 0000000..8c96eec
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/documentation/BuildDocumentationProvider.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.documentation;
+
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.DocStringOwner;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.codeInsight.documentation.DocumentationManagerProtocol;
+import com.intellij.lang.documentation.AbstractDocumentationProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import javax.annotation.Nullable;
+
+/** Provides quick docs for some BUILD elements. */
+public class BuildDocumentationProvider extends AbstractDocumentationProvider {
+
+ private static final String LINK_TYPE_FILE = "#file#";
+
+ @Nullable
+ @Override
+ public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
+ if (element instanceof DocStringOwner) {
+ return buildDocs((DocStringOwner) element);
+ }
+ if (element instanceof FuncallExpression) {
+ return docsForBuiltInRule(
+ element.getProject(), ((FuncallExpression) element).getFunctionName());
+ }
+ return null;
+ }
+
+ /** Returns the corresponding built-in rule in the BUILD file language, if one exists. */
+ @Nullable
+ private static RuleDefinition getBuiltInRule(Project project, @Nullable String ruleName) {
+ BuildLanguageSpec spec = BuildLanguageSpecProvider.getInstance().getLanguageSpec(project);
+ return spec != null ? spec.getRule(ruleName) : null;
+ }
+
+ @Nullable
+ private static String docsForBuiltInRule(Project project, @Nullable String ruleName) {
+ RuleDefinition rule = getBuiltInRule(project, ruleName);
+ if (rule == null) {
+ return null;
+ }
+ String link = Blaze.getBuildSystemProvider(project).getRuleDocumentationUrl(rule);
+ if (link == null) {
+ return null;
+ }
+ return String.format(
+ "External documentation for %s:<br><a href=\"%s\">%s</a>", rule.name, link, link);
+ }
+
+ private static void describeFile(PsiFile file, StringBuilder builder, boolean linkToFile) {
+ if (!(file instanceof BuildFile)) {
+ return;
+ }
+ BuildFile buildFile = (BuildFile) file;
+ String name = buildFile.getBuildLabel();
+ if (name == null) {
+ // fall back to qualitative description
+ name = buildFile.getPresentableText();
+ }
+ if (linkToFile) {
+ builder
+ .append("<a href=\"")
+ .append(DocumentationManagerProtocol.PSI_ELEMENT_PROTOCOL)
+ .append(LINK_TYPE_FILE)
+ .append("\">")
+ .append(name)
+ .append("</a>");
+ } else {
+ builder.append(String.format("<b>%s</b>", name));
+ }
+ builder.append("<br><br>");
+ }
+
+ private static String buildDocs(DocStringOwner element) {
+ StringBuilder docs = new StringBuilder();
+ describeFile(element.getContainingFile(), docs, !(element instanceof BuildFile));
+
+ if (element instanceof FunctionStatement) {
+ describeFunction((FunctionStatement) element, docs);
+ }
+ StringLiteral docString = element.getDocString();
+ if (docString != null) {
+ docs.append(DocStringFormatter.formatDocString(docString, element));
+ }
+ return wrapDocInHtml(docs.toString());
+ }
+
+ private static void describeFunction(FunctionStatement function, StringBuilder builder) {
+ // just show the function declaration verbatim, including the parameter list.
+ ParameterList paramList = function.getParameterList();
+ if (paramList == null) {
+ return;
+ }
+ builder
+ .append("def ")
+ .append("<b>")
+ .append(function.getName())
+ .append("</b>")
+ .append(paramList.getNode().getChars())
+ .append("<br><br>");
+ }
+
+ private static String wrapDocInHtml(String doc) {
+ return "<html><body><code>" + doc + "</code></body></html>";
+ }
+
+ @Nullable
+ @Override
+ public PsiElement getDocumentationElementForLink(
+ PsiManager psiManager, String link, PsiElement context) {
+ if (link.equals(LINK_TYPE_FILE)) {
+ return context.getContainingFile();
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/documentation/DocStringFormatter.java b/base/src/com/google/idea/blaze/base/lang/buildfile/documentation/DocStringFormatter.java
new file mode 100644
index 0000000..fe36a72
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/documentation/DocStringFormatter.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.documentation;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.DocStringOwner;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.intellij.openapi.util.text.StringUtil;
+
+/** Formats docstrings for use in quick doc pop-ups. */
+public class DocStringFormatter {
+
+ /** For now, present docstring almost verbatim, with a minimal indentation handling. */
+ public static String formatDocString(StringLiteral docstring, DocStringOwner owner) {
+ // TODO: Handle Google python docstring style specifically.
+ // (see https://google.github.io/styleguide/pyguide.html#Comments)
+ String raw = docstring.getStringContents();
+ String[] lines = raw.split("\n");
+ StringBuilder output = new StringBuilder();
+ output.append("<pre>");
+
+ int initialIndent = -1;
+ for (String line : lines) {
+ if (initialIndent == -1 && line.startsWith(" ")) {
+ initialIndent = StringUtil.countChars(line, ' ', 0, true);
+ }
+ line = trimStart(line, initialIndent);
+ if (!line.isEmpty()) {
+ output.append(line);
+ }
+ output.append("<br>");
+ }
+ output.append("</pre>");
+ return output.toString();
+ }
+
+ private static String trimStart(String string, int trimLimit) {
+ int index = 0;
+ while (index < trimLimit && index < string.length() && string.charAt(index) == ' ') {
+ index++;
+ }
+ return string.substring(index);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterBetweenBracketsHandler.java b/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterBetweenBracketsHandler.java
new file mode 100644
index 0000000..e750b5a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterBetweenBracketsHandler.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesHandler;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Extends IntelliJ's {@link EnterBetweenBracesHandler}, including square brackets as a valid brace
+ * pair type.
+ */
+public class BuildEnterBetweenBracketsHandler extends EnterBetweenBracesHandler {
+ @Override
+ public Result preprocessEnter(
+ @NotNull PsiFile file,
+ @NotNull Editor editor,
+ @NotNull Ref<Integer> caretOffsetRef,
+ @NotNull Ref<Integer> caretAdvance,
+ @NotNull DataContext dataContext,
+ EditorActionHandler originalHandler) {
+ if (!(file instanceof BuildFile)) {
+ return Result.Continue;
+ }
+ return super.preprocessEnter(
+ file, editor, caretOffsetRef, caretAdvance, dataContext, originalHandler);
+ }
+
+ @Override
+ protected boolean isBracePair(char c1, char c2) {
+ return c1 == '[' && c2 == ']';
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterHandler.java b/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterHandler.java
new file mode 100644
index 0000000..39eb5f7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterHandler.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildListType;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.google.idea.blaze.base.lang.buildfile.psi.PassStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReturnStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.StatementListContainer;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter;
+import com.intellij.ide.DataManager;
+import com.intellij.injected.editor.EditorWindow;
+import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.LogicalPosition;
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import com.intellij.openapi.editor.actions.SplitLineAction;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+import com.intellij.util.text.CharArrayUtil;
+import javax.annotation.Nullable;
+
+/**
+ * Inserts indents as appropriate when enter is pressed.<br>
+ * This is a substitute for implementing a full FormattingModel for the BUILD language. If we ever
+ * decide to do that, this code should be removed.
+ */
+public class BuildEnterHandler extends EnterHandlerDelegateAdapter {
+
+ @Override
+ public Result preprocessEnter(
+ PsiFile file,
+ Editor editor,
+ Ref<Integer> caretOffset,
+ Ref<Integer> caretAdvance,
+ DataContext dataContext,
+ EditorActionHandler originalHandler) {
+ int offset = caretOffset.get();
+ if (editor instanceof EditorWindow) {
+ file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
+ editor = InjectedLanguageUtil.getTopLevelEditor(editor);
+ offset = editor.getCaretModel().getOffset();
+ }
+ if (!isApplicable(file, dataContext)) {
+ return Result.Continue;
+ }
+
+ // Previous enter handler's (e.g. EnterBetweenBracesHandler) can introduce a mismatch
+ // between the editor's caret model and the offset we've been provided with.
+ editor.getCaretModel().moveToOffset(offset);
+
+ Document doc = editor.getDocument();
+ PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
+
+ CodeStyleSettings currentSettings = CodeStyleSettingsManager.getSettings(file.getProject());
+ IndentOptions indentOptions = currentSettings.getIndentOptions(file.getFileType());
+
+ Integer indent = determineIndent(file, editor, offset, indentOptions);
+ if (indent == null) {
+ return Result.Continue;
+ }
+
+ removeTrailingWhitespace(doc, file, offset);
+ originalHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
+ LogicalPosition position = editor.getCaretModel().getLogicalPosition();
+ if (position.column == indent) {
+ return Result.Stop;
+ }
+ if (position.column > indent) {
+ //default enter handler has added too many spaces -- remove them
+ int excess = position.column - indent;
+ doc.deleteString(
+ editor.getCaretModel().getOffset() - excess, editor.getCaretModel().getOffset());
+ } else if (position.column < indent) {
+ String spaces = StringUtil.repeatSymbol(' ', indent - position.column);
+ doc.insertString(editor.getCaretModel().getOffset(), spaces);
+ }
+ editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(position.line, indent));
+ return Result.Stop;
+ }
+
+ private static void removeTrailingWhitespace(Document doc, PsiFile file, int offset) {
+ CharSequence chars = doc.getCharsSequence();
+ int start = offset;
+ while (offset < chars.length() && chars.charAt(offset) == ' ') {
+ PsiElement element = file.findElementAt(offset);
+ if (element == null || !(element instanceof PsiWhiteSpace)) {
+ break;
+ }
+ offset++;
+ }
+ if (start != offset) {
+ doc.deleteString(start, offset);
+ }
+ }
+
+ private static boolean isApplicable(PsiFile file, DataContext dataContext) {
+ if (!(file instanceof BuildFile)) {
+ return false;
+ }
+ Boolean isSplitLine =
+ DataManager.getInstance().loadFromDataContext(dataContext, SplitLineAction.SPLIT_LINE_KEY);
+ if (isSplitLine != null) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns null if an appropriate indent cannot be found. In that case we do nothing, and pass it
+ * along to the next EnterHandler.
+ */
+ @Nullable
+ private static Integer determineIndent(
+ PsiFile file, Editor editor, int offset, IndentOptions indentOptions) {
+ if (offset == 0) {
+ return null;
+ }
+ Document doc = editor.getDocument();
+ PsiElement element = getRelevantElement(file, doc, offset);
+ PsiElement parent = element != null ? element.getParent() : null;
+ if (parent == null) {
+ return null;
+ }
+ if (endsBlock(element)) {
+ // current line indent subtract block indent
+ return Math.max(0, getIndent(doc, element) - indentOptions.INDENT_SIZE);
+ }
+
+ if (parent instanceof BuildListType) {
+ BuildListType list = (BuildListType) parent;
+ if (endsList(list, element) && element.getTextOffset() < offset) {
+ return null;
+ }
+ int listOffset = list.getStartOffset();
+ LogicalPosition caretPosition = editor.getCaretModel().getLogicalPosition();
+ LogicalPosition listStart = editor.offsetToLogicalPosition(listOffset);
+ if (listStart.line != caretPosition.line) {
+ // take the minimum of the current line's indent and the current caret position
+ return indentOfLineUpToCaret(doc, caretPosition.line, offset);
+ }
+ BuildElement firstChild = ((BuildListType) parent).getFirstElement();
+ if (firstChild != null && firstChild.getNode().getStartOffset() < offset) {
+ return getIndent(doc, firstChild);
+ }
+ return lineIndent(doc, listStart.line) + additionalIndent(parent, indentOptions);
+ }
+ if (parent instanceof StatementListContainer && afterColon(doc, offset)) {
+ return getIndent(doc, parent) + additionalIndent(parent, indentOptions);
+ }
+ return null;
+ }
+
+ private static int additionalIndent(PsiElement parent, IndentOptions indentOptions) {
+ return parent instanceof StatementListContainer
+ ? indentOptions.INDENT_SIZE
+ : indentOptions.CONTINUATION_INDENT_SIZE;
+ }
+
+ private static int lineIndent(Document doc, int line) {
+ int startOffset = doc.getLineStartOffset(line);
+ int indentOffset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
+ return indentOffset - startOffset;
+ }
+
+ private static int getIndent(Document doc, PsiElement element) {
+ int offset = element.getNode().getStartOffset();
+ int lineNumber = doc.getLineNumber(offset);
+ return offset - doc.getLineStartOffset(lineNumber);
+ }
+
+ private static int indentOfLineUpToCaret(Document doc, int line, int caretOffset) {
+ int startOffset = doc.getLineStartOffset(line);
+ int indentOffset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
+ return Math.min(indentOffset, caretOffset) - startOffset;
+ }
+
+ private static boolean endsList(BuildListType list, PsiElement element) {
+ String text = element.getText();
+ return text.length() == 1 && list.getEndChars().contains(text.charAt(0));
+ }
+
+ private static boolean endsBlock(PsiElement element) {
+ return element instanceof ReturnStatement || element instanceof PassStatement;
+ }
+
+ private static PsiElement getBlockEndingParent(PsiElement element) {
+ while (element != null && !(element instanceof PsiFileSystemItem)) {
+ if (endsBlock(element)) {
+ return element;
+ }
+ element = element.getParent();
+ }
+ return null;
+ }
+
+ @Nullable
+ private static PsiElement getRelevantElement(PsiFile file, Document doc, int offset) {
+ if (offset == 0) {
+ return null;
+ }
+ if (offset == doc.getTextLength()) {
+ offset--;
+ }
+ PsiElement element = file.findElementAt(offset);
+ while (element != null && isWhiteSpace(element)) {
+ element = PsiUtils.getPreviousNodeInTree(element);
+ }
+ PsiElement blockTerminator = getBlockEndingParent(element);
+ if (blockTerminator != null
+ && blockTerminator.getTextRange().getEndOffset() == element.getTextRange().getEndOffset()) {
+ return blockTerminator;
+ }
+ while (element != null && skipElement(element, offset)) {
+ element = element.getParent();
+ }
+ return element;
+ }
+
+ private static boolean isWhiteSpace(PsiElement element) {
+ if (element instanceof PsiWhiteSpace) {
+ return true;
+ }
+ return BuildToken.WHITESPACE_AND_NEWLINE.contains(element.getNode().getElementType());
+ }
+
+ private static boolean skipElement(PsiElement element, int offset) {
+ PsiElement parent = element.getParent();
+ if (parent == null || parent.getNode() == null || parent instanceof PsiFileSystemItem) {
+ return false;
+ }
+ TextRange childRange = element.getNode().getTextRange();
+ return childRange.equals(parent.getNode().getTextRange())
+ || childRange.getStartOffset() == offset
+ && (parent instanceof Argument || parent instanceof Parameter);
+ }
+
+ private static boolean afterColon(Document doc, int offset) {
+ CharSequence text = doc.getCharsSequence();
+ int previousOffset = CharArrayUtil.shiftBackward(text, offset - 1, " \t");
+ return text.charAt(previousOffset) == ':';
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandler.java b/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandler.java
new file mode 100644
index 0000000..c47f707
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandler.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.codeInsight.editorActions.MultiCharQuoteHandler;
+import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.highlighter.HighlighterIterator;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.tree.IElementType;
+import javax.annotation.Nullable;
+
+/** Provides quote auto-closing support. */
+public class BuildQuoteHandler extends SimpleTokenSetQuoteHandler implements MultiCharQuoteHandler {
+
+ public BuildQuoteHandler() {
+ super(BuildToken.fromKind(TokenKind.STRING));
+ }
+
+ @Override
+ public boolean isOpeningQuote(HighlighterIterator iterator, int offset) {
+ if (!myLiteralTokenSet.contains(iterator.getTokenType())) {
+ return false;
+ }
+ int start = iterator.getStart();
+ if (offset == start) {
+ return true;
+ }
+ final Document document = iterator.getDocument();
+ if (document == null) {
+ return false;
+ }
+ CharSequence text = document.getCharsSequence();
+ char theQuote = text.charAt(offset);
+ if (offset >= 2
+ && text.charAt(offset - 1) == theQuote
+ && text.charAt(offset - 2) == theQuote
+ && (offset < 3 || text.charAt(offset - 3) != theQuote)) {
+ if (super.isOpeningQuote(iterator, offset)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static int getLiteralStartOffset(CharSequence text, int start) {
+ char c = Character.toUpperCase(text.charAt(start));
+ if (c == 'U' || c == 'B') {
+ start++;
+ c = Character.toUpperCase(text.charAt(start));
+ }
+ if (c == 'R') {
+ start++;
+ }
+ return start;
+ }
+
+ @Override
+ protected boolean isNonClosedLiteral(HighlighterIterator iterator, CharSequence chars) {
+ int end = iterator.getEnd();
+ if (getLiteralStartOffset(chars, iterator.getStart()) >= end - 1) {
+ return true;
+ }
+ char endSymbol = chars.charAt(end - 1);
+ if (endSymbol != '"' && endSymbol != '\'') {
+ return true;
+ }
+
+ //for triple quoted string
+ if (end >= 3
+ && (endSymbol == chars.charAt(end - 2))
+ && (chars.charAt(end - 2) == chars.charAt(end - 3))
+ && (end < 4 || chars.charAt(end - 4) != endSymbol)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isClosingQuote(HighlighterIterator iterator, int offset) {
+ final IElementType tokenType = iterator.getTokenType();
+ if (!myLiteralTokenSet.contains(tokenType)) {
+ return false;
+ }
+ int start = iterator.getStart();
+ int end = iterator.getEnd();
+ if (end - start >= 1 && offset == end - 1) {
+ return true; // single quote
+ }
+ if (end - start < 3 || offset < end - 3) {
+ return false;
+ }
+ // check for triple quote
+ Document doc = iterator.getDocument();
+ if (doc == null) {
+ return false;
+ }
+ CharSequence chars = doc.getCharsSequence();
+ char quote = chars.charAt(start);
+ boolean tripleQuote = quote == chars.charAt(start + 1) && quote == chars.charAt(start + 2);
+ if (!tripleQuote) {
+ return false;
+ }
+ for (int i = offset; i < Math.min(offset + 2, end); i++) {
+ if (quote != chars.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public CharSequence getClosingQuote(HighlighterIterator iterator, int offset) {
+ char theQuote = iterator.getDocument().getCharsSequence().charAt(offset - 1);
+ if (super.isOpeningQuote(iterator, offset - 1)) {
+ return String.valueOf(theQuote);
+ }
+ if (super.isOpeningQuote(iterator, offset - 3)) {
+ return StringUtil.repeat(String.valueOf(theQuote), 3);
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildElementDescriptionProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildElementDescriptionProvider.java
new file mode 100644
index 0000000..a5e8984
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildElementDescriptionProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.intellij.psi.ElementDescriptionLocation;
+import com.intellij.psi.ElementDescriptionProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiNameIdentifierOwner;
+import com.intellij.usageView.UsageViewLongNameLocation;
+import com.intellij.usageView.UsageViewShortNameLocation;
+import javax.annotation.Nullable;
+
+/** Controls text shown for target in the 'find usages' dialog. */
+public class BuildElementDescriptionProvider implements ElementDescriptionProvider {
+ @Nullable
+ @Override
+ public String getElementDescription(PsiElement element, ElementDescriptionLocation location) {
+ if (!(element instanceof BuildElement)) {
+ return null;
+ }
+ if (location instanceof UsageViewLongNameLocation) {
+ return ((BuildElement) element).getPresentableText();
+ }
+ if (location instanceof UsageViewShortNameLocation) {
+ if (element instanceof PsiNameIdentifierOwner) {
+ // this is used by rename operations, so needs to be accurate
+ return ((PsiNameIdentifierOwner) element).getName();
+ }
+ if (element instanceof PsiFile) {
+ return ((PsiFile) element).getName();
+ }
+ return ((BuildElement) element).getPresentableText();
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFileGroupingRuleProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFileGroupingRuleProvider.java
new file mode 100644
index 0000000..84d16cb
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFileGroupingRuleProvider.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.usages.Usage;
+import com.intellij.usages.UsageGroup;
+import com.intellij.usages.UsageView;
+import com.intellij.usages.impl.FileStructureGroupRuleProvider;
+import com.intellij.usages.impl.rules.FileGroupingRule;
+import com.intellij.usages.rules.UsageGroupingRule;
+import com.intellij.usages.rules.UsageInFile;
+import javax.swing.Icon;
+
+/**
+ * Allows us to customize the filename string in the 'find usages' dialog, rather than displaying
+ * them all as 'BUILD'.
+ */
+public class BuildFileGroupingRuleProvider implements FileStructureGroupRuleProvider {
+
+ public static UsageGroupingRule getGroupingRule(Project project) {
+ return new BuildFileGroupingRule(project);
+ }
+
+ @Override
+ public UsageGroupingRule getUsageGroupingRule(Project project) {
+ return getGroupingRule(project);
+ }
+
+ private static class BuildFileGroupingRule extends FileGroupingRule {
+
+ private final Project project;
+
+ BuildFileGroupingRule(Project project) {
+ super(project);
+ this.project = project;
+ }
+
+ @Override
+ public UsageGroup groupUsage(Usage usage) {
+ if (!(usage instanceof UsageInFile)) {
+ return null;
+ }
+ final VirtualFile virtualFile = ((UsageInFile) usage).getFile();
+ if (virtualFile.getFileType() != BuildFileType.INSTANCE) {
+ return null;
+ }
+ return new FileUsageGroup(project, virtualFile) {
+ String name;
+
+ @Override
+ public void update() {
+ if (isValid()) {
+ super.update();
+ name = BuildFile.getBuildFileString(project, virtualFile.getPath());
+ }
+ }
+
+ @Override
+ public String getPresentableName() {
+ return name;
+ }
+
+ @Override
+ public String getText(UsageView view) {
+ return name;
+ }
+
+ @Override
+ public Icon getIcon(boolean isOpen) {
+ return null; // already shown by default usage group (which we can't remove...)
+ }
+ };
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFindUsagesProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFindUsagesProvider.java
new file mode 100644
index 0000000..31eac32
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFindUsagesProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase.LexerMode;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.intellij.lang.HelpID;
+import com.intellij.lang.cacheBuilder.DefaultWordsScanner;
+import com.intellij.lang.cacheBuilder.WordsScanner;
+import com.intellij.lang.findUsages.FindUsagesProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.psi.tree.TokenSet;
+
+/**
+ * Required for highlighting references (among other things we don't currently support). Currently
+ * only used by the fallback 'DefaultFindUsagesHandlerFactory'.
+ */
+public class BuildFindUsagesProvider implements FindUsagesProvider {
+
+ @Override
+ public boolean canFindUsagesFor(PsiElement psiElement) {
+ return psiElement instanceof FuncallExpression
+ || psiElement instanceof PsiNamedElement
+ || psiElement instanceof ReferenceExpression;
+ }
+
+ @Override
+ public String getHelpId(PsiElement psiElement) {
+ if (psiElement instanceof FunctionStatement) {
+ return "reference.dialogs.findUsages.method";
+ }
+ if (psiElement instanceof TargetExpression
+ || psiElement instanceof Parameter
+ || psiElement instanceof ReferenceExpression) {
+ return "reference.dialogs.findUsages.variable";
+ }
+ // typically build rules and imported Skylark functions, but also all other function calls
+ return HelpID.FIND_OTHER_USAGES;
+ }
+
+ @Override
+ public String getType(PsiElement element) {
+ if (element instanceof FunctionStatement) {
+ return "function";
+ }
+ if (element instanceof Parameter) {
+ return "parameter";
+ }
+ if (element instanceof ReferenceExpression || element instanceof TargetExpression) {
+ return "variable";
+ }
+ if (element instanceof Argument.Keyword) {
+ return "keyword argument";
+ }
+ if (element instanceof FuncallExpression) {
+ return "rule";
+ }
+ return "";
+ }
+
+ /** Controls text shown for target element in the 'find usages' dialog */
+ @Override
+ public String getDescriptiveName(PsiElement element) {
+ if (element instanceof BuildElement) {
+ return ((BuildElement) element).getPresentableText();
+ }
+ return element.toString();
+ }
+
+ @Override
+ public String getNodeText(PsiElement element, boolean useFullName) {
+ return getDescriptiveName(element);
+ }
+
+ @Override
+ public WordsScanner getWordsScanner() {
+ return new DefaultWordsScanner(
+ new BuildLexer(LexerMode.SyntaxHighlighting),
+ tokenSet(TokenKind.IDENTIFIER),
+ tokenSet(TokenKind.COMMENT),
+ tokenSet(TokenKind.STRING));
+ }
+
+ private static TokenSet tokenSet(TokenKind token) {
+ return TokenSet.create(BuildToken.fromKind(token));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildReadWriteAccessDetector.java b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildReadWriteAccessDetector.java
new file mode 100644
index 0000000..8f01178
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildReadWriteAccessDetector.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.AugmentedAssignmentStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+
+/** Used by find usages tools. */
+public class BuildReadWriteAccessDetector extends ReadWriteAccessDetector {
+ @Override
+ public boolean isReadWriteAccessible(PsiElement element) {
+ return element instanceof TargetExpression || element instanceof ReferenceExpression;
+ }
+
+ @Override
+ public boolean isDeclarationWriteAccess(PsiElement element) {
+ return element instanceof TargetExpression;
+ }
+
+ @Override
+ public Access getReferenceAccess(PsiElement referencedElement, PsiReference reference) {
+ return getExpressionAccess(reference.getElement());
+ }
+
+ @Override
+ public Access getExpressionAccess(PsiElement expression) {
+ if (isDeclarationWriteAccess(expression)) {
+ return Access.Write;
+ }
+ if (expression instanceof ReferenceExpression) {
+ if (PsiUtils.getParentOfType(expression, AugmentedAssignmentStatement.class) != null) {
+ return Access.ReadWrite;
+ }
+ }
+ return Access.Read;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildTargetElementEvaluator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildTargetElementEvaluator.java
new file mode 100644
index 0000000..bc96e3d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildTargetElementEvaluator.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument.Keyword;
+import com.google.idea.blaze.base.lang.buildfile.psi.ArgumentList;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.intellij.codeInsight.TargetElementEvaluatorEx2;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/**
+ * StringLiterals can reference multiple targets (e.g. "package:target" references both the package
+ * and the target). IntelliJ defaults to highlighting / navigating to the innermost reference, but
+ * in this case, we want the opposite behavior (the target reference should trump the package
+ * reference).
+ */
+public class BuildTargetElementEvaluator extends TargetElementEvaluatorEx2 {
+
+ @Override
+ public boolean includeSelfInGotoImplementation(PsiElement element) {
+ return false;
+ }
+
+ /** Returns null in the cases where we're happy with the default behavior. */
+ @Nullable
+ @Override
+ public PsiElement getElementByReference(PsiReference ref, int flags) {
+ if (!(ref instanceof PsiMultiReference) || !(ref.getElement() instanceof StringLiteral)) {
+ return null;
+ }
+ // choose the outer-most reference
+ PsiReference[] refs = ((PsiMultiReference) ref).getReferences().clone();
+ Arrays.sort(refs, COMPARATOR);
+ return refs[0].resolve();
+ }
+
+ private static final Comparator<PsiReference> COMPARATOR =
+ new Comparator<PsiReference>() {
+ @Override
+ public int compare(final PsiReference ref1, final PsiReference ref2) {
+ boolean resolves1 = ref1.resolve() != null;
+ boolean resolves2 = ref2.resolve() != null;
+ if (resolves1 && !resolves2) {
+ return -1;
+ }
+ if (!resolves1 && resolves2) {
+ return 1;
+ }
+
+ final TextRange range1 = ref1.getRangeInElement();
+ final TextRange range2 = ref2.getRangeInElement();
+
+ if (TextRange.areSegmentsEqual(range1, range2)) {
+ return 0;
+ }
+ if (range1.getStartOffset() >= range2.getStartOffset()
+ && range1.getEndOffset() <= range2.getEndOffset()) {
+ return 1;
+ }
+ if (range2.getStartOffset() >= range1.getStartOffset()
+ && range2.getEndOffset() <= range1.getEndOffset()) {
+ return -1;
+ }
+
+ return 0;
+ }
+ };
+
+ /** Redirect 'name' funcall argument values to the funcall expression (b/29088829). */
+ @Nullable
+ @Override
+ public PsiElement getNamedElement(PsiElement element) {
+ return getParentFuncallIfNameString(element);
+ }
+
+ @Nullable
+ private static FuncallExpression getParentFuncallIfNameString(PsiElement element) {
+ PsiElement parent = element.getParent();
+ if (!(parent instanceof StringLiteral)) {
+ return null;
+ }
+ parent = parent.getParent();
+ if (!(parent instanceof Keyword)) {
+ return null;
+ }
+ if (!Objects.equals(((Keyword) parent).getName(), "name")) {
+ return null;
+ }
+ parent = parent.getParent();
+ if (!(parent instanceof ArgumentList)) {
+ return null;
+ }
+ parent = parent.getParent();
+ return parent instanceof FuncallExpression ? (FuncallExpression) parent : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildUsageGroupingRuleProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildUsageGroupingRuleProvider.java
new file mode 100644
index 0000000..265202c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildUsageGroupingRuleProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.usages.UsageView;
+import com.intellij.usages.rules.UsageGroupingRule;
+import com.intellij.usages.rules.UsageGroupingRuleProvider;
+
+/**
+ * This is a gross hack. We want to always include file paths for BUILD files in the 'find usages'
+ * dialog.<br>
+ * This achieves that by inserting an additional UsageGroupingRule for each file usage, regardless
+ * of whether we're grouping by file structure
+ */
+public class BuildUsageGroupingRuleProvider implements UsageGroupingRuleProvider {
+ @Override
+ public UsageGroupingRule[] getActiveRules(Project project) {
+ return new UsageGroupingRule[] {BuildFileGroupingRuleProvider.getGroupingRule(project)};
+ }
+
+ @Override
+ public AnAction[] createGroupingActions(UsageView view) {
+ return new AnAction[0];
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildBraceMatcher.java b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildBraceMatcher.java
new file mode 100644
index 0000000..10d7edd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildBraceMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.lang.BracePair;
+import com.intellij.lang.PairedBraceMatcher;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+import java.util.Arrays;
+import javax.annotation.Nullable;
+
+/**
+ * This adds a close brace automatically once an opening brace is typed by the user in the editor.
+ */
+public class BuildBraceMatcher implements PairedBraceMatcher {
+
+ private static final BracePair[] PAIRS =
+ new BracePair[] {
+ new BracePair(
+ BuildToken.fromKind(TokenKind.LPAREN), BuildToken.fromKind(TokenKind.RPAREN), true),
+ new BracePair(
+ BuildToken.fromKind(TokenKind.LBRACKET), BuildToken.fromKind(TokenKind.RBRACKET), true),
+ new BracePair(
+ BuildToken.fromKind(TokenKind.LBRACE), BuildToken.fromKind(TokenKind.RBRACE), true)
+ };
+
+ private static final TokenSet BRACES_ALLOWED_BEFORE =
+ tokenSet(
+ TokenKind.NEWLINE,
+ TokenKind.WHITESPACE,
+ TokenKind.COMMENT,
+ TokenKind.COLON,
+ TokenKind.COMMA,
+ TokenKind.RPAREN,
+ TokenKind.RBRACKET,
+ TokenKind.RBRACE,
+ TokenKind.LBRACE);
+
+ @Override
+ public BracePair[] getPairs() {
+ return PAIRS;
+ }
+
+ @Override
+ public boolean isPairedBracesAllowedBeforeType(
+ IElementType lbraceType, @Nullable IElementType contextType) {
+ return contextType == null || BRACES_ALLOWED_BEFORE.contains(contextType);
+ }
+
+ @Override
+ public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
+ return openingBraceOffset;
+ }
+
+ private static TokenSet tokenSet(TokenKind... kind) {
+ return TokenSet.create(
+ Arrays.stream(kind).map(BuildToken::fromKind).toArray(IElementType[]::new));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCodeStyleSettingsProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCodeStyleSettingsProvider.java
new file mode 100644
index 0000000..a61a0bd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCodeStyleSettingsProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.intellij.application.options.CodeStyleAbstractConfigurable;
+import com.intellij.application.options.CodeStyleAbstractPanel;
+import com.intellij.application.options.TabbedLanguageCodeStylePanel;
+import com.intellij.openapi.options.Configurable;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.codeStyle.CodeStyleSettingsProvider;
+import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
+import javax.annotation.Nullable;
+
+/** Separate configurable code-style settings for BUILD language. */
+public class BuildCodeStyleSettingsProvider extends CodeStyleSettingsProvider {
+
+ @Override
+ public Configurable createSettingsPage(
+ CodeStyleSettings settings, CodeStyleSettings originalSettings) {
+ return new CodeStyleAbstractConfigurable(
+ settings, originalSettings, BuildFileType.INSTANCE.getDescription()) {
+ @Override
+ protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) {
+ return new TabbedLanguageCodeStylePanel(
+ BuildFileLanguage.INSTANCE, getCurrentSettings(), settings) {
+ @Override
+ protected void initTabs(CodeStyleSettings settings) {
+ LanguageCodeStyleSettingsProvider provider =
+ LanguageCodeStyleSettingsProvider.forLanguage(getDefaultLanguage());
+ addIndentOptionsTab(settings);
+ }
+ };
+ }
+
+ @Override
+ public String getHelpTopic() {
+ return null;
+ }
+ };
+ }
+
+ @Nullable
+ @Override
+ public String getConfigurableDisplayName() {
+ return BuildFileType.INSTANCE.getDescription();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCommenter.java b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCommenter.java
new file mode 100644
index 0000000..34af8b9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCommenter.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.lang.CodeDocumentationAwareCommenter;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.Nullable;
+
+/** Supports (un)commenting lines via IntelliJ */
+public class BuildCommenter implements CodeDocumentationAwareCommenter {
+
+ @Nullable
+ @Override
+ public String getLineCommentPrefix() {
+ return "#";
+ }
+
+ @Nullable
+ @Override
+ public String getBlockCommentPrefix() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getBlockCommentSuffix() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getCommentedBlockCommentPrefix() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getCommentedBlockCommentSuffix() {
+ return null;
+ }
+
+ @Override
+ public IElementType getLineCommentTokenType() {
+ return BuildToken.fromKind(TokenKind.COMMENT);
+ }
+
+ @Override
+ public IElementType getBlockCommentTokenType() {
+ return null;
+ }
+
+ @Override
+ public IElementType getDocumentationCommentTokenType() {
+ return null;
+ }
+
+ @Override
+ public String getDocumentationCommentPrefix() {
+ return null;
+ }
+
+ @Override
+ public String getDocumentationCommentLinePrefix() {
+ return null;
+ }
+
+ @Override
+ public String getDocumentationCommentSuffix() {
+ return null;
+ }
+
+ @Override
+ public boolean isDocumentationComment(PsiComment element) {
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilder.java b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilder.java
new file mode 100644
index 0000000..f627347
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilder.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.FileASTNode;
+import com.intellij.lang.folding.FoldingBuilder;
+import com.intellij.lang.folding.FoldingDescriptor;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.TokenType;
+import com.intellij.psi.tree.IElementType;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Simple code block folding for BUILD files. */
+public class BuildFileFoldingBuilder implements FoldingBuilder {
+
+ /** Currently only folding top-level nodes. */
+ @Override
+ public FoldingDescriptor[] buildFoldRegions(ASTNode node, Document document) {
+ List<FoldingDescriptor> descriptors = Lists.newArrayList();
+ if (node instanceof FileASTNode) {
+ for (ASTNode child : node.getChildren(null)) {
+ addDescriptors(descriptors, child);
+ }
+ } else if (isTopLevel(node)) {
+ addDescriptors(descriptors, node);
+ }
+ return descriptors.toArray(new FoldingDescriptor[0]);
+ }
+
+ /** Only folding top-level statements */
+ private void addDescriptors(List<FoldingDescriptor> descriptors, ASTNode node) {
+ IElementType type = node.getElementType();
+ if (type == BuildElementTypes.FUNCTION_STATEMENT) {
+ ASTNode colon = node.findChildByType(BuildToken.fromKind(TokenKind.COLON));
+ if (colon == null) {
+ return;
+ }
+ ASTNode stmtList = node.findChildByType(BuildElementTypes.STATEMENT_LIST);
+ if (stmtList == null) {
+ return;
+ }
+ int start = colon.getStartOffset() + 1;
+ int end = endOfList(stmtList);
+ descriptors.add(new FoldingDescriptor(node, range(start, end)));
+
+ } else if (type == BuildElementTypes.FUNCALL_EXPRESSION
+ || type == BuildElementTypes.LOAD_STATEMENT) {
+ ASTNode listNode =
+ type == BuildElementTypes.FUNCALL_EXPRESSION
+ ? node.findChildByType(BuildElementTypes.ARGUMENT_LIST)
+ : node;
+ if (listNode == null) {
+ return;
+ }
+ ASTNode lParen = listNode.findChildByType(BuildToken.fromKind(TokenKind.LPAREN));
+ ASTNode rParen = listNode.findChildByType(BuildToken.fromKind(TokenKind.RPAREN));
+ if (lParen == null || rParen == null) {
+ return;
+ }
+ int start = lParen.getStartOffset() + 1;
+ int end = rParen.getTextRange().getEndOffset() - 1;
+ descriptors.add(new FoldingDescriptor(node, range(start, end)));
+ }
+ }
+
+ private static TextRange range(int start, int end) {
+ if (start >= end) {
+ return new TextRange(start, start + 1);
+ }
+ return new TextRange(start, end);
+ }
+
+ /**
+ * Don't include whitespace and newlines at the end of the function.<br>
+ * Could do this in the lexer instead, with additional look-ahead checks.
+ */
+ private int endOfList(ASTNode stmtList) {
+ ASTNode child = stmtList.getLastChildNode();
+ while (child != null) {
+ IElementType type = child.getElementType();
+ if (type != TokenType.WHITE_SPACE && type != BuildToken.fromKind(TokenKind.NEWLINE)) {
+ return child.getTextRange().getEndOffset();
+ }
+ child = child.getTreePrev();
+ }
+ return stmtList.getTextRange().getEndOffset();
+ }
+
+ private boolean isTopLevel(ASTNode node) {
+ return node.getTreeParent() instanceof FileASTNode;
+ }
+
+ @Override
+ @Nullable
+ public String getPlaceholderText(ASTNode node) {
+ PsiElement psi = node.getPsi();
+ if (psi instanceof FuncallExpression) {
+ FuncallExpression expr = (FuncallExpression) psi;
+ String name = expr.getNameArgumentValue();
+ if (name != null) {
+ return "name = \"" + name + "\"...";
+ }
+ }
+ if (psi instanceof LoadStatement) {
+ String fileName = ((LoadStatement) psi).getImportedPath();
+ if (fileName != null) {
+ return "\"" + fileName + "\"...";
+ }
+ }
+ return "...";
+ }
+
+ @Override
+ public boolean isCollapsedByDefault(ASTNode node) {
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildLanguageCodeStyleSettingsProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildLanguageCodeStyleSettingsProvider.java
new file mode 100644
index 0000000..b2295af
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildLanguageCodeStyleSettingsProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
+import com.intellij.application.options.IndentOptionsEditor;
+import com.intellij.application.options.SmartIndentOptionsEditor;
+import com.intellij.lang.Language;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
+import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Allows BUILD language-specific code style settings */
+public class BuildLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider {
+
+ @Override
+ public Language getLanguage() {
+ return BuildFileLanguage.INSTANCE;
+ }
+
+ @Override
+ public IndentOptionsEditor getIndentOptionsEditor() {
+ return new SmartIndentOptionsEditor();
+ }
+
+ @Override
+ public String getCodeSample(@NotNull SettingsType settingsType) {
+ return "";
+ }
+
+ @Nullable
+ @Override
+ public CommonCodeStyleSettings getDefaultCommonSettings() {
+ CommonCodeStyleSettings defaultSettings =
+ new CommonCodeStyleSettings(BuildFileLanguage.INSTANCE);
+ CommonCodeStyleSettings.IndentOptions indentOptions = defaultSettings.initIndentOptions();
+ indentOptions.TAB_SIZE = 2;
+ indentOptions.INDENT_SIZE = 2;
+ indentOptions.CONTINUATION_INDENT_SIZE = 4;
+ return defaultSettings;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java b/base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java
new file mode 100644
index 0000000..321908b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java
@@ -0,0 +1,762 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.globbing;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.base.Throwables;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ForwardingListenableFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.lang.buildfile.validation.GlobPatternValidator;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileSystem;
+import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/**
+ * Implementation of a subset of UNIX-style file globbing, expanding "*" and "?" as wildcards, but
+ * not [a-z] ranges.
+ *
+ * <p><code>**</code> gets special treatment in include patterns. If it is used as a complete path
+ * segment it matches the filenames in subdirectories recursively.
+ *
+ * <p>Largely copied from {@link com.google.devtools.build.lib.vfs.UnixGlob}
+ */
+public final class UnixGlob {
+ private UnixGlob() {}
+
+ private static List<File> globInternal(
+ File base,
+ Collection<String> patterns,
+ Collection<String> excludePatterns,
+ boolean excludeDirectories,
+ Predicate<File> dirPred,
+ ThreadPoolExecutor threadPool)
+ throws IOException, InterruptedException {
+
+ GlobVisitor visitor = (threadPool == null) ? new GlobVisitor() : new GlobVisitor(threadPool);
+ return visitor.glob(base, patterns, excludePatterns, excludeDirectories, dirPred);
+ }
+
+ private static Future<List<File>> globAsyncInternal(
+ File base,
+ Collection<String> patterns,
+ Collection<String> excludePatterns,
+ boolean excludeDirectories,
+ Predicate<File> dirPred,
+ ThreadPoolExecutor threadPool) {
+ Preconditions.checkNotNull(threadPool, "%s %s", base, patterns);
+ try {
+ return new GlobVisitor(threadPool)
+ .globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred);
+ } catch (IOException e) {
+ // We are evaluating asynchronously, so no exceptions should be thrown until the future is
+ // retrieved.
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Checks that each pattern is valid, splits it into segments and checks that each segment
+ * contains only valid wildcards.
+ *
+ * @return list of segment arrays
+ */
+ private static List<String[]> checkAndSplitPatterns(Collection<String> patterns) {
+ List<String[]> list = Lists.newArrayListWithCapacity(patterns.size());
+ for (String pattern : patterns) {
+ String error = GlobPatternValidator.validate(pattern);
+ if (error != null) {
+ throw new IllegalArgumentException(error);
+ }
+ Iterable<String> segments = Splitter.on('/').split(pattern);
+ list.add(Iterables.toArray(segments, String.class));
+ }
+ return list;
+ }
+
+ private static boolean excludedOnMatch(
+ File path, List<String[]> excludePatterns, int idx, Cache<String, Pattern> cache) {
+ for (String[] excludePattern : excludePatterns) {
+ String text = path.getName();
+ if (idx == excludePattern.length && matches(excludePattern[idx - 1], text, cache)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the exclude patterns in {@code excludePatterns} which could apply to the children of
+ * {@code base}
+ *
+ * @param idx index into {@code excludePatterns} for the part of the pattern which might match
+ * {@code base}
+ */
+ private static List<String[]> getRelevantExcludes(
+ final File base,
+ List<String[]> excludePatterns,
+ final int idx,
+ final Cache<String, Pattern> cache) {
+
+ if (excludePatterns.isEmpty()) {
+ return excludePatterns;
+ }
+ List<String[]> list = new ArrayList<>();
+ for (String[] patterns : excludePatterns) {
+ if (excludePatternMatches(patterns, idx, base, cache)) {
+ list.add(patterns);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * @param patterns a list of patterns
+ * @param idx index into {@code patterns}
+ */
+ private static boolean excludePatternMatches(
+ String[] patterns, int idx, File base, Cache<String, Pattern> cache) {
+ if (idx == 0) {
+ return true;
+ }
+ String text = base.getName();
+ return patterns.length > idx && matches(patterns[idx - 1], text, cache);
+ }
+
+ /** Calls {@link #matches(String, String, Cache) matches(pattern, str, null)} */
+ public static boolean matches(String pattern, String str) {
+ return matches(pattern, str, null);
+ }
+
+ /**
+ * Returns whether {@code str} matches the glob pattern {@code pattern}. This method may use the
+ * {@code patternCache} to speed up the matching process.
+ *
+ * @param pattern a glob pattern
+ * @param str the string to match
+ * @param patternCache a cache from patterns to compiled Pattern objects, or {@code null} to skip
+ * caching
+ */
+ public static boolean matches(String pattern, String str, Cache<String, Pattern> patternCache) {
+ if (pattern.length() == 0 || str.length() == 0) {
+ return false;
+ }
+
+ // Common case: **
+ if (pattern.equals("**")) {
+ return true;
+ }
+
+ // Common case: *
+ if (pattern.equals("*")) {
+ return true;
+ }
+
+ // If a filename starts with '.', this char must be matched explicitly.
+ if (str.charAt(0) == '.' && pattern.charAt(0) != '.') {
+ return false;
+ }
+
+ // Common case: *.xyz
+ if (pattern.charAt(0) == '*' && pattern.lastIndexOf('*') == 0) {
+ return str.endsWith(pattern.substring(1));
+ }
+ // Common case: xyz*
+ int lastIndex = pattern.length() - 1;
+ // The first clause of this if statement is unnecessary, but is an
+ // optimization--charAt runs faster than indexOf.
+ if (pattern.charAt(lastIndex) == '*' && pattern.indexOf('*') == lastIndex) {
+ return str.startsWith(pattern.substring(0, lastIndex));
+ }
+
+ Pattern regex = patternCache == null ? null : patternCache.getIfPresent(pattern);
+ if (regex == null) {
+ regex = makePatternFromWildcard(pattern);
+ if (patternCache != null) {
+ patternCache.put(pattern, regex);
+ }
+ }
+ return regex.matcher(str).matches();
+ }
+
+ /**
+ * Returns a regular expression implementing a matcher for "pattern", in which "*" and "?" are
+ * wildcards.
+ *
+ * <p>e.g. "foo*bar?.java" -> "foo.*bar.\\.java"
+ */
+ private static Pattern makePatternFromWildcard(String pattern) {
+ StringBuilder regexp = new StringBuilder();
+ for (int i = 0, len = pattern.length(); i < len; i++) {
+ char c = pattern.charAt(i);
+ switch (c) {
+ case '*':
+ int toIncrement = 0;
+ if (len > i + 1 && pattern.charAt(i + 1) == '*') {
+ // The pattern '**' is interpreted to match 0 or more directory separators, not 1 or
+ // more. We skip the next * and then find a trailing/leading '/' and get rid of it.
+ toIncrement = 1;
+ if (len > i + 2 && pattern.charAt(i + 2) == '/') {
+ // We have '**/' -- skip the '/'.
+ toIncrement = 2;
+ } else if (len == i + 2 && i > 0 && pattern.charAt(i - 1) == '/') {
+ // We have '/**' -- remove the '/'.
+ regexp.delete(regexp.length() - 1, regexp.length());
+ }
+ }
+ regexp.append(".*");
+ i += toIncrement;
+ break;
+ case '?':
+ regexp.append('.');
+ break;
+ //escape the regexp special characters that are allowed in wildcards
+ case '^':
+ case '$':
+ case '|':
+ case '+':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case '\\':
+ case '.':
+ regexp.append('\\');
+ regexp.append(c);
+ break;
+ default:
+ regexp.append(c);
+ break;
+ }
+ }
+ return Pattern.compile(regexp.toString());
+ }
+
+ public static Builder forPath(File path) {
+ return new Builder(path);
+ }
+
+ /** Builder class for UnixGlob. */
+ public static class Builder {
+ private File base;
+ private List<String> patterns;
+ private List<String> excludes;
+ private boolean excludeDirectories;
+ private Predicate<File> pathFilter;
+ private ThreadPoolExecutor threadPool;
+
+ /** Creates a glob builder with the given base path. */
+ public Builder(File base) {
+ this.base = base;
+ this.patterns = Lists.newArrayList();
+ this.excludes = Lists.newArrayList();
+ this.excludeDirectories = false;
+ this.pathFilter = file -> true;
+ }
+
+ /**
+ * Adds a pattern to include to the glob builder.
+ *
+ * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
+ */
+ public Builder addPattern(String pattern) {
+ this.patterns.add(pattern);
+ return this;
+ }
+
+ /**
+ * Adds a pattern to include to the glob builder.
+ *
+ * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
+ */
+ public Builder addPatterns(String... patterns) {
+ Collections.addAll(this.patterns, patterns);
+ return this;
+ }
+
+ /**
+ * Adds a pattern to include to the glob builder.
+ *
+ * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
+ */
+ public Builder addPatterns(Collection<String> patterns) {
+ this.patterns.addAll(patterns);
+ return this;
+ }
+
+ /**
+ * Adds patterns to exclude from the results to the glob builder.
+ *
+ * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
+ */
+ public Builder addExcludes(String... excludes) {
+ Collections.addAll(this.excludes, excludes);
+ return this;
+ }
+
+ /**
+ * Adds patterns to exclude from the results to the glob builder.
+ *
+ * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
+ */
+ public Builder addExcludes(Collection<String> excludes) {
+ this.excludes.addAll(excludes);
+ return this;
+ }
+
+ /** If set to true, directories are not returned in the glob result. */
+ public Builder setExcludeDirectories(boolean excludeDirectories) {
+ this.excludeDirectories = excludeDirectories;
+ return this;
+ }
+
+ /**
+ * Sets the threadpool to use for parallel glob evaluation. If unset, evaluation is done
+ * in-thread.
+ */
+ public Builder setThreadPool(ThreadPoolExecutor pool) {
+ this.threadPool = pool;
+ return this;
+ }
+
+ /**
+ * If set, the given predicate is called for every directory encountered. If it returns false,
+ * the corresponding item is not returned in the output and directories are not traversed
+ * either.
+ */
+ public Builder setDirectoryFilter(Predicate<File> pathFilter) {
+ this.pathFilter = pathFilter;
+ return this;
+ }
+
+ /**
+ * Executes the glob.
+ *
+ * @throws InterruptedException if the thread is interrupted.
+ */
+ public List<File> glob() throws IOException, InterruptedException {
+ return globInternal(base, patterns, excludes, excludeDirectories, pathFilter, threadPool);
+ }
+
+ /**
+ * Executes the glob asynchronously. {@link #setThreadPool} must have been called already with a
+ * non-null argument.
+ *
+ * @param checkForInterrupt if the returned future may throw InterruptedException.
+ */
+ public Future<List<File>> globAsync() {
+ return globAsyncInternal(
+ base, patterns, excludes, excludeDirectories, pathFilter, threadPool);
+ }
+ }
+
+ /** Adapts the result of the glob visitation as a Future. */
+ private static class GlobFuture extends ForwardingListenableFuture<List<File>> {
+ private final GlobVisitor visitor;
+ private final SettableFuture<List<File>> delegate = SettableFuture.create();
+
+ public GlobFuture(GlobVisitor visitor) {
+ this.visitor = visitor;
+ }
+
+ @Override
+ public List<File> get() throws InterruptedException, ExecutionException {
+ return super.get();
+ }
+
+ @Override
+ protected ListenableFuture<List<File>> delegate() {
+ return delegate;
+ }
+
+ public void setException(IOException exception) {
+ delegate.setException(exception);
+ }
+
+ public void set(List<File> paths) {
+ delegate.set(paths);
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ // Best-effort interrupt of the in-flight visitation.
+ visitor.cancel();
+ return true;
+ }
+
+ public void markCanceled() {
+ super.cancel(true);
+ }
+ }
+
+ /**
+ * GlobVisitor executes a glob using parallelism, which is useful when the glob() requires many
+ * readdir() calls on high latency filesystems.
+ */
+ private static final class GlobVisitor {
+ // These collections are used across workers and must therefore be thread-safe.
+ private final Collection<File> results = Sets.newConcurrentHashSet();
+ private final Cache<String, Pattern> cache =
+ CacheBuilder.newBuilder()
+ .build(
+ new CacheLoader<String, Pattern>() {
+ @Override
+ public Pattern load(String wildcard) {
+ return makePatternFromWildcard(wildcard);
+ }
+ });
+
+ private final GlobFuture result;
+ private final ThreadPoolExecutor executor;
+ private final AtomicLong pendingOps = new AtomicLong(0);
+ private final AtomicReference<IOException> failure = new AtomicReference<>();
+ private final FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
+ private volatile boolean canceled = false;
+
+ public GlobVisitor(ThreadPoolExecutor executor) {
+ this.executor = executor;
+ this.result = new GlobFuture(this);
+ }
+
+ public GlobVisitor() {
+ this(null);
+ }
+
+ /**
+ * Performs wildcard globbing: returns the sorted list of filenames that match any of {@code
+ * patterns} relative to {@code base}, but which do not match {@code excludePatterns}.
+ * Directories are traversed if and only if they match {@code dirPred}. The predicate is also
+ * called for the root of the traversal.
+ *
+ * <p>Patterns may include "*" and "?", but not "[a-z]".
+ *
+ * <p><code>**</code> gets special treatment in include patterns. If it is used as a complete
+ * path segment it matches the filenames in subdirectories recursively.
+ *
+ * @throws IllegalArgumentException if any glob or exclude pattern {@linkplain
+ * #checkPatternForError(String) contains errors} or if any exclude pattern segment contains
+ * <code>**</code> or if any include pattern segment contains <code>**</code> but not equal
+ * to it.
+ */
+ public List<File> glob(
+ File base,
+ Collection<String> patterns,
+ Collection<String> excludePatterns,
+ boolean excludeDirectories,
+ Predicate<File> dirPred)
+ throws IOException, InterruptedException {
+ try {
+ return globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred).get();
+ } catch (ExecutionException e) {
+ Throwable cause = e.getCause();
+ Throwables.propagateIfPossible(cause, IOException.class);
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Future<List<File>> globAsync(
+ File base,
+ Collection<String> patterns,
+ Collection<String> excludePatterns,
+ boolean excludeDirectories,
+ Predicate<File> dirPred)
+ throws IOException {
+
+ if (!fileAttributeProvider.exists(base) || patterns.isEmpty()) {
+ return Futures.immediateFuture(Collections.emptyList());
+ }
+ boolean baseIsDirectory = fileAttributeProvider.isDirectory(base);
+
+ List<String[]> splitPatterns = checkAndSplitPatterns(patterns);
+ List<String[]> splitExcludes = checkAndSplitPatterns(excludePatterns);
+
+ // We do a dumb loop, even though it will likely duplicate work
+ // (e.g., readdir calls). In order to optimize, we would need
+ // to keep track of which patterns shared sub-patterns and which did not
+ // (for example consider the glob [*/*.java, sub/*.java, */*.txt]).
+ pendingOps.incrementAndGet();
+ try {
+ for (String[] splitPattern : splitPatterns) {
+ queueGlob(
+ base,
+ baseIsDirectory,
+ splitPattern,
+ 0,
+ excludeDirectories,
+ splitExcludes,
+ 0,
+ results,
+ cache,
+ dirPred);
+ }
+ } finally {
+ decrementAndCheckDone();
+ }
+
+ return result;
+ }
+
+ private void queueGlob(
+ File base,
+ boolean baseIsDirectory,
+ String[] patternParts,
+ int idx,
+ boolean excludeDirectories,
+ List<String[]> excludePatterns,
+ int excludeIdx,
+ Collection<File> results,
+ Cache<String, Pattern> cache,
+ Predicate<File> dirPred)
+ throws IOException {
+ enqueue(
+ () -> {
+ try {
+ reallyGlob(
+ base,
+ baseIsDirectory,
+ patternParts,
+ idx,
+ excludeDirectories,
+ excludePatterns,
+ excludeIdx,
+ results,
+ cache,
+ dirPred);
+ } catch (IOException e) {
+ failure.set(e);
+ }
+ });
+ }
+
+ protected void enqueue(final Runnable r) {
+ pendingOps.incrementAndGet();
+
+ Runnable wrapped =
+ () -> {
+ try {
+ if (!canceled && failure.get() == null) {
+ r.run();
+ }
+ } finally {
+ decrementAndCheckDone();
+ }
+ };
+
+ if (executor == null) {
+ wrapped.run();
+ } else {
+ executor.execute(wrapped);
+ }
+ }
+
+ protected void cancel() {
+ this.canceled = true;
+ }
+
+ private void decrementAndCheckDone() {
+ if (pendingOps.decrementAndGet() == 0) {
+ // We get to 0 iff we are done all the relevant work. This is because we always increment
+ // the pending ops count as we're enqueuing, and don't decrement until the task is complete
+ // (which includes accounting for any additional tasks that one enqueues).
+ if (canceled) {
+ result.markCanceled();
+ } else if (failure.get() != null) {
+ result.setException(failure.get());
+ } else {
+ result.set(Ordering.<File>natural().immutableSortedCopy(results));
+ }
+ }
+ }
+
+ /**
+ * Expressed in Haskell:
+ *
+ * <pre>
+ * reallyGlob base [] = { base }
+ * reallyGlob base [x:xs] = union { reallyGlob(f, xs) | f results "base/x" }
+ * </pre>
+ */
+ private void reallyGlob(
+ File base,
+ boolean baseIsDirectory,
+ String[] patternParts,
+ int idx,
+ boolean excludeDirectories,
+ List<String[]> excludePatterns,
+ int excludeIdx,
+ Collection<File> results,
+ Cache<String, Pattern> cache,
+ Predicate<File> dirPred)
+ throws IOException {
+ ProgressManager.checkCanceled();
+ if (baseIsDirectory && !dirPred.test(base)) {
+ return;
+ }
+
+ if (idx == patternParts.length) { // Base case.
+ if (!(excludeDirectories && baseIsDirectory)
+ && !excludedOnMatch(base, excludePatterns, excludeIdx, cache)) {
+ results.add(base);
+ }
+ return;
+ }
+
+ if (!baseIsDirectory) {
+ // Nothing to find here.
+ return;
+ }
+
+ List<String[]> relevantExcludes =
+ getRelevantExcludes(base, excludePatterns, excludeIdx, cache);
+ final String pattern = patternParts[idx];
+
+ // ** is special: it can match nothing at all.
+ // For example, x/** matches x, **/y matches y, and x/**/y matches x/y.
+ if ("**".equals(pattern)) {
+ queueGlob(
+ base,
+ baseIsDirectory,
+ patternParts,
+ idx + 1,
+ excludeDirectories,
+ excludePatterns,
+ excludeIdx,
+ results,
+ cache,
+ dirPred);
+ }
+
+ if (!pattern.contains("*") && !pattern.contains("?")) {
+ // We do not need to do a readdir in this case, just a stat.
+ File child = new File(base, pattern);
+ boolean childIsDir = fileAttributeProvider.isDirectory(child);
+ if (!childIsDir && !fileAttributeProvider.isFile(child)) {
+ // The file is a dangling symlink, fifo, does not exist, etc.
+ return;
+ }
+
+ queueGlob(
+ child,
+ childIsDir,
+ patternParts,
+ idx + 1,
+ excludeDirectories,
+ relevantExcludes,
+ excludeIdx + 1,
+ results,
+ cache,
+ dirPred);
+ return;
+ }
+
+ File[] children = getChildren(base);
+ if (children == null) {
+ return;
+ }
+ for (File child : children) {
+ boolean childIsDir = fileAttributeProvider.isDirectory(child);
+
+ if ("**".equals(pattern)) {
+ // Recurse without shifting the pattern.
+ if (childIsDir) {
+ queueGlob(
+ child,
+ childIsDir,
+ patternParts,
+ idx,
+ excludeDirectories,
+ relevantExcludes,
+ excludeIdx + 1,
+ results,
+ cache,
+ dirPred);
+ }
+ }
+ if (matches(pattern, child.getName(), cache)) {
+ // Recurse and consume one segment of the pattern.
+ if (childIsDir) {
+ queueGlob(
+ child,
+ childIsDir,
+ patternParts,
+ idx + 1,
+ excludeDirectories,
+ relevantExcludes,
+ excludeIdx + 1,
+ results,
+ cache,
+ dirPred);
+ } else {
+ // Instead of using an async call, just repeat the base case above.
+ if (idx + 1 == patternParts.length
+ && !excludedOnMatch(child, relevantExcludes, excludeIdx + 1, cache)) {
+ results.add(child);
+ }
+ }
+ }
+ }
+ }
+
+ private static VirtualFileSystem getFileSystem() {
+ if (ApplicationManager.getApplication().isUnitTestMode()) {
+ return TempFileSystem.getInstance();
+ }
+ return LocalFileSystem.getInstance();
+ }
+
+ @Nullable
+ private File[] getChildren(File file) {
+ if (!ApplicationManager.getApplication().isUnitTestMode()) {
+ return file.listFiles();
+ }
+ TempFileSystem fs = TempFileSystem.getInstance();
+ VirtualFile vf = fs.findFileByIoFile(file);
+ VirtualFile[] children = vf.getChildren();
+ if (children == null) {
+ return null;
+ }
+ return Arrays.stream(children).map(VirtualFile::getPath).map(File::new).toArray(File[]::new);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildColorsPage.java b/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildColorsPage.java
new file mode 100644
index 0000000..b348256
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildColorsPage.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.highlighting;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.application.options.colors.InspectionColorSettingsPage;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
+import com.intellij.openapi.options.colors.AttributesDescriptor;
+import com.intellij.openapi.options.colors.ColorDescriptor;
+import com.intellij.openapi.options.colors.ColorSettingsPage;
+import com.intellij.psi.codeStyle.DisplayPriority;
+import com.intellij.psi.codeStyle.DisplayPrioritySortable;
+import com.intellij.util.PlatformUtils;
+import java.util.Map;
+import javax.swing.Icon;
+
+/** Allows user to customize colors. */
+public class BuildColorsPage
+ implements ColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable {
+ private static final AttributesDescriptor[] ATTRS =
+ new AttributesDescriptor[] {
+ new AttributesDescriptor("Keyword", BuildSyntaxHighlighter.BUILD_KEYWORD),
+ new AttributesDescriptor("String", BuildSyntaxHighlighter.BUILD_STRING),
+ new AttributesDescriptor("Number", BuildSyntaxHighlighter.BUILD_NUMBER),
+ new AttributesDescriptor("Line Comment", BuildSyntaxHighlighter.BUILD_LINE_COMMENT),
+ new AttributesDescriptor("Operation Sign", BuildSyntaxHighlighter.BUILD_OPERATION_SIGN),
+ new AttributesDescriptor("Parentheses", BuildSyntaxHighlighter.BUILD_PARENS),
+ new AttributesDescriptor("Brackets", BuildSyntaxHighlighter.BUILD_BRACKETS),
+ new AttributesDescriptor("Braces", BuildSyntaxHighlighter.BUILD_BRACES),
+ new AttributesDescriptor("Comma", BuildSyntaxHighlighter.BUILD_COMMA),
+ new AttributesDescriptor("Dot", BuildSyntaxHighlighter.BUILD_DOT),
+ new AttributesDescriptor("Function definition", BuildSyntaxHighlighter.BUILD_FN_DEFINITION),
+ new AttributesDescriptor("Parameter", BuildSyntaxHighlighter.BUILD_PARAMETER),
+ new AttributesDescriptor("Keyword argument", BuildSyntaxHighlighter.BUILD_KEYWORD_ARG),
+ };
+
+ private static final Map<String, TextAttributesKey> ourTagToDescriptorMap =
+ ImmutableMap.<String, TextAttributesKey>builder()
+ .put("funcDef", BuildSyntaxHighlighter.BUILD_FN_DEFINITION)
+ .put("param", BuildSyntaxHighlighter.BUILD_PARAMETER)
+ .put("kwarg", BuildSyntaxHighlighter.BUILD_KEYWORD_ARG)
+ .put("comma", BuildSyntaxHighlighter.BUILD_COMMA)
+ .put("number", BuildSyntaxHighlighter.BUILD_NUMBER)
+ .build();
+
+ @Override
+ public String getDisplayName() {
+ return Blaze.defaultBuildSystemName() + " BUILD files";
+ }
+
+ @Override
+ public Icon getIcon() {
+ return BuildFileType.INSTANCE.getIcon();
+ }
+
+ @Override
+ public AttributesDescriptor[] getAttributeDescriptors() {
+ return ATTRS;
+ }
+
+ @Override
+ public ColorDescriptor[] getColorDescriptors() {
+ return ColorDescriptor.EMPTY_ARRAY;
+ }
+
+ @Override
+ public SyntaxHighlighter getHighlighter() {
+ final SyntaxHighlighter highlighter =
+ SyntaxHighlighterFactory.getSyntaxHighlighter(BuildFileType.INSTANCE, null, null);
+ assert highlighter != null;
+ return highlighter;
+ }
+
+ @Override
+ public String getDemoText() {
+ return "def <funcDef>function</funcDef>(<param>x</param>, <kwarg>whatever</kwarg>=1):\n"
+ + " s = (\"Test\", 2+3, {'a': 'b'}, <param>x</param>) # Comment\n"
+ + " print s[0].lower()\n"
+ + "\n"
+ + "java_library(\n"
+ + " <kwarg>name</kwarg> = \"lib\",\n"
+ + " <kwarg>srcs</kwarg> = glob([\"**/*.java\"]),\n"
+ + ")\n";
+ }
+
+ @Override
+ public Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {
+ return ourTagToDescriptorMap;
+ }
+
+ @Override
+ public DisplayPriority getPriority() {
+ return PlatformUtils.isPyCharm()
+ ? DisplayPriority.KEY_LANGUAGE_SETTINGS
+ : DisplayPriority.LANGUAGE_SETTINGS;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighter.java b/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighter.java
new file mode 100644
index 0000000..b14e89b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.highlighting;
+
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.BRACES;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.BRACKETS;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.COMMA;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.DOT;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.FUNCTION_DECLARATION;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.KEYWORD;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.LINE_COMMENT;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.NUMBER;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.OPERATION_SIGN;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.PARAMETER;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.PARENTHESES;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.SEMICOLON;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.STRING;
+
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
+import com.intellij.psi.tree.IElementType;
+import java.util.Map;
+
+/**
+ * This class maps tokens to highlighting attributes. Each attribute contains the font properties.
+ */
+public class BuildSyntaxHighlighter extends SyntaxHighlighterBase {
+
+ public static final TextAttributesKey BUILD_KEYWORD = key("BUILD.MODIFIER", KEYWORD);
+ public static final TextAttributesKey BUILD_STRING = key("BUILD.STRING", STRING);
+ public static final TextAttributesKey BUILD_NUMBER = key("BUILD.NUMBER", NUMBER);
+ public static final TextAttributesKey BUILD_LINE_COMMENT =
+ key("BUILD.LINE_COMMENT", LINE_COMMENT);
+ public static final TextAttributesKey BUILD_BRACES = key("BUILD.BRACES", BRACES);
+ public static final TextAttributesKey BUILD_PARENS = key("BUILD.PARENS", PARENTHESES);
+ public static final TextAttributesKey BUILD_BRACKETS = key("BUILD.BRACKETS", BRACKETS);
+ public static final TextAttributesKey BUILD_OPERATION_SIGN =
+ key("BUILD.OPERATION_SIGN", OPERATION_SIGN);
+ public static final TextAttributesKey BUILD_DOT = key("BUILD.DOT", DOT);
+ public static final TextAttributesKey BUILD_SEMICOLON = key("BUILD.SEMICOLON", SEMICOLON);
+ public static final TextAttributesKey BUILD_COMMA = key("BUILD.COMMA", COMMA);
+ public static final TextAttributesKey BUILD_PARAMETER = key("BUILD.PARAMETER", PARAMETER);
+ public static final TextAttributesKey BUILD_KEYWORD_ARG = key("BUILD.KEYWORD.ARG", PARAMETER);
+ public static final TextAttributesKey BUILD_FN_DEFINITION =
+ key("BUILD.FN.DEFINITION", FUNCTION_DECLARATION);
+
+ private static TextAttributesKey key(String name, TextAttributesKey fallbackKey) {
+ return TextAttributesKey.createTextAttributesKey(name, fallbackKey);
+ }
+
+ private static final Map<IElementType, TextAttributesKey> keys = Maps.newHashMap();
+
+ static {
+ addAttribute(TokenKind.COMMENT, BUILD_LINE_COMMENT);
+ addAttribute(TokenKind.INT, BUILD_NUMBER);
+ addAttribute(TokenKind.STRING, BUILD_STRING);
+
+ addAttribute(TokenKind.LBRACE, BUILD_BRACES);
+ addAttribute(TokenKind.RBRACE, BUILD_BRACES);
+ addAttribute(TokenKind.LBRACKET, BUILD_BRACKETS);
+ addAttribute(TokenKind.RBRACKET, BUILD_BRACKETS);
+
+ addAttribute(TokenKind.LPAREN, BUILD_PARENS);
+ addAttribute(TokenKind.RPAREN, BUILD_PARENS);
+
+ addAttribute(TokenKind.DOT, BUILD_DOT);
+ addAttribute(TokenKind.SEMI, BUILD_SEMICOLON);
+ addAttribute(TokenKind.COMMA, BUILD_COMMA);
+
+ for (TokenKind kind : TokenKind.OPERATIONS) {
+ addAttribute(kind, BUILD_OPERATION_SIGN);
+ }
+
+ for (TokenKind kind : TokenKind.KEYWORDS) {
+ addAttribute(kind, BUILD_KEYWORD);
+ }
+ }
+
+ private static void addAttribute(TokenKind kind, TextAttributesKey key) {
+ keys.put(BuildToken.fromKind(kind), key);
+ }
+
+ @Override
+ public Lexer getHighlightingLexer() {
+ return new BuildLexer(BuildLexerBase.LexerMode.SyntaxHighlighting);
+ }
+
+ @Override
+ public TextAttributesKey[] getTokenHighlights(IElementType iElementType) {
+ return pack(keys.get(iElementType));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighterFactory.java b/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighterFactory.java
new file mode 100644
index 0000000..7f6ffc7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighterFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.highlighting;
+
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Factory for BuildSyntaxHighlighter */
+public class BuildSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
+
+ @Override
+ public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) {
+ return new BuildSyntaxHighlighter();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileLanguage.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileLanguage.java
new file mode 100644
index 0000000..357791d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileLanguage.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language;
+
+import com.intellij.lang.Language;
+
+/** BUILD file language */
+public class BuildFileLanguage extends Language {
+
+ public static final BuildFileLanguage INSTANCE = new BuildFileLanguage();
+
+ private BuildFileLanguage() {
+ super("BUILD", "text/python");
+ }
+
+ @Override
+ public String getDisplayName() {
+ return "BUILD file";
+ }
+
+ @Override
+ public boolean isCaseSensitive() {
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileType.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileType.java
new file mode 100644
index 0000000..aa084bc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileType.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import icons.BlazeIcons;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** BUILD file type */
+public class BuildFileType extends LanguageFileType {
+
+ public static final BuildFileType INSTANCE = new BuildFileType();
+
+ private BuildFileType() {
+ super(BuildFileLanguage.INSTANCE);
+ }
+
+ @Override
+ public String getName() {
+ // Warning: this is conflated with Language.myID in several places...
+ // They must be identical.
+ return BuildFileLanguage.INSTANCE.getID();
+ }
+
+ @Override
+ public String getDescription() {
+ return Blaze.defaultBuildSystemName() + " BUILD language";
+ }
+
+ @Override
+ public String getDefaultExtension() {
+ return "";
+ }
+
+ @Override
+ @Nullable
+ public Icon getIcon() {
+ return BlazeIcons.BuildFile;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeFactory.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeFactory.java
new file mode 100644
index 0000000..32243bc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.openapi.fileTypes.ExactFileNameMatcher;
+import com.intellij.openapi.fileTypes.ExtensionFileNameMatcher;
+import com.intellij.openapi.fileTypes.FileNameMatcher;
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+/** Factory for BuildFileType */
+public class BuildFileTypeFactory extends FileTypeFactory {
+
+ private static ImmutableList<FileNameMatcher> DEFAULT_ASSOCIATIONS =
+ ImmutableList.of(new ExactFileNameMatcher("BUILD"), new ExtensionFileNameMatcher("bzl"));
+
+ @Override
+ public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
+ consumer.consume(BuildFileType.INSTANCE, DEFAULT_ASSOCIATIONS.toArray(new FileNameMatcher[0]));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/AttributeDefinition.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/AttributeDefinition.java
new file mode 100644
index 0000000..2d1c5ea
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/AttributeDefinition.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Simple implementation of AttributeDefinition, from build.proto */
+public class AttributeDefinition implements Serializable {
+
+ public static AttributeDefinition fromProto(Build.AttributeDefinition attr) {
+ return new AttributeDefinition(
+ attr.getName(),
+ attr.getType(),
+ attr.getMandatory(),
+ attr.hasDocumentation() ? attr.getDocumentation() : null,
+ getAllowedRuleClasses(attr));
+ }
+
+ @Nullable
+ private static ImmutableList<String> getAllowedRuleClasses(Build.AttributeDefinition attr) {
+ if (!attr.hasAllowedRuleClasses()) {
+ return null;
+ }
+ return ImmutableList.copyOf(attr.getAllowedRuleClasses().getAllowedRuleClassList());
+ }
+
+ public final String name;
+ public final Build.Attribute.Discriminator type;
+ public final boolean mandatory;
+ public final String documentation;
+
+ // the names of rules allowed in this attribute, or null if any rules are allowed.
+ @Nullable private final ImmutableList<String> allowedRuleClasses;
+
+ @VisibleForTesting
+ public AttributeDefinition(
+ String name,
+ Build.Attribute.Discriminator type,
+ boolean mandatory,
+ String documentation,
+ @Nullable ImmutableList<String> allowedRuleClasses) {
+
+ this.name = name;
+ this.type = type;
+ this.mandatory = mandatory;
+ this.documentation = documentation;
+ this.allowedRuleClasses = allowedRuleClasses;
+ }
+
+ /**
+ * Only relevant for attributes of type LABEL and LABEL_LIST. Some such attributes can only
+ * contain certain rule types.
+ */
+ public boolean isRuleTypeAllowed(RuleDefinition rule) {
+ return allowedRuleClasses == null || allowedRuleClasses.contains(rule.name);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpec.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpec.java
new file mode 100644
index 0000000..824c262
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpec.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/**
+ * Specification of the BUILD language, as provided by "blaze info build-language".
+ *
+ * <p>This constitutes a set of rules, along with their supported attributes, and other useful
+ * information. We query this once per blaze workspace (it won't change unless the blaze binary is
+ * also changed).
+ *
+ * <p>This rule list is not exhaustive; it's intended to give information about known rules, not
+ * enumerate all possibilities.
+ */
+public class BuildLanguageSpec implements Serializable {
+
+ public static BuildLanguageSpec fromProto(Build.BuildLanguage proto) {
+ ImmutableMap.Builder<String, RuleDefinition> builder = ImmutableMap.builder();
+ for (Build.RuleDefinition rule : proto.getRuleList()) {
+ builder.put(rule.getName(), RuleDefinition.fromProto(rule));
+ }
+ return new BuildLanguageSpec(builder.build());
+ }
+
+ public final ImmutableMap<String, RuleDefinition> rules;
+
+ @VisibleForTesting
+ public BuildLanguageSpec(ImmutableMap<String, RuleDefinition> rules) {
+ this.rules = rules;
+ }
+
+ public ImmutableSet<String> getKnownRuleNames() {
+ return rules.keySet();
+ }
+
+ public boolean hasRule(@Nullable String ruleName) {
+ return getRule(ruleName) != null;
+ }
+
+ @Nullable
+ public RuleDefinition getRule(@Nullable String ruleName) {
+ return ruleName != null ? rules.get(ruleName) : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProvider.java
new file mode 100644
index 0000000..d8ea988
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Provides a BuildLanguageSpec for the given project. */
+public interface BuildLanguageSpecProvider {
+
+ static BuildLanguageSpecProvider getInstance() {
+ return ServiceManager.getService(BuildLanguageSpecProvider.class);
+ }
+
+ /**
+ * Returns null if cancelled or unsuccessful. Also returns null if no WorkspaceRoot can be found
+ * for the project (i.e. because BlazeImportSettings has not been set).
+ */
+ @Nullable
+ BuildLanguageSpec getLanguageSpec(Project project);
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProviderImpl.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProviderImpl.java
new file mode 100644
index 0000000..43ea22a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProviderImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
+
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.lang.buildfile.sync.LanguageSpecResult;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.sync.SyncListener;
+import com.intellij.openapi.project.Project;
+import java.util.Map;
+
+/** Calls 'blaze info build-language', to retrieve the language spec. */
+public class BuildLanguageSpecProviderImpl extends SyncListener.Adapter
+ implements BuildLanguageSpecProvider {
+
+ private static final Map<Project, LanguageSpecResult> calculatedSpecs = Maps.newHashMap();
+
+ @Override
+ public BuildLanguageSpec getLanguageSpec(Project project) {
+ LanguageSpecResult result = calculatedSpecs.get(project);
+ return result != null ? result.spec : null;
+ }
+
+ @Override
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
+ LanguageSpecResult spec = blazeProjectData.syncState.get(LanguageSpecResult.class);
+ if (spec != null) {
+ calculatedSpecs.put(project, spec);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/RuleDefinition.java b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/RuleDefinition.java
new file mode 100644
index 0000000..089b598
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/RuleDefinition.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Simple implementation of RuleDefinition, from build.proto */
+public class RuleDefinition implements Serializable {
+
+ /** This isn't included in the proto -- all other documented attributes seem to be. */
+ private static final AttributeDefinition NAME_ATTRIBUTE =
+ new AttributeDefinition("name", Build.Attribute.Discriminator.STRING, true, null, null);
+
+ public static RuleDefinition fromProto(Build.RuleDefinition rule) {
+ ImmutableMap.Builder<String, AttributeDefinition> map = ImmutableMap.builder();
+ for (Build.AttributeDefinition attr : rule.getAttributeList()) {
+ map.put(attr.getName(), AttributeDefinition.fromProto(attr));
+ }
+ map.put(NAME_ATTRIBUTE.name, NAME_ATTRIBUTE);
+ return new RuleDefinition(
+ rule.getName(), map.build(), rule.hasDocumentation() ? rule.getDocumentation() : null);
+ }
+
+ public final String name;
+ /** This map is not exhaustive; it only contains documented attributes. */
+ public final ImmutableMap<String, AttributeDefinition> attributes;
+
+ @Nullable public final String documentation;
+
+ public RuleDefinition(
+ String name,
+ ImmutableMap<String, AttributeDefinition> attributes,
+ @Nullable String documentation) {
+ this.name = name;
+ this.attributes = attributes;
+ this.documentation = documentation;
+ }
+
+ public ImmutableSet<String> getKnownAttributeNames() {
+ return attributes.keySet();
+ }
+
+ @Nullable
+ public AttributeDefinition getAttribute(@Nullable String attributeName) {
+ return attributeName != null ? attributes.get(attributeName) : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexer.java b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexer.java
new file mode 100644
index 0000000..e026d32
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase.LexerMode;
+import com.intellij.lexer.LexerBase;
+import java.util.Iterator;
+import java.util.List;
+
+/** Implementation of LexerBase using BuildLexerBase to tokenize the input. */
+public class BuildLexer extends LexerBase {
+
+ private final LexerMode mode;
+
+ private int offsetEnd;
+ private int offsetStart;
+ private CharSequence buffer;
+ private Iterator<Token> tokens;
+ private Token currentToken;
+ private int currentState;
+
+ public BuildLexer(LexerMode mode) {
+ this.mode = mode;
+ }
+
+ @Override
+ public void start(CharSequence charSequence, int startOffset, int endOffset, int initialState) {
+ buffer = charSequence;
+ this.offsetEnd = endOffset;
+ this.offsetStart = startOffset;
+
+ BuildLexerBase lexer =
+ new BuildLexerBase(charSequence.subSequence(startOffset, endOffset), initialState, mode);
+ checkNoCharactersMissing(
+ charSequence.subSequence(startOffset, endOffset).length(), lexer.getTokens());
+ tokens = lexer.getTokens().iterator();
+ currentToken = null;
+ if (tokens.hasNext()) {
+ currentToken = tokens.next();
+ }
+ currentState = lexer.getOpenParenStackDepth();
+ }
+
+ /** Temporary debugging code. We need to tokenize every character in the input string. */
+ private void checkNoCharactersMissing(int totalLength, List<Token> tokens) {
+ if (!tokens.isEmpty() && tokens.get(tokens.size() - 1).right != totalLength) {
+ String error =
+ String.format(
+ "Lengths don't match: %s instead of %s",
+ tokens.get(tokens.size() - 1).right, totalLength);
+ throw new RuntimeException(error);
+ }
+ int start = 0;
+ for (int i = 0; i < tokens.size(); i++) {
+ Token token = tokens.get(i);
+ if (token.left != start) {
+ throw new RuntimeException("Gap/inconsistency at: " + start);
+ }
+ start = token.right;
+ }
+ }
+
+ @Override
+ public int getState() {
+ return currentState;
+ }
+
+ @Override
+ public BuildToken getTokenType() {
+ if (currentToken != null) {
+ return BuildToken.fromKind(currentToken.kind);
+ }
+ return null;
+ }
+
+ @Override
+ public int getTokenStart() {
+ if (currentToken == null) {
+ return 0;
+ }
+ return currentToken.left + offsetStart;
+ }
+
+ @Override
+ public int getTokenEnd() {
+ if (currentToken == null) {
+ return 0;
+ }
+ return currentToken.right + offsetStart;
+ }
+
+ @Override
+ public void advance() {
+ if (tokens.hasNext()) {
+ currentToken = tokens.next();
+ } else {
+ currentToken = null;
+ }
+ }
+
+ public TokenKind getTokenKind() {
+ return currentToken.kind;
+ }
+
+ @Override
+ public CharSequence getBufferSequence() {
+ return buffer;
+ }
+
+ @Override
+ public int getBufferEnd() {
+ return offsetEnd;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexerBase.java b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexerBase.java
new file mode 100644
index 0000000..4970281
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexerBase.java
@@ -0,0 +1,849 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import javax.annotation.Nullable;
+
+/**
+ * A tokenizer for the BUILD language.
+ *
+ * <p>Copied from blaze/bazel's lexer. The differences are: 1. Blaze's lexer isn't 'faithful', in
+ * that it reorders characters, skips characters, and adds ghost characters. We can't do that,
+ * because we need to match the editor's view of the document. 2. Blaze's lexer only lexes entire
+ * files (it can't incrementally lex part of a file, starting from a given indent stack depth).
+ */
+public class BuildLexerBase {
+
+ /**
+ * When tokenizing for the purposes of parsing, we handle indentation.<br>
+ * For syntax highlighting, we need to tokenize every character, and don't care about indentation.
+ */
+ public enum LexerMode {
+ Parsing,
+ SyntaxHighlighting
+ }
+
+ // Characters that can come immediately prior to an '=' character to generate
+ // a different token
+ private static final Map<Character, TokenKind> EQUAL_TOKENS =
+ ImmutableMap.<Character, TokenKind>builder()
+ .put('=', TokenKind.EQUALS_EQUALS)
+ .put('!', TokenKind.NOT_EQUALS)
+ .put('>', TokenKind.GREATER_EQUALS)
+ .put('<', TokenKind.LESS_EQUALS)
+ .put('+', TokenKind.PLUS_EQUALS)
+ .put('-', TokenKind.MINUS_EQUALS)
+ .put('*', TokenKind.STAR_EQUALS)
+ .put('/', TokenKind.SLASH_EQUALS)
+ .put('%', TokenKind.PERCENT_EQUALS)
+ .build();
+
+ private final LexerMode mode;
+
+ // Input buffer and position
+ private final char[] buffer;
+ private int pos;
+
+ private final List<Token> tokens;
+
+ // The number of unclosed open-parens ("(", '{', '[') at the current point in
+ // the stream. Whitespace is handled differently when this is nonzero.
+ private int openParenStackDepth = 0;
+
+ // The stack of enclosing indentation levels; always contains '0' at the
+ // bottom.
+ private final Stack<Integer> indentStack = new Stack<>();
+
+ private boolean containsErrors;
+
+ /**
+ * Constructs a lexer which tokenizes the contents of the specified InputBuffer. Any errors during
+ * lexing are reported on "handler".
+ */
+ public BuildLexerBase(CharSequence input, int initialStackDepth, LexerMode mode) {
+ this.buffer = input.toString().toCharArray();
+ // Empirical measurements show roughly 1 token per 8 characters in buffer.
+ this.tokens = Lists.newArrayListWithExpectedSize(buffer.length / 8);
+ this.pos = 0;
+ this.openParenStackDepth = initialStackDepth;
+ this.mode = mode;
+
+ indentStack.push(0);
+ tokenize();
+ }
+
+ /** The number of unclosed open-parens ("(", '{', '[') at the end of this string. */
+ public int getOpenParenStackDepth() {
+ return openParenStackDepth;
+ }
+
+ /**
+ * Returns true if there were errors during scanning of this input file or string. The
+ * BuildLexerBase may attempt to recover from errors, but clients should not rely on the results
+ * of scanning if this flag is set.
+ */
+ public boolean containsErrors() {
+ return containsErrors;
+ }
+
+ /** Returns the (mutable) list of tokens generated by the BuildLexerBase. */
+ public List<Token> getTokens() {
+ return tokens;
+ }
+
+ private void popParen() {
+ if (openParenStackDepth == 0) {
+ error("indentation error");
+ } else {
+ openParenStackDepth--;
+ }
+ }
+
+ private void error(String message) {
+ error(message, pos - 1, pos - 1);
+ }
+
+ protected void error(String message, int start, int end) {
+ this.containsErrors = true;
+ }
+
+ /** invariant: symbol positions are half-open intervals. */
+ private void addToken(TokenKind kind, int left, int right) {
+ addToken(kind, left, right, null);
+ }
+
+ private void addToken(TokenKind kind, int left, int right, @Nullable Object value) {
+ tokens.add(new Token(kind, left, right, value));
+ }
+
+ /**
+ * Parses an end-of-line sequence, handling statement indentation correctly.
+ *
+ * <p>UNIX newlines are assumed (LF). Carriage returns are always ignored.
+ *
+ * <p>ON ENTRY: 'pos' is the index of the char after '\n'. ON EXIT: 'pos' is the index of the next
+ * non-space char after '\n'.
+ */
+ protected void newline() {
+ if (mode == LexerMode.SyntaxHighlighting) {
+ addToken(TokenKind.NEWLINE, pos - 1, pos);
+ return;
+ }
+ if (openParenStackDepth > 0) {
+ newlineInsideExpression(); // in an expression: ignore space
+ } else {
+ newlineOutsideExpression(); // generate NEWLINE/INDENT/DEDENT tokens
+ }
+ }
+
+ private void newlineInsideExpression() {
+ int oldPos = pos - 1;
+ while (pos < buffer.length) {
+ switch (buffer[pos]) {
+ case ' ':
+ case '\t':
+ case '\r':
+ pos++;
+ break;
+ default:
+ // ignored by the parser
+ addToken(TokenKind.WHITESPACE, oldPos, pos);
+ return;
+ }
+ }
+ addToken(TokenKind.WHITESPACE, oldPos, pos);
+ }
+
+ /**
+ * Handle INDENT and DEDENT within statements.
+ *
+ * <p>Note these tokens have zero length -- this is because we can have an arbitrary number of
+ * dedents squeezed into some number of characters, and the size of all the lexical elements must
+ * match the number of characters in the file.
+ */
+ private void newlineOutsideExpression() {
+ int oldPos = pos - 1;
+ if (pos > 1) { // skip over newline at start of file
+ addToken(TokenKind.NEWLINE, oldPos, pos);
+ oldPos = pos;
+ }
+
+ // we're in a stmt: suck up space at beginning of next line
+ int indentLen = 0;
+ while (pos < buffer.length) {
+ char c = buffer[pos];
+ if (c == ' ') {
+ indentLen++;
+ pos++;
+ } else if (c == '\t') {
+ indentLen += 8 - indentLen % 8;
+ pos++;
+ } else if (c == '\n') { // entirely blank line: ignore
+ indentLen = 0;
+ pos++;
+ } else if (c == '#') { // line containing only indented comment
+ if (oldPos != pos) {
+ addToken(TokenKind.WHITESPACE, oldPos, pos);
+ oldPos = pos;
+ }
+ while (pos < buffer.length && c != '\n') {
+ c = buffer[pos++];
+ }
+ addToken(TokenKind.COMMENT, oldPos, pos - 1, bufferSlice(oldPos, pos - 1));
+ oldPos = pos - 1;
+ indentLen = 0;
+ } else { // printing character
+ break;
+ }
+ }
+
+ if (oldPos != pos) {
+ addToken(TokenKind.WHITESPACE, oldPos, pos);
+ }
+ if (pos == buffer.length) {
+ indentLen = 0;
+ } // trailing space on last line
+
+ int peekedIndent = indentStack.peek();
+ if (peekedIndent < indentLen) { // push a level
+ indentStack.push(indentLen);
+ addToken(TokenKind.INDENT, pos, pos);
+
+ } else if (peekedIndent > indentLen) { // pop one or more levels
+ while (peekedIndent > indentLen) {
+ indentStack.pop();
+ addToken(TokenKind.DEDENT, pos, pos);
+ peekedIndent = indentStack.peek();
+ }
+
+ if (peekedIndent < indentLen) {
+ error("indentation error");
+ }
+ }
+ }
+
+ /** Collapse adjacent whitespace characters into a single token */
+ private void addWhitespace() {
+ int oldPos = pos - 1;
+ while (pos < buffer.length) {
+ switch (buffer[pos]) {
+ case ' ':
+ case '\t':
+ case '\r':
+ pos++;
+ break;
+ default:
+ addToken(TokenKind.WHITESPACE, oldPos, pos, bufferSlice(oldPos, pos));
+ return;
+ }
+ }
+ addToken(TokenKind.WHITESPACE, oldPos, pos, bufferSlice(oldPos, pos));
+ }
+
+ /**
+ * Returns true if current position is in the middle of a triple quote delimiter (3 x quot), and
+ * advances 'pos' by two if so.
+ */
+ private boolean skipTripleQuote(char quot) {
+ if (pos + 1 < buffer.length && buffer[pos] == quot && buffer[pos + 1] == quot) {
+ pos += 2;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Scans a string literal delimited by 'quot', containing escape sequences.
+ *
+ * <p>ON ENTRY: 'pos' is 1 + the index of the first delimiter ON EXIT: 'pos' is 1 + the index of
+ * the last delimiter.
+ */
+ private void escapedStringLiteral(char quot, boolean isRaw) {
+ int oldPos = isRaw ? pos - 2 : pos - 1;
+ boolean inTripleQuote = skipTripleQuote(quot);
+
+ // more expensive second choice that expands escaped into a buffer
+ StringBuilder literal = new StringBuilder();
+ while (pos < buffer.length) {
+ char c = buffer[pos];
+ pos++;
+ switch (c) {
+ case '\n':
+ if (inTripleQuote) {
+ literal.append(c);
+ break;
+ } else {
+ error("unterminated string literal at eol", oldPos, pos);
+ addToken(TokenKind.STRING, oldPos, pos - 1, literal.toString());
+ newline();
+ return;
+ }
+ case '\\':
+ if (pos == buffer.length) {
+ error("unterminated string literal at eof", oldPos, pos);
+ addToken(TokenKind.STRING, oldPos, pos - 1, literal.toString());
+ return;
+ }
+ if (isRaw) {
+ // Insert \ and the following character.
+ // As in Python, it means that a raw string can never end with a single \.
+ literal.append('\\');
+ literal.append(buffer[pos]);
+ pos++;
+ break;
+ }
+ c = buffer[pos];
+ pos++;
+ switch (c) {
+ case '\n':
+ // ignore end of line character
+ break;
+ case 'n':
+ literal.append('\n');
+ break;
+ case 'r':
+ literal.append('\r');
+ break;
+ case 't':
+ literal.append('\t');
+ break;
+ case '\\':
+ literal.append('\\');
+ break;
+ case '\'':
+ literal.append('\'');
+ break;
+ case '"':
+ literal.append('"');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ { // octal escape
+ int octal = c - '0';
+ if (pos < buffer.length) {
+ c = buffer[pos];
+ if (c >= '0' && c <= '7') {
+ pos++;
+ octal = (octal << 3) | (c - '0');
+ if (pos < buffer.length) {
+ c = buffer[pos];
+ if (c >= '0' && c <= '7') {
+ pos++;
+ octal = (octal << 3) | (c - '0');
+ }
+ }
+ }
+ }
+ literal.append((char) (octal & 0xff));
+ break;
+ }
+ case 'a':
+ case 'b':
+ case 'f':
+ case 'N':
+ case 'u':
+ case 'U':
+ case 'v':
+ case 'x':
+ // exists in Python but not implemented in Blaze => error
+ error("escape sequence not implemented: \\" + c, oldPos, pos);
+ break;
+ default:
+ // unknown char escape => "\literal"
+ literal.append('\\');
+ literal.append(c);
+ break;
+ }
+ break;
+ case '\'':
+ case '"':
+ if (c != quot || (inTripleQuote && !skipTripleQuote(quot))) {
+ // Non-matching quote, treat it like a regular char.
+ literal.append(c);
+ } else {
+ // Matching close-delimiter, all done.
+ addToken(TokenKind.STRING, oldPos, pos, literal.toString());
+ return;
+ }
+ break;
+ default:
+ literal.append(c);
+ break;
+ }
+ }
+ error("unterminated string literal at eof", oldPos, pos);
+ addToken(TokenKind.STRING, oldPos, pos, literal.toString());
+ }
+
+ /**
+ * Scans a string literal delimited by 'quot'.
+ *
+ * <ul>
+ * <li> ON ENTRY: 'pos' is 1 + the index of the first delimiter
+ * <li> ON EXIT: 'pos' is 1 + the index of the last delimiter.
+ * </ul>
+ *
+ * @param isRaw if true, do not escape the string.
+ */
+ private void addStringLiteral(char quot, boolean isRaw) {
+ int oldPos = isRaw ? pos - 2 : pos - 1;
+ int start = pos;
+
+ // Don't even attempt to parse triple-quotes here.
+ if (skipTripleQuote(quot)) {
+ pos -= 2;
+ escapedStringLiteral(quot, isRaw);
+ return;
+ }
+
+ // first quick optimistic scan for a simple non-escaped string
+ while (pos < buffer.length) {
+ char c = buffer[pos++];
+ switch (c) {
+ case '\n':
+ error("unterminated string literal at eol", oldPos, pos);
+ addToken(TokenKind.STRING, oldPos, pos - 1, bufferSlice(start, pos - 1));
+ newline();
+ return;
+ case '\\':
+ if (isRaw) {
+ // skip the next character
+ pos++;
+ break;
+ }
+ // oops, hit an escape, need to start over & build a new string buffer
+ pos = oldPos + 1;
+ escapedStringLiteral(quot, false);
+ return;
+ case '\'':
+ case '"':
+ if (c == quot) {
+ // close-quote, all done.
+ addToken(TokenKind.STRING, oldPos, pos, bufferSlice(start, pos - 1));
+ return;
+ }
+ }
+ }
+
+ error("unterminated string literal at eof", oldPos, pos);
+ addToken(TokenKind.STRING, oldPos, pos, bufferSlice(start, pos));
+ }
+
+ private static final ImmutableMap<String, TokenKind> KEYWORD_MAP = createKeywordMap();
+
+ private static ImmutableMap<String, TokenKind> createKeywordMap() {
+ ImmutableMap.Builder<String, TokenKind> builder = ImmutableMap.builder();
+ for (TokenKind kind : TokenKind.KEYWORDS) {
+ builder.put(kind.toString(), kind);
+ }
+ return builder.build();
+ }
+
+ private TokenKind getTokenKindForIdentfier(String id) {
+ TokenKind kind = KEYWORD_MAP.get(id);
+ return kind == null ? TokenKind.IDENTIFIER : kind;
+ }
+
+ private String scanIdentifier() {
+ int oldPos = pos - 1;
+ while (pos < buffer.length) {
+ switch (buffer[pos]) {
+ case '_':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ pos++;
+ break;
+ default:
+ return bufferSlice(oldPos, pos);
+ }
+ }
+ return bufferSlice(oldPos, pos);
+ }
+
+ /**
+ * Scans an identifier or keyword.
+ *
+ * <p>ON ENTRY: 'pos' is 1 + the index of the first char in the identifier. ON EXIT: 'pos' is 1 +
+ * the index of the last char in the identifier.
+ *
+ * @return the identifier or keyword token.
+ */
+ private void addIdentifierOrKeyword() {
+ int oldPos = pos - 1;
+ String id = scanIdentifier();
+ TokenKind kind = getTokenKindForIdentfier(id);
+ addToken(kind, oldPos, pos, (kind == TokenKind.IDENTIFIER) ? id : null);
+ }
+
+ private String scanInteger() {
+ int oldPos = pos - 1;
+ while (pos < buffer.length) {
+ char c = buffer[pos];
+ switch (c) {
+ case 'X':
+ case 'x':
+ case 'a':
+ case 'A':
+ case 'b':
+ case 'B':
+ case 'c':
+ case 'C':
+ case 'd':
+ case 'D':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ pos++;
+ break;
+ default:
+ return bufferSlice(oldPos, pos);
+ }
+ }
+ return bufferSlice(oldPos, pos);
+ }
+
+ /**
+ * Scans an addInteger literal.
+ *
+ * <p>ON ENTRY: 'pos' is 1 + the index of the first char in the literal. ON EXIT: 'pos' is 1 + the
+ * index of the last char in the literal.
+ */
+ private void addInteger() {
+ int oldPos = pos - 1;
+ String literal = scanInteger();
+
+ final String substring;
+ final int radix;
+ if (literal.startsWith("0x") || literal.startsWith("0X")) {
+ radix = 16;
+ substring = literal.substring(2);
+ } else if (literal.startsWith("0") && literal.length() > 1) {
+ radix = 8;
+ substring = literal.substring(1);
+ } else {
+ radix = 10;
+ substring = literal;
+ }
+
+ int value = 0;
+ try {
+ value = Integer.parseInt(substring, radix);
+ } catch (NumberFormatException e) {
+ error("invalid base-" + radix + " integer constant: " + literal);
+ }
+
+ addToken(TokenKind.INT, oldPos, pos, value);
+ }
+
+ /**
+ * Tokenizes a two-char operator.
+ *
+ * @return true if it tokenized an operator
+ */
+ private boolean tokenizeTwoChars() {
+ if (pos + 2 >= buffer.length) {
+ return false;
+ }
+ char c1 = buffer[pos];
+ char c2 = buffer[pos + 1];
+ TokenKind tok = null;
+ if (c2 == '=') {
+ tok = EQUAL_TOKENS.get(c1);
+ } else if (c2 == '*' && c1 == '*') {
+ tok = TokenKind.STAR_STAR;
+ }
+ if (tok == null) {
+ return false;
+ }
+ addToken(tok, pos, pos + 2);
+ return true;
+ }
+
+ /** Performs tokenization of the character buffer of file contents provided to the constructor. */
+ private void tokenize() {
+ while (pos < buffer.length) {
+ if (tokenizeTwoChars()) {
+ pos += 2;
+ continue;
+ }
+ char c = buffer[pos];
+ pos++;
+ switch (c) {
+ case '{':
+ {
+ addToken(TokenKind.LBRACE, pos - 1, pos);
+ openParenStackDepth++;
+ break;
+ }
+ case '}':
+ {
+ addToken(TokenKind.RBRACE, pos - 1, pos);
+ popParen();
+ break;
+ }
+ case '(':
+ {
+ addToken(TokenKind.LPAREN, pos - 1, pos);
+ openParenStackDepth++;
+ break;
+ }
+ case ')':
+ {
+ addToken(TokenKind.RPAREN, pos - 1, pos);
+ popParen();
+ break;
+ }
+ case '[':
+ {
+ addToken(TokenKind.LBRACKET, pos - 1, pos);
+ openParenStackDepth++;
+ break;
+ }
+ case ']':
+ {
+ addToken(TokenKind.RBRACKET, pos - 1, pos);
+ popParen();
+ break;
+ }
+ case '>':
+ {
+ addToken(TokenKind.GREATER, pos - 1, pos);
+ break;
+ }
+ case '<':
+ {
+ addToken(TokenKind.LESS, pos - 1, pos);
+ break;
+ }
+ case ':':
+ {
+ addToken(TokenKind.COLON, pos - 1, pos);
+ break;
+ }
+ case ',':
+ {
+ addToken(TokenKind.COMMA, pos - 1, pos);
+ break;
+ }
+ case '+':
+ {
+ addToken(TokenKind.PLUS, pos - 1, pos);
+ break;
+ }
+ case '-':
+ {
+ addToken(TokenKind.MINUS, pos - 1, pos);
+ break;
+ }
+ case '|':
+ {
+ addToken(TokenKind.PIPE, pos - 1, pos);
+ break;
+ }
+ case '=':
+ {
+ addToken(TokenKind.EQUALS, pos - 1, pos);
+ break;
+ }
+ case '%':
+ {
+ addToken(TokenKind.PERCENT, pos - 1, pos);
+ break;
+ }
+ case '/':
+ {
+ addToken(TokenKind.SLASH, pos - 1, pos);
+ break;
+ }
+ case ';':
+ {
+ addToken(TokenKind.SEMI, pos - 1, pos);
+ break;
+ }
+ case '.':
+ {
+ addToken(TokenKind.DOT, pos - 1, pos);
+ break;
+ }
+ case '*':
+ {
+ addToken(TokenKind.STAR, pos - 1, pos);
+ break;
+ }
+ case ' ':
+ case '\t':
+ case '\r':
+ {
+ addWhitespace();
+ break;
+ }
+ case '\\':
+ {
+ // Backslash character is valid only at the end of a line (or in a string)
+ if (pos + 1 < buffer.length && buffer[pos] == '\n') {
+ // treat end of line backslash and newline char as whitespace
+ // (they're ignored by the parser)
+ pos++;
+ addToken(TokenKind.WHITESPACE, pos - 2, pos, Character.toString(c));
+ } else {
+ addToken(TokenKind.ILLEGAL, pos - 1, pos, Character.toString(c));
+ }
+ break;
+ }
+ case '\n':
+ {
+ newline();
+ break;
+ }
+ case '#':
+ {
+ int oldPos = pos - 1;
+ while (pos < buffer.length) {
+ c = buffer[pos];
+ if (c == '\n') {
+ break;
+ } else {
+ pos++;
+ }
+ }
+ addToken(TokenKind.COMMENT, oldPos, pos, bufferSlice(oldPos, pos));
+ break;
+ }
+ case '\'':
+ case '\"':
+ {
+ addStringLiteral(c, false);
+ break;
+ }
+ default:
+ {
+ // detect raw strings, e.g. r"str"
+ if (c == 'r' && pos < buffer.length && (buffer[pos] == '\'' || buffer[pos] == '\"')) {
+ c = buffer[pos];
+ pos++;
+ addStringLiteral(c, true);
+ break;
+ }
+
+ if (Character.isDigit(c)) {
+ addInteger();
+ } else if (Character.isJavaIdentifierStart(c) && c != '$') {
+ addIdentifierOrKeyword();
+ } else {
+ // Some characters in Python are not recognized in Blaze syntax (e.g. '!')
+ addToken(TokenKind.ILLEGAL, pos - 1, pos, Character.toString(c));
+ error("invalid character: '" + c + "'");
+ }
+ break;
+ } // default
+ } // switch
+ } // while
+ }
+
+ /**
+ * Returns parts of the source buffer based on offsets
+ *
+ * @param start the beginning offset for the slice
+ * @param end the offset immediately following the slice
+ * @return the text at offset start with length end - start
+ */
+ private String bufferSlice(int start, int end) {
+ return new String(this.buffer, start, end - start);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildToken.java b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildToken.java
new file mode 100644
index 0000000..afe9252
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildToken.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/** The IElementTypes used by the BUILD language */
+public class BuildToken extends IElementType {
+
+ private static ImmutableMap<TokenKind, BuildToken> types = createMap();
+
+ private static ImmutableMap<TokenKind, BuildToken> createMap() {
+ ImmutableMap.Builder<TokenKind, BuildToken> builder = ImmutableMap.builder();
+ for (TokenKind kind : TokenKind.values()) {
+ builder.put(kind, new BuildToken(kind));
+ }
+ return builder.build();
+ }
+
+ public static BuildToken fromKind(TokenKind kind) {
+ return types.get(kind);
+ }
+
+ public static final BuildToken IDENTIFIER = fromKind(TokenKind.IDENTIFIER);
+
+ public static final TokenSet WHITESPACE_AND_NEWLINE =
+ TokenSet.create(fromKind(TokenKind.WHITESPACE), fromKind(TokenKind.NEWLINE));
+
+ public final TokenKind kind;
+
+ private BuildToken(TokenKind kind) {
+ super(kind.name(), BuildFileType.INSTANCE.getLanguage());
+ this.kind = kind;
+ }
+
+ @Override
+ public String toString() {
+ return kind.toString();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/Token.java b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/Token.java
new file mode 100644
index 0000000..42a05f6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/Token.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+/**
+ * A Token represents an actual lexeme; that is, a lexical unit, its location in the input text, its
+ * lexical kind, and any associated value.
+ */
+public class Token {
+
+ public final TokenKind kind;
+ public final int left;
+ public final int right;
+ public final Object value;
+
+ public Token(TokenKind kind, int left, int right) {
+ this(kind, left, right, null);
+ }
+
+ public Token(TokenKind kind, int left, int right, Object value) {
+ this.kind = kind;
+ this.left = left;
+ this.right = right;
+ this.value = value;
+ }
+
+ /**
+ * Constructs an easy-to-read string representation of token, suitable for use in user error
+ * messages.
+ */
+ @Override
+ public String toString() {
+ if (kind == TokenKind.STRING) {
+ return "\"" + value + "\"";
+ }
+ return value == null ? kind.toString() : value.toString();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/TokenKind.java b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/TokenKind.java
new file mode 100644
index 0000000..c33754f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/lexer/TokenKind.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import com.google.common.collect.ImmutableSet;
+
+/** A TokenKind is an enumeration of each different kind of lexical symbol. */
+public enum TokenKind {
+ ASSERT("assert"),
+ AND("and"),
+ AS("as"),
+ BREAK("break"),
+ CLASS("class"),
+ COLON(":"),
+ COMMA(","),
+ COMMENT("comment"),
+ CONTINUE("continue"),
+ DEF("def"),
+ DEL("del"),
+ DOT("."),
+ ELIF("elif"),
+ ELSE("else"),
+ EOF("EOF"),
+ EQUALS("="),
+ EQUALS_EQUALS("=="),
+ EXCEPT("except"),
+ FALSE("False"),
+ FINALLY("finally"),
+ FOR("for"),
+ FROM("from"),
+ GLOBAL("global"),
+ GREATER(">"),
+ GREATER_EQUALS(">="),
+ IDENTIFIER("identifier"),
+ IF("if"),
+ ILLEGAL("illegal character"),
+ IMPORT("import"),
+ IN("in"),
+ INDENT("indent"),
+ INT("integer"),
+ IS("is"),
+ LAMBDA("lambda"),
+ LBRACE("{"),
+ LBRACKET("["),
+ LESS("<"),
+ LESS_EQUALS("<="),
+ LOAD("load"),
+ LPAREN("("),
+ MINUS("-"),
+ NEWLINE("newline"),
+ NONLOCAL("nonlocal"),
+ NOT("not"),
+ NOT_EQUALS("!="),
+ NOT_IN("not in"), // used internally by the parser; not directly created by the lexer
+ OR("or"),
+ DEDENT("dedent"),
+ PASS("pass"),
+ PERCENT("%"),
+ PIPE("|"),
+ PLUS("+"),
+ PLUS_EQUALS("+="),
+ MINUS_EQUALS("-="),
+ STAR_EQUALS("*="),
+ SLASH_EQUALS("/="),
+ PERCENT_EQUALS("%="),
+ RAISE("raise"),
+ RBRACE("}"),
+ RBRACKET("]"),
+ RETURN("return"),
+ RPAREN(")"),
+ SEMI(";"),
+ SLASH("/"),
+ STAR("*"),
+ STAR_STAR("**"),
+ STRING("string"),
+ TRUE("True"),
+ TRY("try"),
+ WHILE("while"),
+ WITH("with"),
+ YIELD("yield"),
+ // We need to tokenize all characters.
+ // Whitespace will be used for all tokens which should be ignored by the parser.
+ WHITESPACE("whitespace");
+
+ private final String name;
+
+ TokenKind(String name) {
+ this.name = name;
+ }
+
+ /**
+ * This is a user-friendly name. For keywords (if, yield, True, etc.), it's also the exact
+ * character sequence used by the lexer.
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public static ImmutableSet<TokenKind> KEYWORDS =
+ ImmutableSet.of(
+ AND, AS, ASSERT, BREAK, CLASS, CONTINUE, DEF, DEL, ELIF, ELSE, EXCEPT, FALSE, FINALLY,
+ FOR, FROM, GLOBAL, IF, IMPORT, IN, IS, LAMBDA, LOAD, NONLOCAL, NOT, OR, PASS, RAISE,
+ RETURN, TRUE, TRY, WHILE, WITH, YIELD);
+
+ public static ImmutableSet<TokenKind> OPERATIONS =
+ ImmutableSet.of(
+ AND,
+ EQUALS_EQUALS,
+ GREATER,
+ GREATER_EQUALS,
+ IN,
+ LESS,
+ LESS_EQUALS,
+ MINUS,
+ NOT_EQUALS,
+ NOT_IN,
+ OR,
+ PERCENT,
+ SLASH,
+ PLUS,
+ PIPE,
+ STAR);
+
+ public static ImmutableSet<TokenKind> AUGMENTED_ASSIGNMENT_OPS =
+ ImmutableSet.of(PLUS_EQUALS, MINUS_EQUALS, STAR_EQUALS, SLASH_EQUALS, PERCENT_EQUALS);
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserDefinition.java b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserDefinition.java
new file mode 100644
index 0000000..c195cc1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserDefinition.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.parser;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementType;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.common.experiments.DeveloperFlag;
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiParser;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.source.resolve.FileContextUtil;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/** Defines the BUILD file parser */
+public class BuildParserDefinition implements ParserDefinition {
+
+ private static final DeveloperFlag DEBUG = new DeveloperFlag("build.file.debug.mode");
+
+ @Override
+ public Lexer createLexer(Project project) {
+ return new BuildLexer(BuildLexerBase.LexerMode.Parsing);
+ }
+
+ @Override
+ public PsiParser createParser(Project project) {
+ return new BuildParser();
+ }
+
+ @Override
+ public IFileElementType getFileNodeType() {
+ return BuildElementTypes.BUILD_FILE;
+ }
+
+ @Override
+ public TokenSet getWhitespaceTokens() {
+ return convert(TokenKind.WHITESPACE, TokenKind.ILLEGAL);
+ }
+
+ @Override
+ public TokenSet getCommentTokens() {
+ return convert(TokenKind.COMMENT);
+ }
+
+ @Override
+ public TokenSet getStringLiteralElements() {
+ return convert(TokenKind.STRING);
+ }
+
+ @Override
+ public PsiElement createElement(ASTNode node) {
+ IElementType type = node.getElementType();
+ if (type instanceof BuildElementType) {
+ return ((BuildElementType) type).createElement(node);
+ }
+ return new ASTWrapperPsiElement(node);
+ }
+
+ @Override
+ public PsiFile createFile(FileViewProvider viewProvider) {
+ return new BuildFile(viewProvider);
+ }
+
+ @Override
+ public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
+ return SpaceRequirements.MAY;
+ }
+
+ private static TokenSet convert(TokenKind... blazeTokens) {
+ return TokenSet.create(
+ Lists.newArrayList(blazeTokens)
+ .stream()
+ .map(BuildToken::fromKind)
+ .toArray(IElementType[]::new));
+ }
+
+ private static class BuildParser implements PsiParser {
+ @Override
+ public ASTNode parse(IElementType root, PsiBuilder builder) {
+ if (DEBUG.getValue()) {
+ System.err.println(builder.getUserDataUnprotected(FileContextUtil.CONTAINING_FILE_KEY));
+ }
+ PsiBuilder.Marker rootMarker = builder.mark();
+ ParsingContext context = new ParsingContext(builder);
+ context.statementParser.parseFileInput();
+ rootMarker.done(root);
+ return builder.getTreeBuilt();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/parser/ExpressionParsing.java b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/ExpressionParsing.java
new file mode 100644
index 0000000..9c20fd4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/ExpressionParsing.java
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.parser;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementType;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.openapi.diagnostic.Logger;
+import java.util.EnumSet;
+import java.util.List;
+
+/** For parsing expressions in BUILD files. */
+public class ExpressionParsing extends Parsing {
+
+ private static final Logger LOG =
+ Logger.getInstance("com.google.idea.blaze.base.lang.buildfile.parser.ExpressionParsing");
+
+ private static final ImmutableSet<TokenKind> LIST_TERMINATOR_SET =
+ ImmutableSet.of(TokenKind.EOF, TokenKind.RBRACKET, TokenKind.SEMI);
+
+ private static final ImmutableSet<TokenKind> DICT_TERMINATOR_SET =
+ ImmutableSet.of(TokenKind.EOF, TokenKind.RBRACE, TokenKind.SEMI);
+
+ private static final ImmutableSet<TokenKind> EXPR_LIST_TERMINATOR_SET =
+ ImmutableSet.of(
+ TokenKind.EOF,
+ TokenKind.NEWLINE,
+ TokenKind.EQUALS,
+ TokenKind.RBRACE,
+ TokenKind.RBRACKET,
+ TokenKind.RPAREN,
+ TokenKind.SEMI);
+
+ private static final ImmutableSet<TokenKind> EXPR_TERMINATOR_SET =
+ ImmutableSet.of(
+ TokenKind.EOF,
+ TokenKind.COLON,
+ TokenKind.COMMA,
+ TokenKind.FOR,
+ TokenKind.MINUS,
+ TokenKind.PERCENT,
+ TokenKind.PLUS,
+ TokenKind.RBRACKET,
+ TokenKind.RPAREN,
+ TokenKind.SLASH);
+
+ private static final ImmutableSet<TokenKind> BINARY_OPERATORS =
+ ImmutableSet.of(
+ TokenKind.AND,
+ TokenKind.EQUALS_EQUALS,
+ TokenKind.GREATER,
+ TokenKind.GREATER_EQUALS,
+ TokenKind.IN,
+ TokenKind.LESS,
+ TokenKind.LESS_EQUALS,
+ TokenKind.MINUS,
+ TokenKind.NOT_EQUALS,
+ TokenKind.NOT_IN,
+ TokenKind.OR,
+ TokenKind.PERCENT,
+ TokenKind.SLASH,
+ TokenKind.PLUS,
+ TokenKind.PIPE,
+ TokenKind.STAR);
+
+ private static final ImmutableSet<TokenKind> FUNCALL_TERMINATOR_SET =
+ ImmutableSet.of(TokenKind.EOF, TokenKind.RPAREN, TokenKind.SEMI, TokenKind.NEWLINE);
+
+ /**
+ * Highest precedence goes last. Based on:
+ * http://docs.python.org/2/reference/expressions.html#operator-precedence
+ */
+ private static final List<EnumSet<TokenKind>> OPERATOR_PRECEDENCE =
+ ImmutableList.of(
+ EnumSet.of(TokenKind.OR),
+ EnumSet.of(TokenKind.AND),
+ EnumSet.of(TokenKind.NOT),
+ EnumSet.of(
+ TokenKind.EQUALS_EQUALS,
+ TokenKind.NOT_EQUALS,
+ TokenKind.LESS,
+ TokenKind.LESS_EQUALS,
+ TokenKind.GREATER,
+ TokenKind.GREATER_EQUALS,
+ TokenKind.IN,
+ TokenKind.NOT_IN),
+ EnumSet.of(TokenKind.PIPE),
+ EnumSet.of(TokenKind.MINUS, TokenKind.PLUS),
+ EnumSet.of(TokenKind.SLASH, TokenKind.STAR, TokenKind.PERCENT));
+
+ public ExpressionParsing(ParsingContext context) {
+ super(context);
+ }
+
+ public void parseExpression(boolean insideParens) {
+ // handle lists without parens (e.g. 'a,b,c = 1')
+ PsiBuilder.Marker marker = insideParens ? null : builder.mark();
+ parseNonTupleExpression();
+ if (currentToken() == TokenKind.COMMA) {
+ parseExpressionList();
+ if (marker != null) {
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ }
+ } else if (marker != null) {
+ marker.drop();
+ }
+ }
+
+ // expr_list ::= ( ',' expr )* ','?
+ private void parseExpressionList() {
+ while (matches(TokenKind.COMMA)) {
+ if (atAnyOfTokens(EXPR_LIST_TERMINATOR_SET)) {
+ break;
+ }
+ parseNonTupleExpression();
+ }
+ }
+
+ protected void parseNonTupleExpression() {
+ parseNonTupleExpression(0);
+ // don't bother including conditional expressions for now,
+ //just include their components serially
+ if (matches(TokenKind.IF)) {
+ parseNonTupleExpression(0);
+ if (matches(TokenKind.ELSE)) {
+ parseNonTupleExpression();
+ }
+ }
+ }
+
+ private void parseNonTupleExpression(int prec) {
+ if (prec >= OPERATOR_PRECEDENCE.size()) {
+ parsePrimaryWithSuffix();
+ return;
+ }
+ if (currentToken() == TokenKind.NOT && OPERATOR_PRECEDENCE.get(prec).contains(TokenKind.NOT)) {
+ // special case handling of multi-token 'NOT IN' binary operator
+ if (kindFromElement(builder.lookAhead(1)) != TokenKind.IN) {
+ // skip the 'not' -- no need for a specific 'not' expression
+ builder.advanceLexer();
+ parseNonTupleExpression(prec + 1);
+ return;
+ }
+ }
+ parseBinOpExpression(prec);
+ }
+
+ /**
+ * binop_expression ::= binop_expression OP binop_expression | parsePrimaryWithSuffix This
+ * function takes care of precedence between operators (see OPERATOR_PRECEDENCE for the order),
+ * and it assumes left-to-right associativity.
+ */
+ private void parseBinOpExpression(int prec) {
+ PsiBuilder.Marker marker = builder.mark();
+ parseNonTupleExpression(prec + 1);
+
+ while (true) {
+ if (!atBinaryOperator(prec)) {
+ marker.drop();
+ return;
+ }
+ parseNonTupleExpression(prec + 1);
+ marker.done(BuildElementTypes.BINARY_OP_EXPRESSION);
+ marker = marker.precede();
+ }
+ }
+
+ /**
+ * Consumes current token iff it's a binary operator at the given precedence level (with
+ * special-case handling of 'NOT' 'IN' double token binary operator)
+ */
+ private boolean atBinaryOperator(int prec) {
+ if (matchesAnyOf(OPERATOR_PRECEDENCE.get(prec))) {
+ return true;
+ }
+ if (matchesSequence(TokenKind.NOT, TokenKind.IN)) {
+ return true;
+ }
+ return false;
+ }
+
+ // primary_with_suffix ::= primary (selector_suffix | substring_suffix)*
+ private void parsePrimaryWithSuffix() {
+ PsiBuilder.Marker marker = builder.mark();
+ parsePrimary();
+ while (true) {
+ if (matches(TokenKind.DOT)) {
+ marker = parseSelectorSuffix(marker);
+ } else if (matches(TokenKind.LBRACKET)) {
+ marker = parseSubstringSuffix(marker);
+ } else {
+ break;
+ }
+ }
+ marker.drop();
+ }
+
+ // selector_suffix ::= '.' IDENTIFIER [funcall_suffix]
+ private PsiBuilder.Marker parseSelectorSuffix(PsiBuilder.Marker marker) {
+ if (!atToken(TokenKind.IDENTIFIER)) {
+ builder.error("expected identifier after dot");
+ syncPast(EXPR_TERMINATOR_SET);
+ return marker;
+ }
+ parseTargetOrReferenceIdentifier();
+ if (atToken(TokenKind.LPAREN)) {
+ parseFuncallSuffix();
+ marker.done(BuildElementTypes.FUNCALL_EXPRESSION);
+ } else {
+ marker.done(BuildElementTypes.DOT_EXPRESSION);
+ }
+ return marker.precede();
+ }
+
+ // substring_suffix ::= '[' expression? ':' expression? ':' expression? ']'
+ private PsiBuilder.Marker parseSubstringSuffix(PsiBuilder.Marker marker) {
+ if (!atToken(TokenKind.COLON)) {
+ PsiBuilder.Marker pos = builder.mark();
+ parseExpression(false);
+ pos.done(BuildElementTypes.POSITIONAL);
+ }
+ while (!matches(TokenKind.RBRACKET)) {
+ if (expect(TokenKind.COLON)) {
+ if (!atAnyOfTokens(TokenKind.COLON, TokenKind.RBRACKET)) {
+ parseNonTupleExpression();
+ }
+ } else {
+ syncPast(EXPR_LIST_TERMINATOR_SET);
+ break;
+ }
+ }
+ marker.done(BuildElementTypes.FUNCALL_EXPRESSION);
+ return marker.precede();
+ }
+
+ private void parseTargetOrReferenceIdentifier() {
+ if (!atToken(TokenKind.IDENTIFIER)) {
+ builder.error("expected an identifier");
+ return;
+ }
+ // TODO: handle assigning to a list of targets (e.g. "a,b = 1")
+ TokenKind next = kindFromElement(builder.lookAhead(1));
+ if (next == TokenKind.EQUALS || next == TokenKind.IN) {
+ buildTokenElement(BuildElementTypes.TARGET_EXPRESSION);
+ } else {
+ buildTokenElement(BuildElementTypes.REFERENCE_EXPRESSION);
+ }
+ }
+
+ private void parsePrimary() {
+ TokenKind current = currentToken();
+ switch (current) {
+ case INT:
+ buildTokenElement(BuildElementTypes.INTEGER_LITERAL);
+ return;
+ case STRING:
+ parseStringLiteral(true);
+ return;
+ case IDENTIFIER:
+ PsiBuilder.Marker marker = builder.mark();
+ String tokenText = builder.getTokenText();
+ parseTargetOrReferenceIdentifier();
+ if (atToken(TokenKind.LPAREN)) {
+ parseFuncallSuffix();
+ marker.done(getFuncallExpressionType(tokenText));
+ } else {
+ marker.drop();
+ }
+ return;
+ case TRUE: // intentional fall-through -- both treated as vanilla identifiers
+ case FALSE:
+ buildTokenElement(BuildElementTypes.BOOLEAN_LITERAL);
+ return;
+ case LBRACKET:
+ parseListMaker();
+ return;
+ case LBRACE:
+ parseDictExpression();
+ return;
+ case LPAREN:
+ marker = builder.mark();
+ builder.advanceLexer();
+ if (matches(TokenKind.RPAREN)) {
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ return;
+ }
+ parseExpression(true);
+ expect(TokenKind.RPAREN, true);
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ return;
+ case MINUS:
+ marker = builder.mark();
+ builder.advanceLexer();
+ parsePrimaryWithSuffix();
+ marker.done(BuildElementTypes.POSITIONAL);
+ return;
+ default:
+ builder.error("expected an expression");
+ syncPast(EXPR_TERMINATOR_SET);
+ }
+ }
+
+ /** funcall_suffix ::= '(' arg_list? ')' arg_list ::= ((arg ',')* arg ','? )? */
+ private void parseFuncallSuffix() {
+ PsiBuilder.Marker mark = builder.mark();
+ expect(TokenKind.LPAREN, true);
+ if (matches(TokenKind.RPAREN)) {
+ mark.done(BuildElementTypes.ARGUMENT_LIST);
+ return;
+ }
+ parseFuncallArgument();
+ while (!atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
+ expect(TokenKind.COMMA);
+ if (atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
+ break;
+ }
+ parseFuncallArgument();
+ }
+ expect(TokenKind.RPAREN, true);
+ mark.done(BuildElementTypes.ARGUMENT_LIST);
+ }
+
+ private BuildElementType getFuncallExpressionType(String functionName) {
+ if ("glob".equals(functionName)) {
+ return BuildElementTypes.GLOB_EXPRESSION;
+ }
+ return BuildElementTypes.FUNCALL_EXPRESSION;
+ }
+
+ protected void parseFunctionParameters() {
+ if (atToken(TokenKind.RPAREN)) {
+ return;
+ }
+ parseFunctionParameter();
+ while (!atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
+ expect(TokenKind.COMMA);
+ if (atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
+ break;
+ }
+ parseFunctionParameter();
+ }
+ }
+
+ // arg ::= IDENTIFIER '=' nontupleexpr
+ // | expr
+ // | *args
+ // | **kwargs
+ private void parseFuncallArgument() {
+ PsiBuilder.Marker marker = builder.mark();
+ if (matches(TokenKind.STAR_STAR)) {
+ parseNonTupleExpression();
+ marker.done(BuildElementTypes.STAR_STAR);
+ return;
+ }
+ if (matches(TokenKind.STAR)) {
+ parseNonTupleExpression();
+ marker.done(BuildElementTypes.STAR);
+ return;
+ }
+ if (matchesSequence(TokenKind.IDENTIFIER, TokenKind.EQUALS)) {
+ parseNonTupleExpression();
+ marker.done(BuildElementTypes.KEYWORD);
+ return;
+ }
+ parseNonTupleExpression();
+ marker.done(BuildElementTypes.POSITIONAL);
+ }
+
+ /** arg ::= IDENTIFIER ['=' nontupleexpr] */
+ private void parseFunctionParameter() {
+ PsiBuilder.Marker marker = builder.mark();
+ if (matches(TokenKind.STAR_STAR)) {
+ expectIdentifier("invalid parameter name");
+ marker.done(BuildElementTypes.PARAM_STAR_STAR);
+ return;
+ }
+ if (matches(TokenKind.STAR)) {
+ if (atToken(TokenKind.IDENTIFIER)) {
+ builder.advanceLexer();
+ }
+ marker.done(BuildElementTypes.PARAM_STAR);
+ return;
+ }
+ expectIdentifier("invalid parameter name");
+ if (matches(TokenKind.EQUALS)) {
+ parseNonTupleExpression();
+ marker.done(BuildElementTypes.PARAM_OPTIONAL);
+ return;
+ }
+ marker.done(BuildElementTypes.PARAM_MANDATORY);
+ }
+
+ protected void expectIdentifier(String error) {
+ expect(TokenKind.IDENTIFIER, error, true);
+ }
+
+ // list_maker ::= '[' ']'
+ // |'[' expr ']'
+ // |'[' expr expr_list ']'
+ // |'[' expr ('FOR' loop_variables 'IN' expr)+ ']'
+ private void parseListMaker() {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(TokenKind.LBRACKET);
+ if (matches(TokenKind.RBRACKET)) {
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ return;
+ }
+ parseNonTupleExpression();
+ switch (currentToken()) {
+ case RBRACKET:
+ builder.advanceLexer();
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ return;
+ case FOR:
+ parseComprehensionSuffix(TokenKind.RBRACKET);
+ marker.done(BuildElementTypes.LIST_COMPREHENSION_EXPR);
+ return;
+ case COMMA:
+ parseExpressionList();
+ if (!matches(TokenKind.RBRACKET)) {
+ builder.error("expected 'for' or ']'");
+ syncPast(LIST_TERMINATOR_SET);
+ }
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ return;
+ default:
+ builder.error("expected ',', 'for' or ']'");
+ syncPast(LIST_TERMINATOR_SET);
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ }
+ }
+
+ // dict_expression ::= '{' '}'
+ // |'{' dict_entry_list '}'
+ // |'{' dict_entry 'FOR' loop_variables 'IN' expr '}'
+ private void parseDictExpression() {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(TokenKind.LBRACE, true);
+ if (matches(TokenKind.RBRACE)) {
+ marker.done(BuildElementTypes.DICTIONARY_LITERAL);
+ return;
+ }
+ parseDictEntry();
+ if (currentToken() == TokenKind.FOR) {
+ parseComprehensionSuffix(TokenKind.RBRACE);
+ marker.done(BuildElementTypes.LIST_COMPREHENSION_EXPR);
+ return;
+ }
+ if (matches(TokenKind.COMMA)) {
+ parseDictEntryList();
+ }
+ expect(TokenKind.RBRACE, true);
+ marker.done(BuildElementTypes.DICTIONARY_LITERAL);
+ }
+
+ // dict_entry_list ::= ( (dict_entry ',')* dict_entry ','? )?
+ private void parseDictEntryList() {
+ if (atAnyOfTokens(DICT_TERMINATOR_SET)) {
+ return;
+ }
+ parseDictEntry();
+ while (matches(TokenKind.COMMA)) {
+ if (atAnyOfTokens(DICT_TERMINATOR_SET)) {
+ return;
+ }
+ parseDictEntry();
+ }
+ }
+
+ // dict_entry ::= nontupleexpr ':' nontupleexpr
+ private void parseDictEntry() {
+ PsiBuilder.Marker marker = builder.mark();
+ parseNonTupleExpression();
+ expect(TokenKind.COLON);
+ parseNonTupleExpression();
+ marker.done(BuildElementTypes.DICTIONARY_ENTRY_LITERAL);
+ }
+
+ // comprehension_suffix ::= 'FOR' loop_variables 'IN' expr comprehension_suffix
+ // | 'IF' expr comprehension_suffix
+ // | ']'
+ private void parseComprehensionSuffix(TokenKind closingBracket) {
+ while (true) {
+ if (matches(TokenKind.FOR)) {
+ parseForLoopVariables();
+ expect(TokenKind.IN);
+ parseNonTupleExpression(0);
+ } else if (matches(TokenKind.IF)) {
+ parseExpression(true);
+ } else if (matches(closingBracket)) {
+ return;
+ } else {
+ builder.error("expected " + closingBracket + ", 'for' or 'if'");
+ syncPast(EXPR_LIST_TERMINATOR_SET);
+ return;
+ }
+ }
+ }
+
+ // Equivalent to 'exprlist' rule in Python grammar.
+ // loop_variables ::= primary_with_suffix ( ',' primary_with_suffix )* ','?
+ protected void parseForLoopVariables() {
+ PsiBuilder.Marker marker = builder.mark();
+ parsePrimaryWithSuffix();
+ if (currentToken() != TokenKind.COMMA) {
+ marker.drop();
+ return;
+ }
+ while (matches(TokenKind.COMMA)) {
+ if (atAnyOfTokens(EXPR_LIST_TERMINATOR_SET)) {
+ break;
+ }
+ parsePrimaryWithSuffix();
+ }
+ marker.done(BuildElementTypes.LIST_LITERAL);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/parser/Parsing.java b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/Parsing.java
new file mode 100644
index 0000000..7b852b5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/Parsing.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.parser;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementType;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.psi.tree.IElementType;
+import java.util.EnumSet;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/** Base class for BUILD file component parsers */
+public abstract class Parsing {
+
+ // Keywords that exist in Python which we don't parse.
+ protected static final EnumSet<TokenKind> FORBIDDEN_KEYWORDS =
+ EnumSet.of(
+ TokenKind.AS,
+ TokenKind.ASSERT,
+ TokenKind.DEL,
+ TokenKind.EXCEPT,
+ TokenKind.FINALLY,
+ TokenKind.FROM,
+ TokenKind.GLOBAL,
+ TokenKind.IMPORT,
+ TokenKind.IS,
+ TokenKind.LAMBDA,
+ TokenKind.NONLOCAL,
+ TokenKind.RAISE,
+ TokenKind.TRY,
+ TokenKind.WITH,
+ TokenKind.WHILE,
+ TokenKind.YIELD);
+
+ protected ParsingContext context;
+ protected PsiBuilder builder;
+
+ public Parsing(ParsingContext context) {
+ this.context = context;
+ this.builder = context.builder;
+ }
+
+ protected ExpressionParsing getExpressionParser() {
+ return context.expressionParser;
+ }
+
+ /** @return true if a string was parsed */
+ protected boolean parseStringLiteral(boolean alwaysConsume) {
+ if (currentToken() != TokenKind.STRING) {
+ expect(TokenKind.STRING, alwaysConsume);
+ return false;
+ }
+ buildTokenElement(BuildElementTypes.STRING_LITERAL);
+ if (currentToken() == TokenKind.STRING) {
+ builder.error("implicit string concatenation is forbidden; use the '+' operator");
+ }
+ return true;
+ }
+
+ protected void buildTokenElement(BuildElementType type) {
+ PsiBuilder.Marker marker = builder.mark();
+ builder.advanceLexer();
+ marker.done(type);
+ }
+
+ /**
+ * Consume tokens until we reach the first token that has a kind that is in the set of
+ * terminatingTokens.
+ */
+ protected void syncTo(Set<TokenKind> terminatingTokens) {
+ // read past the problematic token
+ while (!atAnyOfTokens(terminatingTokens)) {
+ builder.advanceLexer();
+ }
+ }
+
+ /**
+ * Consume tokens until we consume the first token that has a kind that is in the set of
+ * terminatingTokens.
+ */
+ protected void syncPast(Set<TokenKind> terminatingTokens) {
+ // read past the problematic token
+ while (!matchesAnyOf(terminatingTokens)) {
+ builder.advanceLexer();
+ }
+ }
+
+ /**
+ * Consumes the current token iff it's one of the expected types.<br>
+ * Otherwise, returns false and reports an error.
+ */
+ protected boolean expect(TokenKind kind) {
+ return expect(kind, false);
+ }
+
+ /**
+ * Consumes the current token if 'alwaysConsume' is true or if it's one of the expected types.<br>
+ * Otherwise, returns false and reports an error.
+ */
+ protected boolean expect(TokenKind kind, boolean alwaysConsume) {
+ return expect(kind, String.format("'%s' expected", kind), alwaysConsume);
+ }
+
+ /**
+ * Consumes the current token if 'alwaysConsume' is true or if it's one of the expected types.<br>
+ * Otherwise, returns false and reports an error.
+ */
+ protected boolean expect(TokenKind kind, String message, boolean alwaysConsume) {
+ TokenKind current = currentToken();
+ if (current == kind || alwaysConsume) {
+ builder.advanceLexer();
+ }
+ if (current != kind) {
+ builder.error(message);
+ return false;
+ }
+ return true;
+ }
+
+ /** Checks if we're at the current sequence of tokens. If so, consumes them. */
+ protected boolean matchesSequence(TokenKind... kinds) {
+ PsiBuilder.Marker marker = builder.mark();
+ for (TokenKind kind : kinds) {
+ if (!matches(kind)) {
+ marker.rollbackTo();
+ return false;
+ }
+ }
+ marker.drop();
+ return true;
+ }
+
+ /** Consumes the current token iff it matches the expected type. Otherwise, returns false */
+ protected boolean matches(TokenKind kind) {
+ if (currentToken() == kind) {
+ builder.advanceLexer();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Consumes the current token iff it matches one of the expected types. Otherwise, returns false
+ */
+ protected boolean matchesAnyOf(TokenKind... kinds) {
+ TokenKind current = currentToken();
+ for (TokenKind kind : kinds) {
+ if (kind == current) {
+ builder.advanceLexer();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Consumes the current token iff it's one of the expected types. Otherwise, returns false */
+ protected boolean matchesAnyOf(Set<TokenKind> kinds) {
+ if (kinds.contains(currentToken())) {
+ builder.advanceLexer();
+ return true;
+ }
+ return false;
+ }
+
+ /** Checks if the upcoming sequence of tokens match that expected. Doesn't advance the parser. */
+ protected boolean atTokenSequence(TokenKind... kinds) {
+ for (int i = 0; i < kinds.length; i++) {
+ if (kindFromElement(builder.lookAhead(i)) != kinds[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Checks if the current token matches the expected kind. Doesn't advance the parser. */
+ protected boolean atToken(TokenKind kind) {
+ return currentToken() == kind;
+ }
+
+ /**
+ * Checks if the current token matches any one of the expected kinds. Doesn't advance the parser.
+ */
+ protected boolean atAnyOfTokens(TokenKind... kinds) {
+ TokenKind current = currentToken();
+ for (TokenKind kind : kinds) {
+ if (current == kind) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the current token matches any one of the expected kinds. Doesn't advance the parser.
+ */
+ protected boolean atAnyOfTokens(Set<TokenKind> kinds) {
+ return kinds.contains(currentToken());
+ }
+
+ @Nullable
+ protected TokenKind currentToken() {
+ return builder.eof() ? TokenKind.EOF : kindFromElement(builder.getTokenType());
+ }
+
+ @Nullable
+ protected TokenKind kindFromElement(IElementType type) {
+ if (type == null) {
+ return null;
+ }
+ if (!(type instanceof BuildToken)) {
+ throw new RuntimeException("Invalid type: " + type + " of class " + type.getClass());
+ }
+ TokenKind kind = ((BuildToken) type).kind;
+ checkForbiddenKeywords(kind);
+ return kind;
+ }
+
+ private void checkForbiddenKeywords(TokenKind kind) {
+ if (!FORBIDDEN_KEYWORDS.contains(kind)) {
+ return;
+ }
+ builder.error(forbiddenKeywordError(kind));
+ }
+
+ protected String forbiddenKeywordError(TokenKind kind) {
+ assert FORBIDDEN_KEYWORDS.contains(kind);
+ switch (kind) {
+ case ASSERT:
+ return "'assert' not supported, use 'fail' instead";
+ case TRY:
+ return "'try' not supported, all exceptions are fatal";
+ case IMPORT:
+ return "'import' not supported, use 'load' instead";
+ case IS:
+ return "'is' not supported, use '==' instead";
+ case LAMBDA:
+ return "'lambda' not supported, declare a function instead";
+ case RAISE:
+ return "'raise' not supported, use 'fail' instead";
+ case WHILE:
+ return "'while' not supported, use 'for' instead";
+ default:
+ return "keyword '" + kind + "' not supported";
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/parser/ParsingContext.java b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/ParsingContext.java
new file mode 100644
index 0000000..43b2ffe
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/ParsingContext.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.parser;
+
+import com.intellij.lang.PsiBuilder;
+
+/** Shared context between BUILD file parsing components */
+public class ParsingContext {
+
+ public final StatementParsing statementParser;
+ public final ExpressionParsing expressionParser;
+ public final PsiBuilder builder;
+
+ public ParsingContext(final PsiBuilder builder) {
+ this.builder = builder;
+ statementParser = new StatementParsing(this);
+ expressionParser = new ExpressionParsing(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/parser/StatementParsing.java b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/StatementParsing.java
new file mode 100644
index 0000000..90ad5ff
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/parser/StatementParsing.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.parser;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.tree.IElementType;
+
+/** For parsing statements in BUILD files. */
+public class StatementParsing extends Parsing {
+
+ private static final Logger LOG =
+ Logger.getInstance("com.google.idea.blaze.base.lang.buildfile.parser.StatementParsing");
+
+ private static final ImmutableSet<TokenKind> STATEMENT_TERMINATOR_SET =
+ ImmutableSet.of(TokenKind.EOF, TokenKind.NEWLINE, TokenKind.SEMI);
+
+ private static final ImmutableSet<TokenKind> SMALL_STMT_START =
+ ImmutableSet.of(TokenKind.IDENTIFIER, TokenKind.RETURN);
+
+ public StatementParsing(ParsingContext context) {
+ super(context);
+ }
+
+ /** Called at the start of parsing. Parses an entire file */
+ public void parseFileInput() {
+ builder.setDebugMode(ApplicationManager.getApplication().isUnitTestMode());
+ while (!builder.eof()) {
+ if (matches(TokenKind.NEWLINE)) {
+ continue;
+ }
+ parseTopLevelStatement();
+ }
+ }
+
+ // Unlike in Python grammar, 'load' and 'def' are only allowed as a top-level statement
+ public void parseTopLevelStatement() {
+ if (currentToken() == TokenKind.LOAD) {
+ parseLoadStatement();
+ } else if (currentToken() == TokenKind.DEF) {
+ parseFunctionDefStatement();
+ } else {
+ parseStatement();
+ }
+ }
+
+ // simple_stmt | compound_stmt
+ public void parseStatement() {
+ TokenKind current = currentToken();
+ if (current == TokenKind.IF) {
+ parseIfStatement();
+ } else if (current == TokenKind.FOR) {
+ parseForStatement();
+ } else if (FORBIDDEN_KEYWORDS.contains(current)) {
+ PsiBuilder.Marker mark = builder.mark();
+ syncTo(STATEMENT_TERMINATOR_SET);
+ mark.error(forbiddenKeywordError(current));
+ builder.advanceLexer();
+ } else {
+ parseSimpleStatement();
+ }
+ }
+
+ // func_def_stmt ::= DEF IDENTIFIER funcall_suffix ':' suite
+ private void parseFunctionDefStatement() {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(TokenKind.DEF);
+ getExpressionParser().expectIdentifier("expected a function name");
+ PsiBuilder.Marker listMarker = builder.mark();
+ expect(TokenKind.LPAREN);
+ getExpressionParser().parseFunctionParameters();
+ expect(TokenKind.RPAREN, true);
+ listMarker.done(BuildElementTypes.PARAMETER_LIST);
+ expect(TokenKind.COLON);
+ parseSuite();
+ marker.done(BuildElementTypes.FUNCTION_STATEMENT);
+ }
+
+ // load '(' STRING (',' [IDENTIFIER '='] STRING)* [','] ')'
+ private void parseLoadStatement() {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(TokenKind.LOAD);
+ expect(TokenKind.LPAREN);
+ parseStringLiteral(false);
+ // Not implementing [IDENTIFIER EQUALS] option -- not a documented feature,
+ // so wait for users to complain
+ boolean hasSymbols = false;
+ while (!matches(TokenKind.RPAREN) && !matchesAnyOf(STATEMENT_TERMINATOR_SET)) {
+ expect(TokenKind.COMMA);
+ if (matches(TokenKind.RPAREN) || matchesAnyOf(STATEMENT_TERMINATOR_SET)) {
+ break;
+ }
+ hasSymbols |= parseStringLiteral(true);
+ }
+ if (!hasSymbols) {
+ builder.error("'load' statements must include at least one loaded function");
+ }
+ marker.done(BuildElementTypes.LOAD_STATEMENT);
+ }
+
+ /** if_stmt ::= IF expr ':' suite (ELIF expr ':' suite)* [ELSE ':' suite] */
+ private void parseIfStatement() {
+ PsiBuilder.Marker marker = builder.mark();
+ parseIfStatementPart(TokenKind.IF, BuildElementTypes.IF_PART, true);
+ while (currentToken() == TokenKind.ELIF) {
+ parseIfStatementPart(TokenKind.ELIF, BuildElementTypes.ELSE_IF_PART, true);
+ }
+ if (currentToken() == TokenKind.ELSE) {
+ parseIfStatementPart(TokenKind.ELSE, BuildElementTypes.ELSE_PART, false);
+ }
+ marker.done(BuildElementTypes.IF_STATEMENT);
+ }
+
+ // cond_stmts ::= [EL]IF expr ':' suite
+ private void parseIfStatementPart(TokenKind tokenKind, IElementType type, boolean conditional) {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(tokenKind);
+ if (conditional) {
+ getExpressionParser().parseNonTupleExpression();
+ }
+ expect(TokenKind.COLON);
+ parseSuite();
+ marker.done(type);
+ }
+
+ // for_stmt ::= FOR IDENTIFIER IN expr ':' suite
+ private void parseForStatement() {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(TokenKind.FOR);
+ getExpressionParser().parseForLoopVariables();
+ expect(TokenKind.IN);
+ getExpressionParser().parseExpression(false);
+ expect(TokenKind.COLON);
+ parseSuite();
+ marker.done(BuildElementTypes.FOR_STATEMENT);
+ }
+
+ // simple_stmt ::= small_stmt (';' small_stmt)* ';'? NEWLINE
+ private void parseSimpleStatement() {
+ parseSmallStatementOrPass();
+ while (matches(TokenKind.SEMI)) {
+ if (matches(TokenKind.NEWLINE)) {
+ return;
+ }
+ parseSmallStatementOrPass();
+ }
+ if (!builder.eof()) {
+ expect(TokenKind.NEWLINE);
+ }
+ }
+
+ // small_stmt | 'pass'
+ private void parseSmallStatementOrPass() {
+ if (currentToken() == TokenKind.PASS) {
+ buildTokenElement(BuildElementTypes.PASS_STATMENT);
+ return;
+ }
+ parseSmallStatement();
+ }
+
+ private void parseSmallStatement() {
+ if (currentToken() == TokenKind.RETURN) {
+ parseReturnStatement();
+ return;
+ }
+ if (atAnyOfTokens(TokenKind.BREAK, TokenKind.CONTINUE)) {
+ buildTokenElement(BuildElementTypes.FLOW_STATEMENT);
+ return;
+ }
+ PsiBuilder.Marker refMarker = builder.mark();
+ getExpressionParser().parseExpression(false);
+ if (matches(TokenKind.EQUALS)) {
+ getExpressionParser().parseExpression(false);
+ refMarker.done(BuildElementTypes.ASSIGNMENT_STATEMENT);
+ } else if (matchesAnyOf(TokenKind.AUGMENTED_ASSIGNMENT_OPS)) {
+ getExpressionParser().parseExpression(false);
+ refMarker.done(BuildElementTypes.AUGMENTED_ASSIGNMENT);
+ } else {
+ refMarker.drop();
+ }
+ }
+
+ private void parseReturnStatement() {
+ PsiBuilder.Marker marker = builder.mark();
+ expect(TokenKind.RETURN);
+ if (!STATEMENT_TERMINATOR_SET.contains(currentToken())) {
+ getExpressionParser().parseExpression(false);
+ }
+ marker.done(BuildElementTypes.RETURN_STATEMENT);
+ }
+
+ // suite ::= simple_stmt | (NEWLINE INDENT stmt+ DEDENT)
+ private void parseSuite() {
+ if (!matches(TokenKind.NEWLINE)) {
+ parseSimpleStatement();
+ return;
+ }
+ PsiBuilder.Marker marker = builder.mark();
+ if (expect(TokenKind.INDENT)) {
+ while (!builder.eof() && !matches(TokenKind.DEDENT)) {
+ parseStatement();
+ }
+ }
+ marker.done(BuildElementTypes.STATEMENT_LIST);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Argument.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Argument.java
new file mode 100644
index 0000000..67ff005
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Argument.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.references.ArgumentReference;
+import com.google.idea.blaze.base.lang.buildfile.references.KeywordArgumentReference;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.tree.IElementType;
+import javax.annotation.Nullable;
+
+/** PSI element for an argument, passed via a function call. */
+public abstract class Argument extends BuildElementImpl {
+
+ public static final Argument[] EMPTY_ARRAY = new Argument[0];
+
+ public Argument(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitArgument(this);
+ }
+
+ /** The value passed by this argument */
+ @Nullable
+ public Expression getValue() {
+ // for *args, **kwargs, this should be 'args' or 'kwargs' identifiers.
+ // otherwise the expression after the (optional) '='
+ ASTNode node = getNode().getLastChildNode();
+ while (node != null) {
+ IElementType type = node.getElementType();
+ if (BuildElementTypes.EXPRESSIONS.contains(type)) {
+ return (Expression) node.getPsi();
+ }
+ if (type == BuildToken.fromKind(TokenKind.EQUALS)
+ || type == BuildToken.fromKind(TokenKind.STAR)
+ || type == BuildToken.fromKind(TokenKind.STAR_STAR)) {
+ break;
+ }
+ node = node.getTreePrev();
+ }
+ return null;
+ }
+
+ /** Keyword AST node */
+ public static class Keyword extends Argument {
+ public Keyword(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitKeywordArgument(this);
+ }
+
+ @Nullable
+ public ASTNode getNameNode() {
+ return getNode().findChildByType(BuildToken.IDENTIFIER);
+ }
+
+ @Override
+ @Nullable
+ public String getName() {
+ ASTNode node = getNameNode();
+ return node != null ? node.getText() : null;
+ }
+
+ @Override
+ public KeywordArgumentReference getReference() {
+ ASTNode keywordNode = getNameNode();
+ if (keywordNode != null) {
+ TextRange range = PsiUtils.childRangeInParent(getTextRange(), keywordNode.getTextRange());
+ return new KeywordArgumentReference(this, range);
+ }
+ return null;
+ }
+ }
+
+ /** A positional argument */
+ public static class Positional extends Argument {
+ public Positional(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ public PsiReference getReference() {
+ return new ArgumentReference<>(this, getTextRange(), true);
+ }
+ }
+
+ static class Star extends Argument {
+ public Star(ASTNode node) {
+ super(node);
+ }
+ }
+
+ static class StarStar extends Argument {
+ public StarStar(ASTNode node) {
+ super(node);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ArgumentList.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ArgumentList.java
new file mode 100644
index 0000000..97dc353
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ArgumentList.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+import javax.annotation.Nullable;
+
+/** Argument list of a function call */
+public class ArgumentList extends BuildListType<Argument> {
+
+ public ArgumentList(ASTNode astNode) {
+ super(astNode, Argument.class);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitFuncallArgList(this);
+ }
+
+ public Argument[] getArguments() {
+ return getElements();
+ }
+
+ @Nullable
+ public Argument.Keyword getKeywordArgument(String name) {
+ ASTNode node = getNode().getFirstChildNode();
+ while (node != null) {
+ if (node.getElementType() == BuildElementTypes.KEYWORD) {
+ Argument.Keyword arg = (Argument.Keyword) node.getPsi();
+ String keyword = arg.getName();
+ if (keyword != null && keyword.equals(name)) {
+ return arg;
+ }
+ }
+ node = node.getTreeNext();
+ }
+ return null;
+ }
+
+ @Nullable
+ public Expression getKeywordArgumentValue(String name) {
+ Argument.Keyword keyword = getKeywordArgument(name);
+ return keyword != null ? keyword.getValue() : null;
+ }
+
+ @Override
+ public ImmutableList<Character> getEndChars() {
+ return ImmutableList.of(')');
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/AssignmentStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/AssignmentStatement.java
new file mode 100644
index 0000000..fc0d2e1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/AssignmentStatement.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+import com.intellij.util.PlatformIcons;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** PSI element for an assignment statement [expr ASSIGN_OP expr] */
+public class AssignmentStatement extends BuildElementImpl implements Statement {
+
+ public AssignmentStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ /** Returns the LHS of the assignment */
+ @Nullable
+ public TargetExpression getLeftHandSideExpression() {
+ return findChildByClass(TargetExpression.class);
+ }
+
+ /** Returns the RHS of the assignment */
+ @Nullable
+ public Expression getAssignedValue() {
+ return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitAssignmentStatement(this);
+ }
+
+ @Nullable
+ @Override
+ public String getName() {
+ TargetExpression target = getLeftHandSideExpression();
+ return target != null ? target.getName() : super.getName();
+ }
+
+ @Override
+ public Icon getIcon(int flags) {
+ return PlatformIcons.FIELD_ICON;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/AugmentedAssignmentStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/AugmentedAssignmentStatement.java
new file mode 100644
index 0000000..5d2384d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/AugmentedAssignmentStatement.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+import javax.annotation.Nullable;
+
+/** PSI element for an augmented assignment statement [expr += expr] */
+public class AugmentedAssignmentStatement extends BuildElementImpl implements Statement {
+
+ public AugmentedAssignmentStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ /** Returns the LHS of the assignment */
+ @Nullable
+ public TargetExpression getLeftHandSideExpression() {
+ return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ }
+
+ /** Returns the RHS of the assignment */
+ @Nullable
+ public Expression getAssignedValue() {
+ return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitAugmentedAssignmentStatement(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BinaryOpExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BinaryOpExpression.java
new file mode 100644
index 0000000..76a4387
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BinaryOpExpression.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+import javax.annotation.Nullable;
+
+/** PSI element for an binary operation expression [expr BIN_OP expr] */
+public class BinaryOpExpression extends BuildElementImpl implements Expression {
+
+ public BinaryOpExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitBinaryOpExpression(this);
+ }
+
+ /** Returns the LHS of the expression */
+ @Nullable
+ public Expression getLhs() {
+ return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ }
+
+ /** Returns the RHS of the expression */
+ @Nullable
+ public Expression getRhs() {
+ return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BooleanLiteral.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BooleanLiteral.java
new file mode 100644
index 0000000..112f400
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BooleanLiteral.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI node for boolean literal expressions */
+public class BooleanLiteral extends BuildElementImpl implements LiteralExpression {
+
+ public BooleanLiteral(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitBooleanLiteral(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElement.java
new file mode 100644
index 0000000..35a67c5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElement.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.psi.NavigatablePsiElement;
+import com.intellij.psi.PsiElement;
+import javax.annotation.Nullable;
+
+/** Base class for all BUILD file PSI elements */
+public interface BuildElement extends NavigatablePsiElement {
+
+ @Nullable
+ static BuildElement asBuildElement(PsiElement psiElement) {
+ return psiElement instanceof BuildElement ? (BuildElement) psiElement : null;
+ }
+
+ Statement[] EMPTY_ARRAY = new Statement[0];
+
+ String getPresentableText();
+
+ @Nullable
+ PsiElement getReferencedElement();
+
+ <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass);
+
+ @Nullable
+ <P extends PsiElement> P firstChildOfClass(Class<P> psiClass);
+
+ WorkspacePath getWorkspacePath();
+
+ @Nullable
+ BlazePackage getBlazePackage();
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementImpl.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementImpl.java
new file mode 100644
index 0000000..baf786d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementImpl.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Base PSI class for the BUILD language */
+public abstract class BuildElementImpl extends ASTWrapperPsiElement implements BuildElement {
+
+ public BuildElementImpl(ASTNode astNode) {
+ super(astNode);
+ }
+
+ public <P extends PsiElement> P getPsiChild(IElementType type, Class<P> psiClass) {
+ ASTNode childNode = getNode().findChildByType(type);
+ return childNode != null ? (P) childNode.getPsi() : null;
+ }
+
+ @Override
+ public <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass) {
+ return findChildrenByClass(psiClass);
+ }
+
+ @Nullable
+ @Override
+ public <P extends PsiElement> P firstChildOfClass(Class<P> psiClass) {
+ return findChildByClass(psiClass);
+ }
+
+ /**
+ * Returns the BuildElement child at the specified index, where index is calculated after
+ * filtering out non-BuildElement children.
+ *
+ * @return null if index >= number of BuildElement children
+ */
+ @Nullable
+ protected BuildElement getBuildElementChild(int index) {
+ BuildElement[] children = buildElementChildren();
+ return children.length <= index ? null : children[index];
+ }
+
+ protected BuildElement[] buildElementChildren() {
+ return Arrays.stream(getNode().getChildren(null))
+ .map(ASTNode::getPsi)
+ .filter(psiElement -> psiElement instanceof BuildElement)
+ .toArray(BuildElement[]::new);
+ }
+
+ protected <T extends BuildElement> T[] childrenToPsi(TokenSet filterSet, T[] array) {
+ final ASTNode[] nodes = getNode().getChildren(filterSet);
+ T[] psiElements = (T[]) Array.newInstance(array.getClass().getComponentType(), nodes.length);
+ for (int i = 0; i < nodes.length; i++) {
+ psiElements[i] = (T) nodes[i].getPsi();
+ }
+ return psiElements;
+ }
+
+ @Nullable
+ protected <T extends BuildElement> T childToPsi(TokenSet filterSet, int index) {
+ final ASTNode[] nodes = getNode().getChildren(filterSet);
+ if (nodes.length <= index) {
+ return null;
+ }
+ return (T) nodes[index].getPsi();
+ }
+
+ @Nullable
+ protected IElementType getParentType() {
+ ASTNode node = getNode().getTreeParent();
+ return node != null ? node.getElementType() : null;
+ }
+
+ public String nonNullName() {
+ String name = getName();
+ return name != null ? name : "<unnamed>";
+ }
+
+ @Override
+ public String getPresentableText() {
+ return nonNullName();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ": " + getPresentableText();
+ }
+
+ @Override
+ public void accept(PsiElementVisitor visitor) {
+ if (visitor instanceof BuildElementVisitor) {
+ acceptVisitor(((BuildElementVisitor) visitor));
+ } else {
+ super.accept(visitor);
+ }
+ }
+
+ protected abstract void acceptVisitor(BuildElementVisitor visitor);
+
+ @Nullable
+ @Override
+ public PsiElement getReferencedElement() {
+ PsiReference[] refs = getReferences();
+ for (PsiReference ref : refs) {
+ PsiElement element = ref.resolve();
+ if (element != null) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ItemPresentation getPresentation() {
+ final BuildElement element = this;
+ return new ItemPresentation() {
+ @Override
+ public String getPresentableText() {
+ return element.getPresentableText();
+ }
+
+ @Override
+ public String getLocationString() {
+ return null;
+ }
+
+ @Override
+ public Icon getIcon(boolean unused) {
+ return element.getIcon(0);
+ }
+ };
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getWorkspacePath() {
+ BuildFile file = (BuildFile) getContainingFile();
+ return file.getWorkspacePath();
+ }
+
+ @Nullable
+ @Override
+ public BlazePackage getBlazePackage() {
+ PsiFile file = getContainingFile();
+ return file != null ? BlazePackage.getContainingPackage(file) : null;
+ }
+
+ @Nullable
+ @Override
+ public BuildFile getContainingFile() {
+ return (BuildFile) super.getContainingFile();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementType.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementType.java
new file mode 100644
index 0000000..f46e3e8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementType.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.tree.IElementType;
+import java.lang.reflect.Constructor;
+
+/**
+ * IElementTypes used in the AST by the parser (as opposed to the types used by the lexer).<br>
+ * Modelled on IntelliJ's java and python language support conventions.
+ */
+public class BuildElementType extends IElementType {
+
+ private static final Class[] PARAMETER_TYPES = new Class[] {ASTNode.class};
+ private final Class<? extends PsiElement> psiElementClass;
+ private Constructor<? extends PsiElement> constructor;
+
+ public BuildElementType(String name, Class<? extends PsiElement> psiElementClass) {
+ super(name, BuildFileType.INSTANCE.getLanguage());
+ this.psiElementClass = psiElementClass;
+ }
+
+ public PsiElement createElement(ASTNode node) {
+ try {
+ if (constructor == null) {
+ constructor = psiElementClass.getConstructor(PARAMETER_TYPES);
+ }
+ return constructor.newInstance(node);
+ } catch (Exception e) {
+ throw new IllegalStateException("No necessary constructor for " + node.getElementType(), e);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementTypes.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementTypes.java
new file mode 100644
index 0000000..e19ba6c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementTypes.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/** Collects the types used by the PsiBuilder to construct the AST */
+public interface BuildElementTypes {
+
+ IFileElementType BUILD_FILE = new IFileElementType(BuildFileType.INSTANCE.getLanguage());
+
+ // Statements
+ BuildElementType RETURN_STATEMENT = new BuildElementType("return", ReturnStatement.class);
+ BuildElementType PASS_STATMENT = new BuildElementType("pass", PassStatement.class);
+ BuildElementType ASSIGNMENT_STATEMENT =
+ new BuildElementType("assignment", AssignmentStatement.class);
+ BuildElementType AUGMENTED_ASSIGNMENT =
+ new BuildElementType("aug_assign", AugmentedAssignmentStatement.class);
+ BuildElementType FLOW_STATEMENT = new BuildElementType("flow", FlowStatement.class);
+ BuildElementType LOAD_STATEMENT = new BuildElementType("load", LoadStatement.class);
+ BuildElementType FUNCTION_STATEMENT =
+ new BuildElementType("function_def", FunctionStatement.class);
+ BuildElementType FOR_STATEMENT = new BuildElementType("for", ForStatement.class);
+ BuildElementType IF_STATEMENT = new BuildElementType("if", IfStatement.class);
+
+ BuildElementType IF_PART = new BuildElementType("if_part", IfPart.class);
+ BuildElementType ELSE_IF_PART = new BuildElementType("else_if_part", ElseIfPart.class);
+ BuildElementType ELSE_PART = new BuildElementType("else_part", ElsePart.class);
+
+ BuildElementType STATEMENT_LIST = new BuildElementType("stmt_list", StatementList.class);
+
+ // passed arguments
+ BuildElementType ARGUMENT_LIST = new BuildElementType("arg_list", ArgumentList.class);
+ BuildElementType KEYWORD = new BuildElementType("keyword", Argument.Keyword.class);
+ BuildElementType POSITIONAL = new BuildElementType("positional", Argument.Positional.class);
+ BuildElementType STAR = new BuildElementType("*", Argument.Star.class);
+ BuildElementType STAR_STAR = new BuildElementType("**", Argument.StarStar.class);
+
+ // parameters
+ BuildElementType PARAMETER_LIST = new BuildElementType("parameter_list", ParameterList.class);
+ BuildElementType PARAM_OPTIONAL =
+ new BuildElementType("optional_param", Parameter.Optional.class);
+ BuildElementType PARAM_MANDATORY =
+ new BuildElementType("mandatory_param", Parameter.Mandatory.class);
+ BuildElementType PARAM_STAR = new BuildElementType("*", Parameter.Star.class);
+ BuildElementType PARAM_STAR_STAR = new BuildElementType("**", Parameter.StarStar.class);
+
+ // Expressions
+ BuildElementType DICTIONARY_LITERAL = new BuildElementType("dict", DictionaryLiteral.class);
+ BuildElementType DICTIONARY_ENTRY_LITERAL =
+ new BuildElementType("dict_entry", DictionaryEntryLiteral.class);
+ BuildElementType BINARY_OP_EXPRESSION =
+ new BuildElementType("binary_op", BinaryOpExpression.class);
+ BuildElementType FUNCALL_EXPRESSION =
+ new BuildElementType("function_call", FuncallExpression.class);
+ BuildElementType DOT_EXPRESSION = new BuildElementType("dot_expr", DotExpression.class);
+ BuildElementType STRING_LITERAL = new BuildElementType("string", StringLiteral.class);
+ BuildElementType INTEGER_LITERAL = new BuildElementType("int", IntegerLiteral.class);
+ BuildElementType BOOLEAN_LITERAL = new BuildElementType("bool", BooleanLiteral.class);
+ BuildElementType LIST_LITERAL = new BuildElementType("list", ListLiteral.class);
+ BuildElementType GLOB_EXPRESSION = new BuildElementType("glob", GlobExpression.class);
+ BuildElementType REFERENCE_EXPRESSION =
+ new BuildElementType("reference", ReferenceExpression.class);
+ BuildElementType TARGET_EXPRESSION = new BuildElementType("target", TargetExpression.class);
+ BuildElementType LIST_COMPREHENSION_EXPR =
+ new BuildElementType("list_comp", ListComprehensionExpression.class);
+
+ TokenSet EXPRESSIONS =
+ TokenSet.create(
+ FUNCALL_EXPRESSION,
+ DICTIONARY_LITERAL,
+ DICTIONARY_ENTRY_LITERAL,
+ BINARY_OP_EXPRESSION,
+ DOT_EXPRESSION,
+ STRING_LITERAL,
+ INTEGER_LITERAL,
+ BOOLEAN_LITERAL,
+ LIST_LITERAL,
+ REFERENCE_EXPRESSION,
+ TARGET_EXPRESSION,
+ LIST_COMPREHENSION_EXPR,
+ GLOB_EXPRESSION);
+
+ TokenSet STATEMENTS =
+ TokenSet.create(
+ RETURN_STATEMENT,
+ PASS_STATMENT,
+ ASSIGNMENT_STATEMENT,
+ FLOW_STATEMENT,
+ LOAD_STATEMENT,
+ FUNCTION_STATEMENT,
+ FOR_STATEMENT,
+ IF_STATEMENT);
+
+ TokenSet ARGUMENTS = TokenSet.create(KEYWORD, POSITIONAL, STAR, STAR_STAR);
+
+ TokenSet PARAMETERS =
+ TokenSet.create(PARAM_OPTIONAL, PARAM_MANDATORY, PARAM_STAR, PARAM_STAR_STAR);
+
+ TokenSet STRINGS = TokenSet.create(STRING_LITERAL);
+ TokenSet FUNCTIONS = TokenSet.create(FUNCTION_STATEMENT);
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementVisitor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementVisitor.java
new file mode 100644
index 0000000..f62775b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementVisitor.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.psi.PsiElementVisitor;
+
+/** Visitor for BUILD file PSI nodes */
+public class BuildElementVisitor extends PsiElementVisitor {
+
+ public void visitAssignmentStatement(AssignmentStatement node) {
+ visitElement(node);
+ }
+
+ public void visitAugmentedAssignmentStatement(AugmentedAssignmentStatement node) {
+ visitElement(node);
+ }
+
+ public void visitReturnStatement(ReturnStatement node) {
+ visitElement(node);
+ }
+
+ public void visitArgument(Argument node) {
+ visitElement(node);
+ }
+
+ public void visitKeywordArgument(Argument.Keyword node) {
+ visitElement(node);
+ }
+
+ public void visitParameter(Parameter node) {
+ visitElement(node);
+ }
+
+ public void visitLoadStatement(LoadStatement node) {
+ visitElement(node);
+ }
+
+ public void visitIfStatement(IfStatement node) {
+ visitElement(node);
+ }
+
+ public void visitIfPart(IfPart node) {
+ visitElement(node);
+ }
+
+ public void visitElsePart(ElsePart node) {
+ visitElement(node);
+ }
+
+ public void visitElseIfPart(ElseIfPart node) {
+ visitElement(node);
+ }
+
+ public void visitFunctionStatement(FunctionStatement node) {
+ visitElement(node);
+ }
+
+ public void visitFuncallExpression(FuncallExpression node) {
+ visitElement(node);
+ }
+
+ public void visitForStatement(ForStatement node) {
+ visitElement(node);
+ }
+
+ public void visitFlowStatement(FlowStatement node) {
+ visitElement(node);
+ }
+
+ public void visitDotExpression(DotExpression node) {
+ visitElement(node);
+ }
+
+ public void visitDictionaryLiteral(DictionaryLiteral node) {
+ visitElement(node);
+ }
+
+ public void visitDictionaryEntryLiteral(DictionaryEntryLiteral node) {
+ visitElement(node);
+ }
+
+ public void visitBinaryOpExpression(BinaryOpExpression node) {
+ visitElement(node);
+ }
+
+ public void visitStringLiteral(StringLiteral node) {
+ visitElement(node);
+ }
+
+ public void visitIntegerLiteral(IntegerLiteral node) {
+ visitElement(node);
+ }
+
+ public void visitBooleanLiteral(BooleanLiteral node) {
+ visitElement(node);
+ }
+
+ public void visitListLiteral(ListLiteral node) {
+ visitElement(node);
+ }
+
+ public void visitStatementList(StatementList node) {
+ visitElement(node);
+ }
+
+ public void visitFuncallArgList(ArgumentList node) {
+ visitElement(node);
+ }
+
+ public void visitReferenceExpression(ReferenceExpression node) {
+ visitElement(node);
+ }
+
+ public void visitTargetExpression(TargetExpression node) {
+ visitElement(node);
+ }
+
+ public void visitListComprehensionSuffix(ListComprehensionExpression node) {
+ visitElement(node);
+ }
+
+ public void visitFunctionParameterList(ParameterList node) {
+ visitElement(node);
+ }
+
+ public void visitGlobExpression(GlobExpression node) {
+ visitElement(node);
+ }
+
+ public void visitPassStatement(PassStatement node) {
+ visitElement(node);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildFile.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildFile.java
new file mode 100644
index 0000000..348f8a6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildFile.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.psi.tree.TokenSet;
+import com.intellij.util.PathUtil;
+import com.intellij.util.Processor;
+import icons.BlazeIcons;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Build file PSI element */
+public class BuildFile extends PsiFileBase implements BuildElement, DocStringOwner {
+
+ /** The blaze file type */
+ public enum BlazeFileType {
+ SkylarkExtension,
+ BuildPackage // "BUILD", plus hacks such as "BUILD.tools", "BUILD.bazel"
+ }
+
+ @Nullable
+ public static WorkspacePath getWorkspacePath(Project project, String filePath) {
+ return BuildReferenceManager.getInstance(project).getWorkspaceRelativePath(filePath);
+ }
+
+ public static String getBuildFileString(Project project, String filePath) {
+ WorkspacePath workspacePath = getWorkspacePath(project, PathUtil.getParentPath(filePath));
+ if (workspacePath == null) {
+ return "BUILD file: " + filePath;
+ }
+ String fileName = PathUtil.getFileName(filePath);
+ if (fileName.startsWith("BUILD")) {
+ return "//" + workspacePath + "/" + fileName;
+ }
+ return "//" + workspacePath + ":" + fileName;
+ }
+
+ public BuildFile(FileViewProvider viewProvider) {
+ super(viewProvider, BuildFileType.INSTANCE.getLanguage());
+ }
+
+ @Override
+ public FileType getFileType() {
+ return BuildFileType.INSTANCE;
+ }
+
+ public BlazeFileType getBlazeFileType() {
+ String fileName = getFileName();
+ if (fileName.startsWith("BUILD")) {
+ return BlazeFileType.BuildPackage;
+ }
+ return BlazeFileType.SkylarkExtension;
+ }
+
+ @Nullable
+ @Override
+ public StringLiteral getDocString() {
+ if (getBlazeFileType() != BlazeFileType.SkylarkExtension) {
+ return null;
+ }
+ for (PsiElement cur = getFirstChild(); cur != null; cur = cur.getNextSibling()) {
+ if (cur instanceof StringLiteral
+ && ((StringLiteral) cur).getQuoteType() == QuoteType.TripleDouble) {
+ return (StringLiteral) cur;
+ }
+ if (cur instanceof BuildElement) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public BlazePackage getBlazePackage() {
+ return BlazePackage.getContainingPackage(this);
+ }
+
+ public String getFileName() {
+ return getViewProvider().getVirtualFile().getName();
+ }
+
+ public String getFilePath() {
+ return getOriginalFile().getViewProvider().getVirtualFile().getPath();
+ }
+
+ public File getFile() {
+ return new File(getFilePath());
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getWorkspacePath() {
+ return getWorkspacePath(getProject(), getFilePath());
+ }
+
+ /**
+ * The workspace path of the containing blaze package (this is always the parent directory for
+ * BUILD files, but may be a more distant ancestor for Skylark extensions)
+ */
+ @Nullable
+ public WorkspacePath getPackageWorkspacePath() {
+ BlazePackage parentPackage = getBlazePackage();
+ if (parentPackage == null) {
+ return null;
+ }
+ String filePath = parentPackage.buildFile.getFilePath();
+ return filePath != null
+ ? getWorkspacePath(getProject(), PathUtil.getParentPath(filePath))
+ : null;
+ }
+
+ @Nullable
+ public String getWorkspaceRelativePackagePath() {
+ WorkspacePath packagePath = getPackageWorkspacePath();
+ return packagePath != null ? packagePath.relativePath() : null;
+ }
+
+ /** The path for this file, formatted as a BUILD label. */
+ @Nullable
+ public String getBuildLabel() {
+ BlazePackage containingPackage = getBlazePackage();
+ return containingPackage != null
+ ? containingPackage.getBuildLabelForChild(getFilePath())
+ : null;
+ }
+
+ /** Finds a top-level rule with a "name" keyword argument with the given value. */
+ @Nullable
+ public FuncallExpression findRule(String name) {
+ for (FuncallExpression expr : findChildrenByClass(FuncallExpression.class)) {
+ String ruleName = expr.getNameArgumentValue();
+ if (name.equals(ruleName)) {
+ return expr;
+ }
+ }
+ return null;
+ }
+
+ /** .bzl files referenced in 'load' statements */
+ @Nullable
+ public String[] getImportedPaths() {
+ ASTNode[] loadStatements =
+ getNode().getChildren(TokenSet.create(BuildElementTypes.LOAD_STATEMENT));
+ if (loadStatements.length == 0) {
+ return null;
+ }
+ List<String> importedPaths = Lists.newArrayListWithCapacity(loadStatements.length);
+ for (int i = 0; i < loadStatements.length; i++) {
+ String path = ((LoadStatement) loadStatements[i].getPsi()).getImportedPath();
+ if (path != null) {
+ importedPaths.add(path);
+ }
+ }
+ return importedPaths.toArray(new String[importedPaths.size()]);
+ }
+
+ @Nullable
+ public FunctionStatement findDeclaredFunction(String name) {
+ for (FunctionStatement fn : getFunctionDeclarations()) {
+ if (name.equals(fn.getName())) {
+ return fn;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ public TargetExpression findTopLevelVariable(String name) {
+ return ResolveUtil.searchChildAssignmentStatements(this, name);
+ }
+
+ @Nullable
+ public FunctionStatement findLoadedFunction(String name) {
+ for (LoadStatement loadStatement : findChildrenByClass(LoadStatement.class)) {
+ for (StringLiteral importedFunctionNode : loadStatement.getImportedSymbolElements()) {
+ if (name.equals(importedFunctionNode.getStringContents())) {
+ PsiElement element = importedFunctionNode.getReferencedElement();
+ return element instanceof FunctionStatement ? (FunctionStatement) element : null;
+ }
+ }
+ }
+ return null;
+ }
+
+ public BuildElement findSymbolInScope(String name) {
+ BuildElement[] resultHolder = new BuildElement[1];
+ Processor<BuildElement> processor =
+ buildElement -> {
+ if (buildElement instanceof StringLiteral) {
+ buildElement = BuildElement.asBuildElement(buildElement.getReferencedElement());
+ }
+ if (buildElement instanceof PsiNamedElement && name.equals(buildElement.getName())) {
+ resultHolder[0] = buildElement;
+ return false;
+ }
+ return true;
+ };
+ searchSymbolsInScope(processor, null);
+ return resultHolder[0];
+ }
+
+ /**
+ * Iterates over all top-level assignment statements, function definitions and loaded symbols.
+ *
+ * @return false if searching was stopped (e.g. because the desired element was found).
+ */
+ public boolean searchSymbolsInScope(
+ Processor<BuildElement> processor, @Nullable PsiElement stopAtElement) {
+ for (BuildElement child : findChildrenByClass(BuildElement.class)) {
+ if (child == stopAtElement) {
+ break;
+ }
+ if (child instanceof AssignmentStatement) {
+ TargetExpression target = ((AssignmentStatement) child).getLeftHandSideExpression();
+ if (target != null && !processor.process(target)) {
+ return false;
+ }
+ } else if (child instanceof FunctionStatement) {
+ if (!processor.process(child)) {
+ return false;
+ }
+ }
+ }
+ // search nested load statements last (breadth-first search)
+ for (BuildElement child : findChildrenByClass(BuildElement.class)) {
+ if (child == stopAtElement) {
+ break;
+ }
+ if (child instanceof LoadStatement) {
+ for (StringLiteral importedSymbol : ((LoadStatement) child).getImportedSymbolElements()) {
+ if (!processor.process(importedSymbol)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /** Searches functions declared in this file, then loaded Skylark extensions, if relevant. */
+ @Nullable
+ public FunctionStatement findFunctionInScope(String name) {
+ FunctionStatement localFn = findDeclaredFunction(name);
+ if (localFn != null) {
+ return localFn;
+ }
+ return findLoadedFunction(name);
+ }
+
+ public FunctionStatement[] getFunctionDeclarations() {
+ return findChildrenByClass(FunctionStatement.class);
+ }
+
+ @Override
+ public Icon getIcon(int flags) {
+ return BlazeIcons.BuildFile;
+ }
+
+ @Override
+ public String getPresentableText() {
+ return toString();
+ }
+
+ @Override
+ public String toString() {
+ return getBuildFileString(getProject(), getFilePath());
+ }
+
+ @Nullable
+ @Override
+ public PsiElement getReferencedElement() {
+ return null;
+ }
+
+ @Override
+ public <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass) {
+ return findChildrenByClass(psiClass);
+ }
+
+ @Override
+ public <P extends PsiElement> P firstChildOfClass(Class<P> psiClass) {
+ return findChildByClass(psiClass);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildListType.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildListType.java
new file mode 100644
index 0000000..67b6263
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildListType.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+import javax.annotation.Nullable;
+
+/** Common interface for BUILD psi elements containing a list / sequence of child elements. */
+public abstract class BuildListType<E extends BuildElement> extends BuildElementImpl {
+
+ private final Class<E> elementClass;
+
+ public BuildListType(ASTNode astNode, Class<E> elementClass) {
+ super(astNode);
+ this.elementClass = elementClass;
+ }
+
+ public E[] getElements() {
+ return findChildrenByClass(elementClass);
+ }
+
+ @Nullable
+ public E getFirstElement() {
+ return findChildByClass(elementClass);
+ }
+
+ public boolean isEmpty() {
+ return getFirstElement() != null;
+ }
+
+ /**
+ * The offset into the document at which child elements start. For lists wrapped in braces, this
+ * is the offset after the opening brace. For statement lists, this is the offset after the colon.
+ */
+ public int getStartOffset() {
+ return getNode().getStartOffset() + 1;
+ }
+
+ /** The character(s) which can end this list */
+ public abstract ImmutableList<Character> getEndChars();
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryEntryLiteral.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryEntryLiteral.java
new file mode 100644
index 0000000..37c2684
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryEntryLiteral.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for an dictionary entry literal (dictEntry ::= nonTupleExpr ':' nonTupleExpr) */
+public class DictionaryEntryLiteral extends BuildElementImpl implements LiteralExpression {
+
+ public DictionaryEntryLiteral(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitDictionaryEntryLiteral(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryLiteral.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryLiteral.java
new file mode 100644
index 0000000..db57f21
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryLiteral.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+
+/** PSI element for an dictionary literal. */
+public class DictionaryLiteral extends BuildListType<DictionaryEntryLiteral>
+ implements LiteralExpression {
+
+ public DictionaryLiteral(ASTNode astNode) {
+ super(astNode, DictionaryEntryLiteral.class);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitDictionaryLiteral(this);
+ }
+
+ @Override
+ public ImmutableList<Character> getEndChars() {
+ return ImmutableList.of('}');
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DocStringOwner.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DocStringOwner.java
new file mode 100644
index 0000000..fa67c5b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DocStringOwner.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import javax.annotation.Nullable;
+
+/** BUILD psi element which can have docstring. */
+public interface DocStringOwner extends BuildElement {
+
+ @Nullable
+ StringLiteral getDocString();
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DotExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DotExpression.java
new file mode 100644
index 0000000..093cc82
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/DotExpression.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for a dot expression. */
+public class DotExpression extends BuildElementImpl implements Expression {
+
+ public DotExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitDotExpression(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElseIfPart.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElseIfPart.java
new file mode 100644
index 0000000..7e717ec
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElseIfPart.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for an elif part of an IfStatement. */
+public class ElseIfPart extends BuildElementImpl implements Statement, StatementListContainer {
+
+ public ElseIfPart(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitElseIfPart(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElsePart.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElsePart.java
new file mode 100644
index 0000000..5fae25f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElsePart.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for an else part of an IfStatement. */
+public class ElsePart extends BuildElementImpl implements Statement, StatementListContainer {
+
+ public ElsePart(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitElsePart(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Expression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Expression.java
new file mode 100644
index 0000000..dd0ddfa
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Expression.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+/** Interface for all expression PSI elements in a BUILD file */
+public interface Expression extends BuildElement {
+
+ Expression[] EMPTY_ARRAY = new Expression[0];
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FlowStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FlowStatement.java
new file mode 100644
index 0000000..8f0ee93
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FlowStatement.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for a flow statement. */
+public class FlowStatement extends BuildElementImpl implements Statement {
+
+ public FlowStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitFlowStatement(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ForStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ForStatement.java
new file mode 100644
index 0000000..1d85bf3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ForStatement.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import java.util.List;
+
+/** PSI element for a for statement. */
+public class ForStatement extends BuildElementImpl implements Statement, StatementListContainer {
+
+ public ForStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitForStatement(this);
+ }
+
+ public List<Expression> getForLoopVariables() {
+ List<Expression> loopVariableExpressions = Lists.newArrayList();
+ for (PsiElement child : getChildren()) {
+ if (child.getNode().getElementType() == BuildToken.fromKind(TokenKind.IN)) {
+ return loopVariableExpressions;
+ }
+ if (child instanceof Expression) {
+ loopVariableExpressions.add((Expression) child);
+ } else if (child instanceof ListLiteral) {
+ for (Expression expr : ((ListLiteral) child).childrenOfClass(Expression.class)) {
+ loopVariableExpressions.add(expr);
+ }
+ }
+ }
+ return loopVariableExpressions;
+ }
+
+ @Override
+ public String getPresentableText() {
+ return "for loop";
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FuncallExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FuncallExpression.java
new file mode 100644
index 0000000..154d5d9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FuncallExpression.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.references.FuncallReference;
+import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNameIdentifierOwner;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.Processor;
+import icons.BlazeIcons;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * PSI element for an function call.<br>
+ * Could be a top-level rule, Skylark function reference, or general some other python function call
+ */
+public class FuncallExpression extends BuildElementImpl
+ implements Expression, PsiNameIdentifierOwner {
+
+ public FuncallExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitFuncallExpression(this);
+ }
+
+ /** The name of the function being called. */
+ @Nullable
+ public String getFunctionName() {
+ ASTNode node = getFunctionNameNode();
+ return node != null ? node.getText() : null;
+ }
+
+ @Override
+ @Nullable
+ public String getName() {
+ return getNameArgumentValue();
+ }
+
+ @Nullable
+ @Override
+ public PsiElement getNameIdentifier() {
+ Argument.Keyword name = getNameArgument();
+ return name != null ? name.getValue() : null;
+ }
+
+ @Override
+ public PsiElement setName(String name) throws IncorrectOperationException {
+ StringLiteral nameNode = getNameArgumentValueNode();
+ if (nameNode == null) {
+ return this;
+ }
+ ASTNode newChild = PsiUtils.createNewLabel(getProject(), name);
+ nameNode.getNode().replaceChild(nameNode.getNode().getFirstChildNode(), newChild);
+ return this;
+ }
+
+ /** The function name */
+ @Nullable
+ public ASTNode getFunctionNameNode() {
+ PsiElement argList = getArgList();
+ if (argList != null) {
+ // We want the reference expr directly prior to the open parenthesis.
+ // This accounts for Skylark native.rule calls.
+ PsiElement prev = argList.getPrevSibling();
+ if (prev instanceof ReferenceExpression) {
+ return prev.getNode();
+ }
+ }
+ return getNode().findChildByType(BuildElementTypes.REFERENCE_EXPRESSION);
+ }
+
+ /** Top-level funcalls are almost always BUILD rules. */
+ public boolean isTopLevel() {
+ ASTNode parent = getNode().getTreeParent();
+ return parent == null || parent.getElementType() == BuildElementTypes.BUILD_FILE;
+ }
+
+ public boolean mightBeBuildRule() {
+ return isTopLevel() || getNameArgument() != null;
+ }
+
+ @Nullable
+ public Label resolveBuildLabel() {
+ BuildFile containingFile = getContainingFile();
+ if (containingFile == null
+ || containingFile.getBlazeFileType() == BuildFile.BlazeFileType.SkylarkExtension) {
+ return null;
+ }
+ return LabelUtils.createLabelFromRuleName(getBlazePackage(), getNameArgumentValue());
+ }
+
+ @Nullable
+ public ArgumentList getArgList() {
+ return findChildByType(BuildElementTypes.ARGUMENT_LIST);
+ }
+
+ public Argument[] getArguments() {
+ ArgumentList argList = getArgList();
+ return argList != null ? argList.getArguments() : Argument.EMPTY_ARRAY;
+ }
+
+ /** Keyword argument with name "name", if one is present. */
+ @Nullable
+ public Argument.Keyword getNameArgument() {
+ return getKeywordArgument("name");
+ }
+
+ public Argument.Keyword getKeywordArgument(String name) {
+ ArgumentList argList = getArgList();
+ return argList != null ? argList.getKeywordArgument(name) : null;
+ }
+
+ /** StringLiteral value of keyword argument with name "name", if one is present. */
+ @Nullable
+ public StringLiteral getNameArgumentValueNode() {
+ Argument.Keyword name = getNameArgument();
+ Expression expr = name != null ? name.getValue() : null;
+ if (expr instanceof StringLiteral) {
+ return ((StringLiteral) expr);
+ }
+ return null;
+ }
+
+ /** Value of keyword argument with name "name", if one is present. */
+ @Nullable
+ public String getNameArgumentValue() {
+ StringLiteral node = getNameArgumentValueNode();
+ return node != null ? node.getStringContents() : null;
+ }
+
+ @Override
+ public Icon getIcon(int flags) {
+ return mightBeBuildRule() ? BlazeIcons.BuildRule : null;
+ }
+
+ @Override
+ public String getPresentableText() {
+ String name = getFunctionName();
+ if (name == null) {
+ return super.getPresentableText();
+ }
+ String targetName = getNameArgumentValue();
+ return targetName != null ? name + "(\"" + targetName + "\")" : name;
+ }
+
+ @Override
+ @Nullable
+ public FuncallReference getReference() {
+ ASTNode nameNode = getFunctionNameNode();
+ if (nameNode == null) {
+ return null;
+ }
+ BuildLanguageSpec spec = BuildLanguageSpecProvider.getInstance().getLanguageSpec(getProject());
+ if (spec != null && spec.hasRule(nameNode.getText())) {
+ // don't try to follow references to built-in rules
+ return null;
+ }
+ TextRange range = PsiUtils.childRangeInParent(getTextRange(), nameNode.getTextRange());
+ return new FuncallReference(this, range);
+ }
+
+ /**
+ * Searches all StringLiteral children of this element, for one which references the desired
+ * target expression.
+ */
+ @Nullable
+ public StringLiteral findChildReferenceToTarget(final FuncallExpression targetRule) {
+ final StringLiteral[] child = new StringLiteral[1];
+ Processor<StringLiteral> processor =
+ stringLiteral -> {
+ PsiElement ref = stringLiteral.getReferencedElement();
+ if (targetRule.equals(ref)) {
+ child[0] = stringLiteral;
+ return false;
+ }
+ return true;
+ };
+ PsiUtils.processChildrenOfType(this, processor, StringLiteral.class);
+ return child[0];
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FunctionStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FunctionStatement.java
new file mode 100644
index 0000000..0dce2fe
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/FunctionStatement.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.PlatformIcons;
+import javax.swing.Icon;
+import org.jetbrains.annotations.Nullable;
+
+/** PSI element for a function definition statement. */
+public class FunctionStatement extends NamedBuildElement
+ implements Statement, StatementListContainer, DocStringOwner {
+
+ public FunctionStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitFunctionStatement(this);
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon(int flags) {
+ return PlatformIcons.FUNCTION_ICON;
+ }
+
+ @Nullable
+ public ParameterList getParameterList() {
+ return getPsiChild(BuildElementTypes.PARAMETER_LIST, ParameterList.class);
+ }
+
+ public Parameter[] getParameters() {
+ ParameterList list = getParameterList();
+ return list != null ? list.getElements() : Parameter.EMPTY_ARRAY;
+ }
+
+ @Override
+ public String getPresentableText() {
+ return nonNullName() + getParameterList().getPresentableText();
+ }
+
+ @Nullable
+ @Override
+ public StringLiteral getDocString() {
+ StatementList stmtList = getStatementList();
+ if (stmtList == null) {
+ return null;
+ }
+ for (PsiElement cur = stmtList.getFirstChild(); cur != null; cur = cur.getNextSibling()) {
+ if (cur instanceof StringLiteral
+ && ((StringLiteral) cur).getQuoteType() == QuoteType.TripleDouble) {
+ return (StringLiteral) cur;
+ }
+ if (cur instanceof BuildElement) {
+ return null;
+ }
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/GlobExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/GlobExpression.java
new file mode 100644
index 0000000..e31338a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/GlobExpression.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.references.GlobReference;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import javax.annotation.Nullable;
+
+/** PSI element for a glob expression. */
+public class GlobExpression extends BuildElementImpl implements Expression {
+
+ public GlobExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitGlobExpression(this);
+ }
+
+ @Nullable
+ public ArgumentList getArgList() {
+ return findChildByType(BuildElementTypes.ARGUMENT_LIST);
+ }
+
+ public Argument[] getArguments() {
+ ArgumentList argList = getArgList();
+ return argList != null ? argList.getArguments() : Argument.EMPTY_ARRAY;
+ }
+
+ @Nullable
+ public Argument.Keyword getKeywordArgument(String name) {
+ ArgumentList list = getArgList();
+ return list != null ? list.getKeywordArgument(name) : null;
+ }
+
+ @Nullable
+ public Expression getIncludes() {
+ Argument arg = getKeywordArgument("include");
+ if (arg == null) {
+ Argument[] allArgs = getArguments();
+ if (allArgs.length != 0 && allArgs[0] instanceof Argument.Positional) {
+ arg = allArgs[0];
+ }
+ }
+ return getArgValue(arg);
+ }
+
+ @Nullable
+ public Expression getExcludes() {
+ return getArgValue(getKeywordArgument("exclude"));
+ }
+
+ @Nullable
+ private static Expression getArgValue(@Nullable Argument arg) {
+ return arg != null ? arg.getValue() : null;
+ }
+
+ public boolean areDirectoriesExcluded() {
+ Argument.Keyword arg = getKeywordArgument("exclude_directories");
+ if (arg != null) {
+ // '0' and '1' are the only accepted values
+ Expression value = arg.getValue();
+ return value == null || !value.getText().equals("0");
+ }
+ return true;
+ }
+
+ @Nullable
+ public ASTNode getGlobFuncallElement() {
+ return getNode().findChildByType(BuildElementTypes.REFERENCE_EXPRESSION);
+ }
+
+ private volatile GlobReference reference = null;
+
+ @Override
+ public GlobReference getReference() {
+ GlobReference ref = reference;
+ if (ref != null) {
+ return ref;
+ }
+ synchronized (this) {
+ if (reference == null) {
+ reference = new GlobReference(this);
+ }
+ return reference;
+ }
+ }
+
+ /**
+ * The text range within the glob expression used for references. This is the text the user needs
+ * to click on for navigation support, and also the destination when finding usages in a glob.
+ */
+ public TextRange getReferenceTextRange() {
+ // Ideally, this would be either the full range of the expression,
+ // or the range of the specific pattern matching
+ // a given file. However, that leads to conflicts with the individual string references,
+ // causing unnecessary and expensive de-globbing.
+ // e.g. while typing the glob patterns, IJ will be looking for code-completion possibilities,
+ // and need to de-glob to do this
+ // (due to a lack of communication between the different code-completion components).
+
+ return new TextRange(0, 4);
+ }
+
+ public boolean matches(String packageRelativePath, boolean isDirectory) {
+ return getReference().matches(packageRelativePath, isDirectory);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfPart.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfPart.java
new file mode 100644
index 0000000..75f257f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfPart.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for an if part of an IfStatement. */
+public class IfPart extends BuildElementImpl implements Statement, StatementListContainer {
+
+ public IfPart(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitIfPart(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfStatement.java
new file mode 100644
index 0000000..2c244cd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfStatement.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI element for an if statement. */
+public class IfStatement extends BuildElementImpl implements Statement {
+
+ public IfStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitIfStatement(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IntegerLiteral.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IntegerLiteral.java
new file mode 100644
index 0000000..8aa30e5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/IntegerLiteral.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** PSI node for integer literal expressions */
+public class IntegerLiteral extends BuildElementImpl implements LiteralExpression {
+
+ public IntegerLiteral(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitIntegerLiteral(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListComprehensionExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListComprehensionExpression.java
new file mode 100644
index 0000000..094b61e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListComprehensionExpression.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/**
+ * PSI element for a list comprehension expression (comprehension suffix of: '[' expr ('FOR'
+ * loop_variables 'IN' expr)+ ']')
+ */
+public class ListComprehensionExpression extends BuildElementImpl implements Expression {
+
+ public ListComprehensionExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitListComprehensionSuffix(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListLiteral.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListLiteral.java
new file mode 100644
index 0000000..65fe842
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListLiteral.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+
+/** PSI element for list and tuple literals */
+public class ListLiteral extends BuildListType<Expression> implements LiteralExpression {
+
+ public ListLiteral(ASTNode astNode) {
+ super(astNode, Expression.class);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitListLiteral(this);
+ }
+
+ @Override
+ public String getPresentableText() {
+ return "list";
+ }
+
+ public Expression[] getChildExpressions() {
+ return findChildrenByClass(Expression.class);
+ }
+
+ @Override
+ public Expression[] getElements() {
+ return getChildExpressions();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return findChildByClass(Expression.class) != null;
+ }
+
+ @Override
+ public ImmutableList<Character> getEndChars() {
+ return ImmutableList.of(')', ']');
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/LiteralExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/LiteralExpression.java
new file mode 100644
index 0000000..1331f2b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/LiteralExpression.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+/** Interface for literal expressions. */
+public interface LiteralExpression extends Expression {}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/LoadStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/LoadStatement.java
new file mode 100644
index 0000000..cd92715
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/LoadStatement.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
+import com.intellij.lang.ASTNode;
+import com.intellij.util.PlatformIcons;
+import java.util.Arrays;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** PSI element for a load statement. */
+public class LoadStatement extends BuildElementImpl implements Statement {
+
+ public LoadStatement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitLoadStatement(this);
+ }
+
+ @Nullable
+ public ASTNode getImportNode() {
+ return getNode().findChildByType(BuildElementTypes.STRING_LITERAL);
+ }
+
+ @Nullable
+ public StringLiteral getImportPsiElement() {
+ return findChildByType(BuildElementTypes.STRING_LITERAL);
+ }
+
+ @Nullable
+ public String getImportedPath() {
+ ASTNode firstString = getImportNode();
+ return firstString != null ? StringLiteral.stripQuotes(firstString.getText()) : null;
+ }
+
+ /** The string nodes referencing imported functions. */
+ public FunctionStatement[] getImportedFunctionReferences() {
+ return Arrays.stream(getChildStrings())
+ .skip(1)
+ .map(BuildElement::getReferencedElement)
+ .filter(e -> e instanceof FunctionStatement)
+ .toArray(FunctionStatement[]::new);
+ }
+
+ /** The string nodes referencing imported functions. */
+ public StringLiteral[] getImportedSymbolElements() {
+ StringLiteral[] childStrings = getChildStrings();
+ return childStrings.length < 2
+ ? new StringLiteral[0]
+ : Arrays.copyOfRange(childStrings, 1, childStrings.length);
+ }
+
+ public String[] getImportedSymbolNames() {
+ return Arrays.stream(getImportedSymbolElements())
+ .map(StringLiteral::getStringContents)
+ .toArray(String[]::new);
+ }
+
+ @Nullable
+ public StringLiteral findImportedSymbolElement(String name) {
+ for (StringLiteral string : getImportedSymbolElements()) {
+ if (name.equals(string.getStringContents())) {
+ return string;
+ }
+ }
+ return null;
+ }
+
+ public StringLiteral[] getChildStrings() {
+ return Arrays.stream(getNode().getChildren(BuildElementTypes.STRINGS))
+ .map(ASTNode::getPsi)
+ .toArray(StringLiteral[]::new);
+ }
+
+ @Override
+ public Icon getIcon(int flags) {
+ return PlatformIcons.IMPORT_ICON;
+ }
+
+ @Override
+ public String getPresentableText() {
+ String path = LabelUtils.getNiceSkylarkFileName(getImportedPath());
+ return path != null ? "load: " + path : "load";
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/NamedBuildElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/NamedBuildElement.java
new file mode 100644
index 0000000..a50c15a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/NamedBuildElement.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNameIdentifierOwner;
+import javax.annotation.Nullable;
+
+/** Base class for PsiNamedElements in BUILD files. */
+public abstract class NamedBuildElement extends BuildElementImpl implements PsiNameIdentifierOwner {
+
+ public NamedBuildElement(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Nullable
+ public ASTNode getNameNode() {
+ return getNode().findChildByType(BuildToken.IDENTIFIER);
+ }
+
+ @Override
+ @Nullable
+ public String getName() {
+ ASTNode node = getNameNode();
+ return node != null ? node.getText() : null;
+ }
+
+ @Override
+ @Nullable
+ public PsiElement getNameIdentifier() {
+ final ASTNode nameNode = getNameNode();
+ return nameNode != null ? nameNode.getPsi() : null;
+ }
+
+ @Override
+ public PsiElement setName(String name) {
+ final ASTNode nameElement = PsiUtils.createNewName(getProject(), name);
+ final ASTNode nameNode = getNameNode();
+ if (nameNode != null) {
+ getNode().replaceChild(nameNode, nameElement);
+ }
+ return this;
+ }
+
+ @Override
+ public int getTextOffset() {
+ final ASTNode name = getNameNode();
+ return name != null ? name.getStartOffset() : super.getTextOffset();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "('" + getName() + "')";
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Parameter.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Parameter.java
new file mode 100644
index 0000000..c873bb6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Parameter.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.icons.AllIcons;
+import com.intellij.lang.ASTNode;
+import javax.swing.Icon;
+import org.jetbrains.annotations.Nullable;
+
+/** PSI nodes for parameters in a function declaration */
+public abstract class Parameter extends NamedBuildElement {
+
+ public static final Parameter[] EMPTY_ARRAY = new Parameter[0];
+
+ public Parameter(ASTNode node) {
+ super(node);
+ }
+
+ public boolean hasDefaultValue() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon(int flags) {
+ return AllIcons.Nodes.Parameter;
+ }
+
+ /** Includes stars where relevant. */
+ public String getPresentableName() {
+ return getName();
+ }
+
+ static class Optional extends Parameter {
+ public Optional(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitParameter(this);
+ }
+
+ public Expression getDefaultValue() {
+ ASTNode node = getNode().getLastChildNode();
+ while (node != null) {
+ if (BuildElementTypes.EXPRESSIONS.contains(node.getElementType())) {
+ return (Expression) node.getPsi();
+ }
+ if (node.getElementType() == BuildToken.fromKind(TokenKind.EQUALS)) {
+ break;
+ }
+ node = node.getTreePrev();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasDefaultValue() {
+ return true;
+ }
+ }
+
+ static class Mandatory extends Parameter {
+ public Mandatory(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitParameter(this);
+ }
+ }
+
+ static class Star extends Parameter {
+ public Star(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitParameter(this);
+ }
+
+ @Override
+ public String getPresentableName() {
+ return "*" + getName();
+ }
+ }
+
+ /** */
+ public static class StarStar extends Parameter {
+ public StarStar(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitParameter(this);
+ }
+
+ @Override
+ public String getPresentableName() {
+ return "**" + getName();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ParameterList.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ParameterList.java
new file mode 100644
index 0000000..99074d5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ParameterList.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+import java.util.StringJoiner;
+import javax.annotation.Nullable;
+
+/** Parameter list in a function declaration */
+public class ParameterList extends BuildListType<Parameter> {
+
+ public ParameterList(ASTNode astNode) {
+ super(astNode, Parameter.class);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitFunctionParameterList(this);
+ }
+
+ @Nullable
+ public Parameter findParameterByName(String name) {
+ ASTNode node = getNode().getFirstChildNode();
+ while (node != null) {
+ if (node.getElementType() == BuildElementTypes.PARAM_OPTIONAL
+ || node.getElementType() == BuildElementTypes.PARAM_MANDATORY) {
+ Parameter param = (Parameter) node.getPsi();
+ if (name.equals(param.getName())) {
+ return param;
+ }
+ }
+ node = node.getTreeNext();
+ }
+ return null;
+ }
+
+ public boolean hasStarStar() {
+ return !findChildrenByType(BuildElementTypes.PARAM_STAR_STAR).isEmpty();
+ }
+
+ public boolean hasStar() {
+ return !findChildrenByType(BuildElementTypes.PARAM_STAR).isEmpty();
+ }
+
+ @Override
+ public String getPresentableText() {
+ StringJoiner joiner = new StringJoiner(", ", "(", ")");
+ for (Parameter param : getElements()) {
+ joiner.add(param.getPresentableName());
+ }
+ return joiner.toString();
+ }
+
+ @Override
+ public ImmutableList<Character> getEndChars() {
+ return ImmutableList.of(')');
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/PassStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/PassStatement.java
new file mode 100644
index 0000000..eeb9ae3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/PassStatement.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** Psi element for pass statement. */
+public class PassStatement extends BuildElementImpl implements Statement {
+
+ public PassStatement(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitPassStatement(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReferenceExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReferenceExpression.java
new file mode 100644
index 0000000..287402c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReferenceExpression.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.references.LocalReference;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.Nullable;
+
+/** References a PsiNamedElement */
+public class ReferenceExpression extends BuildElementImpl implements Expression {
+
+ public ReferenceExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitReferenceExpression(this);
+ }
+
+ @Nullable
+ public ASTNode getNameElement() {
+ return getNode().findChildByType(BuildToken.IDENTIFIER);
+ }
+
+ @Nullable
+ public String getReferencedName() {
+ ASTNode node = getNameElement();
+ return node != null ? node.getText() : null;
+ }
+
+ @Override
+ public PsiReference getReference() {
+ IElementType parentType = getParentType();
+ // function names are resolved by the parent funcall node
+ if (BuildElementTypes.FUNCALL_EXPRESSION.equals(parentType) && !beforeDot(getNode())) {
+ return null;
+ }
+ if (BuildElementTypes.GLOB_EXPRESSION.equals(parentType)) {
+ return null;
+ }
+ if (BuildElementTypes.DOT_EXPRESSION.equals(parentType) && !beforeDot(getNode())) {
+ return null;
+ }
+ return new LocalReference(this);
+ }
+
+ @Override
+ public String getName() {
+ return getReferencedName();
+ }
+
+ private static boolean beforeDot(ASTNode node) {
+ ASTNode prev = node.getTreeNext();
+ return prev != null && prev.getText().equals(".");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReturnStatement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReturnStatement.java
new file mode 100644
index 0000000..a334c00
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReturnStatement.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.intellij.lang.ASTNode;
+import javax.annotation.Nullable;
+
+/** A wrapper Statement class for return expressions. */
+public class ReturnStatement extends BuildElementImpl implements Statement {
+
+ public ReturnStatement(ASTNode node) {
+ super(node);
+ }
+
+ @Nullable
+ public Expression getReturnExpression() {
+ return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitReturnStatement(this);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Statement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Statement.java
new file mode 100644
index 0000000..9d45385
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/Statement.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+/** Base class for all statements nodes in the PSI tree */
+public interface Statement extends BuildElement {
+
+ Statement[] EMPTY_ARRAY = new Statement[0];
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementList.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementList.java
new file mode 100644
index 0000000..22c02db
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementList.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+
+/** PSI element for a list of statements */
+public class StatementList extends BuildListType<Statement> {
+
+ public StatementList(ASTNode astNode) {
+ super(astNode, Statement.class);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitStatementList(this);
+ }
+
+ @Override
+ public int getStartOffset() {
+ PsiElement prevSibling = getPrevSibling();
+ while (prevSibling != null) {
+ if (prevSibling.getText().equals(":")) {
+ return prevSibling.getNode().getStartOffset() + 1;
+ }
+ prevSibling = prevSibling.getPrevSibling();
+ }
+ return getNode().getStartOffset();
+ }
+
+ @Override
+ public ImmutableList<Character> getEndChars() {
+ return ImmutableList.of();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementListContainer.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementListContainer.java
new file mode 100644
index 0000000..4da6412
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementListContainer.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import javax.annotation.Nullable;
+
+/** Anything of the form type ':' suite */
+public interface StatementListContainer extends BuildElement {
+
+ @Nullable
+ default StatementList getStatementList() {
+ return firstChildOfClass(StatementList.class);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StringLiteral.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StringLiteral.java
new file mode 100644
index 0000000..9afb380
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/StringLiteral.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.references.LabelReference;
+import com.google.idea.blaze.base.lang.buildfile.references.LoadedSymbolReference;
+import com.google.idea.blaze.base.lang.buildfile.references.PackageReferenceFragment;
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import javax.annotation.Nullable;
+
+/** PSI node for string literal expressions */
+public class StringLiteral extends BuildElementImpl implements LiteralExpression {
+
+ /**
+ * Removes the leading and trailing quotes. Naive implementation intended for resolving references
+ * (in which case escaped characters, raw strings, etc. are unlikely).
+ */
+ public static String stripQuotes(String string) {
+ // TODO: Handle escaped characters, etc. here?
+ // (extract logic from BuildLexerBase.addStringLiteral)
+ if (string.startsWith("\"\"\"")) {
+ return string.length() <= 3 ? "" : string.substring(3, endTrimIndex(string, '"', 3));
+ }
+ if (string.startsWith("'''")) {
+ return string.length() <= 3 ? "" : string.substring(3, endTrimIndex(string, '\'', 3));
+ }
+ if (string.startsWith("\"")) {
+ return string.substring(1, endTrimIndex(string, '"', 1));
+ }
+ if (string.startsWith("'")) {
+ return string.substring(1, endTrimIndex(string, '\'', 1));
+ }
+ return string;
+ }
+
+ private static int endTrimIndex(String string, char quoteChar, int numberQuoteChars) {
+ int trimIndex = string.length();
+ for (int i = 1;
+ i <= Math.min(numberQuoteChars, string.length() - numberQuoteChars);
+ i++, trimIndex--) {
+ if (string.charAt(string.length() - i) != quoteChar) {
+ break;
+ }
+ }
+ return trimIndex;
+ }
+
+ public static QuoteType getQuoteType(@Nullable String rawText) {
+ if (rawText == null) {
+ return QuoteType.NoQuotes;
+ }
+ if (rawText.startsWith("\"\"\"")) {
+ return QuoteType.TripleDouble;
+ }
+ if (rawText.startsWith("'''")) {
+ return QuoteType.TripleSingle;
+ }
+ if (rawText.startsWith("'")) {
+ return QuoteType.Single;
+ }
+ if (rawText.startsWith("\"")) {
+ return QuoteType.Double;
+ }
+ return QuoteType.NoQuotes;
+ }
+
+ public StringLiteral(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitStringLiteral(this);
+ }
+
+ /** Removes the leading and trailing quotes */
+ public String getStringContents() {
+ return stripQuotes(getText());
+ }
+
+ public QuoteType getQuoteType() {
+ return getQuoteType(getText());
+ }
+
+ /**
+ * Labels are taken to reference: - the actual target they reference - the BUILD package specified
+ * before the colon (only if explicitly present)
+ */
+ @Override
+ public PsiReference[] getReferences() {
+ PsiReference primaryReference = getReference();
+ if (primaryReference instanceof LabelReference) {
+ return new PsiReference[] {
+ primaryReference, new PackageReferenceFragment((LabelReference) primaryReference)
+ };
+ }
+ return primaryReference != null
+ ? new PsiReference[] {primaryReference}
+ : PsiReference.EMPTY_ARRAY;
+ }
+
+ /** The primary reference -- this is the target referenced by the full label */
+ @Nullable
+ @Override
+ public PsiReference getReference() {
+ PsiElement parent = getParent();
+ if (parent instanceof LoadStatement) {
+ LoadStatement load = (LoadStatement) parent;
+ StringLiteral importNode = load.getImportPsiElement();
+ if (importNode == null) {
+ return null;
+ }
+ LabelReference importReference = new LabelReference(importNode, false);
+ if (this.equals(importNode)) {
+ return importReference;
+ }
+ return new LoadedSymbolReference(this, importReference);
+ }
+ return new LabelReference(this, true);
+ }
+
+ public boolean insideLoadStatement() {
+ return getParentType() == BuildElementTypes.LOAD_STATEMENT;
+ }
+
+ @Override
+ public String getPresentableText() {
+ return getText();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/TargetExpression.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/TargetExpression.java
new file mode 100644
index 0000000..405d0de
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/TargetExpression.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.references.TargetReference;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiReference;
+import com.intellij.util.PlatformIcons;
+import javax.swing.Icon;
+import org.jetbrains.annotations.Nullable;
+
+/** References a PsiNamedElement */
+public class TargetExpression extends NamedBuildElement implements Expression {
+
+ public TargetExpression(ASTNode astNode) {
+ super(astNode);
+ }
+
+ @Override
+ protected void acceptVisitor(BuildElementVisitor visitor) {
+ visitor.visitTargetExpression(this);
+ }
+
+ @Override
+ public PsiReference getReference() {
+ return new TargetReference(this);
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon(int flags) {
+ return PlatformIcons.VARIABLE_ICON;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/BuildElementGenerator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/BuildElementGenerator.java
new file mode 100644
index 0000000..4c3e3c2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/BuildElementGenerator.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi.util;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileFactory;
+import com.intellij.psi.impl.PsiFileFactoryImpl;
+import com.intellij.testFramework.LightVirtualFile;
+
+/** Creates dummy BuildElements, e.g. for renaming purposes. */
+public class BuildElementGenerator {
+
+ public static BuildElementGenerator getInstance(Project project) {
+ return ServiceManager.getService(project, BuildElementGenerator.class);
+ }
+
+ private static final String DUMMY_FILENAME = "dummy.bzl";
+
+ private final Project project;
+
+ public BuildElementGenerator(Project project) {
+ this.project = project;
+ }
+
+ public PsiFile createDummyFile(String contents) {
+ PsiFileFactory factory = PsiFileFactory.getInstance(project);
+ LightVirtualFile virtualFile =
+ new LightVirtualFile(DUMMY_FILENAME, BuildFileType.INSTANCE, contents);
+ PsiFile psiFile =
+ ((PsiFileFactoryImpl) factory)
+ .trySetupPsiForFile(virtualFile, BuildFileLanguage.INSTANCE, false, true);
+ assert psiFile != null;
+ return psiFile;
+ }
+
+ public ASTNode createNameIdentifier(String name) {
+ PsiFile dummyFile = createDummyFile(name);
+ ASTNode referenceNode = dummyFile.getNode().getFirstChildNode();
+ ASTNode nameNode = referenceNode.getFirstChildNode();
+ if (nameNode.getElementType() != BuildToken.IDENTIFIER) {
+ throw new RuntimeException(
+ "Expecting an IDENTIFIER node directly below the BuildFile PSI element");
+ }
+ return nameNode;
+ }
+
+ public ASTNode createStringNode(String contents) {
+ PsiFile dummyFile = createDummyFile('"' + contents + '"');
+ ASTNode literalNode = dummyFile.getNode().getFirstChildNode();
+ ASTNode stringNode = literalNode.getFirstChildNode();
+ assert (stringNode.getElementType() == BuildToken.fromKind(TokenKind.STRING));
+ return stringNode;
+ }
+
+ public Argument.Keyword createKeywordArgument(String keyword, String value) {
+ String dummyText = String.format("foo(%s = \"%s\")", keyword, value);
+ FuncallExpression funcall = (FuncallExpression) createExpressionFromText(dummyText);
+ return (Argument.Keyword) funcall.getArguments()[0];
+ }
+
+ public Expression createExpressionFromText(String text) {
+ PsiFile dummyFile = createDummyFile(text);
+ PsiElement element = dummyFile.getFirstChild();
+ if (element instanceof Expression) {
+ return (Expression) element;
+ }
+ throw new RuntimeException("Could not parse text as expression: '" + text + "'");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/PsiUtils.java b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/PsiUtils.java
new file mode 100644
index 0000000..229220b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/PsiUtils.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi.util;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.CommonProcessors;
+import com.intellij.util.Processor;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Utility methods for working with PSI elements */
+public class PsiUtils {
+
+ public static ASTNode createNewName(Project project, String name) {
+ return BuildElementGenerator.getInstance(project).createNameIdentifier(name);
+ }
+
+ public static ASTNode createNewLabel(Project project, String labelString) {
+ return BuildElementGenerator.getInstance(project).createStringNode(labelString);
+ }
+
+ @Nullable
+ public static PsiElement getPreviousNodeInTree(PsiElement element) {
+ PsiElement prevSibling = null;
+ while (element != null && (prevSibling = element.getPrevSibling()) == null) {
+ element = element.getParent();
+ }
+ return prevSibling != null ? lastElementInSubtree(prevSibling) : null;
+ }
+
+ /** The last element in the tree rooted at the given element. */
+ public static PsiElement lastElementInSubtree(PsiElement element) {
+ PsiElement lastChild;
+ while ((lastChild = element.getLastChild()) != null) {
+ element = lastChild;
+ }
+ return element;
+ }
+
+ /**
+ * Walks up PSI tree, looking for a parent of the specified class. Stops searching when it reaches
+ * a parent of type PsiDirectory.
+ */
+ @Nullable
+ public static <T extends PsiElement> T getParentOfType(PsiElement element, Class<T> psiClass) {
+ PsiElement parent = element.getParent();
+ while (parent != null && !(parent instanceof PsiDirectory)) {
+ if (psiClass.isInstance(parent)) {
+ return (T) parent;
+ }
+ parent = parent.getParent();
+ }
+ return null;
+ }
+
+ @Nullable
+ public static <T extends PsiElement> T findFirstChildOfClassRecursive(
+ PsiElement parent, Class<T> psiClass) {
+ List<T> holder = Lists.newArrayListWithExpectedSize(1);
+ Processor<T> getFirst =
+ t -> {
+ holder.add(t);
+ return false;
+ };
+ processChildrenOfType(parent, getFirst, psiClass);
+ return holder.isEmpty() ? null : holder.get(0);
+ }
+
+ @Nullable
+ public static <T extends PsiElement> T findLastChildOfClassRecursive(
+ PsiElement parent, Class<T> psiClass) {
+ List<T> holder = Lists.newArrayListWithExpectedSize(1);
+ Processor<T> getFirst =
+ t -> {
+ holder.add(t);
+ return false;
+ };
+ processChildrenOfType(parent, getFirst, psiClass, true);
+ return holder.isEmpty() ? null : holder.get(0);
+ }
+
+ public static <T extends PsiElement> List<T> findAllChildrenOfClassRecursive(
+ PsiElement parent, Class<T> psiClass) {
+ List<T> result = Lists.newArrayList();
+ processChildrenOfType(parent, new CommonProcessors.CollectProcessor(result), psiClass);
+ return result;
+ }
+
+ /**
+ * Walk through entire PSI tree rooted at 'element', processing all children of the given type.
+ *
+ * @return true if processing was stopped by the processor
+ */
+ public static <T extends PsiElement> boolean processChildrenOfType(
+ PsiElement element, Processor<T> processor, Class<T> psiClass) {
+ return processChildrenOfType(element, processor, psiClass, false);
+ }
+
+ /**
+ * Walk through entire PSI tree rooted at 'element', processing all children of the given type.
+ *
+ * @return true if processing was stopped by the processor
+ */
+ private static <T extends PsiElement> boolean processChildrenOfType(
+ PsiElement element, Processor<T> processor, Class<T> psiClass, boolean reverseOrder) {
+ PsiElement child = reverseOrder ? element.getLastChild() : element.getFirstChild();
+ while (child != null) {
+ if (psiClass.isInstance(child)) {
+ if (!processor.process((T) child)) {
+ return true;
+ }
+ }
+ if (processChildrenOfType(child, processor, psiClass, reverseOrder)) {
+ return true;
+ }
+ child = reverseOrder ? child.getPrevSibling() : child.getNextSibling();
+ }
+ return false;
+ }
+
+ public static TextRange childRangeInParent(TextRange parentRange, TextRange childRange) {
+ return childRange.shiftRight(-parentRange.getStartOffset());
+ }
+
+ @Nullable
+ public static String getFilePath(@Nullable PsiFile file) {
+ VirtualFile virtualFile = file != null ? file.getVirtualFile() : null;
+ return virtualFile != null ? virtualFile.getPath() : null;
+ }
+
+ /**
+ * For ReferenceExpressions, follows the chain of references until it hits a
+ * non-ReferenceExpression. For other types, returns the input expression.
+ */
+ public static PsiElement getReferencedTarget(Expression expr) {
+ PsiElement element = expr;
+ while (element instanceof ReferenceExpression) {
+ PsiElement referencedElement = ((ReferenceExpression) element).getReferencedElement();
+ if (referencedElement == null) {
+ return element;
+ }
+ element = referencedElement;
+ }
+ return element;
+ }
+
+ /**
+ * For ReferenceExpressions, follows the chain of references until it hits a
+ * non-ReferenceExpression, then evaluates the value of that target. For other types, returns the
+ * input expression.
+ */
+ public static PsiElement getReferencedTargetValue(Expression expr) {
+ PsiElement element = getReferencedTarget(expr);
+ if (element instanceof TargetExpression) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof AssignmentStatement) {
+ return ((AssignmentStatement) parent).getAssignedValue();
+ }
+ }
+ return element;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildNamesValidator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildNamesValidator.java
new file mode 100644
index 0000000..f85425d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildNamesValidator.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
+
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
+import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase;
+import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
+import com.intellij.lang.refactoring.NamesValidator;
+import com.intellij.openapi.project.Project;
+
+/** Used for rename validation */
+public class BuildNamesValidator implements NamesValidator {
+
+ @Override
+ public boolean isKeyword(String s, Project project) {
+ return false;
+ }
+
+ @Override
+ public boolean isIdentifier(String s, Project project) {
+ BuildLexer lexer = new BuildLexer(BuildLexerBase.LexerMode.Parsing);
+ lexer.start(s);
+ return lexer.getTokenEnd() == s.length() && lexer.getTokenKind() == TokenKind.IDENTIFIER;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildRefactoringSupportProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildRefactoringSupportProvider.java
new file mode 100644
index 0000000..8ede27b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildRefactoringSupportProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.intellij.lang.refactoring.RefactoringSupportProvider;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+
+/** Supports 'safe delete' */
+public class BuildRefactoringSupportProvider extends RefactoringSupportProvider {
+
+ @Override
+ public boolean isSafeDeleteAvailable(@NotNull PsiElement element) {
+ // basically a promise that 'find usages' works for this element
+ return element instanceof FunctionStatement
+ || element instanceof TargetExpression
+ || element instanceof FuncallExpression;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/ArgumentReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/ArgumentReference.java
new file mode 100644
index 0000000..bb740a4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/ArgumentReference.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.completion.NamedBuildLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.psi.util.PsiTreeUtil;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/**
+ * Only keyword arguments resolve, but we include this class for code completion purposes. As the
+ * user is typing a keyword arg, they'll start with a positional arg element.
+ */
+public class ArgumentReference<T extends Argument> extends PsiReferenceBase<T> {
+
+ public ArgumentReference(T element, TextRange rangeInElement, boolean soft) {
+ super(element, rangeInElement, false);
+ }
+
+ @Nullable
+ protected FunctionStatement resolveFunction() {
+ FuncallExpression call = PsiTreeUtil.getParentOfType(myElement, FuncallExpression.class);
+ if (call == null) {
+ return null;
+ }
+ PsiElement callee = call.getReferencedElement();
+ return callee instanceof FunctionStatement ? (FunctionStatement) callee : null;
+ }
+
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ return null;
+ }
+
+ @Override
+ public Object[] getVariants() {
+ FunctionStatement function = resolveFunction();
+ if (function == null) {
+ return EMPTY_ARRAY;
+ }
+ List<LookupElement> params = Lists.newArrayList();
+ for (Parameter param : function.getParameters()) {
+ params.add(new NamedBuildLookupElement(param, QuoteType.NoQuotes));
+ }
+ return params.toArray();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java
new file mode 100644
index 0000000..454ab79
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.RuleName;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileSystem;
+import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.PsiManager;
+import com.intellij.util.PathUtil;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Handles reference caching and resolving labels to PSI elements. */
+public class BuildReferenceManager {
+
+ public static BuildReferenceManager getInstance(Project project) {
+ return ServiceManager.getService(project, BuildReferenceManager.class);
+ }
+
+ private final Project project;
+
+ public BuildReferenceManager(Project project) {
+ this.project = project;
+ }
+
+ /** Finds the PSI element associated with the given label. */
+ @Nullable
+ public PsiElement resolveLabel(Label label) {
+ return resolveLabel(label.blazePackage(), label.ruleName(), false);
+ }
+
+ /** Finds the PSI element associated with the given label. */
+ @Nullable
+ public PsiElement resolveLabel(
+ WorkspacePath packagePath, RuleName ruleName, boolean excludeRules) {
+ File packageDir = resolvePackage(packagePath);
+ if (packageDir == null) {
+ return null;
+ }
+
+ if (!excludeRules) {
+ FuncallExpression target = findRule(packageDir, ruleName);
+ if (target != null) {
+ return target;
+ }
+ }
+
+ // try a direct file reference (e.g. ":a.java")
+ File fullFile = new File(packageDir, ruleName.toString());
+ if (FileAttributeProvider.getInstance().exists(fullFile)) {
+ return resolveFile(fullFile);
+ }
+
+ return null;
+ }
+
+ private FuncallExpression findRule(File packageDir, RuleName ruleName) {
+ BuildFile psiFile = findBuildFile(packageDir);
+ return psiFile != null ? psiFile.findRule(ruleName.toString()) : null;
+ }
+
+ @Nullable
+ public PsiFileSystemItem resolveFile(File file) {
+ VirtualFile vf = getFileSystem().findFileByPath(file.getPath());
+ if (vf == null) {
+ return null;
+ }
+ PsiManager manager = PsiManager.getInstance(project);
+ return vf.isDirectory() ? manager.findDirectory(vf) : manager.findFile(vf);
+ }
+
+ @Nullable
+ public File resolvePackage(@Nullable WorkspacePath packagePath) {
+ return resolveWorkspaceRelativePath(packagePath != null ? packagePath.relativePath() : null);
+ }
+
+ @Nullable
+ private File resolveWorkspaceRelativePath(@Nullable String relativePath) {
+ WorkspacePathResolver pathResolver = getWorkspacePathResolver();
+ if (pathResolver == null || relativePath == null) {
+ return null;
+ }
+ return pathResolver.resolveToFile(relativePath);
+ }
+
+ @Nullable
+ private WorkspacePathResolver getWorkspacePathResolver() {
+ return WorkspacePathResolverProvider.getInstance(project).getPathResolver();
+ }
+
+ /**
+ * Finds all child directories. If exactly one is found, continue traversing (and appending to
+ * LookupElement string) until there are multiple options.<br>
+ * Used for package path completion suggestions.
+ */
+ public BuildLookupElement[] resolvePackageLookupElements(FileLookupData lookupData) {
+ String relativePath = lookupData.filePathFragment;
+ File file = resolveWorkspaceRelativePath(relativePath);
+
+ FileAttributeProvider provider = FileAttributeProvider.getInstance();
+ String pathFragment = "";
+ if (file == null || (!provider.isDirectory(file) && !relativePath.endsWith("/"))) {
+ // we might be partway through a file name. Try the parent directory
+ relativePath = PathUtil.getParentPath(relativePath);
+ file = resolveWorkspaceRelativePath(relativePath);
+ pathFragment =
+ StringUtil.trimStart(lookupData.filePathFragment.substring(relativePath.length()), "/");
+ }
+ if (file == null || !provider.isDirectory(file)) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ VirtualFile vf = getFileSystem().findFileByPath(file.getPath());
+ if (vf == null || !vf.isDirectory()) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ BuildLookupElement[] uniqueLookup = new BuildLookupElement[1];
+ while (true) {
+ VirtualFile[] children = vf.getChildren();
+ if (children == null || children.length == 0) {
+ return uniqueLookup[0] != null ? uniqueLookup : BuildLookupElement.EMPTY_ARRAY;
+ }
+ List<VirtualFile> validChildren = Lists.newArrayListWithCapacity(children.length);
+ for (VirtualFile child : children) {
+ ProgressManager.checkCanceled();
+ if (child.getName().startsWith(pathFragment) && lookupData.acceptFile(child)) {
+ validChildren.add(child);
+ }
+ }
+ if (validChildren.isEmpty()) {
+ return uniqueLookup[0] != null ? uniqueLookup : BuildLookupElement.EMPTY_ARRAY;
+ }
+ if (validChildren.size() > 1) {
+ return uniqueLookup[0] != null ? uniqueLookup : lookupsForFiles(validChildren, lookupData);
+ }
+ // continue traversing while there's only one option
+ uniqueLookup[0] = lookupForFile(validChildren.get(0), lookupData);
+ pathFragment = "";
+ vf = validChildren.get(0);
+ }
+ }
+
+ private BuildLookupElement[] lookupsForFiles(List<VirtualFile> files, FileLookupData lookupData) {
+ BuildLookupElement[] lookups = new BuildLookupElement[files.size()];
+ for (int i = 0; i < files.size(); i++) {
+ lookups[i] = lookupForFile(files.get(i), lookupData);
+ }
+ return lookups;
+ }
+
+ private BuildLookupElement lookupForFile(VirtualFile file, FileLookupData lookupData) {
+ WorkspacePath workspacePath = getWorkspaceRelativePath(file.getPath());
+ return lookupData.lookupElementForFile(project, file, workspacePath);
+ }
+
+ @Nullable
+ public BuildFile resolveBlazePackage(String workspaceRelativePath) {
+ workspaceRelativePath = StringUtil.trimStart(workspaceRelativePath, "//");
+ return resolveBlazePackage(WorkspacePath.createIfValid(workspaceRelativePath));
+ }
+
+ @Nullable
+ public BuildFile resolveBlazePackage(@Nullable WorkspacePath path) {
+ return findBuildFile(resolvePackage(path));
+ }
+
+ @Nullable
+ private BuildFile findBuildFile(@Nullable File packageDirectory) {
+ FileAttributeProvider provider = FileAttributeProvider.getInstance();
+ if (packageDirectory == null || !provider.isDirectory(packageDirectory)) {
+ return null;
+ }
+ File buildFile = new File(packageDirectory, "BUILD");
+ if (!provider.exists(buildFile)) {
+ return null;
+ }
+ VirtualFile vf = getFileSystem().findFileByPath(buildFile.getPath());
+ if (vf == null) {
+ return null;
+ }
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(vf);
+ return psiFile instanceof BuildFile ? (BuildFile) psiFile : null;
+ }
+
+ /**
+ * For files references, returns the parent directory.<br>
+ * For rule references, return the blaze package directory.
+ */
+ @Nullable
+ public File resolveParentDirectory(@Nullable Label label) {
+ return label != null ? resolveParentDirectory(label.blazePackage(), label.ruleName()) : null;
+ }
+
+ @Nullable
+ private File resolveParentDirectory(WorkspacePath packagePath, RuleName ruleName) {
+ File packageFile = resolvePackage(packagePath);
+ if (packageFile == null) {
+ return null;
+ }
+ String rulePathParent = PathUtil.getParentPath(ruleName.toString());
+ return new File(packageFile, rulePathParent);
+ }
+
+ @Nullable
+ public WorkspacePath getWorkspaceRelativePath(String absolutePath) {
+ WorkspacePathResolver pathResolver = getWorkspacePathResolver();
+ return pathResolver != null ? pathResolver.getWorkspacePath(new File(absolutePath)) : null;
+ }
+
+ private static VirtualFileSystem getFileSystem() {
+ if (ApplicationManager.getApplication().isUnitTestMode()) {
+ return TempFileSystem.getInstance();
+ }
+ return LocalFileSystem.getInstance();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java
new file mode 100644
index 0000000..c6fe9ed
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.completion.FilePathLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.NullableLazyValue;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileFilter;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.util.PathUtil;
+import com.intellij.util.PlatformIcons;
+import icons.BlazeIcons;
+import javax.swing.Icon;
+import org.jetbrains.annotations.Nullable;
+
+/** The data relevant to finding file lookups. */
+public class FileLookupData {
+
+ /** The type of path string format */
+ public enum PathFormat {
+ /** BUILD label without a leading '//', which can only reference targets in the same package. */
+ PackageLocal,
+ /** a BUILD label with leading '//', which can reference targets in other packages. */
+ NonLocal,
+ /** a path string which can reference any files, and has no leading '//'. */
+ NonLocalWithoutInitialBackslashes
+ }
+
+ @Nullable
+ public static FileLookupData nonLocalFileLookup(String originalLabel, StringLiteral element) {
+ return nonLocalFileLookup(
+ originalLabel, element.getContainingFile(), element.getQuoteType(), PathFormat.NonLocal);
+ }
+
+ @Nullable
+ public static FileLookupData nonLocalFileLookup(
+ String originalLabel,
+ @Nullable BuildFile containingFile,
+ QuoteType quoteType,
+ PathFormat pathFormat) {
+ if (originalLabel.indexOf(':') != -1) {
+ // it's a package-local reference
+ return null;
+ }
+ // handle the single '/' case by calling twice.
+ String relativePath = StringUtil.trimStart(StringUtil.trimStart(originalLabel, "/"), "/");
+ if (relativePath.startsWith("/")) {
+ return null;
+ }
+ return new FileLookupData(
+ originalLabel, containingFile, null, relativePath, pathFormat, quoteType, null);
+ }
+
+ @Nullable
+ public static FileLookupData packageLocalFileLookup(String originalLabel, StringLiteral element) {
+ if (originalLabel.startsWith("/")) {
+ return null;
+ }
+ BlazePackage blazePackage = element.getBlazePackage();
+ BuildFile baseBuildFile = blazePackage != null ? blazePackage.buildFile : null;
+ return packageLocalFileLookup(originalLabel, element, baseBuildFile, null);
+ }
+
+ @Nullable
+ public static FileLookupData packageLocalFileLookup(
+ String originalLabel,
+ StringLiteral element,
+ @Nullable BuildFile basePackage,
+ @Nullable VirtualFileFilter fileFilter) {
+ String basePackagePath =
+ basePackage != null ? basePackage.getWorkspaceRelativePackagePath() : null;
+ if (basePackagePath == null) {
+ return null;
+ }
+ String filePath = basePackagePath + "/" + LabelUtils.getRuleComponent(originalLabel);
+ return new FileLookupData(
+ originalLabel,
+ basePackage,
+ basePackagePath,
+ filePath,
+ PathFormat.PackageLocal,
+ element.getQuoteType(),
+ fileFilter);
+ }
+
+ private final String originalLabel;
+ private final BuildFile containingFile;
+ @Nullable private final String containingPackage;
+ public final String filePathFragment;
+ public final PathFormat pathFormat;
+ private final QuoteType quoteType;
+ @Nullable private final VirtualFileFilter fileFilter;
+
+ private FileLookupData(
+ String originalLabel,
+ @Nullable BuildFile containingFile,
+ @Nullable String containingPackage,
+ String filePathFragment,
+ PathFormat pathFormat,
+ QuoteType quoteType,
+ @Nullable VirtualFileFilter fileFilter) {
+
+ this.originalLabel = originalLabel;
+ this.containingFile = containingFile;
+ this.containingPackage = containingPackage;
+ this.fileFilter = fileFilter;
+ this.filePathFragment = filePathFragment;
+ this.pathFormat = pathFormat;
+ this.quoteType = quoteType;
+
+ assert (pathFormat != PathFormat.PackageLocal
+ || (containingPackage != null && containingFile != null));
+ }
+
+ public boolean acceptFile(VirtualFile file) {
+ if (fileFilter != null && !fileFilter.accept(file)) {
+ return false;
+ }
+ if (pathFormat != PathFormat.PackageLocal) {
+ return file.isDirectory();
+ }
+ if (file.equals(containingFile.getOriginalFile().getVirtualFile())) {
+ return false;
+ }
+ boolean blazePackage = file.findChild("BUILD") != null;
+ return !blazePackage;
+ }
+
+ public FilePathLookupElement lookupElementForFile(
+ Project project, VirtualFile file, @Nullable WorkspacePath workspacePath) {
+ NullableLazyValue<Icon> icon =
+ new NullableLazyValue<Icon>() {
+ @Override
+ protected Icon compute() {
+ if (file.findChild("BUILD") != null) {
+ return BlazeIcons.BuildFile;
+ }
+ if (file.isDirectory()) {
+ return PlatformIcons.FOLDER_ICON;
+ }
+ PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
+ return psiFile != null ? psiFile.getIcon(0) : AllIcons.FileTypes.Any_type;
+ }
+ };
+ String fullLabel =
+ workspacePath != null ? getFullLabel(workspacePath.relativePath()) : file.getPath();
+ String itemText = workspacePath != null ? getItemText(workspacePath.relativePath()) : fullLabel;
+ return new FilePathLookupElement(fullLabel, itemText, quoteType, icon);
+ }
+
+ private String getFullLabel(String relativePath) {
+ if (pathFormat != PathFormat.PackageLocal) {
+ if (pathFormat == PathFormat.NonLocal) {
+ relativePath = "//" + relativePath;
+ }
+ return relativePath;
+ }
+ String prefix;
+ int colonIndex = originalLabel.indexOf(':');
+ if (originalLabel.startsWith("/")) {
+ prefix = colonIndex == -1 ? originalLabel + ":" : originalLabel.substring(0, colonIndex + 1);
+ } else {
+ prefix = originalLabel.substring(0, colonIndex + 1);
+ }
+ return prefix + getItemText(relativePath);
+ }
+
+ private String getItemText(String relativePath) {
+ if (pathFormat == PathFormat.PackageLocal) {
+ return StringUtil.trimStart(relativePath.substring(containingPackage.length()), "/");
+ }
+ String parentPath = PathUtil.getParentPath(relativePath);
+ while (!parentPath.isEmpty()) {
+ if (filePathFragment.startsWith(parentPath + "/")) {
+ return StringUtil.trimStart(relativePath, parentPath + "/");
+ } else if (filePathFragment.startsWith(parentPath)) {
+ return StringUtil.trimStart(relativePath, parentPath);
+ }
+ parentPath = PathUtil.getParentPath(parentPath);
+ }
+ return relativePath;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/FuncallReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FuncallReference.java
new file mode 100644
index 0000000..7f6cca8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FuncallReference.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.IncorrectOperationException;
+import javax.annotation.Nullable;
+
+/** Reference from a function call to the function declaration */
+public class FuncallReference extends PsiReferenceBase<FuncallExpression> {
+
+ public FuncallReference(FuncallExpression element, TextRange rangeInElement) {
+ super(element, rangeInElement, /*soft*/ true);
+ }
+
+ @Nullable
+ @Override
+ public FunctionStatement resolve() {
+ String functionName = myElement.getFunctionName();
+ BuildFile file = (BuildFile) myElement.getContainingFile();
+ if (functionName == null || file == null) {
+ return null;
+ }
+ return file.findFunctionInScope(functionName);
+ }
+
+ @Override
+ public Object[] getVariants() {
+ return EMPTY_ARRAY;
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ ASTNode oldNode = myElement.getFunctionNameNode();
+ if (oldNode != null) {
+ ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
+ myElement.getNode().replaceChild(oldNode, newNode);
+ }
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/GlobReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/GlobReference.java
new file mode 100644
index 0000000..c880fb8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/GlobReference.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.lang.buildfile.globbing.UnixGlob;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
+import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.ListLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementResolveResult;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.ResolveResult;
+import com.intellij.psi.impl.source.resolve.reference.impl.PsiPolyVariantCachingReference;
+import com.intellij.util.IncorrectOperationException;
+import java.io.File;
+import java.util.List;
+import java.util.function.Predicate;
+
+/** References from a glob to a list of files contained in the same blaze package. */
+public class GlobReference extends PsiPolyVariantCachingReference {
+
+ private static final Logger LOG = Logger.getInstance(GlobReference.class);
+
+ private final GlobExpression element;
+
+ public GlobReference(GlobExpression element) {
+ this.element = element;
+ }
+
+ /**
+ * Returns true iff the complete, resolved glob references the specified file.
+ *
+ * <p>In particular, it's not concerned with individual patterns referencing the file, only
+ * whether the overall glob does (i.e. returns false if the file is explicitly excluded).
+ */
+ public boolean matches(String packageRelativePath, boolean isDirectory) {
+ if (isDirectory && element.areDirectoriesExcluded()) {
+ return false;
+ }
+ for (String exclude : resolveListContents(element.getExcludes())) {
+ if (UnixGlob.matches(exclude, packageRelativePath)) {
+ return false;
+ }
+ }
+ for (String include : resolveListContents(element.getIncludes())) {
+ if (UnixGlob.matches(include, packageRelativePath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true iff an include pattern *without wildcards* matches the given path and it's not
+ * excluded.
+ */
+ public boolean matchesDirectly(String packageRelativePath, boolean isDirectory) {
+ if (isDirectory && element.areDirectoriesExcluded()) {
+ return false;
+ }
+ for (String exclude : resolveListContents(element.getExcludes())) {
+ if (UnixGlob.matches(exclude, packageRelativePath)) {
+ return false;
+ }
+ }
+ for (String include : resolveListContents(element.getIncludes())) {
+ if (!hasWildcard(include) && UnixGlob.matches(include, packageRelativePath)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean hasWildcard(String pattern) {
+ return pattern.contains("*");
+ }
+
+ @Override
+ protected ResolveResult[] resolveInner(boolean incompleteCode, PsiFile containingFile) {
+ File containingDirectory = ((BuildFile) containingFile).getFile().getParentFile();
+ if (containingDirectory == null) {
+ return ResolveResult.EMPTY_ARRAY;
+ }
+ List<String> includes = resolveListContents(element.getIncludes());
+ List<String> excludes = resolveListContents(element.getExcludes());
+ boolean directoriesExcluded = element.areDirectoriesExcluded();
+ if (includes.isEmpty()) {
+ return ResolveResult.EMPTY_ARRAY;
+ }
+
+ try {
+ List<File> files =
+ UnixGlob.forPath(containingDirectory)
+ .addPatterns(includes)
+ .addExcludes(excludes)
+ .setExcludeDirectories(directoriesExcluded)
+ .setDirectoryFilter(directoryFilter(containingDirectory.getPath()))
+ .glob();
+ List<ResolveResult> results = Lists.newArrayListWithCapacity(files.size());
+ for (File file : files) {
+ PsiFileSystemItem psiFile =
+ BuildReferenceManager.getInstance(element.getProject()).resolveFile(file);
+ if (psiFile != null) {
+ results.add(new PsiElementResolveResult(psiFile));
+ }
+ }
+ return results.toArray(ResolveResult.EMPTY_ARRAY);
+
+ } catch (Exception e) {
+ return ResolveResult.EMPTY_ARRAY;
+ }
+ }
+
+ private static Predicate<File> directoryFilter(String base) {
+ return file -> {
+ if (base.equals(file.getPath())) {
+ return true;
+ }
+ File child = new File(file, "BUILD");
+ FileAttributeProvider attributeProvider = FileAttributeProvider.getInstance();
+ return !attributeProvider.exists(child) || attributeProvider.isDirectory(child);
+ };
+ }
+
+ private static List<String> resolveListContents(Expression expr) {
+ if (expr == null) {
+ return ImmutableList.of();
+ }
+ PsiElement rootElement = PsiUtils.getReferencedTargetValue(expr);
+ if (!(rootElement instanceof ListLiteral)) {
+ return ImmutableList.of();
+ }
+ Expression[] children = ((ListLiteral) rootElement).getElements();
+ List<String> strings = Lists.newArrayListWithCapacity(children.length);
+ for (Expression child : children) {
+ if (child instanceof StringLiteral) {
+ strings.add(((StringLiteral) child).getStringContents());
+ }
+ }
+ return strings;
+ }
+
+ @Override
+ public GlobExpression getElement() {
+ return element;
+ }
+
+ @Override
+ public TextRange getRangeInElement() {
+ return element.getReferenceTextRange();
+ }
+
+ @Override
+ public boolean isSoft() {
+ return true;
+ }
+
+ @Override
+ public Object[] getVariants() {
+ return EMPTY_ARRAY;
+ }
+
+ @Override
+ public String getCanonicalText() {
+ return getValue();
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ return element;
+ }
+
+ @Override
+ public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
+ return this.element;
+ }
+
+ public String getValue() {
+ String text = element.getText();
+ final TextRange range = getRangeInElement();
+ try {
+ return range.substring(text);
+ } catch (StringIndexOutOfBoundsException e) {
+ LOG.error(
+ "Wrong range in reference " + this + ": " + range + ". Reference text: '" + text + "'",
+ e);
+ return text;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/KeywordArgumentReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/KeywordArgumentReference.java
new file mode 100644
index 0000000..194bfe7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/KeywordArgumentReference.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.IncorrectOperationException;
+import javax.annotation.Nullable;
+
+/**
+ * Reference from keyword argument to a named function parameter. TODO: This is soft, because we
+ * can't always find the function. However we should implement error highlighting for imported
+ * Skylark functions.
+ */
+public class KeywordArgumentReference extends ArgumentReference<Argument.Keyword> {
+
+ public KeywordArgumentReference(Argument.Keyword element, TextRange rangeInElement) {
+ super(element, rangeInElement, false);
+ }
+
+ /**
+ * Find the referenced function. If it has a keyword parameter with matching name, return that.
+ * Otherwise if it has a **kwargs param, return that. Else return the function itself.
+ */
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ String keyword = myElement.getName();
+ if (keyword == null) {
+ return null;
+ }
+ FunctionStatement function = resolveFunction();
+ if (function == null) {
+ return null;
+ }
+ Parameter.StarStar kwargsParameter = null;
+ for (Parameter param : function.getParameters()) {
+ if (param instanceof Parameter.StarStar) {
+ kwargsParameter = (Parameter.StarStar) param;
+ continue;
+ }
+ if (keyword.equals(param.getName())) {
+ return param;
+ }
+ }
+ if (kwargsParameter != null) {
+ return kwargsParameter;
+ }
+ return null;
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ ASTNode oldNode = myElement.getNameNode();
+ if (oldNode != null) {
+ ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
+ myElement.getNode().replaceChild(oldNode, newNode);
+ }
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelReference.java
new file mode 100644
index 0000000..75c2aba
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelReference.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.completion.LabelRuleLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile.BlazeFileType;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.vfs.VirtualFileFilter;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Converts a blaze label into an absolute path, then resolves that path to a PsiElements */
+public class LabelReference extends PsiReferenceBase<StringLiteral> {
+
+ public LabelReference(StringLiteral element, boolean soft) {
+ super(element, new TextRange(0, element.getTextLength()), soft);
+ }
+
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ /* Possibilities:
+ * - target
+ * - data file (.java, .txt, etc.)
+ * - glob contents (not yet handling globs)
+ */
+ return resolveTarget(myElement.getStringContents());
+ }
+
+ @Nullable
+ private PsiElement resolveTarget(String labelString) {
+ Label label = getLabel(labelString);
+ if (label == null) {
+ return null;
+ }
+ if (!validLabelLocation(myElement)) {
+ return null;
+ }
+ if (!labelString.startsWith("//") && insideSkylarkExtension(myElement)) {
+ return getReferenceManager().resolveLabel(label.blazePackage(), label.ruleName(), true);
+ }
+ return getReferenceManager().resolveLabel(label);
+ }
+
+ /**
+ * Hack: don't include 'name' keyword arguments -- they'll be a reference to the enclosing
+ * function call / rule, and show up as unnecessary references to that rule.
+ */
+ private static boolean validLabelLocation(StringLiteral element) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof Argument.Keyword) {
+ String argName = ((Argument.Keyword) parent).getName();
+ if ("name".equals(argName)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @NotNull
+ @Override
+ public Object[] getVariants() {
+ if (!validLabelLocation(myElement)) {
+ return EMPTY_ARRAY;
+ }
+ String labelString = LabelUtils.trimToDummyIdentifier(myElement.getStringContents());
+ return ArrayUtil.mergeArrays(getRuleLookups(labelString), getFileLookups(labelString));
+ }
+
+ private BuildLookupElement[] getRuleLookups(String labelString) {
+ if (labelString.endsWith("/")
+ || (labelString.startsWith("/") && !labelString.contains(":"))
+ || skylarkExtensionReference(myElement)) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
+ BuildFile referencedBuildFile =
+ LabelUtils.getReferencedBuildFile(myElement.getContainingFile(), packagePrefix);
+ if (referencedBuildFile == null) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ String self = null;
+ if (referencedBuildFile == myElement.getContainingFile()) {
+ FuncallExpression funcall = PsiUtils.getParentOfType(myElement, FuncallExpression.class);
+ if (funcall != null) {
+ self = funcall.getName();
+ }
+ }
+ return LabelRuleLookupElement.collectAllRules(
+ referencedBuildFile, labelString, packagePrefix, self, myElement.getQuoteType());
+ }
+
+ private BuildLookupElement[] getFileLookups(String labelString) {
+ if (labelString.startsWith("//") || labelString.equals("/")) {
+ return getNonLocalFileLookups(labelString);
+ }
+ return getPackageLocalFileLookups(labelString);
+ }
+
+ private BuildLookupElement[] getNonLocalFileLookups(String labelString) {
+ BuildLookupElement[] skylarkExtLookups = getSkylarkExtensionLookups(labelString);
+ FileLookupData lookupData = FileLookupData.nonLocalFileLookup(labelString, myElement);
+ BuildLookupElement[] packageLookups =
+ lookupData != null
+ ? getReferenceManager().resolvePackageLookupElements(lookupData)
+ : BuildLookupElement.EMPTY_ARRAY;
+ return ArrayUtil.mergeArrays(skylarkExtLookups, packageLookups);
+ }
+
+ private BuildLookupElement[] getPackageLocalFileLookups(String labelString) {
+ if (skylarkExtensionReference(myElement)) {
+ return getSkylarkExtensionLookups(labelString);
+ }
+ FileLookupData lookupData = FileLookupData.packageLocalFileLookup(labelString, myElement);
+ return lookupData != null
+ ? getReferenceManager().resolvePackageLookupElements(lookupData)
+ : BuildLookupElement.EMPTY_ARRAY;
+ }
+
+ private BuildLookupElement[] getSkylarkExtensionLookups(String labelString) {
+ if (!skylarkExtensionReference(myElement)) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
+ BuildFile parentFile = myElement.getContainingFile();
+ if (parentFile == null) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ BlazePackage containingPackage = BlazePackage.getContainingPackage(parentFile);
+ if (containingPackage == null) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ BuildFile referencedBuildFile =
+ LabelUtils.getReferencedBuildFile(containingPackage.buildFile, packagePrefix);
+
+ // Directories before the colon are already covered.
+ // We're only concerned with package-local directories.
+ boolean hasColon = labelString.indexOf(':') != -1;
+ VirtualFileFilter filter =
+ file ->
+ ("bzl".equals(file.getExtension()) && !file.getPath().equals(parentFile.getFilePath()))
+ || (hasColon && file.isDirectory());
+ FileLookupData lookupData =
+ FileLookupData.packageLocalFileLookup(labelString, myElement, referencedBuildFile, filter);
+
+ return lookupData != null
+ ? getReferenceManager().resolvePackageLookupElements(lookupData)
+ : BuildLookupElement.EMPTY_ARRAY;
+ }
+
+ private BuildReferenceManager getReferenceManager() {
+ return BuildReferenceManager.getInstance(myElement.getProject());
+ }
+
+ @Override
+ public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
+ PsiFile file = ResolveUtil.asFileSearch(element);
+ if (file == null) {
+ return super.bindToElement(element);
+ }
+ if (file.equals(resolve())) {
+ return myElement;
+ }
+ BlazePackage currentPackageDir = myElement.getBlazePackage();
+ if (currentPackageDir == null) {
+ return myElement;
+ }
+ BlazePackage newPackageDir = BlazePackage.getContainingPackage(file);
+ if (!currentPackageDir.equals(newPackageDir)) {
+ return myElement;
+ }
+
+ String newRuleName =
+ newPackageDir.getPackageRelativePath(file.getViewProvider().getVirtualFile().getPath());
+ return handleRename(newRuleName);
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ String currentString = myElement.getStringContents();
+ Label label = getLabel(currentString);
+ if (label == null) {
+ return myElement;
+ }
+ String ruleName = label.ruleName().toString();
+ String newRuleName = newElementName;
+
+ // handle subdirectories
+ int lastSlashIndex = ruleName.lastIndexOf('/');
+ if (lastSlashIndex != -1) {
+ newRuleName = ruleName.substring(0, lastSlashIndex + 1) + newElementName;
+ }
+
+ String packageString = LabelUtils.getPackagePathComponent(currentString);
+ if (packageString.isEmpty() && !currentString.contains(":")) {
+ return handleRename(newRuleName);
+ }
+ return handleRename(packageString + ":" + newRuleName);
+ }
+
+ private PsiElement handleRename(String newStringContents) {
+ ASTNode node = myElement.getNode();
+ node.replaceChild(
+ node.getFirstChildNode(),
+ PsiUtils.createNewLabel(myElement.getProject(), newStringContents));
+ return myElement;
+ }
+
+ @Nullable
+ private Label getLabel(String labelString) {
+ if (labelString.indexOf('*') != -1) {
+ // don't even try to handle globs, yet.
+ return null;
+ }
+ BlazePackage blazePackage = myElement.getBlazePackage();
+ return LabelUtils.createLabelFromString(
+ blazePackage != null ? blazePackage.buildFile : null, labelString);
+ }
+
+ private static boolean skylarkExtensionReference(StringLiteral element) {
+ PsiElement parent = element.getParent();
+ if (!(parent instanceof LoadStatement)) {
+ return false;
+ }
+ return ((LoadStatement) parent).getImportPsiElement() == element;
+ }
+
+ private static boolean insideSkylarkExtension(StringLiteral element) {
+ BuildFile containingFile = element.getContainingFile();
+ return containingFile != null
+ && containingFile.getBlazeFileType() == BlazeFileType.SkylarkExtension;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelUtils.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelUtils.java
new file mode 100644
index 0000000..251baed
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelUtils.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.RuleName;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.codeInsight.completion.CompletionUtilCore;
+import com.intellij.util.PathUtil;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Utility methods for working with blaze labels. */
+public class LabelUtils {
+
+ /** Label referring to the given file, or null if it cannot be determined. */
+ @Nullable
+ public static Label createLabelForFile(BlazePackage blazePackage, @Nullable String filePath) {
+ if (blazePackage == null || filePath == null) {
+ return null;
+ }
+ String relativeFilePath = blazePackage.getPackageRelativePath(filePath);
+ if (relativeFilePath == null) {
+ return null;
+ }
+ return createLabelFromRuleName(blazePackage, relativeFilePath);
+ }
+
+ /**
+ * Returns null if this is not a valid Label (if either the package path or rule name are invalid)
+ */
+ @Nullable
+ public static Label createLabelFromRuleName(
+ @Nullable BlazePackage blazePackage, @Nullable String ruleName) {
+ if (blazePackage == null || ruleName == null) {
+ return null;
+ }
+ WorkspacePath packagePath = blazePackage.buildFile.getPackageWorkspacePath();
+ RuleName name = RuleName.createIfValid(ruleName);
+ if (packagePath == null || name == null) {
+ return null;
+ }
+ // TODO: Is Label too inefficient?
+ // (validation done twice,creating List during constructor,
+ // re-parsing to extract the package/rule each time)
+ return new Label(packagePath, name);
+ }
+
+ /**
+ * Canonicalizes the label (to the form //packagePath:packageRelativeTarget). Returns null if the
+ * string does not represent a valid label.
+ */
+ @Nullable
+ public static Label createLabelFromString(
+ @Nullable BuildFile file, @Nullable String labelString) {
+ if (labelString == null) {
+ return null;
+ }
+ int colonIndex = labelString.indexOf(':');
+ if (labelString.startsWith("//")) {
+ if (colonIndex == -1) {
+ // add the implicit rule name
+ labelString += ":" + PathUtil.getFileName(labelString);
+ }
+ return Label.createIfValid(labelString);
+ }
+ WorkspacePath packagePath = file != null ? file.getPackageWorkspacePath() : null;
+ if (packagePath == null) {
+ return null;
+ }
+ String localPath = colonIndex == -1 ? labelString : labelString.substring(1);
+ return Label.createIfValid("//" + packagePath.relativePath() + ":" + localPath);
+ }
+
+ /** The blaze file referenced by the label. */
+ @Nullable
+ public static BuildFile getReferencedBuildFile(
+ @Nullable BuildFile containingFile, String packagePathComponent) {
+ if (containingFile == null) {
+ return null;
+ }
+ if (!packagePathComponent.startsWith("//")) {
+ return containingFile;
+ }
+ return BuildReferenceManager.getInstance(containingFile.getProject())
+ .resolveBlazePackage(packagePathComponent);
+ }
+
+ public static String getRuleComponent(String labelString) {
+ if (labelString.startsWith("/")) {
+ int colonIndex = labelString.indexOf(':');
+ return colonIndex == -1 ? "" : labelString.substring(colonIndex + 1);
+ }
+ return labelString.startsWith(":") ? labelString.substring(1) : labelString;
+ }
+
+ public static String getPackagePathComponent(String labelString) {
+ if (!labelString.startsWith("//")) {
+ return "";
+ }
+ int colonIndex = labelString.indexOf(':');
+ return colonIndex == -1 ? labelString : labelString.substring(0, colonIndex);
+ }
+
+ /** 'load' reference. Of the form [path][/ or :][extra_path/]file_name.bzl */
+ @Nullable
+ public static String getNiceSkylarkFileName(@Nullable String path) {
+ if (path == null) {
+ return null;
+ }
+ int colonIndex = path.lastIndexOf(":");
+ if (colonIndex != -1) {
+ path = path.substring(colonIndex + 1);
+ }
+ int lastSlash = path.lastIndexOf("/");
+ if (lastSlash == -1) {
+ return path;
+ }
+ return path.substring(lastSlash + 1);
+ }
+
+ /**
+ * All the possible strings which could resolve to the given target.
+ *
+ * @param includePackageLocalLabels if true, include strings omitting the package path
+ */
+ public static List<String> getAllValidLabelStrings(
+ Label label, boolean includePackageLocalLabels) {
+ List<String> strings = Lists.newArrayList();
+ strings.add(label.toString());
+ String packagePath = label.blazePackage().relativePath();
+ if (packagePath.isEmpty()) {
+ return strings;
+ }
+ String ruleName = label.ruleName().toString();
+ if (PathUtil.getFileName(packagePath).equals(ruleName)) {
+ strings.add("//" + packagePath); // implicit rule name equal to package name
+ }
+ if (includePackageLocalLabels) {
+ strings.add(":" + ruleName);
+ strings.add(ruleName);
+ }
+ return strings;
+ }
+
+ /**
+ * IntelliJ inserts an identifier string at the caret position during code completion.<br>
+ * We're only interested in the portion of the string before the caret, so trim the rest.
+ */
+ public static String trimToDummyIdentifier(String string) {
+ int dummyIdentifierIndex = string.indexOf(CompletionUtilCore.DUMMY_IDENTIFIER);
+ if (dummyIdentifierIndex == -1) {
+ dummyIdentifierIndex = string.indexOf(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED);
+ }
+ return dummyIdentifierIndex == -1 ? string : string.substring(0, dummyIdentifierIndex);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/LoadedSymbolReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LoadedSymbolReference.java
new file mode 100644
index 0000000..219d843
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LoadedSymbolReference.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.completion.CompletionResultsProcessor;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.IncorrectOperationException;
+import javax.annotation.Nullable;
+
+/** References from load statement string to a function or variable in a Skylark extension */
+public class LoadedSymbolReference extends PsiReferenceBase<StringLiteral> {
+
+ private final LabelReference bzlFileReference;
+
+ public LoadedSymbolReference(StringLiteral element, LabelReference bzlFileReference) {
+ super(element, new TextRange(0, element.getTextLength()), /*soft*/ false);
+ this.bzlFileReference = bzlFileReference;
+ }
+
+ @Nullable
+ @Override
+ public BuildElement resolve() {
+ PsiElement bzlFile = bzlFileReference.resolve();
+ if (!(bzlFile instanceof BuildFile)) {
+ return null;
+ }
+ return ((BuildFile) bzlFile).findSymbolInScope(myElement.getStringContents());
+ }
+
+ @Override
+ public Object[] getVariants() {
+ PsiElement bzlFile = bzlFileReference.resolve();
+ if (!(bzlFile instanceof BuildFile)) {
+ return EMPTY_ARRAY;
+ }
+ CompletionResultsProcessor processor =
+ new CompletionResultsProcessor(myElement, myElement.getQuoteType());
+ ((BuildFile) bzlFile).searchSymbolsInScope(processor, null);
+ return processor.getResults().toArray();
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ ASTNode newNode = PsiUtils.createNewLabel(myElement.getProject(), newElementName);
+ myElement.getNode().replaceChild(myElement.getNode().getFirstChildNode(), newNode);
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/LocalReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LocalReference.java
new file mode 100644
index 0000000..85808b1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/LocalReference.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.completion.CompletionResultsProcessor;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.IncorrectOperationException;
+import javax.annotation.Nullable;
+
+/**
+ * Reference from a ReferenceExpression to a PsiNamedElement in the same scope. This includes
+ * symbols accessible via 'load' statments.
+ */
+public class LocalReference extends PsiReferenceBase<ReferenceExpression> {
+
+ public LocalReference(ReferenceExpression element) {
+ super(element, new TextRange(0, element.getTextLength()), /*soft*/ false);
+ }
+
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ String referencedName = myElement.getReferencedName();
+ if (referencedName == null) {
+ return null;
+ }
+ return ResolveUtil.findInScope(myElement, referencedName);
+ }
+
+ @Override
+ public Object[] getVariants() {
+ CompletionResultsProcessor processor =
+ new CompletionResultsProcessor(myElement, QuoteType.NoQuotes);
+ ResolveUtil.searchInScope(myElement, processor);
+ return processor.getResults().toArray();
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ ASTNode oldNode = myElement.getNameElement();
+ if (oldNode != null) {
+ ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
+ myElement.getNode().replaceChild(oldNode, newNode);
+ }
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceFragment.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceFragment.java
new file mode 100644
index 0000000..6dba496
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceFragment.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.PathUtil;
+import javax.annotation.Nullable;
+
+/** The label component preceeding the colon. */
+public class PackageReferenceFragment extends PsiReferenceBase<StringLiteral> {
+
+ public PackageReferenceFragment(LabelReference labelReference) {
+ super(labelReference.getElement(), labelReference.getRangeInElement(), labelReference.isSoft());
+ }
+
+ @Nullable
+ private WorkspacePath getWorkspacePath(String labelString) {
+ if (!labelString.startsWith("//")) {
+ return null;
+ }
+ int colonIndex = labelString.indexOf(':');
+ int endIndex = colonIndex != -1 ? colonIndex : labelString.length();
+ return WorkspacePath.createIfValid(labelString.substring(2, endIndex));
+ }
+
+ @Override
+ public TextRange getRangeInElement() {
+ String rawText = myElement.getText();
+ boolean valid = getWorkspacePath(myElement.getStringContents()) != null;
+ if (!valid) {
+ return TextRange.EMPTY_RANGE;
+ }
+ int endIndex = rawText.indexOf(':');
+ if (endIndex == -1) {
+ endIndex = rawText.length() - 1;
+ }
+ return new TextRange(1, endIndex);
+ }
+
+ @Nullable
+ @Override
+ public BuildFile resolve() {
+ WorkspacePath workspacePath = getWorkspacePath(myElement.getStringContents());
+ return BuildReferenceManager.getInstance(myElement.getProject())
+ .resolveBlazePackage(workspacePath);
+ }
+
+ @Override
+ public Object[] getVariants() {
+ return EMPTY_ARRAY;
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ return myElement; // renaming a BUILD file has no effect on the package label fragments
+ }
+
+ @Override
+ public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
+ if (!(element instanceof BuildFile)) {
+ return super.bindToElement(element);
+ }
+ if (element.equals(resolve())) {
+ return myElement;
+ }
+ WorkspacePath newPath = ((BuildFile) element).getPackageWorkspacePath();
+ if (newPath == null) {
+ return myElement;
+ }
+ String labelString = myElement.getStringContents();
+ int colonIndex = labelString.indexOf(':');
+ if (colonIndex != -1) {
+ return handleRename("//" + newPath + labelString.substring(colonIndex));
+ }
+ // need to assume there's an implicit rule name
+ return handleRename("//" + newPath + ":" + PathUtil.getFileName(labelString));
+ }
+
+ private PsiElement handleRename(String newStringContents) {
+ ASTNode node = myElement.getNode();
+ node.replaceChild(
+ node.getFirstChildNode(),
+ PsiUtils.createNewLabel(myElement.getProject(), newStringContents));
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/QuoteType.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/QuoteType.java
new file mode 100644
index 0000000..316f0d1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/QuoteType.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+/** The type of quotes surrounding a PSI element. */
+public enum QuoteType {
+ Single("'"),
+ Double("\""),
+ TripleSingle("'''"),
+ TripleDouble("\"\"\""),
+ NoQuotes("");
+
+ public final String quoteString;
+
+ QuoteType(String quoteString) {
+ this.quoteString = quoteString;
+ }
+
+ public String wrap(String unquotedText) {
+ return quoteString + unquotedText + quoteString;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/TargetReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/TargetReference.java
new file mode 100644
index 0000000..52ee6da
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/TargetReference.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import com.google.idea.blaze.base.lang.buildfile.completion.CompletionResultsProcessor;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.IncorrectOperationException;
+import javax.annotation.Nullable;
+
+/**
+ * A reference to an earlier declaration of this symbol (to handle cases where a symbol is the
+ * target of multiple assignment statements).
+ */
+public class TargetReference extends PsiReferenceBase<TargetExpression> {
+
+ public TargetReference(TargetExpression element) {
+ super(element, new TextRange(0, element.getTextLength()), /*soft*/ true);
+ }
+
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ String referencedName = myElement.getName();
+ if (referencedName == null) {
+ return null;
+ }
+ PsiNamedElement target = ResolveUtil.findInScope(myElement, referencedName);
+ return target != null ? target : null;
+ }
+
+ @Override
+ public Object[] getVariants() {
+ CompletionResultsProcessor processor =
+ new CompletionResultsProcessor(myElement, QuoteType.NoQuotes);
+ ResolveUtil.searchInScope(myElement, processor);
+ return processor.getResults().toArray();
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ ASTNode oldNode = myElement.getNameNode();
+ if (oldNode != null) {
+ ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
+ myElement.getNode().replaceChild(oldNode, newNode);
+ }
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackage.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackage.java
new file mode 100644
index 0000000..6c2e3a3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackage.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.history.core.Paths;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PackagePrefixFileSystemItem;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.PathUtil;
+import com.intellij.util.Processor;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/** Defines the files accessible by a given blaze package. */
+public class BlazePackage {
+
+ @Nullable
+ public static BlazePackage getContainingPackage(PsiFileSystemItem file) {
+ if (file instanceof PsiFile) {
+ file = ((PsiFile) file).getOriginalFile();
+ }
+ if (file instanceof BuildFile && file.getName().equals("BUILD")) {
+ return new BlazePackage((BuildFile) file);
+ }
+ return getContainingPackage(getPsiDirectory(file));
+ }
+
+ @Nullable
+ private static PsiDirectory getPsiDirectory(PsiFileSystemItem file) {
+ if (file instanceof PsiDirectory) {
+ return (PsiDirectory) file;
+ }
+ if (file instanceof PsiFile) {
+ return ((PsiFile) file).getContainingDirectory();
+ }
+ if (file instanceof PackagePrefixFileSystemItem) {
+ return ((PackagePrefixFileSystemItem) file).getDirectory();
+ }
+ return null;
+ }
+
+ @Nullable
+ public static BlazePackage getContainingPackage(@Nullable PsiDirectory dir) {
+ while (dir != null) {
+ PsiFile buildFile = dir.findFile("BUILD");
+ if (buildFile != null) {
+ return buildFile instanceof BuildFile ? new BlazePackage((BuildFile) buildFile) : null;
+ }
+ dir = dir.getParentDirectory();
+ }
+ return null;
+ }
+
+ public final BuildFile buildFile;
+
+ private BlazePackage(BuildFile buildFile) {
+ this.buildFile = buildFile;
+ }
+
+ @Nullable
+ public PsiDirectory getContainingDirectory() {
+ return buildFile.getParent();
+ }
+
+ /**
+ * The search scope corresponding to this package (i.e. not crossing package boundaries).
+ *
+ * @param onlyBlazeFiles if true, the scope is limited to BUILD and Skylark files.
+ */
+ public GlobalSearchScope getSearchScope(boolean onlyBlazeFiles) {
+ return new BlazePackageSearchScope(this, onlyBlazeFiles);
+ }
+
+ /**
+ * Returns the file path relative to this blaze package, or null if it does lie inside this
+ * package
+ */
+ @Nullable
+ public String getPackageRelativePath(String filePath) {
+ String packageFilePath = PathUtil.getParentPath(buildFile.getFilePath());
+ return Paths.relativeIfUnder(filePath, packageFilePath);
+ }
+
+ /** Formats the child file path as a BUILD label (i.e. "//package_path[:relative_path]") */
+ @Nullable
+ public String getBuildLabelForChild(String filePath) {
+ WorkspacePath packagePath = buildFile.getPackageWorkspacePath();
+ if (packagePath == null) {
+ return null;
+ }
+ String relativePath = getPackageRelativePath(filePath);
+ if (relativePath == null) {
+ return null;
+ }
+ if (relativePath.isEmpty()) {
+ return "//" + packagePath;
+ }
+ return "//" + packagePath + ":" + relativePath;
+ }
+
+ /**
+ * The path from the blaze package directory to the child file, or null if the package directory
+ * is not an ancestor of the provided file.
+ */
+ @Nullable
+ public String getRelativePathToChild(@Nullable VirtualFile child) {
+ if (child == null) {
+ return null;
+ }
+ String packagePath = PathUtil.getParentPath(buildFile.getFilePath());
+ return Paths.relativeIfUnder(child.getPath(), packagePath);
+ }
+
+ /**
+ * Walks the directory tree, processing all files accessible by this package (i.e. not processing
+ * child packages).
+ */
+ public void processPackageFiles(Processor<PsiFile> processor) {
+ PsiDirectory dir = getContainingDirectory();
+ if (dir == null) {
+ return;
+ }
+ processPackageFiles(processor, dir);
+ }
+
+ private static void processPackageFiles(Processor<PsiFile> processor, PsiDirectory directory) {
+ processDirectory(processor, directory);
+ for (PsiDirectory child : directory.getSubdirectories()) {
+ if (!isBlazePackage(child)) {
+ processPackageFiles(processor, directory);
+ }
+ }
+ }
+
+ private static boolean isBlazePackage(PsiDirectory directory) {
+ return directory.findFile("BUILD") != null;
+ }
+
+ private static void processDirectory(Processor<PsiFile> processor, PsiDirectory directory) {
+ for (PsiFile file : directory.getFiles()) {
+ processor.process(file);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BlazePackage)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ BlazePackage that = (BlazePackage) obj;
+ return Objects.equals(buildFile.getFilePath(), that.buildFile.getFilePath());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(buildFile.getFilePath());
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "%s package: %s",
+ Blaze.buildSystemName(buildFile.getProject()), buildFile.getPackageWorkspacePath());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageSearchScope.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageSearchScope.java
new file mode 100644
index 0000000..d5f6606
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageSearchScope.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
+
+/** A scope limited to a single blaze/bazel package, which doesn't cross package boundaries. */
+public class BlazePackageSearchScope extends GlobalSearchScope {
+
+ private final BlazePackage blazePackage;
+ private final boolean onlyBlazeFiles;
+
+ public BlazePackageSearchScope(BlazePackage blazePackage, boolean onlyBlazeFiles) {
+ super(blazePackage.buildFile.getProject());
+ this.blazePackage = blazePackage;
+ this.onlyBlazeFiles = onlyBlazeFiles;
+ }
+
+ @Override
+ public boolean contains(@NotNull VirtualFile file) {
+ PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
+ if (onlyBlazeFiles && !(psiFile instanceof BuildFile)) {
+ return false;
+ }
+ return blazePackage.equals(BlazePackage.getContainingPackage(psiFile));
+ }
+
+ @Override
+ public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
+ return 0;
+ }
+
+ @Override
+ public boolean isSearchInModuleContent(@NotNull Module aModule) {
+ return true;
+ }
+
+ @Override
+ public boolean isSearchInLibraries() {
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "%s directory scope: %s",
+ Blaze.buildSystemName(getProject()), blazePackage.buildFile.getPackageWorkspacePath());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BlazePackageSearchScope)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ BlazePackageSearchScope other = (BlazePackageSearchScope) obj;
+ return blazePackage.equals(other.blazePackage) && onlyBlazeFiles == other.onlyBlazeFiles;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(blazePackage, onlyBlazeFiles);
+ }
+
+ @Override
+ public String getDisplayName() {
+ return blazePackage.toString();
+ }
+
+ @Override
+ public GlobalSearchScope uniteWith(@NotNull GlobalSearchScope scope) {
+ if (scope instanceof BlazePackageSearchScope) {
+ BlazePackageSearchScope other = (BlazePackageSearchScope) scope;
+ if (!blazePackage.equals(other.blazePackage)) {
+ return GlobalSearchScope.EMPTY_SCOPE;
+ }
+ return onlyBlazeFiles ? this : other;
+ }
+ return super.uniteWith(scope);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java
new file mode 100644
index 0000000..688cc95
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile.BlazeFileType;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.openapi.application.QueryExecutorBase;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.UsageSearchContext;
+import com.intellij.psi.search.searches.ReferencesSearch.SearchParameters;
+import com.intellij.util.Processor;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** String search for label references in BUILD files */
+public class BuildLabelReferenceSearcher extends QueryExecutorBase<PsiReference, SearchParameters> {
+
+ public BuildLabelReferenceSearcher() {
+ super(true);
+ }
+
+ @Override
+ public void processQuery(SearchParameters params, Processor<PsiReference> consumer) {
+ PsiElement element = params.getElementToSearch();
+ if (element instanceof FunctionStatement) {
+ String fnName = ((FunctionStatement) element).getName();
+ if (fnName != null) {
+ searchForString(params, element, fnName);
+ }
+ return;
+ }
+ PsiFile file = ResolveUtil.asFileSearch(element);
+ if (file != null) {
+ processFileReferences(params, file);
+ return;
+ }
+
+ if (!(element instanceof FuncallExpression)) {
+ return;
+ }
+
+ Label label = ((FuncallExpression) element).resolveBuildLabel();
+ PsiFile localFile = element.getContainingFile();
+ if (label == null || localFile == null) {
+ return;
+ }
+ List<String> stringsToSearch = LabelUtils.getAllValidLabelStrings(label, true);
+ for (String string : stringsToSearch) {
+ if (string.startsWith("//")) {
+ searchForString(params, element, string);
+ } else {
+ // only a valid reference from local package -- restrict the search scope accordingly
+ SearchScope scope = limitScopeToFile(params.getScopeDeterminedByUser(), localFile);
+ if (scope != null) {
+ searchForString(params, scope, element, string);
+ }
+ }
+ }
+ }
+
+ /** Find all references to the given file within BUILD files. */
+ private void processFileReferences(SearchParameters params, PsiFile file) {
+ if (file instanceof BuildFile) {
+ BuildFile buildFile = (BuildFile) file;
+ processBuildFileReferences(params, buildFile);
+ if (buildFile.getBlazeFileType() == BlazeFileType.BuildPackage) {
+ return;
+ }
+ // for skylark extensions, we also check for package-local references, below
+ }
+ BlazePackage blazePackage = BlazePackage.getContainingPackage(file);
+ PsiDirectory directory = blazePackage != null ? blazePackage.getContainingDirectory() : null;
+ if (directory == null) {
+ return;
+ }
+ Label label = LabelUtils.createLabelForFile(blazePackage, PsiUtils.getFilePath(file));
+ if (label == null) {
+ return;
+ }
+
+ // files can only be directly referenced in the containing blaze package
+ List<String> stringsToSearch = LabelUtils.getAllValidLabelStrings(label, true);
+ SearchScope scope =
+ params.getScopeDeterminedByUser().intersectWith(blazePackage.getSearchScope(true));
+
+ for (String string : stringsToSearch) {
+ searchForString(params, scope, file, string);
+ }
+ }
+
+ /** Find references to both the file itself, and build targets defined in the file. */
+ private void processBuildFileReferences(SearchParameters params, BuildFile file) {
+ WorkspacePath workspacePath = file.getPackageWorkspacePath();
+ if (workspacePath == null) {
+ return;
+ }
+ List<String> stringsToSearch = Lists.newArrayList();
+ if (file.getBlazeFileType() == BlazeFileType.BuildPackage) {
+ stringsToSearch.add("//" + workspacePath);
+ } else {
+ stringsToSearch.add("//" + workspacePath + ":" + file.getName());
+ stringsToSearch.add(
+ "//" + workspacePath + "/" + file.getName()); // deprecated load/subinclude format
+ }
+ for (String string : stringsToSearch) {
+ searchForString(params, file, string);
+ }
+ }
+
+ /**
+ * Search for package-local references.<br>
+ * Returns null if the resulting scope is empty
+ */
+ @Nullable
+ private static SearchScope limitScopeToFile(SearchScope scope, PsiFile file) {
+ if (scope instanceof LocalSearchScope) {
+ return ((LocalSearchScope) scope).isInScope(file.getVirtualFile())
+ ? new LocalSearchScope(file)
+ : null;
+ }
+ return scope.intersectWith(new LocalSearchScope(file));
+ }
+
+ private static void searchForString(SearchParameters params, PsiElement element, String string) {
+ searchForString(params, params.getScopeDeterminedByUser(), element, string);
+ }
+
+ private static void searchForString(
+ SearchParameters params, SearchScope scope, PsiElement element, String string) {
+ if (scope instanceof GlobalSearchScope) {
+ scope =
+ GlobalSearchScope.getScopeRestrictedByFileTypes(
+ (GlobalSearchScope) scope, BuildFileType.INSTANCE);
+ }
+ params.getOptimizer().searchWord(string, scope, UsageSearchContext.IN_STRINGS, true, element);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/ExcludeBuildFilesScope.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/ExcludeBuildFilesScope.java
new file mode 100644
index 0000000..3fa294b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/ExcludeBuildFilesScope.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.search.EverythingGlobalScope;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.UseScopeOptimizer;
+import javax.annotation.Nullable;
+
+/**
+ * Causes all calls to PsiSearchHelper.getUseScope to exclude BUILD files, when searching for files.
+ * <br>
+ * BUILD file / BUILD package references are handled by a separate reference searcher.
+ *
+ * <p>This is a hack, but greatly improves efficiency. The reasoning behind this: - BUILD files have
+ * very strict file reference patterns, and very narrow direct reference scopes (a package can't
+ * directly reference files in another package). - IJ *constantly* performs global searches on
+ * strings when manipulating files (e.g. searching for file uses for highlighting, rename, move
+ * operations). This causes us to re-parse every BUILD file in the project, multiple times.
+ */
+public class ExcludeBuildFilesScope extends UseScopeOptimizer {
+
+ @Nullable
+ @Override
+ public GlobalSearchScope getScopeToExclude(PsiElement element) {
+ if (element instanceof PsiFileSystemItem) {
+ return GlobalSearchScope.getScopeRestrictedByFileTypes(
+ new EverythingGlobalScope(), BuildFileType.INSTANCE);
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/FindUsages.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/FindUsages.java
new file mode 100644
index 0000000..4a05e5c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/FindUsages.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.PsiSearchHelper;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.searches.ReferencesSearch;
+
+/** Utility methods for finding all references to a PsiElement */
+public class FindUsages {
+
+ public static PsiReference[] findAllReferences(PsiElement element) {
+ return findReferencesInScope(element, GlobalSearchScope.allScope(element.getProject()));
+ }
+
+ /**
+ * Search scope taken from PsiSearchHelper::getUseScope, which incorporates UseScopeEnlarger /
+ * UseScopeOptimizer EPs.
+ */
+ public static PsiReference[] findReferencesInElementScope(PsiElement element) {
+ return findReferencesInScope(
+ element, PsiSearchHelper.SERVICE.getInstance(element.getProject()).getUseScope(element));
+ }
+
+ public static PsiReference[] findReferencesInScope(PsiElement element, SearchScope scope) {
+ return ReferencesSearch.search(element, scope, true).toArray(new PsiReference[0]);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/GlobReferenceSearcher.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/GlobReferenceSearcher.java
new file mode 100644
index 0000000..ac77523
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/GlobReferenceSearcher.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.openapi.application.QueryExecutorBase;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.searches.ReferencesSearch.SearchParameters;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.Processor;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Searches for references to a file in globs. These aren't picked up by a standard string search,
+ * and are only evaluated on demand, so we can't just check a reference cache.
+ *
+ * <p>Unlike resolving a glob, this requires no file system calls (beyond finding the parent blaze
+ * package), because we're only interested in a single file, which is already known to exist.
+ *
+ * <p>This is always a local search (as glob references can't cross package boundaries).
+ */
+public class GlobReferenceSearcher extends QueryExecutorBase<PsiReference, SearchParameters> {
+
+ public GlobReferenceSearcher() {
+ super(true);
+ }
+
+ @Override
+ public void processQuery(SearchParameters queryParameters, Processor<PsiReference> consumer) {
+ PsiFileSystemItem file =
+ ResolveUtil.asFileSystemItemSearch(queryParameters.getElementToSearch());
+ if (file == null) {
+ return;
+ }
+ BlazePackage containingPackage = BlazePackage.getContainingPackage(file);
+ if (containingPackage == null || !inScope(queryParameters, containingPackage.buildFile)) {
+ return;
+ }
+ String relativePath = containingPackage.getRelativePathToChild(file.getVirtualFile());
+ if (relativePath == null) {
+ return;
+ }
+
+ List<GlobExpression> globs =
+ PsiUtils.findAllChildrenOfClassRecursive(containingPackage.buildFile, GlobExpression.class);
+ for (GlobExpression glob : globs) {
+ if (glob.matches(relativePath, file.isDirectory())) {
+ consumer.process(globReference(glob, file));
+ }
+ }
+ }
+
+ private static PsiReference globReference(GlobExpression glob, PsiFileSystemItem file) {
+ return new PsiReferenceBase.Immediate<GlobExpression>(
+ glob, glob.getReferenceTextRange(), file) {
+ @Override
+ public PsiElement bindToElement(@NotNull PsiElement element)
+ throws IncorrectOperationException {
+ return glob;
+ }
+ };
+ }
+
+ private static boolean inScope(SearchParameters queryParameters, BuildFile buildFile) {
+ SearchScope scope = queryParameters.getScopeDeterminedByUser();
+ if (scope instanceof GlobalSearchScope) {
+ return ((GlobalSearchScope) scope).contains(buildFile.getVirtualFile());
+ }
+ return ((LocalSearchScope) scope).isInScope(buildFile.getVirtualFile());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/PsiFileProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/PsiFileProvider.java
new file mode 100644
index 0000000..164046e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/PsiFileProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import javax.annotation.Nullable;
+
+/**
+ * Checks if the PsiElement represents a top-level PsiFile (e.g. a top-level java PsiClass can be
+ * interchanged with the corresponding PsiFile, when searching for usages).
+ */
+public interface PsiFileProvider {
+
+ ExtensionPointName<PsiFileProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.PsiFileProvider");
+
+ @Nullable
+ PsiFile asFileSearch(PsiElement elementToSearch);
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/search/ResolveUtil.java b/base/src/com/google/idea/blaze/base/lang/buildfile/search/ResolveUtil.java
new file mode 100644
index 0000000..e7854c5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/ResolveUtil.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
+import com.google.idea.blaze.base.lang.buildfile.psi.ForStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.google.idea.blaze.base.lang.buildfile.psi.StatementList;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.util.Processor;
+import javax.annotation.Nullable;
+
+/** Utilities methods for resolving references */
+public class ResolveUtil {
+
+ /** Walks up PSI tree of local file, checking PsiNamedElements */
+ public static void searchInScope(PsiElement originalElement, Processor<BuildElement> processor) {
+ // TODO: Handle list comprehension (where variable is defined *later* in the code)
+ boolean topLevelScope = true;
+ PsiElement element = originalElement;
+ while (!(element instanceof PsiFileSystemItem)) {
+ PsiElement parent = element.getParent();
+ if (parent instanceof BuildFile) {
+ if (!((BuildFile) parent).searchSymbolsInScope(processor, topLevelScope ? element : null)) {
+ return;
+ }
+ } else if (parent instanceof FunctionStatement) {
+ topLevelScope = false;
+ for (Parameter param : ((FunctionStatement) parent).getParameters()) {
+ if (!processor.process(param)) {
+ return;
+ }
+ }
+ } else if (parent instanceof ForStatement) {
+ for (Expression expr : ((ForStatement) parent).getForLoopVariables()) {
+ if (expr instanceof TargetExpression && !processor.process(expr)) {
+ return;
+ }
+ }
+ } else if (parent instanceof StatementList) {
+ if (!visitChildAssignmentStatements((BuildElement) parent, (Processor) processor)) {
+ return;
+ }
+ }
+ element = parent;
+ }
+ }
+
+ /** Walks up PSI tree of local file, checking PsiNamedElements */
+ @Nullable
+ public static PsiNamedElement findInScope(PsiElement element, String name) {
+ PsiNamedElement[] resultHolder = new PsiNamedElement[1];
+ Processor<BuildElement> processor =
+ buildElement -> {
+ if (buildElement == element) {
+ return true;
+ }
+ if (buildElement instanceof PsiNamedElement && name.equals(buildElement.getName())) {
+ resultHolder[0] = (PsiNamedElement) buildElement;
+ return false;
+ } else if (buildElement instanceof StringLiteral) {
+ StringLiteral stringLiteral = (StringLiteral) buildElement;
+ if (name.equals(stringLiteral.getStringContents())) {
+ PsiElement referencedSymbol = stringLiteral.getReferencedElement();
+ if (referencedSymbol instanceof PsiNamedElement) {
+ resultHolder[0] = (PsiNamedElement) referencedSymbol;
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+ searchInScope(element, processor);
+ return resultHolder[0];
+ }
+
+ /** @return false if processing was stopped */
+ public static boolean visitChildAssignmentStatements(
+ BuildElement parent, Processor<TargetExpression> processor) {
+ for (AssignmentStatement stmt : parent.childrenOfClass(AssignmentStatement.class)) {
+ TargetExpression target = stmt.getLeftHandSideExpression();
+ if (target != null && !processor.process(target)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Nullable
+ public static TargetExpression searchChildAssignmentStatements(BuildElement parent, String name) {
+ TargetExpression[] resultHolder = new TargetExpression[1];
+ visitChildAssignmentStatements(
+ parent,
+ targetExpr -> {
+ if (name.equals(targetExpr.getName())) {
+ resultHolder[0] = targetExpr;
+ return false;
+ }
+ return true;
+ });
+ return resultHolder[0];
+ }
+
+ /** @return false if processing was stopped */
+ public static boolean visitLoadedSymbols(BuildFile file, Processor<BuildElement> processor) {
+ for (LoadStatement loadStatement : file.findChildrenByClass(LoadStatement.class)) {
+ for (StringLiteral symbol : loadStatement.getImportedSymbolElements()) {
+ if (!processor.process(symbol)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the element we're searching for is represented by a file or directory.<br>
+ * e.g. a java class PSI element, or an actual PsiFile element.
+ */
+ @Nullable
+ public static PsiFileSystemItem asFileSystemItemSearch(PsiElement elementToSearch) {
+ if (elementToSearch instanceof PsiFileSystemItem) {
+ return (PsiFileSystemItem) elementToSearch;
+ }
+ return asFileSearch(elementToSearch);
+ }
+
+ /**
+ * Checks if the element we're searching for is represented by a file.<br>
+ * e.g. a java class PSI element, or an actual PsiFile element.
+ */
+ @Nullable
+ public static PsiFile asFileSearch(PsiElement elementToSearch) {
+ if (elementToSearch instanceof PsiFile) {
+ return (PsiFile) elementToSearch;
+ }
+ for (PsiFileProvider provider : PsiFileProvider.EP_NAME.getExtensions()) {
+ PsiFile file = provider.asFileSearch(elementToSearch);
+ if (file != null) {
+ return file;
+ }
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/stubs/BuildFileStubBuilder.java b/base/src/com/google/idea/blaze/base/lang/buildfile/stubs/BuildFileStubBuilder.java
new file mode 100644
index 0000000..73d1e58
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/stubs/BuildFileStubBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.stubs;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.stubs.BinaryFileStubBuilder;
+import com.intellij.psi.stubs.Stub;
+import com.intellij.util.indexing.FileContent;
+import org.jetbrains.annotations.Nullable;
+
+/** Empty stub builder to suppress errors when IntelliJ is looking for stubs. */
+public class BuildFileStubBuilder implements BinaryFileStubBuilder {
+ private static final int STUB_VERSION = 0;
+
+ @Override
+ public boolean acceptsFile(VirtualFile file) {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public Stub buildStubTree(FileContent fileContent) {
+ return null;
+ }
+
+ @Override
+ public int getStubVersion() {
+ return STUB_VERSION;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/sync/BuildLangSyncPlugin.java b/base/src/com/google/idea/blaze/base/lang/buildfile/sync/BuildLangSyncPlugin.java
new file mode 100644
index 0000000..5bd69c7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/sync/BuildLangSyncPlugin.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
+import com.google.repackaged.protobuf.InvalidProtocolBufferException;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
+
+/** Updates the language specification during the blaze sync process */
+public class BuildLangSyncPlugin extends BlazeSyncPlugin.Adapter {
+
+ private static final Logger LOG = Logger.getInstance(BuildLangSyncPlugin.class);
+
+ @Override
+ public void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {
+
+ LanguageSpecResult spec =
+ getBuildLanguageSpec(project, workspaceRoot, previousSyncState, context);
+ if (spec != null) {
+ syncStateBuilder.put(LanguageSpecResult.class, spec);
+ }
+ }
+
+ @Nullable
+ private static LanguageSpecResult getBuildLanguageSpec(
+ Project project,
+ WorkspaceRoot workspace,
+ @Nullable SyncState previousSyncState,
+ BlazeContext parentContext) {
+ LanguageSpecResult oldResult =
+ previousSyncState != null ? previousSyncState.get(LanguageSpecResult.class) : null;
+ if (oldResult != null && !oldResult.shouldRecalculateSpec()) {
+ return oldResult;
+ }
+ LanguageSpecResult result =
+ Scope.push(
+ parentContext,
+ (context) -> {
+ context.push(new TimingScope("BUILD language spec"));
+ BuildLanguageSpec spec = parseLanguageSpec(project, workspace, context);
+ if (spec != null) {
+ return new LanguageSpecResult(spec, System.currentTimeMillis());
+ }
+ return null;
+ });
+ return result != null ? result : oldResult;
+ }
+
+ @Nullable
+ private static BuildLanguageSpec parseLanguageSpec(
+ Project project, WorkspaceRoot workspace, BlazeContext context) {
+ try {
+ // it's wasteful converting to a string and back, but uses existing code,
+ // and has a very minor cost (this is only run once per workspace)
+ ListenableFuture<byte[]> future =
+ BlazeInfo.getInstance()
+ .runBlazeInfoGetBytes(
+ context,
+ Blaze.getBuildSystem(project),
+ workspace,
+ ImmutableList.of(),
+ BlazeInfo.BUILD_LANGUAGE);
+
+ return BuildLanguageSpec.fromProto(Build.BuildLanguage.parseFrom(future.get()));
+
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ } catch (ExecutionException | InvalidProtocolBufferException | NullPointerException e) {
+ if (!ApplicationManager.getApplication().isUnitTestMode()) {
+ LOG.error(e);
+ }
+ return null;
+ } catch (Throwable e) {
+ LOG.error(e);
+ return null;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/sync/LanguageSpecResult.java b/base/src/com/google/idea/blaze/base/lang/buildfile/sync/LanguageSpecResult.java
new file mode 100644
index 0000000..49da1b6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/sync/LanguageSpecResult.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.sync;
+
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import java.io.Serializable;
+
+/** The BUILD language specifications, serialized along with the sync data. */
+public class LanguageSpecResult implements Serializable {
+
+ private static final long ONE_DAY_IN_MILLISECONDS = 1000 * 60 * 60 * 24;
+
+ public final BuildLanguageSpec spec;
+ public final long timestampMillis;
+
+ public LanguageSpecResult(BuildLanguageSpec spec, long timestampMillis) {
+ this.spec = spec;
+ this.timestampMillis = timestampMillis;
+ }
+
+ public boolean shouldRecalculateSpec() {
+ return System.currentTimeMillis() - timestampMillis > ONE_DAY_IN_MILLISECONDS;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildAnnotator.java
new file mode 100644
index 0000000..84028f8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildAnnotator.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.validation;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementVisitor;
+import com.intellij.lang.annotation.AnnotationHolder;
+import com.intellij.lang.annotation.Annotator;
+import com.intellij.psi.PsiElement;
+
+/** Base class for Annotator implementations using type-specific methods in BuildElementVisitor */
+public abstract class BuildAnnotator extends BuildElementVisitor implements Annotator {
+
+ private volatile AnnotationHolder holder;
+
+ protected AnnotationHolder getHolder() {
+ return holder;
+ }
+
+ @Override
+ public synchronized void annotate(PsiElement element, AnnotationHolder holder) {
+ this.holder = holder;
+ try {
+ element.accept(this);
+ } finally {
+ this.holder = null;
+ }
+ }
+
+ protected void markError(PsiElement element, String message) {
+ getHolder().createErrorAnnotation(element, message);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/ErrorAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/ErrorAnnotator.java
new file mode 100644
index 0000000..58e7476
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/ErrorAnnotator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.validation;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.references.LabelReference;
+import com.intellij.psi.PsiElement;
+
+/**
+ * Additional error annotations, post parsing.
+ *
+ * <p>This has been turned off because it's unusable. BuildFile is re-parsed *every* time it's
+ * touched, and is never cached. Until this is fixed, we can't run any annotators touching the file.
+ *
+ * <p>One option: try moving all expensive checks to 'visitFile', so they're not run in parallel
+ */
+public class ErrorAnnotator extends BuildAnnotator {
+
+ @Override
+ public void visitLoadStatement(LoadStatement node) {
+ StringLiteral[] strings = node.getChildStrings();
+ if (strings.length == 0) {
+ return;
+ }
+ PsiElement skylarkRef = new LabelReference(strings[0], false).resolve();
+ if (skylarkRef == null) {
+ markError(strings[0], "Cannot find this Skylark module");
+ return;
+ }
+ if (!(skylarkRef instanceof BuildFile)) {
+ markError(strings[0], strings[0].getText() + " is not a Skylark module");
+ return;
+ }
+ if (strings.length == 1) {
+ markError(node, "No definitions imported from Skylark module");
+ return;
+ }
+ BuildFile skylarkModule = (BuildFile) skylarkRef;
+ for (int i = 1; i < strings.length; i++) {
+ String text = strings[i].getStringContents();
+ FunctionStatement fn = skylarkModule.findDeclaredFunction(text);
+ if (fn == null) {
+ markError(
+ strings[i],
+ "Function '" + text + "' not found in Skylark module " + skylarkModule.getFileName());
+ }
+ }
+ }
+
+ @Override
+ public void visitFuncallExpression(FuncallExpression node) {
+ FunctionStatement function = (FunctionStatement) node.getReferencedElement();
+ if (function == null) {
+ // likely a built-in rule. We don't yet recognize these.
+ return;
+ }
+ // check keyword args match function parameters
+ ParameterList params = function.getParameterList();
+ if (params == null || params.hasStarStar()) {
+ return;
+ }
+ for (Argument arg : node.getArguments()) {
+ if (arg instanceof Argument.Keyword) {
+ String name = arg.getName();
+ if (name != null && params.findParameterByName(name) == null) {
+ markError(
+ arg,
+ "No parameter found in '" + node.getFunctionName() + "' with name '" + name + "'");
+ }
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobErrorAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobErrorAnnotator.java
new file mode 100644
index 0000000..9cf5e7b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobErrorAnnotator.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.validation;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.ListLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.LiteralExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.psi.PsiElement;
+import javax.annotation.Nullable;
+
+/** Checks that glob expressions are valid */
+public class GlobErrorAnnotator extends BuildAnnotator {
+
+ @Override
+ public void visitGlobExpression(GlobExpression node) {
+ Argument[] args = node.getArguments();
+ boolean hasIncludes = false;
+ for (int i = 0; i < args.length; i++) {
+ Argument arg = args[i];
+ String name = arg instanceof Argument.Keyword ? arg.getName() : null;
+ if ("include".equals(name) || (arg instanceof Argument.Positional && i == 0)) {
+ hasIncludes = checkIncludes(arg.getValue());
+ } else if ("exclude".equals(name)) {
+ checkListContents("exclude", arg.getValue());
+ } else if ("exclude_directories".equals(name)) {
+ checkExcludeDirsNode(arg);
+ } else {
+ markError(arg, "Unrecognized glob argument");
+ }
+ }
+ if (!hasIncludes) {
+ markError(node, "Glob expression must contain at least one included string");
+ }
+ }
+
+ private void checkExcludeDirsNode(Argument arg) {
+ Expression value = arg.getValue();
+ if (value == null || !(value.getText().equals("0") || value.getText().equals("1"))) {
+ markError(arg, "exclude_directories parameter to glob must be 0 or 1");
+ }
+ }
+
+ /** @return true if glob contains at least one included string */
+ private boolean checkIncludes(@Nullable Expression expr) {
+ return checkListContents("include", expr);
+ }
+
+ /**
+ * @return false if 'expr' is known with certainty not to be a list containing at least one string
+ */
+ private boolean checkListContents(String keyword, @Nullable Expression expr) {
+ if (expr == null) {
+ return false;
+ }
+ PsiElement rootElement = PsiUtils.getReferencedTargetValue(expr);
+ if (rootElement instanceof ListLiteral) {
+ return validatePatternList(keyword, ((ListLiteral) rootElement).getChildExpressions());
+ }
+ if (rootElement instanceof ReferenceExpression || !possiblyValidListLiteral(rootElement)) {
+ markError(expr, "Glob parameter '" + keyword + "' must be a list of strings");
+ return false;
+ }
+ // might possibly be a list, default to not showing any errors
+ return true;
+ }
+
+ /** @return false if 'expr' is known with certainty not to contain at least one string */
+ private boolean validatePatternList(String keyword, Expression[] expressions) {
+ boolean possiblyHasString = false;
+ for (Expression expr : expressions) {
+ PsiElement rootElement = PsiUtils.getReferencedTargetValue(expr);
+ if (rootElement instanceof ReferenceExpression || !possiblyValidStringLiteral(rootElement)) {
+ markError(expr, "Glob parameter '" + keyword + "' must be a list of strings");
+ } else {
+ possiblyHasString = true;
+ if (rootElement instanceof StringLiteral) {
+ validatePattern((StringLiteral) rootElement);
+ }
+ }
+ }
+ return possiblyHasString;
+ }
+
+ private void validatePattern(StringLiteral pattern) {
+ String error = GlobPatternValidator.validate(pattern.getStringContents());
+ if (error != null) {
+ markError(pattern, error);
+ }
+ }
+
+ /** Returns false iff we know with certainty that the element cannot resolve to a list literal. */
+ private static boolean possiblyValidListLiteral(PsiElement element) {
+ if (element instanceof ListLiteral || element instanceof GlobExpression) {
+ return true; // these evaluate directly to list literals
+ }
+ if (element instanceof LiteralExpression) {
+ return false; // all other literals cannot evaluate to a ListLiteral
+ }
+ if (element instanceof LoadStatement || element instanceof FunctionStatement) {
+ return false;
+ }
+ // everything else treated as possibly evaluating to a list
+ return true;
+ }
+
+ /**
+ * Returns false iff we know with certainty that the element cannot resolve to a string literal.
+ */
+ private static boolean possiblyValidStringLiteral(PsiElement element) {
+ if (element instanceof StringLiteral) {
+ return true;
+ }
+ if (element instanceof LiteralExpression) {
+ return false; // all other literals cannot evaluate to a StringLiteral
+ }
+ if (element instanceof LoadStatement
+ || element instanceof FunctionStatement
+ || element instanceof GlobExpression) {
+ return false;
+ }
+ // everything else treated as possibly evaluating to a string
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobPatternValidator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobPatternValidator.java
new file mode 100644
index 0000000..c82d736
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobPatternValidator.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.validation;
+
+import com.google.common.base.Splitter;
+import javax.annotation.Nullable;
+
+/**
+ * Support for resolving globs.
+ *
+ * <p>
+ */
+public class GlobPatternValidator {
+
+ /**
+ * Validate a single glob pattern. If it's invalid, returns an error message. Otherwise, returns
+ * null.
+ *
+ * <p>
+ */
+ @Nullable
+ public static String validate(String pattern) {
+ String error = checkPatternForError(pattern);
+ if (error != null) {
+ return "Invalid glob pattern: " + error;
+ }
+ return null;
+ }
+
+ @Nullable
+ private static String checkPatternForError(String pattern) {
+ if (pattern.isEmpty()) {
+ return "pattern cannot be empty";
+ }
+ if (pattern.charAt(0) == '/') {
+ return "pattern cannot be absolute";
+ }
+ for (int i = 0; i < pattern.length(); i++) {
+ char c = pattern.charAt(i);
+ switch (c) {
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ return "illegal character '" + c + "'";
+ }
+ }
+ Iterable<String> segments = Splitter.on('/').split(pattern);
+ for (String segment : segments) {
+ if (segment.isEmpty()) {
+ return "empty segment not permitted";
+ }
+ if (segment.equals(".") || segment.equals("..")) {
+ return "segment '" + segment + "' not permitted";
+ }
+ if (segment.contains("**") && !segment.equals("**")) {
+ return "recursive wildcard must be its own segment";
+ }
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/HighlightingAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/HighlightingAnnotator.java
new file mode 100644
index 0000000..c2a3f40
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/HighlightingAnnotator.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.validation;
+
+import com.google.idea.blaze.base.lang.buildfile.highlighting.BuildSyntaxHighlighter;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.annotation.Annotation;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+
+/**
+ * Additional syntax highlighting, based on parsed PSI elements TODO: Special highlighting for blaze
+ * built-in names? (e.g. android_library) -- see PyBuiltInAnnotator
+ */
+public class HighlightingAnnotator extends BuildAnnotator {
+
+ @Override
+ public void visitParameter(Parameter node) {
+ FunctionStatement function = PsiTreeUtil.getParentOfType(node, FunctionStatement.class);
+ if (function != null) {
+ PsiElement anchor = node.hasDefaultValue() ? node.getFirstChild() : node;
+ final Annotation annotation = getHolder().createInfoAnnotation(anchor, null);
+ annotation.setTextAttributes(BuildSyntaxHighlighter.BUILD_PARAMETER);
+ }
+ }
+
+ @Override
+ public void visitKeywordArgument(Argument.Keyword node) {
+ ASTNode keywordNode = node.getNameNode();
+ if (keywordNode != null) {
+ Annotation annotation = getHolder().createInfoAnnotation(keywordNode, null);
+ annotation.setTextAttributes(BuildSyntaxHighlighter.BUILD_KEYWORD_ARG);
+ }
+ }
+
+ @Override
+ public void visitFunctionStatement(FunctionStatement node) {
+ ASTNode nameNode = node.getNameNode();
+ if (nameNode != null) {
+ Annotation annotation = getHolder().createInfoAnnotation(nameNode, null);
+ annotation.setTextAttributes(BuildSyntaxHighlighter.BUILD_FN_DEFINITION);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewElement.java
new file mode 100644
index 0000000..1f71b8c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewElement.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.views;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.ListLiteral;
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
+import java.util.Collection;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Handles nodes in Structure View. */
+public class BuildStructureViewElement extends PsiTreeElementBase<BuildElement> {
+
+ private final BuildElement element;
+
+ public BuildStructureViewElement(BuildElement element) {
+ super(element);
+ this.element = element;
+ }
+
+ @NotNull
+ @Override
+ public Collection<StructureViewTreeElement> getChildrenBase() {
+ if (element instanceof ListLiteral) {}
+
+ if (!(element instanceof BuildFile)) {
+ // TODO: show inner build rules in Skylark .bzl extensions
+ return ImmutableList.of();
+ }
+ ImmutableList.Builder<StructureViewTreeElement> builder = ImmutableList.builder();
+ for (BuildElement child : ((BuildFile) element).findChildrenByClass(BuildElement.class)) {
+ builder.add(new BuildStructureViewElement(child));
+ }
+ return builder.build();
+ }
+
+ @Nullable
+ @Override
+ public String getPresentableText() {
+ return element.getPresentableText();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewFactory.java b/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewFactory.java
new file mode 100644
index 0000000..0d66994
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.views;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.ide.structureView.StructureViewBuilder;
+import com.intellij.ide.structureView.StructureViewModel;
+import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
+import com.intellij.lang.PsiStructureViewFactory;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiFile;
+import javax.annotation.Nullable;
+
+/** PsiStructureViewFactory implementation */
+public class BuildStructureViewFactory implements PsiStructureViewFactory {
+ @Override
+ @Nullable
+ public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
+ if (!(psiFile instanceof BuildFile)) {
+ return null;
+ }
+ return new TreeBasedStructureViewBuilder() {
+ @Override
+ public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
+ return new BuildStructureViewModel((BuildFile) psiFile, editor);
+ }
+ };
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewModel.java b/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewModel.java
new file mode 100644
index 0000000..b0f53f6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewModel.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.views;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.intellij.ide.structureView.StructureViewModel;
+import com.intellij.ide.structureView.StructureViewModelBase;
+import com.intellij.ide.structureView.StructureViewTreeElement;
+import com.intellij.ide.util.treeView.smartTree.Sorter;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiFile;
+import javax.annotation.Nullable;
+
+/**
+ * Implements structure view for a BUILD file. TODO: Include inner build rules for Skylark files
+ * (when we can identify them -- e.g. via list of blaze rule types)
+ */
+public class BuildStructureViewModel extends StructureViewModelBase
+ implements StructureViewModel.ElementInfoProvider, StructureViewModel.ExpandInfoProvider {
+
+ public BuildStructureViewModel(BuildFile psiFile, @Nullable Editor editor) {
+ this(psiFile, editor, new BuildStructureViewElement(psiFile));
+ withSorters(Sorter.ALPHA_SORTER);
+ withSuitableClasses(FunctionStatement.class, LoadStatement.class, FuncallExpression.class);
+ }
+
+ public BuildStructureViewModel(
+ PsiFile file, @Nullable Editor editor, StructureViewTreeElement element) {
+ super(file, editor, element);
+ }
+
+ @Override
+ public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
+ final Object value = element.getValue();
+ return value instanceof BuildFile;
+ }
+
+ @Override
+ public boolean isAlwaysLeaf(StructureViewTreeElement element) {
+ return element.getValue() instanceof TargetExpression;
+ }
+
+ @Override
+ public boolean shouldEnterElement(Object element) {
+ return element instanceof BuildFile; // only show top-level elements
+ }
+
+ @Override
+ public boolean isAutoExpand(StructureViewTreeElement element) {
+ return element.getValue() instanceof PsiFile;
+ }
+
+ @Override
+ public boolean isSmartExpand() {
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/completion/AdditionalLanguagesCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/projectview/completion/AdditionalLanguagesCompletionContributor.java
new file mode 100644
index 0000000..4cf2f36
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/completion/AdditionalLanguagesCompletionContributor.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiListSection;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection;
+import com.intellij.codeInsight.completion.AutoCompletionContext;
+import com.intellij.codeInsight.completion.AutoCompletionDecision;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.patterns.StandardPatterns;
+import com.intellij.util.ProcessingContext;
+
+/** Code completion for additional language types. */
+public class AdditionalLanguagesCompletionContributor extends CompletionContributor {
+
+ @Override
+ public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ // auto-insert the obvious only case; else show other cases.
+ final LookupElement[] items = context.getItems();
+ if (items.length == 1) {
+ return AutoCompletionDecision.insertItem(items[0]);
+ }
+ return AutoCompletionDecision.SHOW_LOOKUP;
+ }
+
+ public AdditionalLanguagesCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement()
+ .withLanguage(ProjectViewLanguage.INSTANCE)
+ .inside(
+ psiElement(ProjectViewPsiListSection.class)
+ .withText(
+ StandardPatterns.string()
+ .startsWith(AdditionalLanguagesSection.KEY.getName()))),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters,
+ ProcessingContext context,
+ CompletionResultSet result) {
+ for (LanguageClass type : LanguageClass.values()) {
+ result.addElement(LookupElementBuilder.create(type.getName()));
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/completion/ProjectViewKeywordCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/projectview/completion/ProjectViewKeywordCompletionContributor.java
new file mode 100644
index 0000000..f1bf85a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/completion/ProjectViewKeywordCompletionContributor.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.projectview.section.sections.Sections;
+import com.intellij.codeInsight.completion.AutoCompletionContext;
+import com.intellij.codeInsight.completion.AutoCompletionDecision;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.completion.InsertHandler;
+import com.intellij.codeInsight.completion.InsertionContext;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.ProcessingContext;
+import java.util.List;
+import org.jetbrains.annotations.Nullable;
+
+/** Completes project view section names. */
+public class ProjectViewKeywordCompletionContributor extends CompletionContributor {
+
+ @Override
+ public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ // auto-insert the obvious only case; else show other cases.
+ final LookupElement[] items = context.getItems();
+ if (items.length == 1) {
+ return AutoCompletionDecision.insertItem(items[0]);
+ }
+ return AutoCompletionDecision.SHOW_LOOKUP;
+ }
+
+ public ProjectViewKeywordCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement()
+ .withLanguage(ProjectViewLanguage.INSTANCE)
+ .withElementType(ProjectViewTokenType.IDENTIFIERS)
+ .andOr(psiElement().afterLeaf("\n"), psiElement().afterLeaf(psiElement().isNull())),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters,
+ ProcessingContext context,
+ CompletionResultSet result) {
+ result.addAllElements(keywordLookups);
+ }
+ });
+ }
+
+ private static final List<LookupElement> keywordLookups = getLookups();
+
+ private static List<LookupElement> getLookups() {
+ ImmutableList.Builder<LookupElement> list = ImmutableList.builder();
+ for (SectionParser parser : Sections.getUndeprecatedParsers()) {
+ list.add(forSectionParser(parser));
+ }
+ return list.build();
+ }
+
+ private static LookupElement forSectionParser(SectionParser parser) {
+ return LookupElementBuilder.create(parser.getName()).withInsertHandler(insertDivider(parser));
+ }
+
+ private static InsertHandler<LookupElement> insertDivider(SectionParser parser) {
+ return (context, item) -> {
+ Editor editor = context.getEditor();
+ Document document = editor.getDocument();
+ context.commitDocument();
+
+ String nextTokenText = findNextTokenText(context);
+ if (nextTokenText == null || nextTokenText == "\n") {
+ document.insertString(context.getTailOffset(), getDivider(parser));
+ editor.getCaretModel().moveToOffset(context.getTailOffset());
+ }
+ };
+ }
+
+ private static String getDivider(SectionParser parser) {
+ if (parser instanceof ListSectionParser) {
+ return ":\n ";
+ }
+ char div = ((ScalarSectionParser) parser).getDivider();
+ return div == ' ' ? String.valueOf(div) : (div + " ");
+ }
+
+ @Nullable
+ protected static String findNextTokenText(final InsertionContext context) {
+ final PsiFile file = context.getFile();
+ PsiElement element = file.findElementAt(context.getTailOffset());
+ while (element != null && element.getTextLength() == 0) {
+ ASTNode next = element.getNode().getTreeNext();
+ element = next != null ? next.getPsi() : null;
+ }
+ return element != null ? element.getText() : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/completion/WorkspaceTypeCompletionContributor.java b/base/src/com/google/idea/blaze/base/lang/projectview/completion/WorkspaceTypeCompletionContributor.java
new file mode 100644
index 0000000..47b45e9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/completion/WorkspaceTypeCompletionContributor.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.completion;
+
+import static com.intellij.patterns.PlatformPatterns.psiElement;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiScalarSection;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
+import com.intellij.codeInsight.completion.AutoCompletionContext;
+import com.intellij.codeInsight.completion.AutoCompletionDecision;
+import com.intellij.codeInsight.completion.CompletionContributor;
+import com.intellij.codeInsight.completion.CompletionParameters;
+import com.intellij.codeInsight.completion.CompletionProvider;
+import com.intellij.codeInsight.completion.CompletionResultSet;
+import com.intellij.codeInsight.completion.CompletionType;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.util.ProcessingContext;
+
+/** Code completion for workspace types. */
+public class WorkspaceTypeCompletionContributor extends CompletionContributor {
+
+ @Override
+ public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
+ // auto-insert the obvious only case; else show other cases.
+ final LookupElement[] items = context.getItems();
+ if (items.length == 1) {
+ return AutoCompletionDecision.insertItem(items[0]);
+ }
+ return AutoCompletionDecision.SHOW_LOOKUP;
+ }
+
+ public WorkspaceTypeCompletionContributor() {
+ extend(
+ CompletionType.BASIC,
+ psiElement()
+ .withLanguage(ProjectViewLanguage.INSTANCE)
+ .inside(ProjectViewPsiScalarSection.class)
+ .afterLeaf(psiElement().withText(":").afterLeaf(WorkspaceTypeSection.KEY.getName())),
+ new CompletionProvider<CompletionParameters>() {
+ @Override
+ protected void addCompletions(
+ CompletionParameters parameters,
+ ProcessingContext context,
+ CompletionResultSet result) {
+ for (WorkspaceType type : WorkspaceType.values()) {
+ result.addElement(LookupElementBuilder.create(type.getName()));
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCommenter.java b/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCommenter.java
new file mode 100644
index 0000000..09aaa68
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCommenter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.formatting;
+
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.intellij.lang.CodeDocumentationAwareCommenter;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.Nullable;
+
+/** Supports (un)commenting lines via IntelliJ */
+public class ProjectViewCommenter implements CodeDocumentationAwareCommenter {
+
+ @Nullable
+ @Override
+ public String getLineCommentPrefix() {
+ return "#";
+ }
+
+ @Nullable
+ @Override
+ public String getBlockCommentPrefix() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getBlockCommentSuffix() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getCommentedBlockCommentPrefix() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getCommentedBlockCommentSuffix() {
+ return null;
+ }
+
+ @Override
+ public IElementType getLineCommentTokenType() {
+ return ProjectViewTokenType.COMMENT;
+ }
+
+ @Override
+ public IElementType getBlockCommentTokenType() {
+ return null;
+ }
+
+ @Override
+ public IElementType getDocumentationCommentTokenType() {
+ return null;
+ }
+
+ @Override
+ public String getDocumentationCommentPrefix() {
+ return null;
+ }
+
+ @Override
+ public String getDocumentationCommentLinePrefix() {
+ return null;
+ }
+
+ @Override
+ public String getDocumentationCommentSuffix() {
+ return null;
+ }
+
+ @Override
+ public boolean isDocumentationComment(PsiComment element) {
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewEnterHandler.java b/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewEnterHandler.java
new file mode 100644
index 0000000..58988c1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewEnterHandler.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.formatting;
+
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiFile;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter;
+import com.intellij.ide.DataManager;
+import com.intellij.injected.editor.EditorWindow;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.LogicalPosition;
+import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
+import com.intellij.openapi.editor.actions.SplitLineAction;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
+
+/** Inserts indents as appropriate when enter is pressed. */
+public class ProjectViewEnterHandler extends EnterHandlerDelegateAdapter {
+
+ @Override
+ public Result preprocessEnter(
+ PsiFile file,
+ Editor editor,
+ Ref<Integer> caretOffset,
+ Ref<Integer> caretAdvance,
+ DataContext dataContext,
+ EditorActionHandler originalHandler) {
+ int offset = caretOffset.get();
+ if (editor instanceof EditorWindow) {
+ file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
+ editor = InjectedLanguageUtil.getTopLevelEditor(editor);
+ offset = editor.getCaretModel().getOffset();
+ }
+ if (!isApplicable(file, dataContext) || !insertIndent(file, offset)) {
+ return Result.Continue;
+ }
+ int indent = SectionParser.INDENT;
+
+ editor.getCaretModel().moveToOffset(offset);
+ Document doc = editor.getDocument();
+ PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
+
+ originalHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
+ LogicalPosition position = editor.getCaretModel().getLogicalPosition();
+ if (position.column < indent) {
+ String spaces = StringUtil.repeatSymbol(' ', indent - position.column);
+ doc.insertString(editor.getCaretModel().getOffset(), spaces);
+ }
+ editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(position.line, indent));
+ return Result.Stop;
+ }
+
+ private static boolean isApplicable(PsiFile file, DataContext dataContext) {
+ if (!(file instanceof ProjectViewPsiFile)) {
+ return false;
+ }
+ Boolean isSplitLine =
+ DataManager.getInstance().loadFromDataContext(dataContext, SplitLineAction.SPLIT_LINE_KEY);
+ if (isSplitLine != null) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean insertIndent(PsiFile file, int offset) {
+ if (offset == 0) {
+ return false;
+ }
+ PsiElement element = file.findElementAt(offset - 1);
+ while (element != null && element instanceof PsiWhiteSpace) {
+ element = element.getPrevSibling();
+ }
+ if (element == null || element.getText() != ":") {
+ return false;
+ }
+ ASTNode prev = element.getNode().getTreePrev();
+ return prev != null && prev.getElementType() == ProjectViewTokenType.LIST_KEYWORD;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighter.java b/base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighter.java
new file mode 100644
index 0000000..01ec2fd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.highlighting;
+
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.IDENTIFIER;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.KEYWORD;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.LINE_COMMENT;
+import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.SEMICOLON;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexer;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
+import com.intellij.psi.tree.IElementType;
+import java.util.Map;
+
+/**
+ * This class maps tokens to highlighting attributes. Each attribute contains the font properties.
+ */
+public class ProjectViewSyntaxHighlighter extends SyntaxHighlighterBase {
+
+ private static final Map<IElementType, TextAttributesKey> keys =
+ ImmutableMap.of(
+ ProjectViewTokenType.COMMENT, LINE_COMMENT,
+ ProjectViewTokenType.COLON, SEMICOLON,
+ ProjectViewTokenType.IDENTIFIER, IDENTIFIER,
+ ProjectViewTokenType.LIST_KEYWORD, KEYWORD,
+ ProjectViewTokenType.SCALAR_KEYWORD, KEYWORD);
+
+ @Override
+ public Lexer getHighlightingLexer() {
+ return new ProjectViewLexer();
+ }
+
+ @Override
+ public TextAttributesKey[] getTokenHighlights(IElementType iElementType) {
+ return pack(keys.get(iElementType));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighterFactory.java b/base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighterFactory.java
new file mode 100644
index 0000000..96c4b25
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighterFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.highlighting;
+
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Factory for BuildSyntaxHighlighter */
+public class ProjectViewSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
+
+ @Override
+ public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) {
+ return new ProjectViewSyntaxHighlighter();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileType.java b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileType.java
new file mode 100644
index 0000000..558a60e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileType.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.language;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import icons.BlazeIcons;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Blaze project view file type */
+public class ProjectViewFileType extends LanguageFileType {
+
+ public static final ProjectViewFileType INSTANCE = new ProjectViewFileType();
+
+ private ProjectViewFileType() {
+ super(ProjectViewLanguage.INSTANCE);
+ }
+
+ @Override
+ public String getName() {
+ // Warning: this is conflated with Language.myID in several places...
+ // They must be identical.
+ return ProjectViewLanguage.INSTANCE.getID();
+ }
+
+ @Override
+ public String getDescription() {
+ return Blaze.defaultBuildSystemName() + " project view files";
+ }
+
+ @Override
+ public String getDefaultExtension() {
+ // Ideally we'd return a build-system specific extension here, but that would require
+ // a hack to guess the current project, or choosing either the blaze or bazel
+ // extension. Instead don't specify a default extension.
+ return "";
+ }
+
+ @Override
+ @Nullable
+ public Icon getIcon() {
+ return BlazeIcons.Blaze;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileTypeFactory.java b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileTypeFactory.java
new file mode 100644
index 0000000..5e8408a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileTypeFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.language;
+
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.intellij.openapi.fileTypes.ExtensionFileNameMatcher;
+import com.intellij.openapi.fileTypes.FileNameMatcher;
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+/** Factory for ProjectViewFileType */
+public class ProjectViewFileTypeFactory extends FileTypeFactory {
+
+ @Override
+ public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
+ FileNameMatcher[] matchers =
+ ProjectViewStorageManager.VALID_EXTENSIONS
+ .stream()
+ .map(ExtensionFileNameMatcher::new)
+ .toArray(ExtensionFileNameMatcher[]::new);
+ consumer.consume(ProjectViewFileType.INSTANCE, matchers);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewKeywords.java b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewKeywords.java
new file mode 100644
index 0000000..9c7cf8d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewKeywords.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.language;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionParser.ItemType;
+import com.google.idea.blaze.base.projectview.section.sections.Sections;
+
+/** Section parser keywords accepted in project view files. */
+public class ProjectViewKeywords {
+
+ public static final ImmutableMap<String, ListSectionParser> LIST_KEYWORD_MAP =
+ getListKeywordMap();
+ public static final ImmutableMap<String, ScalarSectionParser> SCALAR_KEYWORD_MAP =
+ getScalarKeywordMap();
+ public static final ImmutableMap<String, ItemType> ITEM_TYPES = getItemTypes();
+
+ private static ImmutableMap<String, ListSectionParser> getListKeywordMap() {
+ ImmutableMap.Builder<String, ListSectionParser> builder = ImmutableMap.builder();
+ for (SectionParser parser : Sections.getParsers()) {
+ if (parser instanceof ListSectionParser) {
+ builder.put(parser.getName(), (ListSectionParser) parser);
+ }
+ }
+ return builder.build();
+ }
+
+ /** We get the parser so we have access to both the keyword and the divider char. */
+ private static ImmutableMap<String, ScalarSectionParser> getScalarKeywordMap() {
+ ImmutableMap.Builder<String, ScalarSectionParser> builder = ImmutableMap.builder();
+ for (SectionParser parser : Sections.getParsers()) {
+ if (parser instanceof ScalarSectionParser) {
+ builder.put(parser.getName(), (ScalarSectionParser) parser);
+ }
+ }
+ return builder.build();
+ }
+
+ private static ImmutableMap<String, ItemType> getItemTypes() {
+ ImmutableMap.Builder<String, ItemType> builder = ImmutableMap.builder();
+ for (SectionParser parser : Sections.getParsers()) {
+ builder.put(parser.getName(), parser.getItemType());
+ }
+ return builder.build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewLanguage.java b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewLanguage.java
new file mode 100644
index 0000000..efde5bf
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewLanguage.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.language;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.lang.Language;
+
+/** Blaze project file language */
+public class ProjectViewLanguage extends Language {
+
+ public static final ProjectViewLanguage INSTANCE = new ProjectViewLanguage();
+
+ private ProjectViewLanguage() {
+ super("projectview");
+ }
+
+ @Override
+ public String getDisplayName() {
+ return Blaze.defaultBuildSystemName() + " project view";
+ }
+
+ @Override
+ public boolean isCaseSensitive() {
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexer.java b/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexer.java
new file mode 100644
index 0000000..6000fad
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexer.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.lexer;
+
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexerBase.Token;
+import com.intellij.lexer.LexerBase;
+import com.intellij.psi.tree.IElementType;
+import java.util.Iterator;
+import java.util.List;
+
+/** Implementation of LexerBase using BuildLexerBase to tokenize the input. */
+public class ProjectViewLexer extends LexerBase {
+
+ private int offsetEnd;
+ private int offsetStart;
+ private CharSequence buffer;
+ private Iterator<Token> tokens;
+ private Token currentToken;
+
+ @Override
+ public void start(CharSequence charSequence, int startOffset, int endOffset, int initialState) {
+ buffer = charSequence;
+ this.offsetEnd = endOffset;
+ this.offsetStart = startOffset;
+
+ ProjectViewLexerBase lexer =
+ new ProjectViewLexerBase(charSequence.subSequence(startOffset, endOffset));
+ checkNoCharactersMissing(
+ charSequence.subSequence(startOffset, endOffset).length(), lexer.getTokens());
+ tokens = lexer.getTokens().iterator();
+ currentToken = null;
+ if (tokens.hasNext()) {
+ currentToken = tokens.next();
+ }
+ }
+
+ /** Temporary debugging code. We need to tokenize every character in the input string. */
+ private static void checkNoCharactersMissing(int totalLength, List<Token> tokens) {
+ if (!tokens.isEmpty() && tokens.get(tokens.size() - 1).right != totalLength) {
+ String error =
+ String.format(
+ "Lengths don't match: %s instead of %s",
+ tokens.get(tokens.size() - 1).right, totalLength);
+ throw new RuntimeException(error);
+ }
+ int start = 0;
+ for (int i = 0; i < tokens.size(); i++) {
+ Token token = tokens.get(i);
+ if (token.left != start) {
+ throw new RuntimeException("Gap/inconsistency at: " + start);
+ }
+ start = token.right;
+ }
+ }
+
+ @Override
+ public int getState() {
+ return 0;
+ }
+
+ @Override
+ public IElementType getTokenType() {
+ if (currentToken != null) {
+ return currentToken.type;
+ }
+ return null;
+ }
+
+ @Override
+ public int getTokenStart() {
+ if (currentToken == null) {
+ return 0;
+ }
+ return currentToken.left + offsetStart;
+ }
+
+ @Override
+ public int getTokenEnd() {
+ if (currentToken == null) {
+ return 0;
+ }
+ return currentToken.right + offsetStart;
+ }
+
+ @Override
+ public void advance() {
+ if (tokens.hasNext()) {
+ currentToken = tokens.next();
+ } else {
+ currentToken = null;
+ }
+ }
+
+ @Override
+ public CharSequence getBufferSequence() {
+ return buffer;
+ }
+
+ @Override
+ public int getBufferEnd() {
+ return offsetEnd;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerBase.java b/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerBase.java
new file mode 100644
index 0000000..e840dcb
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerBase.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.lexer;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewKeywords;
+import java.util.List;
+
+/** Lexer for project view files. */
+public class ProjectViewLexerBase {
+
+ @VisibleForTesting
+ static class Token {
+ final ProjectViewTokenType type;
+ final int left;
+ final int right;
+
+ private Token(ProjectViewTokenType type, int left, int right) {
+ this.type = type;
+ this.left = left;
+ this.right = right;
+ }
+ }
+
+ private final List<Token> tokens;
+
+ // Input buffer and position
+ private final char[] buffer;
+ private int pos;
+
+ private int identifierStart = -1;
+ private boolean lineHasPrecedingNonWhitespaceChar = false;
+
+ public ProjectViewLexerBase(CharSequence input) {
+ this.buffer = input.toString().toCharArray();
+ this.tokens = Lists.newArrayList();
+ this.pos = 0;
+ tokenize();
+ }
+
+ public List<Token> getTokens() {
+ return tokens;
+ }
+
+ /** Performs tokenization of the character buffer of file contents provided to the constructor. */
+ private void tokenize() {
+ while (pos < buffer.length) {
+ char c = buffer[pos];
+ pos++;
+ switch (c) {
+ case '\n':
+ addPrecedingIdentifier(pos - 1);
+ tokens.add(new Token(ProjectViewTokenType.NEWLINE, pos - 1, pos));
+ lineHasPrecedingNonWhitespaceChar = false;
+ break;
+ case ' ':
+ case '\t':
+ case '\r':
+ addPrecedingIdentifier(pos - 1);
+ handleWhitespace();
+ break;
+ case ':':
+ addPrecedingIdentifier(pos - 1);
+ tokens.add(new Token(ProjectViewTokenType.COLON, pos - 1, pos));
+ break;
+ case '#':
+ if (!lineHasPrecedingNonWhitespaceChar) {
+ addPrecedingIdentifier(pos - 1);
+ addCommentLine(pos - 1);
+ break;
+ }
+ // otherwise '#' treated as part of the identifier; intentional fall-through
+ default:
+ lineHasPrecedingNonWhitespaceChar = true;
+ // all other characters combined into an 'identifier' lexical token
+ if (identifierStart == -1) {
+ identifierStart = pos - 1;
+ }
+ }
+ }
+ addPrecedingIdentifier(pos);
+ }
+
+ private void addPrecedingIdentifier(int end) {
+ if (identifierStart != -1) {
+ tokens.add(new Token(getIdentifierToken(identifierStart, end), identifierStart, end));
+ identifierStart = -1;
+ }
+ }
+
+ private void addCommentLine(int start) {
+ while (pos < buffer.length) {
+ char c = buffer[pos];
+ if (c == '\n') {
+ break;
+ }
+ pos++;
+ }
+ tokens.add(new Token(ProjectViewTokenType.COMMENT, start, pos));
+ }
+
+ /**
+ * If the whitespace is followed by an end-of-line comment or a newline, it's combined with those
+ * tokens.
+ */
+ private void handleWhitespace() {
+ int oldPos = pos - 1;
+ while (pos < buffer.length) {
+ char c = buffer[pos];
+ switch (c) {
+ case ' ':
+ case '\t':
+ case '\r':
+ pos++;
+ break;
+ default:
+ if (lineHasPrecedingNonWhitespaceChar || c == '#' || c == '\n') {
+ tokens.add(new Token(ProjectViewTokenType.WHITESPACE, oldPos, pos));
+ } else {
+ tokens.add(new Token(ProjectViewTokenType.INDENT, oldPos, pos));
+ }
+ return;
+ }
+ }
+ tokens.add(new Token(ProjectViewTokenType.WHITESPACE, oldPos, pos));
+ }
+
+ private ProjectViewTokenType getIdentifierToken(int start, int end) {
+ String string = bufferSlice(start, end);
+ if (ProjectViewKeywords.LIST_KEYWORD_MAP.keySet().contains(string)) {
+ return ProjectViewTokenType.LIST_KEYWORD;
+ }
+ if (ProjectViewKeywords.SCALAR_KEYWORD_MAP.keySet().contains(string)) {
+ return ProjectViewTokenType.SCALAR_KEYWORD;
+ }
+ return ProjectViewTokenType.IDENTIFIER;
+ }
+
+ private String bufferSlice(int start, int end) {
+ return new String(this.buffer, start, end - start);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewTokenType.java b/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewTokenType.java
new file mode 100644
index 0000000..5b9e09e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewTokenType.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.lexer;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/** Lexical elements for the project view language. */
+public class ProjectViewTokenType extends IElementType {
+
+ // only start-of-line (ignoring whitespace) comments are valid
+ public static final ProjectViewTokenType COMMENT = create("comment");
+ public static final ProjectViewTokenType WHITESPACE = create("whitespace");
+ public static final ProjectViewTokenType NEWLINE = create("newline");
+ public static final ProjectViewTokenType COLON = create(":");
+
+ // any amount of whitespace at the start of a line, followed by a non-'#', non-newline character
+ public static final ProjectViewTokenType INDENT = create("indent");
+
+ // all remaining characters that aren't preceded by a start-of-line comments
+ public static final ProjectViewTokenType IDENTIFIER = create("identifier");
+
+ public static final ProjectViewTokenType LIST_KEYWORD = create("list_keyword");
+ public static final ProjectViewTokenType SCALAR_KEYWORD = create("scalar_keyword");
+
+ private static ProjectViewTokenType create(String debugName) {
+ return new ProjectViewTokenType(debugName);
+ }
+
+ private ProjectViewTokenType(String debugName) {
+ super(debugName, ProjectViewLanguage.INSTANCE);
+ }
+
+ public static final TokenSet IDENTIFIERS =
+ TokenSet.create(IDENTIFIER, LIST_KEYWORD, SCALAR_KEYWORD);
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewParserDefinition.java b/base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewParserDefinition.java
new file mode 100644
index 0000000..702b80b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewParserDefinition.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.parser;
+
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexer;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementType;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementTypes;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiFile;
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.lang.PsiParser;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.tree.IFileElementType;
+import com.intellij.psi.tree.TokenSet;
+
+/** Defines the project view file parser */
+public class ProjectViewParserDefinition implements ParserDefinition {
+
+ @Override
+ public Lexer createLexer(Project project) {
+ return new ProjectViewLexer();
+ }
+
+ @Override
+ public PsiParser createParser(Project project) {
+ return (root, builder) -> {
+ PsiBuilder.Marker rootMarker = builder.mark();
+ new ProjectViewPsiParser(builder).parseFile();
+ rootMarker.done(root);
+ return builder.getTreeBuilt();
+ };
+ }
+
+ @Override
+ public IFileElementType getFileNodeType() {
+ return ProjectViewElementTypes.FILE;
+ }
+
+ @Override
+ public TokenSet getWhitespaceTokens() {
+ return TokenSet.create(ProjectViewTokenType.WHITESPACE);
+ }
+
+ @Override
+ public TokenSet getCommentTokens() {
+ return TokenSet.create(ProjectViewTokenType.COMMENT);
+ }
+
+ @Override
+ public TokenSet getStringLiteralElements() {
+ return TokenSet.EMPTY;
+ }
+
+ @Override
+ public PsiElement createElement(ASTNode node) {
+ IElementType type = node.getElementType();
+ if (type instanceof ProjectViewElementType) {
+ return ((ProjectViewElementType) type).createElement(node);
+ }
+ return new ASTWrapperPsiElement(node);
+ }
+
+ @Override
+ public PsiFile createFile(FileViewProvider viewProvider) {
+ return new ProjectViewPsiFile(viewProvider);
+ }
+
+ @Override
+ public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewPsiParser.java b/base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewPsiParser.java
new file mode 100644
index 0000000..2703bd2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewPsiParser.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.parser;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewKeywords;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementType;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementTypes;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.intellij.lang.PsiBuilder;
+import com.intellij.openapi.application.ApplicationManager;
+import javax.annotation.Nullable;
+
+/** Project view psi parser. */
+public class ProjectViewPsiParser {
+
+ private final PsiBuilder builder;
+
+ public ProjectViewPsiParser(PsiBuilder builder) {
+ this.builder = builder;
+ }
+
+ public void parseFile() {
+ builder.setDebugMode(ApplicationManager.getApplication().isUnitTestMode());
+ while (!builder.eof()) {
+ if (matches(ProjectViewTokenType.NEWLINE)) {
+ continue;
+ }
+ parseSection();
+ }
+ }
+
+ /** A block is one of: - scalar section - list section */
+ private void parseSection() {
+ PsiBuilder.Marker marker = builder.mark();
+ if (matches(ProjectViewTokenType.LIST_KEYWORD)) {
+ expect(ProjectViewTokenType.COLON);
+ skipPastNewline();
+ parseListItems();
+ marker.done(ProjectViewElementTypes.LIST_SECTION);
+ return;
+ }
+ if (currentToken() == ProjectViewTokenType.SCALAR_KEYWORD) {
+ ScalarSectionParser parser =
+ ProjectViewKeywords.SCALAR_KEYWORD_MAP.get(builder.getTokenText());
+ if (parser != null) {
+ parseScalarSection(parser);
+ marker.done(ProjectViewElementTypes.SCALAR_SECTION);
+ return;
+ }
+ }
+ // handle each of the error cases
+ if (matches(ProjectViewTokenType.INDENT)) {
+ skipBlockAndError(
+ marker, "Invalid indentation. Indented lines must be preceded by a list keyword");
+ return;
+ }
+ if (matches(ProjectViewTokenType.COLON)) {
+ skipBlockAndError(marker, "Invalid section: lines cannot begin with a colon.");
+ return;
+ }
+ skipBlockAndError(marker, "Unrecognized keyword: " + builder.getTokenText());
+ }
+
+ private void parseListItems() {
+ while (!builder.eof()) {
+ if (matches(ProjectViewTokenType.NEWLINE)) {
+ continue;
+ }
+ if (!matches(ProjectViewTokenType.INDENT)) {
+ return;
+ }
+ PsiBuilder.Marker marker = builder.mark();
+ skipToNewlineToken();
+ marker.done(ProjectViewElementTypes.LIST_ITEM);
+ builder.advanceLexer();
+ }
+ }
+
+ private void parseScalarSection(ScalarSectionParser parser) {
+ boolean whitespaceDivider = builder.rawLookup(1) == ProjectViewTokenType.WHITESPACE;
+ builder.advanceLexer();
+
+ char divider = parser.getDivider();
+ if (divider == ' ') {
+ if (!whitespaceDivider) {
+ builder.error("Whitespace divider expected after '" + parser.getName() + "'");
+ builder.advanceLexer();
+ }
+ parseScalarItem();
+ return;
+ }
+ if (whitespaceDivider || !Character.toString(divider).equals(builder.getTokenText())) {
+ builder.error(String.format("'%s' expected", divider));
+ }
+ if (!whitespaceDivider) {
+ builder.advanceLexer();
+ }
+ parseScalarItem();
+ }
+
+ private void parseScalarItem() {
+ PsiBuilder.Marker marker = builder.mark();
+ skipToNewlineToken();
+ marker.done(ProjectViewElementTypes.SCALAR_ITEM);
+ builder.advanceLexer();
+ }
+
+ /** Consumes the current token iff it matches the expected type. Otherwise, returns false */
+ private boolean matches(ProjectViewTokenType kind) {
+ if (currentToken() == kind) {
+ builder.advanceLexer();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Consumes the current token if it's of the expected type. Otherwise, returns false and reports
+ * an error.
+ */
+ private boolean expect(ProjectViewTokenType kind) {
+ if (matches(kind)) {
+ return true;
+ }
+ builder.error(String.format("'%s' expected", kind));
+ return false;
+ }
+
+ /** Checks if the upcoming sequence of tokens match that expected. Doesn't advance the parser. */
+ private boolean atTokenSequence(ProjectViewTokenType... kinds) {
+ for (int i = 0; i < kinds.length; i++) {
+ if (builder.lookAhead(i) != kinds[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Nullable
+ private ProjectViewTokenType currentToken() {
+ return (ProjectViewTokenType) builder.getTokenType();
+ }
+
+ private void skipBlockAndError(PsiBuilder.Marker marker, String message) {
+ skipToNextBlock();
+ marker.error(message);
+ }
+
+ /** Skip to the start of the next unindented line */
+ private void skipToNextBlock() {
+ while (!builder.eof()) {
+ if (atTokenSequence(ProjectViewTokenType.NEWLINE, ProjectViewTokenType.IDENTIFIER)) {
+ builder.advanceLexer();
+ return;
+ }
+ builder.advanceLexer();
+ }
+ }
+
+ /** Skip to the start of the next line */
+ private void skipPastNewline() {
+ while (!builder.eof()) {
+ if (matches(ProjectViewTokenType.NEWLINE)) {
+ return;
+ }
+ builder.advanceLexer();
+ }
+ }
+
+ /** Skip to the end of the current line */
+ private void skipToNewlineToken() {
+ while (!builder.eof()) {
+ if (currentToken() == ProjectViewTokenType.NEWLINE) {
+ return;
+ }
+ builder.advanceLexer();
+ }
+ }
+
+ private void buildTokenElement(ProjectViewElementType type) {
+ PsiBuilder.Marker marker = builder.mark();
+ builder.advanceLexer();
+ marker.done(type);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementType.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementType.java
new file mode 100644
index 0000000..b5c1ced
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementType.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.tree.IElementType;
+import java.lang.reflect.Constructor;
+
+/**
+ * IElementTypes used in the AST by the parser (as opposed to the types used by the lexer).<br>
+ * Modelled on IntelliJ's core language conventions.
+ */
+public class ProjectViewElementType extends IElementType {
+
+ private static final Class[] PARAMETER_TYPES = new Class[] {ASTNode.class};
+ private final Class<? extends PsiElement> psiElementClass;
+ private Constructor<? extends PsiElement> constructor;
+
+ public ProjectViewElementType(String name, Class<? extends PsiElement> psiElementClass) {
+ super(name, ProjectViewFileType.INSTANCE.getLanguage());
+ this.psiElementClass = psiElementClass;
+ }
+
+ public PsiElement createElement(ASTNode node) {
+ try {
+ if (constructor == null) {
+ constructor = psiElementClass.getConstructor(PARAMETER_TYPES);
+ }
+ return constructor.newInstance(node);
+ } catch (Exception e) {
+ throw new IllegalStateException("No necessary constructor for " + node.getElementType(), e);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementTypes.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementTypes.java
new file mode 100644
index 0000000..29b2ebb
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementTypes.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
+import com.intellij.psi.tree.IFileElementType;
+
+/** Collects the types used by the PsiBuilder to construct the AST */
+public interface ProjectViewElementTypes {
+
+ IFileElementType FILE = new IFileElementType(ProjectViewFileType.INSTANCE.getLanguage());
+
+ ProjectViewElementType LIST_SECTION =
+ new ProjectViewElementType("list_section", ProjectViewPsiListSection.class);
+ ProjectViewElementType SCALAR_SECTION =
+ new ProjectViewElementType("scalar_section", ProjectViewPsiScalarSection.class);
+
+ ProjectViewElementType LIST_ITEM =
+ new ProjectViewElementType("list_item", ProjectViewPsiListItem.class);
+ ProjectViewElementType SCALAR_ITEM =
+ new ProjectViewElementType("scalar_item", ProjectViewPsiScalarItem.class);
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiElement.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiElement.java
new file mode 100644
index 0000000..b64e6a6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiElement.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.intellij.extapi.psi.ASTWrapperPsiElement;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+
+/** Base psi element for project view files. */
+public abstract class ProjectViewPsiElement extends ASTWrapperPsiElement {
+ public ProjectViewPsiElement(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ public PsiReference[] getReferences() {
+ return PsiReference.EMPTY_ARRAY;
+ }
+
+ public <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass) {
+ return findChildrenByClass(psiClass);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiFile.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiFile.java
new file mode 100644
index 0000000..2d754a1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiFile.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
+import com.intellij.extapi.psi.PsiFileBase;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.psi.FileViewProvider;
+
+/** PSI file for project view file. */
+public class ProjectViewPsiFile extends PsiFileBase {
+
+ public ProjectViewPsiFile(FileViewProvider viewProvider) {
+ super(viewProvider, ProjectViewFileType.INSTANCE.getLanguage());
+ }
+
+ @Override
+ public FileType getFileType() {
+ return ProjectViewFileType.INSTANCE;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListItem.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListItem.java
new file mode 100644
index 0000000..9f383aa
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListItem.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** Psi element for a list item. */
+public class ProjectViewPsiListItem extends ProjectViewPsiSectionItem {
+
+ public ProjectViewPsiListItem(ASTNode node) {
+ super(node);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListSection.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListSection.java
new file mode 100644
index 0000000..d75547a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListSection.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** Psi element for list section. */
+public class ProjectViewPsiListSection extends ProjectViewPsiElement {
+
+ public ProjectViewPsiListSection(ASTNode node) {
+ super(node);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarItem.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarItem.java
new file mode 100644
index 0000000..de2f3a4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarItem.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** Psi element for a scalar item. */
+public class ProjectViewPsiScalarItem extends ProjectViewPsiSectionItem {
+
+ public ProjectViewPsiScalarItem(ASTNode node) {
+ super(node);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarSection.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarSection.java
new file mode 100644
index 0000000..6f03ff4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarSection.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.intellij.lang.ASTNode;
+
+/** Psi element for scalar section. */
+public class ProjectViewPsiScalarSection extends ProjectViewPsiElement {
+
+ public ProjectViewPsiScalarSection(ASTNode node) {
+ super(node);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiSectionItem.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiSectionItem.java
new file mode 100644
index 0000000..2ec19be
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiSectionItem.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.references.FileLookupData.PathFormat;
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewKeywords;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
+import com.google.idea.blaze.base.lang.projectview.references.ProjectViewLabelReference;
+import com.google.idea.blaze.base.projectview.section.SectionParser.ItemType;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.SharedPsiElementImplUtil;
+import javax.annotation.Nullable;
+
+/** Psi element for a list or scalar item. */
+public abstract class ProjectViewPsiSectionItem extends ProjectViewPsiElement {
+
+ public ProjectViewPsiSectionItem(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ public PsiReference[] getReferences() {
+ return SharedPsiElementImplUtil.getReferences(this);
+ }
+
+ @Override
+ public PsiReference getReference() {
+ ASTNode identifier = getNode().findChildByType(ProjectViewTokenType.IDENTIFIER);
+ PathFormat pathFormat = getLabelType();
+ if (identifier != null && pathFormat != null) {
+ return new ProjectViewLabelReference(this, pathFormat);
+ }
+ return null;
+ }
+
+ @Nullable
+ public PathFormat getLabelType() {
+ ASTNode parent = getNode().getTreeParent();
+ ASTNode identifier = parent != null ? parent.getFirstChildNode() : null;
+ if (identifier == null) {
+ return null;
+ }
+ ItemType itemType = ProjectViewKeywords.ITEM_TYPES.get(identifier.getText());
+ if (itemType == null) {
+ return null;
+ }
+ switch (itemType) {
+ case Label:
+ return PathFormat.NonLocal;
+ case FileSystemItem:
+ return PathFormat.NonLocalWithoutInitialBackslashes;
+ default:
+ return null;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/util/ProjectViewElementGenerator.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/util/ProjectViewElementGenerator.java
new file mode 100644
index 0000000..ac82870
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/util/ProjectViewElementGenerator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.psi.util;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiElement;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiSectionItem;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiFileFactory;
+import com.intellij.psi.impl.PsiFileFactoryImpl;
+import com.intellij.testFramework.LightVirtualFile;
+import javax.annotation.Nullable;
+
+/** Creates dummy BuildElements, e.g. for renaming purposes. */
+public class ProjectViewElementGenerator {
+
+ private static final String DUMMY_FILENAME = "dummy.bazelproject";
+
+ private static PsiFile createDummyFile(Project project, String contents) {
+ PsiFileFactory factory = PsiFileFactory.getInstance(project);
+ LightVirtualFile virtualFile =
+ new LightVirtualFile(DUMMY_FILENAME, ProjectViewFileType.INSTANCE, contents);
+ PsiFile psiFile =
+ ((PsiFileFactoryImpl) factory)
+ .trySetupPsiForFile(virtualFile, ProjectViewLanguage.INSTANCE, false, true);
+ assert psiFile != null;
+ return psiFile;
+ }
+
+ @Nullable
+ public static ASTNode createReplacementItemNode(
+ ProjectViewPsiSectionItem sectionItem, String newStringContents) {
+ TextRange itemRange = sectionItem.getTextRange();
+ ProjectViewPsiElement parent = (ProjectViewPsiElement) sectionItem.getParent();
+ if (parent == null) {
+ return sectionItem.getNode();
+ }
+ int startOffset = sectionItem.getStartOffsetInParent();
+ String originalSectionText = parent.getText();
+ String newSectionText =
+ StringUtil.replaceSubstring(
+ originalSectionText,
+ new TextRange(startOffset, startOffset + itemRange.getLength()),
+ newStringContents);
+ PsiFile dummyFile = createDummyFile(sectionItem.getProject(), newSectionText);
+ PsiElement leafElement = dummyFile.findElementAt(startOffset);
+ return leafElement != null ? leafElement.getParent().getNode() : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/references/ProjectViewLabelReference.java b/base/src/com/google/idea/blaze/base/lang/projectview/references/ProjectViewLabelReference.java
new file mode 100644
index 0000000..bcb06d0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/references/ProjectViewLabelReference.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.references;
+
+import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.completion.LabelRuleLookupElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
+import com.google.idea.blaze.base.lang.buildfile.references.FileLookupData;
+import com.google.idea.blaze.base.lang.buildfile.references.FileLookupData.PathFormat;
+import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
+import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiSectionItem;
+import com.google.idea.blaze.base.lang.projectview.psi.util.ProjectViewElementGenerator;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.IncorrectOperationException;
+import javax.annotation.Nullable;
+
+/** A blaze label reference. */
+public class ProjectViewLabelReference extends PsiReferenceBase<ProjectViewPsiSectionItem> {
+
+ private final PathFormat pathFormat;
+
+ public ProjectViewLabelReference(ProjectViewPsiSectionItem element, PathFormat pathFormat) {
+ super(element, new TextRange(0, element.getTextLength()));
+ this.pathFormat = pathFormat;
+ }
+
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ Label label = getLabel(myElement.getText());
+ if (label == null) {
+ return null;
+ }
+ return BuildReferenceManager.getInstance(myElement.getProject()).resolveLabel(label);
+ }
+
+ @Nullable
+ private static Label getLabel(@Nullable String labelString) {
+ if (labelString == null || !labelString.startsWith("//") || labelString.indexOf('*') != -1) {
+ return null;
+ }
+ return LabelUtils.createLabelFromString(null, labelString);
+ }
+
+ @Override
+ public Object[] getVariants() {
+ String labelString = LabelUtils.trimToDummyIdentifier(myElement.getText());
+ return ArrayUtil.mergeArrays(getRuleLookups(labelString), getFileLookups(labelString));
+ }
+
+ private BuildLookupElement[] getRuleLookups(String labelString) {
+ if (!labelString.startsWith("//") || !labelString.contains(":")) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
+ BuildFile referencedBuildFile =
+ BuildReferenceManager.getInstance(myElement.getProject())
+ .resolveBlazePackage(packagePrefix);
+ if (referencedBuildFile == null) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ return LabelRuleLookupElement.collectAllRules(
+ referencedBuildFile, labelString, packagePrefix, null, QuoteType.NoQuotes);
+ }
+
+ private BuildLookupElement[] getFileLookups(String labelString) {
+ if (pathFormat == PathFormat.NonLocalWithoutInitialBackslashes) {
+ labelString = StringUtil.trimStart(labelString, "-");
+ }
+ FileLookupData lookupData =
+ FileLookupData.nonLocalFileLookup(labelString, null, QuoteType.NoQuotes, pathFormat);
+ if (lookupData == null) {
+ return BuildLookupElement.EMPTY_ARRAY;
+ }
+ return BuildReferenceManager.getInstance(myElement.getProject())
+ .resolvePackageLookupElements(lookupData);
+ }
+
+ @Override
+ public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
+ return myElement;
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ String currentString = myElement.getText();
+ Label label = getLabel(currentString);
+ if (label == null) {
+ return myElement;
+ }
+ String ruleName = label.ruleName().toString();
+ String newRuleName = newElementName;
+
+ // handle subdirectories
+ int lastSlashIndex = ruleName.lastIndexOf('/');
+ if (lastSlashIndex != -1) {
+ newRuleName = ruleName.substring(0, lastSlashIndex + 1) + newElementName;
+ }
+
+ String packageString = LabelUtils.getPackagePathComponent(currentString);
+ if (packageString.isEmpty() && !currentString.contains(":")) {
+ return handleRename(newRuleName);
+ }
+ return handleRename(packageString + ":" + newRuleName);
+ }
+
+ private PsiElement handleRename(String newStringContents) {
+ ASTNode replacement =
+ ProjectViewElementGenerator.createReplacementItemNode(myElement, newStringContents);
+ if (replacement != null) {
+ myElement.getNode().replaceAllChildrenToChildrenOf(replacement);
+ }
+ return myElement;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/metrics/Action.java b/base/src/com/google/idea/blaze/base/metrics/Action.java
new file mode 100644
index 0000000..9292cdc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/metrics/Action.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.metrics;
+
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An item that can be logged. All actions contain a name that is used as a primary key. The name
+ * should be immutable forever to keep the logs sane.
+ *
+ * <p>The name used by each {@link Action} should be [a-zA-Z0-9]* to keep things robust since
+ * various log back ends may have different rules about what may or may not be in a key.
+ *
+ * <p>Do not use any of the following retired values for enums: INDEX_TOTAL_TIME("index")
+ * REBUILD_TOTAL_TIME("rtt") SYNC_SAVE_FILES("ssf") SYNC_COMPUTE_MODULE_DIFF("scmd")
+ * RUN_TOTAL_TIME("ttrp") DEBUG_TOTAL_TIME("ttsbp") RUN_TOTAL_TIME_FOR_ANDROID_TEST("ttrpat")
+ * DEBUG_TOTAL_TIME_FOR_ANDROID_TEST("ttsbpat") IMPORT_TOTAL_TIME("tip")
+ * IDE_BUILD_INFO_RESPONSE("ibi") RULES_EXTRACTION("re") BLAZE_MODULES_CREATION("mvc")
+ * INTELLIJ_MODULE_CREATION("imc") SYNC_RESET_PROJECT("srp")
+ *
+ * <p>
+ */
+public enum Action {
+ MAKE_PROJECT_TOTAL_TIME("mtt"),
+ MAKE_MODULE_TOTAL_TIME("mmtt"),
+
+ SYNC_TOTAL_TIME("stt"),
+ SYNC_IMPORT_DATA_TIME("sidt"),
+ BLAZE_BUILD_DURING_SYNC("bb"),
+ BLAZE_BUILD("bld"),
+
+ APK_BUILD_AND_INSTALL("apkbi"),
+
+ BLAZE_COMMAND_USAGE("ttrpbc"),
+
+ OPEN_IN_CODESEARCH("oics"),
+ COPY_GOOGLE3_PATH("cg3p"),
+ OPEN_CORRESPONDING_BUILD_FILE("ocbf"),
+
+ CREATE_BLAZE_RULE("cbr"),
+ CREATE_BLAZE_PACKAGE("cbp"),
+
+ SYNC_SDK("ssdk"),
+
+ C_RESOLVE_FILE("crf"),
+ BLAZE_CLION_TEST_RUN("ctr"),
+ BLAZE_CLION_TEST_DEBUG("ctd");
+
+ @NotNull @NonNls private final String name;
+
+ Action(@NotNull String name) {
+ this.name = name;
+ }
+
+ @NotNull
+ public String getName() {
+ return name;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/metrics/LoggingService.java b/base/src/com/google/idea/blaze/base/metrics/LoggingService.java
new file mode 100644
index 0000000..47a03df
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/metrics/LoggingService.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.metrics;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/**
+ * Logging service that handles logging timing, hit, and other events to an external sink for later
+ * analysis.
+ */
+public interface LoggingService {
+
+ ExtensionPointName<LoggingService> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.LoggingService");
+
+ /**
+ * Report a value for an event to the available logging services.
+ *
+ * @param variable The variable to report to. Once a value is selected for a logical measurement,
+ * the variable's name should never change, even if the colloquial name for the variable
+ * changes.
+ */
+ static void reportEvent(Project project, Action variable) {
+ reportEvent(project, variable, 0);
+ }
+
+ /**
+ * Report a value for an event to the available logging services.
+ *
+ * @param variable The variable to report to. Once a value is selected for a logical measurement,
+ * the variable's name should never change, even if the colloquial name for the variable
+ * changes.
+ * @param value should be >= 0, set the value to 0 if the value is meaningless
+ */
+ static void reportEvent(Project project, Action variable, long value) {
+ for (LoggingService service : EP_NAME.getExtensions()) {
+ service.doReportEvent(project, variable, value);
+ }
+ }
+
+ /**
+ * Report a value for an event to the logging service
+ *
+ * @param variable The variable to report to. Once a value is selected for a logical measurement,
+ * the variable's name should never change, even if the colloquial name for the variable
+ * changes.
+ * @param value should be >= 0, set the value to 0 if the value is meaningless
+ */
+ void doReportEvent(@Nullable Project project, Action variable, long value);
+}
diff --git a/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java b/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
new file mode 100644
index 0000000..d4e84f7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/** The top-level object serialized to cache. */
+@Immutable
+public class BlazeProjectData implements Serializable {
+ private static final long serialVersionUID = 21L;
+
+ public final long syncTime;
+ public final RuleMap ruleMap;
+ public final BlazeRoots blazeRoots;
+ @Nullable public final WorkingSet workingSet;
+ public final WorkspacePathResolver workspacePathResolver;
+ public final WorkspaceLanguageSettings workspaceLanguageSettings;
+ public final SyncState syncState;
+ public final ImmutableMultimap<Label, Label> reverseDependencies;
+ @Nullable public final String vcsName;
+
+ public BlazeProjectData(
+ long syncTime,
+ RuleMap ruleMap,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ WorkspaceLanguageSettings workspaceLangaugeSettings,
+ SyncState syncState,
+ ImmutableMultimap<Label, Label> reverseDependencies,
+ String vcsName) {
+ this.syncTime = syncTime;
+ this.ruleMap = ruleMap;
+ this.blazeRoots = blazeRoots;
+ this.workingSet = workingSet;
+ this.workspacePathResolver = workspacePathResolver;
+ this.workspaceLanguageSettings = workspaceLangaugeSettings;
+ this.syncState = syncState;
+ this.reverseDependencies = reverseDependencies;
+ this.vcsName = vcsName;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/BlazeWorkspaceType.java b/base/src/com/google/idea/blaze/base/model/BlazeWorkspaceType.java
new file mode 100644
index 0000000..d57270a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/BlazeWorkspaceType.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model;
+
+enum BlazeWorkspaceType {
+ BASE,
+ JAVA,
+ ANDROID
+}
diff --git a/base/src/com/google/idea/blaze/base/model/RuleMap.java b/base/src/com/google/idea/blaze/base/model/RuleMap.java
new file mode 100644
index 0000000..0a46316
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/RuleMap.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.io.Serializable;
+
+/** Map of configured targets (and soon aspects). */
+public class RuleMap implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final ImmutableMap<Label, RuleIdeInfo> ruleMap;
+
+ public RuleMap(ImmutableMap<Label, RuleIdeInfo> ruleMap) {
+ this.ruleMap = ruleMap;
+ }
+
+ public RuleIdeInfo get(Label label) {
+ return ruleMap.get(label);
+ }
+
+ public boolean contains(Label label) {
+ return ruleMap.containsKey(label);
+ }
+
+ public ImmutableCollection<RuleIdeInfo> rules() {
+ return ruleMap.values();
+ }
+
+ public ImmutableMap<Label, RuleIdeInfo> map() {
+ return ruleMap;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/SyncState.java b/base/src/com/google/idea/blaze/base/model/SyncState.java
new file mode 100644
index 0000000..ecdbc5e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/SyncState.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model;
+
+import com.google.common.collect.ImmutableMap;
+import java.io.Serializable;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+/** Used to save arbitrary state with the sync task. */
+public class SyncState implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final ImmutableMap<String, Serializable> syncStateMap;
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T extends Serializable> T get(Class<T> klass) {
+ return (T) syncStateMap.get(klass.getName());
+ }
+
+ /** Builder for a sync state */
+ public static class Builder {
+ ImmutableMap.Builder<Class, Serializable> syncStateMap = ImmutableMap.builder();
+
+ public <K extends Serializable, V extends K> Builder put(Class<K> klass, V instance) {
+ syncStateMap.put(klass, instance);
+ return this;
+ }
+
+ public SyncState build() {
+ return new SyncState(syncStateMap.build());
+ }
+ }
+
+ SyncState(ImmutableMap<Class, Serializable> syncStateMap) {
+ ImmutableMap.Builder<String, Serializable> extraProjectSyncStateMap = ImmutableMap.builder();
+ for (Map.Entry<Class, Serializable> entry : syncStateMap.entrySet()) {
+ extraProjectSyncStateMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ this.syncStateMap = extraProjectSyncStateMap.build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java b/base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java
new file mode 100644
index 0000000..1a7f550
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.common.base.Objects;
+import com.intellij.openapi.util.io.FileUtil;
+import java.io.File;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/**
+ * An absolute or relative path returned from Blaze. If it is a relative path, it is relative to the
+ * execution root.
+ */
+public final class ExecutionRootPath implements Serializable {
+ public static final long serialVersionUID = 3L;
+
+ private final File path;
+
+ public ExecutionRootPath(String path) {
+ this.path = new File(path);
+ }
+
+ public ExecutionRootPath(File path) {
+ this.path = path;
+ }
+
+ public File getAbsoluteOrRelativeFile() {
+ return path;
+ }
+
+ public File getFileRootedAt(File absoluteRoot) {
+ if (path.isAbsolute()) {
+ return path;
+ }
+ return new File(absoluteRoot, path.getPath());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ExecutionRootPath that = (ExecutionRootPath) o;
+ return Objects.equal(path, that.path);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(path);
+ }
+
+ @Override
+ public String toString() {
+ return "ExecutionRootPath{" + "path='" + path + '\'' + '}';
+ }
+
+ /**
+ * Returns the relative {@link ExecutionRootPath} if {@code root} is an ancestor of {@code path}
+ * otherwise returns null.
+ */
+ @Nullable
+ public static ExecutionRootPath createAncestorRelativePath(File root, File path) {
+ // We cannot find the relative path between an absolute and relative path.
+ // The underlying code will make the relative path absolute
+ // by rooting it at the current working directory which is almost never what you want.
+ if (root.isAbsolute() != path.isAbsolute()) {
+ return null;
+ }
+ if (!isAncestor(root.getPath(), path.getPath(), false /* strict */)) {
+ return null;
+ }
+ String relativePath = FileUtil.getRelativePath(root, path);
+ if (relativePath == null) {
+ return null;
+ }
+ return new ExecutionRootPath(new File(relativePath));
+ }
+
+ /**
+ * @param possibleParent
+ * @param possibleChild
+ * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent}
+ * equals to {@code possibleChild}.
+ */
+ public static boolean isAncestor(
+ ExecutionRootPath possibleParent, ExecutionRootPath possibleChild, boolean strict) {
+ return isAncestor(
+ possibleParent.getAbsoluteOrRelativeFile().getPath(),
+ possibleChild.getAbsoluteOrRelativeFile().getPath(),
+ strict);
+ }
+
+ /**
+ * @param possibleParentPath
+ * @param possibleChild
+ * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent}
+ * equals to {@code possibleChild}.
+ */
+ public static boolean isAncestor(
+ String possibleParentPath, ExecutionRootPath possibleChild, boolean strict) {
+ return isAncestor(
+ possibleParentPath, possibleChild.getAbsoluteOrRelativeFile().getPath(), strict);
+ }
+
+ /**
+ * @param possibleParent
+ * @param possibleChildPath
+ * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent}
+ * equals to {@code possibleChild}.
+ */
+ public static boolean isAncestor(
+ ExecutionRootPath possibleParent, String possibleChildPath, boolean strict) {
+ return isAncestor(
+ possibleParent.getAbsoluteOrRelativeFile().getPath(), possibleChildPath, strict);
+ }
+
+ /**
+ * @param possibleParentPath
+ * @param possibleChildPath
+ * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent}
+ * equals to {@code possibleChild}.
+ */
+ public static boolean isAncestor(
+ String possibleParentPath, String possibleChildPath, boolean strict) {
+ return FileUtil.isAncestor(possibleParentPath, possibleChildPath, strict);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/Kind.java b/base/src/com/google/idea/blaze/base/model/primitives/Kind.java
new file mode 100644
index 0000000..96bf0ab
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/Kind.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Arrays;
+import java.util.List;
+
+/** Wrapper around a string for a blaze kind (android_library, android_test...) */
+public enum Kind {
+ ANDROID_BINARY("android_binary", LanguageClass.ANDROID),
+ ANDROID_LIBRARY("android_library", LanguageClass.ANDROID),
+ ANDROID_TEST("android_test", LanguageClass.ANDROID),
+ ANDROID_ROBOLECTRIC_TEST("android_robolectric_test", LanguageClass.ANDROID),
+ JAVA_LIBRARY("java_library", LanguageClass.JAVA),
+ JAVA_TEST("java_test", LanguageClass.JAVA),
+ JAVA_BINARY("java_binary", LanguageClass.JAVA),
+ JAVA_IMPORT("java_import", LanguageClass.JAVA),
+ JAVA_TOOLCHAIN("java_toolchain", LanguageClass.JAVA),
+ PROTO_LIBRARY(
+ "proto_library",
+ LanguageClass.JAVA), // The LanguageClass might have to change if we support other languages
+ JAVA_PLUGIN("java_plugin", LanguageClass.JAVA),
+ ANDROID_RESOURCES("android_resources", LanguageClass.ANDROID),
+ CC_LIBRARY("cc_library", LanguageClass.C),
+ CC_BINARY("cc_binary", LanguageClass.C),
+ CC_TEST("cc_test", LanguageClass.C),
+ CC_INC_LIBRARY("cc_inc_library", LanguageClass.C),
+ CC_TOOLCHAIN("cc_toolchain", LanguageClass.C),
+ JAVA_WRAP_CC("java_wrap_cc", LanguageClass.JAVA),
+ GWT_APPLICATION("gwt_application", LanguageClass.JAVA),
+ GWT_HOST("gwt_host", LanguageClass.JAVA),
+ GWT_MODULE("gwt_module", LanguageClass.JAVA),
+ GWT_TEST("gwt_test", LanguageClass.JAVA),
+ ;
+
+ static final ImmutableMap<String, Kind> STRING_TO_KIND = makeStringToKindMap();
+
+ private static ImmutableMap<String, Kind> makeStringToKindMap() {
+ ImmutableMap.Builder<String, Kind> result = ImmutableMap.builder();
+ for (Kind kind : Kind.values()) {
+ result.put(kind.toString(), kind);
+ }
+ return result.build();
+ }
+
+ public static Kind fromString(String kindString) {
+ return STRING_TO_KIND.get(kindString);
+ }
+
+ private final String kind;
+ private final LanguageClass languageClass;
+
+ Kind(String kind, LanguageClass languageClass) {
+ this.kind = kind;
+ this.languageClass = languageClass;
+ }
+
+ @Override
+ public String toString() {
+ return kind;
+ }
+
+ public LanguageClass getLanguageClass() {
+ return languageClass;
+ }
+
+ public boolean isOneOf(Kind... kinds) {
+ return isOneOf(Arrays.asList(kinds));
+ }
+
+ public boolean isOneOf(List<Kind> kinds) {
+ for (Kind kind : kinds) {
+ if (this.equals(kind)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/Label.java b/base/src/com/google/idea/blaze/base/model/primitives/Label.java
new file mode 100644
index 0000000..532c347
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/Label.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import com.intellij.openapi.diagnostic.Logger;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/** Wrapper around a string for a blaze label (//package:rule). */
+@Immutable
+public final class Label extends TargetExpression {
+ private static final Logger LOG = Logger.getInstance(Label.class);
+
+ public static final Comparator<Label> COMPARATOR =
+ (o1, o2) -> String.CASE_INSENSITIVE_ORDER.compare(o1.toString(), o2.toString());
+
+ public static final long serialVersionUID = 2L;
+
+ /** Silently returns null if this is not a valid Label */
+ @Nullable
+ public static Label createIfValid(String label) {
+ if (validate(label)) {
+ return new Label(label);
+ }
+ return null;
+ }
+
+ public Label(String label) {
+ super(label);
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!validate(label, errors)) {
+ BlazeValidationError.throwError(errors);
+ }
+ }
+
+ public Label(WorkspacePath packageName, RuleName newRuleName) {
+ this("//" + packageName.toString() + ":" + newRuleName.toString());
+ }
+
+ public static boolean validate(String label) {
+ return validate(label, null);
+ }
+
+ public static boolean validate(String label, @Nullable Collection<BlazeValidationError> errors) {
+ int colonIndex = label.indexOf(':');
+ if (label.startsWith("//") && colonIndex >= 0) {
+ String packageName = label.substring("//".length(), colonIndex);
+ if (!validatePackagePath(packageName, errors)) {
+ return false;
+ }
+ String ruleName = label.substring(colonIndex + 1);
+ if (!RuleName.validate(ruleName, errors)) {
+ return false;
+ }
+ return true;
+ }
+ if (label.startsWith("@") && colonIndex >= 0) {
+ // a bazel-specific label pointing to a different repository
+ int slashIndex = label.indexOf("//");
+ if (slashIndex >= 0) {
+ return validate(label.substring(slashIndex), errors);
+ }
+ }
+ if (errors != null) {
+ errors.add(new BlazeValidationError("Not a valid label, no target name found: " + label));
+ }
+ return false;
+ }
+
+ /**
+ * Extract the rule name from a label. The rule name follows a colon at the end of the label.
+ *
+ * @return the rule name
+ */
+ public RuleName ruleName() {
+ String labelStr = toString();
+ int colonLocation = labelStr.lastIndexOf(':');
+ int ruleNameStart = colonLocation + 1;
+ String ruleNameStr = labelStr.substring(ruleNameStart);
+ return RuleName.create(ruleNameStr);
+ }
+
+ /**
+ * Return the workspace path for the package label for the given label. For example, if the
+ * package is //j/c/g/a/apps/docs:release, it returns j/c/g/a/apps/docs.
+ */
+ public WorkspacePath blazePackage() {
+ String labelStr = toString();
+ int startIndex = labelStr.indexOf("//") + "//".length();
+ int colonIndex = labelStr.lastIndexOf(':');
+ LOG.assertTrue(colonIndex >= 0);
+ return new WorkspacePath(labelStr.substring(startIndex, colonIndex));
+ }
+
+ public static boolean validatePackagePath(String path) {
+ return validatePackagePath(path, null);
+ }
+
+ public static boolean validatePackagePath(
+ String path, @Nullable Collection<BlazeValidationError> errors) {
+ // Empty packages are legal but not recommended
+ if (path.isEmpty()) {
+ return true;
+ }
+
+ if (path.charAt(0) == '/') {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid package name: " + path + "\n" + "Package names may not start with \"/\"."));
+ return false;
+ }
+ if (path.contains("//")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid package name: "
+ + path
+ + "\n "
+ + "package names may not contain \"//\" path separators."));
+ return false;
+ }
+ if (path.endsWith("/")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid package name: " + path + "\n " + "package names may not end with \"/\""));
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java b/base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java
new file mode 100644
index 0000000..4ea1df8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+/** Language classes. */
+public enum LanguageClass {
+ GENERIC("generic"),
+ C("c"),
+ JAVA("java"),
+ ANDROID("android"),
+ JAVASCRIPT("javascript"),
+ TYPESCRIPT("typescript"),
+ DART("dart");
+
+ private final String name;
+
+ LanguageClass(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static LanguageClass fromString(String name) {
+ for (LanguageClass ruleClass : LanguageClass.values()) {
+ if (ruleClass.name.equals(name)) {
+ return ruleClass;
+ }
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/RuleName.java b/base/src/com/google/idea/blaze/base/model/primitives/RuleName.java
new file mode 100644
index 0000000..b535a2c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/RuleName.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** The rule name part of a label */
+public final class RuleName {
+
+ // This is a subset of the allowable target names in Blaze
+ private static final String ALNUM_REGEX_STR = "[a-zA-Z0-9]*";
+ private static final Pattern ALNUM_REGEX = Pattern.compile(ALNUM_REGEX_STR);
+
+ // Rule names must be alpha-numeric or consist of the following allowed chars:
+ // (note, rule names can also contain '/'; we handle that case separately)
+ private static final ImmutableSet<Character> ALLOWED_META =
+ ImmutableSet.of('+', '_', ',', '=', '-', '.', '@', '~');
+
+ private final String name;
+
+ private RuleName(String ruleName) {
+ this.name = ruleName;
+ }
+
+ /** Silently returns null if the string is not a valid rule name. */
+ @Nullable
+ public static RuleName createIfValid(String ruleName) {
+ if (validate(ruleName, null)) {
+ return new RuleName(ruleName);
+ }
+ return null;
+ }
+
+ public static RuleName create(String ruleName) {
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!validate(ruleName, errors)) {
+ BlazeValidationError.throwError(errors);
+ }
+ return new RuleName(ruleName);
+ }
+
+ /** Validates a rule name using the same logic as Blaze */
+ public static boolean validate(String ruleName) {
+ return validate(ruleName, null);
+ }
+
+ /** Validates a rule name using the same logic as Blaze */
+ public static boolean validate(
+ String ruleName, @Nullable Collection<BlazeValidationError> errors) {
+ if (ruleName.isEmpty()) {
+ BlazeValidationError.collect(
+ errors, new BlazeValidationError("target names cannot be empty"));
+ return false;
+ }
+ // Forbidden start chars:
+ if (ruleName.charAt(0) == '/') {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: " + ruleName + "\n" + "target names may not start with \"/\""));
+ return false;
+ } else if (ruleName.charAt(0) == '.') {
+ if (ruleName.startsWith("../") || ruleName.equals("..")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: "
+ + ruleName
+ + "\n"
+ + "target names may not contain up-level references \"..\""));
+ return false;
+ } else if (ruleName.equals(".")) {
+ return true;
+ } else if (ruleName.startsWith("./")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: "
+ + ruleName
+ + "\n"
+ + "target names may not contain \".\" as a path segment"));
+ return false;
+ }
+ }
+
+ for (int i = 0; i < ruleName.length(); ++i) {
+ char c = ruleName.charAt(i);
+ if (ALLOWED_META.contains(c)) {
+ continue;
+ }
+ if (c == '/') {
+ // Forbidden substrings: "/../", "/./", "//"
+ if (ruleName.contains("/../")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: "
+ + ruleName
+ + "\n"
+ + "target names may not contain up-level references \"..\""));
+ return false;
+ } else if (ruleName.contains("/./")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: "
+ + ruleName
+ + "\n"
+ + "target names may not contain \".\" as a path segment"));
+ return false;
+ } else if (ruleName.contains("//")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: "
+ + ruleName
+ + "\n"
+ + "target names may not contain \"//\" path separators"));
+ return false;
+ }
+ continue;
+ }
+ boolean isAlnum = ALNUM_REGEX.matcher(String.valueOf(c)).matches();
+ if (!isAlnum) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: " + ruleName + "\n" + "target names may not contain " + c));
+ return false;
+ }
+ }
+
+ // Forbidden end chars:
+ if (ruleName.endsWith("/..")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: "
+ + ruleName
+ + "\n"
+ + "target names may not contain up-level references \"..\""));
+ return false;
+ } else if (ruleName.endsWith("/.")) {
+ return true;
+ } else if (ruleName.endsWith("/")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError(
+ "Invalid target name: " + ruleName + "\n" + "target names may not end with \"/\""));
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof RuleName) {
+ RuleName that = (RuleName) obj;
+ return Objects.equal(name, that.name);
+ }
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java b/base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java
new file mode 100644
index 0000000..ea3d847
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.common.base.Preconditions;
+import java.io.Serializable;
+
+/**
+ * An interface for objects that represent targets you could pass to Blaze on the command line. See
+ * {@link com.google.idea.blaze.base.model.primitives.Label},
+ */
+public class TargetExpression implements Serializable, Comparable<TargetExpression> {
+ public static final long serialVersionUID = 1L;
+
+ private final String expression;
+
+ /**
+ * @return A Label instance if the expression is a valid label, or a TargetExpression instance if
+ * it is not.
+ */
+ public static TargetExpression fromString(String expression) {
+ return Label.validate(expression) ? new Label(expression) : new TargetExpression(expression);
+ }
+
+ TargetExpression(String expression) {
+ // TODO(joshgiles): Validation/canonicalization for target expressions.
+ // For reference, handled in Blaze/Bazel in TargetPattern.java.
+ Preconditions.checkArgument(!expression.isEmpty(), "Target should be non-empty.");
+ this.expression = expression;
+ }
+
+ @Override
+ public String toString() {
+ return expression;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TargetExpression)) {
+ return false;
+ }
+ TargetExpression that = (TargetExpression) o;
+ return expression.equals(that.expression);
+ }
+
+ @Override
+ public int hashCode() {
+ return expression.hashCode();
+ }
+
+ /** All targets in all packages below the given path */
+ public static TargetExpression allFromPackageRecursive(WorkspacePath localPackage) {
+ if (localPackage.relativePath().isEmpty()) {
+ // localPackage is the workspace root
+ return new TargetExpression("//...:all");
+ }
+ return new TargetExpression("//" + localPackage.relativePath() + "/...:all");
+ }
+
+ public static TargetExpression allFromPackageNonRecursive(WorkspacePath localPackage) {
+ return new TargetExpression("//" + localPackage.relativePath() + ":all");
+ }
+
+ @Override
+ public int compareTo(TargetExpression o) {
+ return expression.compareTo(o.expression);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java b/base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java
new file mode 100644
index 0000000..3bb2ccd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.io.Serializable;
+import java.util.Collection;
+import javax.annotation.concurrent.Immutable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Represents a path relative to the workspace root. The path component separator is Blaze specific.
+ *
+ * <p>A {@link WorkspacePath} is *not* necessarily a valid package name/path. The primary reason is
+ * because it could represent a file and files don't have to follow the same conventions as package
+ * names.
+ */
+@Immutable
+public class WorkspacePath implements Serializable {
+ public static final long serialVersionUID = 1L;
+
+ /** Silently returns null if this is not a valid workspace path. */
+ @Nullable
+ public static WorkspacePath createIfValid(String relativePath) {
+ if (validate(relativePath)) {
+ return new WorkspacePath(relativePath);
+ }
+ return null;
+ }
+
+ private static final char BLAZE_COMPONENT_SEPARATOR = '/';
+
+ @NotNull private final String relativePath;
+
+ /**
+ * @param relativePath relative path that must use the Blaze specific separator char to separate
+ * path components
+ */
+ public WorkspacePath(@NotNull String relativePath) {
+ if (!validate(relativePath)) {
+ throw new IllegalArgumentException("Invalid workspace path: " + relativePath);
+ }
+ this.relativePath = relativePath;
+ }
+
+ public WorkspacePath(@NotNull WorkspacePath parentPath, @NotNull String childPath) {
+ this(parentPath.relativePath() + BLAZE_COMPONENT_SEPARATOR + childPath);
+ }
+
+ public static boolean validate(@NotNull String relativePath) {
+ return validate(relativePath, null);
+ }
+
+ public static boolean validate(
+ @NotNull String relativePath, @Nullable Collection<BlazeValidationError> errors) {
+ if (relativePath.startsWith("/")) {
+ BlazeValidationError.collect(
+ errors,
+ new BlazeValidationError("Workspace path may not start with '/': " + relativePath));
+ return false;
+ }
+
+ if (relativePath.endsWith("/")) {
+ BlazeValidationError.collect(
+ errors, new BlazeValidationError("Workspace path may not end with '/': " + relativePath));
+ return false;
+ }
+
+ if (relativePath.indexOf(':') >= 0) {
+ BlazeValidationError.collect(
+ errors, new BlazeValidationError("Workspace path may not contain ':': " + relativePath));
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean isWorkspaceRoot() {
+ return relativePath.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ return relativePath;
+ }
+
+ public String relativePath() {
+ return relativePath;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || this.getClass() != o.getClass()) {
+ return false;
+ }
+
+ WorkspacePath that = (WorkspacePath) o;
+ return relativePath.equals(that.relativePath);
+ }
+
+ @Override
+ public int hashCode() {
+ return relativePath.hashCode();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java
new file mode 100644
index 0000000..b4a0a13
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Represents a workspace root */
+public class WorkspaceRoot implements Serializable {
+ public static final long serialVersionUID = 1L;
+
+ private final File directory;
+
+ public WorkspaceRoot(File directory) {
+ this.directory = directory;
+ }
+
+ /**
+ * Get the workspace root for a project
+ *
+ * @param blazeSettings settings for the project in question
+ * @return the path to workspace root that is used for the project
+ */
+ public static WorkspaceRoot fromImportSettings(BlazeImportSettings blazeSettings) {
+ return new WorkspaceRoot(new File(blazeSettings.getWorkspaceRoot()));
+ }
+
+ /**
+ * Tries to load the import settings for the given project and get the workspace root directory.
+ * <br>
+ * Unlike {@link #fromProject}, it will silently return null if this is not a blaze project.
+ */
+ @Nullable
+ public static WorkspaceRoot fromProjectSafe(Project project) {
+ if (Blaze.isBlazeProject(project)) {
+ return fromProject(project);
+ }
+ return null;
+ }
+
+ /**
+ * Tries to load the import settings for the given project and get the workspace root directory.
+ */
+ public static WorkspaceRoot fromProject(Project project) {
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings == null) {
+ throw new IllegalStateException("null BlazeImportSettings.");
+ }
+ return fromImportSettings(importSettings);
+ }
+
+ public File fileForPath(WorkspacePath workspacePath) {
+ return new File(directory, workspacePath.relativePath());
+ }
+
+ public File directory() {
+ return directory;
+ }
+
+ public WorkspacePath workspacePathFor(VirtualFile file) {
+ return workspacePathFor(file.getPath());
+ }
+
+ public boolean isInWorkspace(VirtualFile file) {
+ return isInWorkspace(file.getPath());
+ }
+
+ /**
+ * Returns the WorkspacePath for the given absolute file, if it's a child of this WorkspaceRoot.
+ * Otherwise returns null.
+ */
+ @Nullable
+ public WorkspacePath workspacePathForSafe(File absoluteFile) {
+ if (isInWorkspace(absoluteFile)) {
+ return workspacePathFor(absoluteFile);
+ }
+ return null;
+ }
+
+ public WorkspacePath workspacePathFor(File file) {
+ return workspacePathFor(file.getPath());
+ }
+
+ public boolean isInWorkspace(File file) {
+ return isInWorkspace(file.getPath());
+ }
+
+ private WorkspacePath workspacePathFor(String path) {
+ if (!isInWorkspace(path)) {
+ throw new IllegalArgumentException("File is not under this workspace");
+ }
+ if (directory.getPath().length() == path.length()) {
+ return new WorkspacePath("");
+ }
+ return new WorkspacePath(path.substring(directory.getPath().length() + 1));
+ }
+
+ private boolean isInWorkspace(String path) {
+ return FileUtil.isAncestor(directory.getPath(), path, false);
+ }
+
+ @Override
+ public String toString() {
+ return directory.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ WorkspaceRoot that = (WorkspaceRoot) o;
+ return directory.equals(that.directory);
+ }
+
+ @Override
+ public int hashCode() {
+ return directory.hashCode();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceType.java b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceType.java
new file mode 100644
index 0000000..1e69fce
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceType.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+/**
+ * Workspace types.
+ *
+ * <p>If the user doesn't specify a workspace, she gets the highest supported workspace type by enum
+ * ordinal.
+ */
+public enum WorkspaceType {
+ INTELLIJ_PLUGIN("intellij_plugin", LanguageClass.JAVA),
+ C("c", LanguageClass.C),
+ JAVA("java", LanguageClass.JAVA),
+ ANDROID_NDK("android_ndk", LanguageClass.ANDROID, LanguageClass.JAVA, LanguageClass.C),
+ ANDROID("android", LanguageClass.ANDROID, LanguageClass.JAVA),
+ JAVASCRIPT("javascript");
+
+ private final String name;
+ private final LanguageClass[] languages;
+
+ WorkspaceType(String name, LanguageClass... languages) {
+ this.name = name;
+ this.languages = languages;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public LanguageClass[] getLanguages() {
+ return languages;
+ }
+
+ public static WorkspaceType fromString(String name) {
+ for (WorkspaceType ruleClass : WorkspaceType.values()) {
+ if (ruleClass.name.equals(name)) {
+ return ruleClass;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java b/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
new file mode 100644
index 0000000..17e6043
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+
+/** Wraps an action and makes it invisible for blaze-based projects. */
+public class BlazeActionRemover extends AnAction {
+
+ public static void hideAction(String actionId) {
+ AnAction oldAction = ActionManager.getInstance().getAction(actionId);
+ if (oldAction != null) {
+ replaceAction(actionId, new BlazeActionRemover(oldAction));
+ }
+ }
+
+ private static void replaceAction(String actionId, AnAction newAction) {
+ ActionManager actionManager = ActionManager.getInstance();
+ AnAction oldAction = actionManager.getAction(actionId);
+ if (oldAction != null) {
+ newAction.getTemplatePresentation().setIcon(oldAction.getTemplatePresentation().getIcon());
+ actionManager.unregisterAction(actionId);
+ }
+ actionManager.registerAction(actionId, newAction);
+ }
+
+ private final AnAction delegate;
+
+ private BlazeActionRemover(AnAction delegate) {
+ super(
+ delegate.getTemplatePresentation().getTextWithMnemonic(),
+ delegate.getTemplatePresentation().getDescription(),
+ delegate.getTemplatePresentation().getIcon());
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ delegate.actionPerformed(e);
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ Project project = e.getProject();
+ if (project != null && Blaze.isBlazeProject(project)) {
+ presentation.setEnabledAndVisible(false);
+ return;
+ }
+ delegate.update(e);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/BlazeBinaryFileType.java b/base/src/com/google/idea/blaze/base/plugin/BlazeBinaryFileType.java
new file mode 100644
index 0000000..114117d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/BlazeBinaryFileType.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin;
+
+import com.intellij.openapi.fileTypes.UserBinaryFileType;
+
+/** Marker type to mark something as binary. */
+public class BlazeBinaryFileType extends UserBinaryFileType {
+ public static final BlazeBinaryFileType INSTANCE;
+
+ static {
+ INSTANCE = new BlazeBinaryFileType();
+ INSTANCE.setName("Binary File");
+ INSTANCE.setDescription(
+ "The blaze plugin has guessed this file type as binary for performance.");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/BlazeFileTypeFactory.java b/base/src/com/google/idea/blaze/base/plugin/BlazeFileTypeFactory.java
new file mode 100644
index 0000000..0254c89
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/BlazeFileTypeFactory.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin;
+
+import com.intellij.ide.highlighter.ArchiveFileType;
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+/** @author chuckj */
+public class BlazeFileTypeFactory extends FileTypeFactory {
+ @Override
+ public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
+ consumer.consume(ArchiveFileType.INSTANCE, "srcjar");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/BlazePluginId.java b/base/src/com/google/idea/blaze/base/plugin/BlazePluginId.java
new file mode 100644
index 0000000..64fbb90
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/BlazePluginId.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin;
+
+import com.intellij.openapi.components.ServiceManager;
+
+/** Supplies the ID of the sync plugin. */
+public interface BlazePluginId {
+
+ static BlazePluginId getInstance() {
+ return ServiceManager.getService(BlazePluginId.class);
+ }
+
+ /** @return the plugin ID (same as in the plugin.xml). */
+ String getPluginId();
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/BlazeSpecificInitializer.java b/base/src/com/google/idea/blaze/base/plugin/BlazeSpecificInitializer.java
new file mode 100644
index 0000000..d399f97
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/BlazeSpecificInitializer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin;
+
+import com.intellij.openapi.actionSystem.IdeActions;
+import com.intellij.openapi.components.ApplicationComponent;
+
+/** Runs on startup. */
+public class BlazeSpecificInitializer extends ApplicationComponent.Adapter {
+
+ @Override
+ public void initComponent() {
+ hideMakeActions();
+ }
+
+ // The original actions will be visible only on plain IDEA projects.
+ private static void hideMakeActions() {
+ // 'Build' > 'Make Project' action
+ BlazeActionRemover.hideAction("CompileDirty");
+
+ // 'Build' > 'Make Modules' action
+ BlazeActionRemover.hideAction(IdeActions.ACTION_MAKE_MODULE);
+
+ // 'Build' > 'Rebuild' action
+ BlazeActionRemover.hideAction(IdeActions.ACTION_COMPILE_PROJECT);
+
+ // 'Build' > 'Compile Modules' action
+ BlazeActionRemover.hideAction(IdeActions.ACTION_COMPILE);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/Version.java b/base/src/com/google/idea/blaze/base/plugin/Version.java
new file mode 100644
index 0000000..dc86694
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/Version.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.intellij.ide.plugins.IdeaPluginDescriptor;
+import com.intellij.ide.plugins.PluginManager;
+import com.intellij.openapi.extensions.PluginId;
+
+/** Blaze sync plugin ID and version information. */
+public class Version {
+
+ /** The plugin ID and version from plugin.xml */
+ public static class PluginInfo {
+ public final String id;
+ public final String version;
+
+ @VisibleForTesting
+ public static final PluginInfo UNKNOWN = new PluginInfo("UNKNOWN_PLUGIN", "UNKNOWN_VERSION");
+
+ public PluginInfo(String id, String version) {
+ this.id = id;
+ this.version = version;
+ }
+ }
+
+ public static PluginInfo getSyncPluginInfo() {
+ BlazePluginId idService = BlazePluginId.getInstance();
+ if (idService != null) {
+ PluginId pluginId = PluginId.getId(idService.getPluginId());
+ IdeaPluginDescriptor pluginInfo = PluginManager.getPlugin(pluginId);
+ if (pluginInfo != null) {
+ return new PluginInfo(pluginId.getIdString(), pluginInfo.getVersion());
+ }
+ }
+ return PluginInfo.UNKNOWN;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/dependency/PluginDependencyHelper.java b/base/src/com/google/idea/blaze/base/plugin/dependency/PluginDependencyHelper.java
new file mode 100644
index 0000000..4ab0bed
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/dependency/PluginDependencyHelper.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin.dependency;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.plugin.BlazePluginId;
+import com.intellij.externalDependencies.DependencyOnPlugin;
+import com.intellij.externalDependencies.ExternalDependenciesManager;
+import com.intellij.externalDependencies.ProjectExternalDependency;
+import com.intellij.openapi.project.Project;
+import java.util.Iterator;
+import java.util.List;
+
+/** Helper class to add plugin dependencies to the project */
+public class PluginDependencyHelper {
+
+ public static void addDependencyOnSyncPlugin(Project blazeProject) {
+ BlazePluginId idService = BlazePluginId.getInstance();
+ if (idService != null) {
+ addDependency(
+ blazeProject, new DependencyOnPlugin(idService.getPluginId(), null, null, null));
+ }
+ }
+
+ /**
+ * Removes a project depedency on a given plugin, if one exists. Doesn't trigger any update
+ * checking. This is to handle migration of the IntelliJ-with-Bazel plugin to a different plugin
+ * ID. This is introduced in v1.9, remove in v2.2+
+ */
+ @Deprecated
+ public static void removeDependencyOnOldPlugin(Project project, String pluginId) {
+ ExternalDependenciesManager manager = ExternalDependenciesManager.getInstance(project);
+ List<ProjectExternalDependency> deps = Lists.newArrayList(manager.getAllDependencies());
+ Iterator<ProjectExternalDependency> iter = deps.iterator();
+ while (iter.hasNext()) {
+ ProjectExternalDependency dep = iter.next();
+ if (!(dep instanceof DependencyOnPlugin)) {
+ continue;
+ }
+ DependencyOnPlugin pluginDep = (DependencyOnPlugin) dep;
+ if (pluginDep.getPluginId().equals(pluginId)) {
+ iter.remove();
+ }
+ }
+ manager.setAllDependencies(deps);
+ }
+
+ /**
+ * Adds dependency, or replaces existing dependency of same type. Doesn't trigger any update
+ * checking
+ */
+ private static void addDependency(Project project, DependencyOnPlugin newDep) {
+
+ ExternalDependenciesManager manager = ExternalDependenciesManager.getInstance(project);
+ List<ProjectExternalDependency> deps = Lists.newArrayList(manager.getAllDependencies());
+ boolean added = false;
+ for (int i = 0; i < deps.size(); i++) {
+ ProjectExternalDependency dep = deps.get(i);
+ if (!(dep instanceof DependencyOnPlugin)) {
+ continue;
+ }
+ DependencyOnPlugin pluginDep = (DependencyOnPlugin) dep;
+ if (pluginDep.getPluginId().equals(newDep.getPluginId())) {
+ added = true;
+ deps.set(i, newDep);
+ }
+ }
+ if (!added) {
+ deps.add(newDep);
+ }
+ manager.setAllDependencies(deps);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/plugin/dependency/ProjectDependencyMigration.java b/base/src/com/google/idea/blaze/base/plugin/dependency/ProjectDependencyMigration.java
new file mode 100644
index 0000000..6f3be8b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/dependency/ProjectDependencyMigration.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.plugin.dependency;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.project.ProjectManagerAdapter;
+
+/**
+ * Temporary migration code. Listens for blaze projects opening and closing, and adds required
+ * plugin dependencies
+ */
+public class ProjectDependencyMigration extends ApplicationComponent.Adapter {
+
+ @Override
+ public void initComponent() {
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.addProjectManagerListener(
+ new ProjectManagerAdapter() {
+ @Override
+ public void projectOpened(Project project) {
+ if (Blaze.isBlazeProject(project)) {
+ PluginDependencyHelper.addDependencyOnSyncPlugin(project);
+ }
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/FetchExecutor.java b/base/src/com/google/idea/blaze/base/prefetch/FetchExecutor.java
new file mode 100644
index 0000000..c89cc4f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/prefetch/FetchExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.prefetch;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.intellij.util.concurrency.BoundedTaskExecutor;
+import java.util.concurrent.Executors;
+
+/** Shared executors for any prefetch/copy operations. */
+public class FetchExecutor {
+ private static final int THREAD_COUNT = 32;
+ public static final ListeningExecutorService EXECUTOR =
+ MoreExecutors.listeningDecorator(
+ new BoundedTaskExecutor(Executors.newFixedThreadPool(THREAD_COUNT), THREAD_COUNT));
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java b/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java
new file mode 100644
index 0000000..dcdc666
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.prefetch;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Set;
+
+/** Provides a source of files to prefetch */
+public interface PrefetchFileSource {
+ ExtensionPointName<PrefetchFileSource> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.PrefetchFileSource");
+ /** Adds any files or directories that we would be interested in prefetching. */
+ void addFilesToPrefetch(
+ Project project, BlazeProjectData blazeProjectData, Collection<File> files);
+
+ /** Returns any source file extensions that are a good candidate for the {@link Prefetcher}. */
+ Set<String> prefetchSrcFileExtensions();
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java b/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
new file mode 100644
index 0000000..fc5f5e2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.prefetch;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+
+/** Interface to request prefetching of files */
+public interface PrefetchService {
+ static PrefetchService getInstance() {
+ return ServiceManager.getService(PrefetchService.class);
+ }
+
+ /** Instructs all prefetchers to prefetch these files. */
+ ListenableFuture<?> prefetchFiles(Project project, Collection<File> files);
+
+ ListenableFuture<?> prefetchProjectFiles(Project project, BlazeProjectData blazeProjectData);
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java b/base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java
new file mode 100644
index 0000000..8046db0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.prefetch;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/** Implementation for prefetcher. */
+public class PrefetchServiceImpl implements PrefetchService {
+
+ @Override
+ public ListenableFuture<?> prefetchFiles(Project project, Collection<File> files) {
+ List<ListenableFuture<?>> futures = Lists.newArrayList();
+ for (Prefetcher prefetcher : Prefetcher.EP_NAME.getExtensions()) {
+ futures.add(prefetcher.prefetchFiles(project, files, FetchExecutor.EXECUTOR));
+ }
+ return Futures.allAsList(futures);
+ }
+
+ @Override
+ public ListenableFuture<?> prefetchProjectFiles(
+ Project project, BlazeProjectData blazeProjectData) {
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return Futures.immediateFuture(null);
+ }
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings == null) {
+ return Futures.immediateFuture(null);
+ }
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, importSettings.getBuildSystem())
+ .add(projectViewSet)
+ .build();
+
+ Set<File> files = Sets.newHashSet();
+ for (WorkspacePath workspacePath : importRoots.rootDirectories()) {
+ files.add(workspaceRoot.fileForPath(workspacePath));
+ }
+ for (PrefetchFileSource fileSource : PrefetchFileSource.EP_NAME.getExtensions()) {
+ fileSource.addFilesToPrefetch(project, blazeProjectData, files);
+ }
+ return prefetchFiles(project, files);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/Prefetcher.java b/base/src/com/google/idea/blaze/base/prefetch/Prefetcher.java
new file mode 100644
index 0000000..64503e0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/prefetch/Prefetcher.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.prefetch;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+
+/** Prefetches files when a project is opened or roots change. */
+public interface Prefetcher {
+ ExtensionPointName<Prefetcher> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.Prefetcher");
+
+ /**
+ * Prefetches the given list of files.
+ *
+ * <p>It is the responsibility of the prefetcher to filter out any files it isn't interested in.
+ */
+ ListenableFuture<?> prefetchFiles(
+ Project project, Collection<File> file, ListeningExecutorService executor);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectView.java b/base/src/com/google/idea/blaze/base/projectview/ProjectView.java
new file mode 100644
index 0000000..8dfc6f3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectView.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.section.Section;
+import com.google.idea.blaze.base.projectview.section.SectionBuilder;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import java.io.Serializable;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Represents instructions for what should be included in a project. */
+public final class ProjectView implements Serializable {
+ private static final long serialVersionUID = 3L;
+
+ private final ImmutableList<Section<?>> sections;
+
+ public ProjectView(ImmutableList<Section<?>> sections) {
+ this.sections = sections;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T, SectionType extends Section<T>> ImmutableList<SectionType> getSectionsOfType(
+ SectionKey<T, SectionType> key) {
+ ImmutableList.Builder<SectionType> result = ImmutableList.builder();
+ for (Section<?> section : sections) {
+ if (section.isSectionType(key)) {
+ result.add((SectionType) section);
+ }
+ }
+ return result.build();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder builder(ProjectView projectView) {
+ return new Builder(projectView);
+ }
+
+ public ImmutableList<Section<?>> getSections() {
+ return sections;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ProjectView that = (ProjectView) o;
+ return Objects.equal(sections, that.sections);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(sections);
+ }
+
+ /** Builder class. */
+ public static class Builder {
+ private final List<Section<?>> sections = Lists.newArrayList();
+
+ Builder() {}
+
+ Builder(ProjectView projectView) {
+ sections.addAll(projectView.sections);
+ }
+
+ /** Gets the last section of the type in the builder. Useful to add on to sections. */
+ @SuppressWarnings("unchecked")
+ @Nullable
+ public <T, SectionType extends Section<T>> SectionType getLast(SectionKey<T, SectionType> key) {
+ for (Section<?> section : sections) {
+ if (section.isSectionType(key)) {
+ return (SectionType) section;
+ }
+ }
+ return null;
+ }
+
+ public <T, SectionType extends Section<T>> Builder add(SectionBuilder<T, SectionType> builder) {
+ return add(builder.build());
+ }
+
+ public <T, SectionType extends Section<T>> Builder add(SectionType section) {
+ sections.add(section);
+ return this;
+ }
+
+ /** Replaces a section if it already exists. If it doesn't, just add the section. */
+ public <T, SectionType extends Section<T>> Builder replace(
+ @Nullable Section<T> section, SectionBuilder<T, SectionType> builder) {
+ return replace(section, builder.build());
+ }
+
+ /** Replaces a section if it already exists. If it doesn't, just add the section. */
+ public <T> Builder replace(@Nullable Section<T> toReplace, Section<T> replaceWith) {
+ if (toReplace == null) {
+ return add(replaceWith);
+ }
+
+ int i = sections.indexOf(toReplace);
+ if (i == -1) {
+ throw new IllegalArgumentException("Section not in this builder.");
+ }
+ sections.remove(i);
+ sections.add(i, replaceWith);
+ return this;
+ }
+
+ public ProjectView build() {
+ return new ProjectView(ImmutableList.copyOf(sections));
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewEdit.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewEdit.java
new file mode 100644
index 0000000..7087681
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewEdit.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.util.SaveUtil;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Represents a modification to one or more project view files. */
+public class ProjectViewEdit {
+
+ private static final Logger LOG = Logger.getInstance(ProjectViewEdit.class);
+ private final Project project;
+ private final List<Modification> modifications;
+
+ ProjectViewEdit(Project project, List<Modification> modifications) {
+ this.project = project;
+ this.modifications = modifications;
+ }
+
+ private static class Modification {
+ ProjectView oldProjectView;
+ ProjectView newProjectView;
+ File projectViewFile;
+ }
+
+ /** Creates a new edit that modifies the local project view only. */
+ @Nullable
+ public static ProjectViewEdit editLocalProjectView(Project project, ProjectViewEditor editor) {
+ List<Modification> modifications = Lists.newArrayList();
+ BlazeProjectData projectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (projectData == null) {
+ return null;
+ }
+ ProjectViewSet oldProjectViewSet =
+ Scope.root(
+ (context) -> {
+ SaveUtil.saveAllFiles();
+ return ProjectViewManager.getInstance(project)
+ .reloadProjectView(context, projectData.workspacePathResolver);
+ });
+ if (oldProjectViewSet == null) {
+ return null;
+ }
+
+ ProjectViewSet.ProjectViewFile projectViewFile = oldProjectViewSet.getTopLevelProjectViewFile();
+ if (projectViewFile == null) {
+ return null;
+ }
+
+ ProjectView.Builder builder = ProjectView.builder(projectViewFile.projectView);
+ if (editor.editProjectView(builder)) {
+ Modification modification = new Modification();
+ modification.newProjectView = builder.build();
+ modification.oldProjectView = projectViewFile.projectView;
+ modification.projectViewFile = projectViewFile.projectViewFile;
+ modifications.add(modification);
+ }
+ return new ProjectViewEdit(project, modifications);
+ }
+
+ public void apply() {
+ apply(true);
+ }
+
+ public void undo() {
+ apply(false);
+ }
+
+ private void apply(boolean isApply) {
+ SaveUtil.saveAllFiles();
+ for (Modification modification : modifications) {
+ ProjectView projectView = isApply ? modification.newProjectView : modification.oldProjectView;
+ String projectViewText = ProjectViewParser.projectViewToString(projectView);
+ try {
+ ProjectViewStorageManager.getInstance()
+ .writeProjectView(projectViewText, modification.projectViewFile);
+ } catch (IOException e) {
+ LOG.error(e);
+ Messages.showErrorDialog(
+ project,
+ "Could not write updated project view. Is the file write protected?",
+ "Edit Failed");
+ }
+ }
+ }
+
+ public boolean hasModifications() {
+ return !modifications.isEmpty();
+ }
+
+ /** Interface for an edit to the project view */
+ public interface ProjectViewEditor {
+ boolean editProjectView(ProjectView.Builder builder);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewManager.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewManager.java
new file mode 100644
index 0000000..bbf77d3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewManager.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Class that manages access to a project's {@link ProjectView}. */
+public abstract class ProjectViewManager {
+
+ public static ProjectViewManager getInstance(Project project) {
+ return ServiceManager.getService(project, ProjectViewManager.class);
+ }
+
+ /** Returns the current project view collection. If there is an error, returns null. */
+ @Nullable
+ public abstract ProjectViewSet getProjectViewSet();
+
+ /**
+ * Reloads the project view, replacing the current one only if there are no errors.
+ *
+ * @return Success.
+ */
+ @Nullable
+ public abstract ProjectViewSet reloadProjectView(
+ BlazeContext context, WorkspacePathResolver workspacePathResolver);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
new file mode 100644
index 0000000..1e48489
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.util.SerializationUtil;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Project view manager implementation. */
+/** Stores mutable per-project user settings. */
+final class ProjectViewManagerImpl extends ProjectViewManager {
+
+ private static final Logger LOG = Logger.getInstance(ProjectViewManagerImpl.class);
+ private static final String CACHE_FILE_NAME = "project.view.dat";
+
+ private final Project project;
+ @Nullable private ProjectViewSet projectViewSet;
+ private boolean projectViewSetLoaded = false;
+
+ public ProjectViewManagerImpl(@NotNull Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public ProjectViewSet getProjectViewSet() {
+ if (projectViewSet == null && !projectViewSetLoaded) {
+ ProjectViewSet loadedProjectViewSet = null;
+ try {
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings == null) {
+ return null;
+ }
+ File file = getCacheFile(project, importSettings);
+
+ List<ClassLoader> classLoaders = Lists.newArrayList();
+ classLoaders.add(getClass().getClassLoader());
+ classLoaders.add(Thread.currentThread().getContextClassLoader());
+ loadedProjectViewSet = (ProjectViewSet) SerializationUtil.loadFromDisk(file, classLoaders);
+ } catch (IOException e) {
+ LOG.info(e);
+ }
+ this.projectViewSet = loadedProjectViewSet;
+ this.projectViewSetLoaded = true;
+ }
+ return projectViewSet;
+ }
+
+ @Override
+ public ProjectViewSet reloadProjectView(
+ BlazeContext context, WorkspacePathResolver workspacePathResolver) {
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ assert importSettings != null;
+ assert importSettings.getProjectViewFile() != null;
+ File projectViewFile = new File(importSettings.getProjectViewFile());
+ ProjectViewParser parser = new ProjectViewParser(context, workspacePathResolver);
+ parser.parseProjectView(projectViewFile);
+
+ boolean success = !context.hasErrors();
+ if (success) {
+ ProjectViewSet projectViewSet = parser.getResult();
+ File file = getCacheFile(project, importSettings);
+ try {
+ SerializationUtil.saveToDisk(file, projectViewSet);
+ } catch (IOException e) {
+ LOG.error(e);
+ }
+ this.projectViewSet = projectViewSet;
+ }
+ return success ? projectViewSet : null;
+ }
+
+ private static File getCacheFile(Project project, BlazeImportSettings importSettings) {
+ return new File(BlazeDataStorage.getProjectCacheDir(project, importSettings), CACHE_FILE_NAME);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
new file mode 100644
index 0000000..1f3ed1f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.Section;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import java.io.File;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** A collection of project views and their file names. */
+public final class ProjectViewSet implements Serializable {
+ private static final long serialVersionUID = 2L;
+
+ private final ImmutableList<ProjectViewFile> projectViewFiles;
+
+ public ProjectViewSet(ImmutableList<ProjectViewFile> projectViewFiles) {
+ this.projectViewFiles = projectViewFiles;
+ }
+
+ /** Returns all values from all list sections in the project views, in order */
+ public <T> List<T> listItems(SectionKey<T, ListSection<T>> key) {
+ List<T> result = Lists.newArrayList();
+ for (ListSection<T> section : getSections(key)) {
+ result.addAll(section.items());
+ }
+ return result;
+ }
+
+ /** Returns all values from all scalar sections in the project views, in order */
+ public <T> List<T> listScalarItems(SectionKey<T, ScalarSection<T>> key) {
+ List<T> result = Lists.newArrayList();
+ for (ScalarSection<T> section : getSections(key)) {
+ result.add(section.getValue());
+ }
+ return result;
+ }
+
+ /** Gets the last value from any scalar sections */
+ @Nullable
+ public <T> T getScalarValue(SectionKey<T, ScalarSection<T>> key) {
+ return getScalarValue(key, null);
+ }
+
+ /** Gets the last value from any scalar sections */
+ public <T> T getScalarValue(SectionKey<T, ScalarSection<T>> key, T defaultValue) {
+ Collection<ScalarSection<T>> sections = getSections(key);
+ if (sections.isEmpty()) {
+ return defaultValue;
+ } else {
+ return Iterables.getLast(sections).getValue();
+ }
+ }
+
+ public <T, SectionType extends Section<T>> Collection<SectionType> getSections(
+ SectionKey<T, SectionType> key) {
+ List<SectionType> result = Lists.newArrayList();
+ for (ProjectViewFile projectViewFile : projectViewFiles) {
+ ProjectView projectView = projectViewFile.projectView;
+ result.addAll(projectView.getSectionsOfType(key));
+ }
+ return result;
+ }
+
+ public Collection<ProjectViewFile> getProjectViewFiles() {
+ return projectViewFiles;
+ }
+
+ @Nullable
+ public ProjectViewFile getTopLevelProjectViewFile() {
+ return !projectViewFiles.isEmpty() ? projectViewFiles.get(projectViewFiles.size() - 1) : null;
+ }
+
+ /** A project view/file pair */
+ public static class ProjectViewFile implements Serializable {
+ private static final long serialVersionUID = 1L;
+ public final ProjectView projectView;
+ @Nullable public final File projectViewFile;
+
+ public ProjectViewFile(ProjectView projectView, @Nullable File projectViewFile) {
+ this.projectView = projectView;
+ this.projectViewFile = projectViewFile;
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** Builder for a project view */
+ public static class Builder {
+ ImmutableList.Builder<ProjectViewFile> projectViewFiles = ImmutableList.builder();
+
+ public Builder add(ProjectView projectView) {
+ return add(null, projectView);
+ }
+
+ public Builder add(@Nullable File projectViewFile, ProjectView projectView) {
+ projectViewFiles.add(new ProjectViewFile(projectView, projectViewFile));
+ return this;
+ }
+
+ public Builder addAll(Collection<ProjectViewFile> projectViewFiles) {
+ this.projectViewFiles.addAll(projectViewFiles);
+ return this;
+ }
+
+ public ProjectViewSet build() {
+ return new ProjectViewSet(projectViewFiles.build());
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManager.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManager.java
new file mode 100644
index 0000000..4288c1a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManager.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.components.ServiceManager;
+import java.io.File;
+import java.io.IOException;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Manages project view storage.
+ *
+ * <p>For the most part, use ProjectViewManager instead. This is a lower-level API intended for use
+ * by ProjectViewManager itself, and during the import process before a project exists.
+ */
+public abstract class ProjectViewStorageManager {
+
+ private static final String BLAZE_EXTENSION = "blazeproject";
+ private static final String BAZEL_EXTENSION = "bazelproject";
+ private static final String LEGACY_EXTENSION = "asproject";
+
+ public static final ImmutableList<String> VALID_EXTENSIONS =
+ ImmutableList.of(BLAZE_EXTENSION, BAZEL_EXTENSION, LEGACY_EXTENSION);
+
+ public static boolean isProjectViewFile(@NotNull File file) {
+ return isProjectViewFile(file.getName());
+ }
+
+ public static boolean isProjectViewFile(String fileName) {
+ for (String ext : VALID_EXTENSIONS) {
+ if (fileName.endsWith("." + ext)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static String getProjectViewFileName(BuildSystem buildSystem) {
+ switch (buildSystem) {
+ case Blaze:
+ return "." + BLAZE_EXTENSION;
+ case Bazel:
+ return "." + BAZEL_EXTENSION;
+ default:
+ throw new IllegalArgumentException("Unrecognized build system type: " + buildSystem);
+ }
+ }
+
+ public static File getLocalProjectViewFileName(
+ BuildSystem buildSystem, File projectDataDirectory) {
+ return new File(projectDataDirectory, getProjectViewFileName(buildSystem));
+ }
+
+ public static ProjectViewStorageManager getInstance() {
+ return ServiceManager.getService(ProjectViewStorageManager.class);
+ }
+
+ @Nullable
+ public abstract String loadProjectView(File projectViewFile) throws IOException;
+
+ public abstract void writeProjectView(String projectViewText, File projectViewFile)
+ throws IOException;
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
new file mode 100644
index 0000000..de784d7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Project view storage implementation. */
+final class ProjectViewStorageManagerImpl extends ProjectViewStorageManager {
+ private static final Logger LOG = Logger.getInstance(ProjectViewManagerImpl.class);
+
+ @Nullable
+ @Override
+ public String loadProjectView(@NotNull File projectViewFile) throws IOException {
+ FileInputStream fis = new FileInputStream(projectViewFile);
+ byte[] data = new byte[(int) projectViewFile.length()];
+ fis.read(data);
+ fis.close();
+ return new String(data, Charsets.UTF_8);
+ }
+
+ @Override
+ public void writeProjectView(@NotNull String projectViewText, @NotNull File projectViewFile)
+ throws IOException {
+ FileWriter fileWriter = new FileWriter(projectViewFile);
+ try {
+ fileWriter.write(projectViewText);
+ } finally {
+ fileWriter.close();
+ }
+
+ LocalFileSystem.getInstance().refreshIoFiles(ImmutableList.of(projectViewFile));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
new file mode 100644
index 0000000..4d7d56a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.io.WorkspaceScanner;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.projectview.section.sections.ExcludedSourceSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.openapi.util.io.FileUtil;
+import java.util.List;
+
+/** Verifies project views. */
+public class ProjectViewVerifier {
+
+ private static class MissingDirectoryIssueData extends IssueOutput.IssueData {
+ public final WorkspacePath workspacePath;
+
+ public MissingDirectoryIssueData(WorkspacePath workspacePath) {
+ this.workspacePath = workspacePath;
+ }
+ }
+
+ /** Verifies the project view. Any errors are output to the context as issues. */
+ public static boolean verifyProjectView(
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
+ if (!verifyIncludedPackagesExistOnDisk(context, workspaceRoot, projectViewSet)) {
+ return false;
+ }
+ if (!verifyIncludedPackagesAreNotExcluded(context, projectViewSet)) {
+ return false;
+ }
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ if (!syncPlugin.validateProjectView(context, projectViewSet, workspaceLanguageSettings)) {
+ return false;
+ }
+ }
+ if (!projectViewSet.listItems(ExcludedSourceSection.KEY).isEmpty()) {
+ IssueOutput.warn("excluded_sources is deprecated and has no effect.")
+ .inFile(projectViewSet.getTopLevelProjectViewFile().projectViewFile)
+ .submit(context);
+ }
+ return true;
+ }
+
+ private static boolean verifyIncludedPackagesAreNotExcluded(
+ BlazeContext context, ProjectViewSet projectViewSet) {
+ boolean ok = true;
+
+ List<WorkspacePath> includedDirectories = getIncludedDirectories(projectViewSet);
+
+ for (WorkspacePath includedDirectory : includedDirectories) {
+ for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
+ List<DirectoryEntry> directoryEntries = Lists.newArrayList();
+ for (ListSection<DirectoryEntry> section :
+ projectViewFile.projectView.getSectionsOfType(DirectorySection.KEY)) {
+ directoryEntries.addAll(section.items());
+ }
+
+ for (DirectoryEntry entry : directoryEntries) {
+ if (entry.included) {
+ continue;
+ }
+
+ WorkspacePath excludedDirectory = entry.directory;
+ if (FileUtil.isAncestor(
+ excludedDirectory.relativePath(), includedDirectory.relativePath(), false)) {
+ IssueOutput.error(
+ String.format(
+ "%s is included, but that contradicts %s which was excluded",
+ includedDirectory.toString(), excludedDirectory.toString()))
+ .inFile(projectViewFile.projectViewFile)
+ .submit(context);
+ ok = false;
+ }
+ }
+ }
+ }
+ return ok;
+ }
+
+ private static List<WorkspacePath> getIncludedDirectories(ProjectViewSet projectViewSet) {
+ List<WorkspacePath> includedDirectories = Lists.newArrayList();
+ for (DirectoryEntry entry : projectViewSet.listItems(DirectorySection.KEY)) {
+ if (entry.included) {
+ includedDirectories.add(entry.directory);
+ }
+ }
+ return includedDirectories;
+ }
+
+ private static boolean verifyIncludedPackagesExistOnDisk(
+ BlazeContext context, WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
+ boolean ok = true;
+
+ WorkspaceScanner workspaceScanner = WorkspaceScanner.getInstance();
+
+ for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
+ List<DirectoryEntry> directoryEntries = Lists.newArrayList();
+ for (ListSection<DirectoryEntry> section :
+ projectViewFile.projectView.getSectionsOfType(DirectorySection.KEY)) {
+ directoryEntries.addAll(section.items());
+ }
+ for (DirectoryEntry entry : directoryEntries) {
+ if (!entry.included) {
+ continue;
+ }
+ WorkspacePath workspacePath = entry.directory;
+ if (!workspaceScanner.exists(workspaceRoot, workspacePath)) {
+ IssueOutput.error(
+ String.format(
+ "Directory '%s' specified in import roots not found "
+ + "under workspace root '%s'",
+ workspacePath, workspaceRoot))
+ .inFile(projectViewFile.projectViewFile)
+ .withData(new MissingDirectoryIssueData(workspacePath))
+ .submit(context);
+ ok = false;
+ }
+ }
+ }
+ return ok;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java b/base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java
new file mode 100644
index 0000000..a7b626a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.parser;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.io.File;
+import java.util.List;
+import org.jetbrains.annotations.Nullable;
+
+/** Context for the project view parser. */
+public class ParseContext {
+ private final BlazeContext context;
+ private final WorkspacePathResolver workspacePathResolver;
+ @Nullable private final File file;
+ private final List<String> lines;
+
+ @Nullable private Line currentLine;
+ @Nullable private String currentRawLine;
+ private int currentLineIndex;
+ private int savedPosition = -1;
+
+ /** A line that is being parsed */
+ public static class Line {
+ public final String text;
+ public final int indent;
+
+ public Line(String text, int indent) {
+ this.text = text;
+ this.indent = indent;
+ }
+ }
+
+ public ParseContext(
+ BlazeContext context,
+ WorkspacePathResolver workspacePathResolver,
+ @Nullable File file,
+ String text) {
+ this.context = context;
+ this.workspacePathResolver = workspacePathResolver;
+ this.file = file;
+ this.lines = Lists.newArrayList(text.split("\n"));
+ this.currentLine = null;
+ this.currentLineIndex = -1;
+ consume();
+ }
+
+ public Line current() {
+ assert currentLine != null;
+ return currentLine;
+ }
+
+ public String currentRawLine() {
+ assert currentRawLine != null;
+ return currentRawLine;
+ }
+
+ public void consume() {
+ while (++currentLineIndex < lines.size()) {
+ update();
+ break;
+ }
+ }
+
+ private void update() {
+ String line = lines.get(currentLineIndex);
+ int indent = 0;
+ while (indent < line.length() && line.charAt(indent) == ' ') {
+ ++indent;
+ }
+ currentLine = new Line(line.trim(), indent);
+ currentRawLine = line;
+ }
+
+ public boolean atEnd() {
+ return currentLineIndex >= lines.size();
+ }
+
+ public BlazeContext getContext() {
+ return context;
+ }
+
+ public WorkspacePathResolver getWorkspacePathResolver() {
+ return workspacePathResolver;
+ }
+
+ public void savePosition() {
+ savedPosition = currentLineIndex;
+ }
+
+ public void clearSavedPosition() {
+ savedPosition = -1;
+ }
+
+ public void resetToSavedPosition() {
+ if (savedPosition != -1) {
+ currentLineIndex = savedPosition;
+ savedPosition = -1;
+ update();
+ }
+ }
+
+ @Nullable
+ public File getProjectViewFile() {
+ return file;
+ }
+
+ public void addErrors(List<BlazeValidationError> errors) {
+ for (BlazeValidationError error : errors) {
+ addError(error.getError());
+ }
+ }
+
+ public void addError(String error) {
+ IssueOutput.error(error).inFile(file).onLine(currentLineIndex).submit(context);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java b/base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java
new file mode 100644
index 0000000..2f4707f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.parser;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.projectview.section.Section;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.projectview.section.sections.Sections;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+
+/** Parses and writes project views. */
+public class ProjectViewParser {
+
+ private final BlazeContext context;
+ private final WorkspacePathResolver workspacePathResolver;
+ private final boolean recursive;
+
+ Set<File> encounteredProjectViewFiles = Sets.newHashSet();
+ ImmutableList.Builder<ProjectViewSet.ProjectViewFile> projectViewFiles = ImmutableList.builder();
+
+ public ProjectViewParser(BlazeContext context, WorkspacePathResolver workspacePathResolver) {
+ this.context = context;
+ this.workspacePathResolver = workspacePathResolver;
+ this.recursive = true;
+ }
+
+ public void parseProjectView(File projectViewFile) {
+ if (!encounteredProjectViewFiles.add(projectViewFile)) {
+ return;
+ }
+ String projectViewText = null;
+ try {
+ projectViewText = ProjectViewStorageManager.getInstance().loadProjectView(projectViewFile);
+ } catch (IOException e) {
+ // Error handled below
+ }
+ if (projectViewText == null) {
+ IssueOutput.error(
+ String.format("Could not load project view file: '%s'", projectViewFile.getPath()))
+ .submit(context);
+ return;
+ }
+ parseProjectView(
+ new ParseContext(context, workspacePathResolver, projectViewFile, projectViewText));
+ }
+
+ public void parseProjectView(String text) {
+ parseProjectView(new ParseContext(context, workspacePathResolver, null, text));
+ }
+
+ private void parseProjectView(ParseContext parseContext) {
+ ImmutableList.Builder<Section<?>> sections = ImmutableList.builder();
+
+ List<SectionParser> sectionParsers = Sections.getParsers();
+ while (!parseContext.atEnd()) {
+ Section section = null;
+ for (SectionParser sectionParser : sectionParsers) {
+ section = sectionParser.parse(this, parseContext);
+ if (section != null) {
+ sections.add(section);
+ break;
+ }
+ }
+ if (section == null) {
+ if (parseContext.current().indent != 0) {
+ parseContext.addError(
+ String.format("Invalid indentation on line: '%s'", parseContext.current().text));
+ skipSection(parseContext);
+ } else {
+ parseContext.addError(
+ String.format("Could not parse: '%s'", parseContext.current().text));
+ parseContext.consume();
+
+ // Skip past the entire section
+ skipSection(parseContext);
+ }
+ }
+ }
+
+ ProjectView projectView = new ProjectView(sections.build());
+ projectViewFiles.add(
+ new ProjectViewSet.ProjectViewFile(projectView, parseContext.getProjectViewFile()));
+ }
+
+ /** Skips all lines until the next unindented, non-empty line. */
+ private static void skipSection(ParseContext parseContext) {
+ while (!parseContext.atEnd() && parseContext.current().indent != 0) {
+ parseContext.consume();
+ }
+ }
+
+ public boolean isRecursive() {
+ return recursive;
+ }
+
+ public ProjectViewSet getResult() {
+ return new ProjectViewSet(projectViewFiles.build());
+ }
+
+ public static String projectViewToString(ProjectView projectView) {
+ StringBuilder sb = new StringBuilder();
+
+ List<SectionParser> sectionParsers = Sections.getParsers();
+ for (Section<?> section : projectView.getSections()) {
+ SectionParser sectionParser =
+ sectionParsers
+ .stream()
+ .filter(parser -> section.isSectionType(parser.getSectionKey()))
+ .findFirst()
+ .orElse(null);
+ if (sectionParser != null) {
+ sectionParser.print(sb, section);
+ }
+ }
+
+ // Because we split lines we'll always have an extra newline at the end
+ if (sb.length() > 0) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ return sb.toString();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/Glob.java b/base/src/com/google/idea/blaze/base/projectview/section/Glob.java
new file mode 100644
index 0000000..7b42abe
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/Glob.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Lists;
+import com.intellij.openapi.fileTypes.FileNameMatcher;
+import java.io.Serializable;
+import java.util.Collection;
+import org.jetbrains.jps.model.fileTypes.FileNameMatcherFactory;
+
+/** Glob matcher. */
+public class Glob implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private String pattern;
+ private transient FileNameMatcher matcher;
+
+ public Glob(String pattern) {
+ this.pattern = pattern;
+ }
+
+ /** A set of globs */
+ public static class GlobSet implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final Collection<Glob> globs = Lists.newArrayList();
+
+ public GlobSet(Collection<Glob> globs) {
+ this.globs.addAll(globs);
+ }
+
+ public boolean isEmpty() {
+ return globs.isEmpty();
+ }
+
+ public void add(Glob glob) {
+ globs.add(glob);
+ }
+
+ public boolean matches(String string) {
+ for (Glob glob : globs) {
+ if (glob.matches(string)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public boolean matches(String string) {
+ if (matcher == null) {
+ matcher = FileNameMatcherFactory.getInstance().createMatcher(pattern);
+ }
+ return matcher.accept(string);
+ }
+
+ @Override
+ public String toString() {
+ return pattern;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Glob glob = (Glob) o;
+ return Objects.equal(pattern, glob.pattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(pattern);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/GlobSectionParser.java b/base/src/com/google/idea/blaze/base/projectview/section/GlobSectionParser.java
new file mode 100644
index 0000000..01eb2d2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/GlobSectionParser.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import java.util.regex.PatternSyntaxException;
+import javax.annotation.Nullable;
+
+/** Parses glob sections. */
+public class GlobSectionParser extends ListSectionParser<Glob> {
+
+ public GlobSectionParser(SectionKey<Glob, ListSection<Glob>> key) {
+ super(key);
+ }
+
+ @Nullable
+ @Override
+ protected final Glob parseItem(ProjectViewParser parser, ParseContext parseContext) {
+ String text = parseContext.current().text;
+ try {
+ Glob glob = new Glob(text);
+ return glob;
+ } catch (PatternSyntaxException e) {
+ parseContext.addError(e.getMessage());
+ return null;
+ }
+ }
+
+ @Override
+ protected final void printItem(Glob item, StringBuilder sb) {
+ sb.append(item.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.FileSystemItem;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java b/base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java
new file mode 100644
index 0000000..bc1ed4a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Section of labels */
+public final class LabelSectionParser extends ListSectionParser<Label> {
+ public LabelSectionParser(SectionKey<Label, ListSection<Label>> key) {
+ super(key);
+ }
+
+ @Nullable
+ @Override
+ protected Label parseItem(ProjectViewParser parser, ParseContext parseContext) {
+ String text = parseContext.current().text;
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!Label.validate(text, errors)) {
+ parseContext.addErrors(errors);
+ return null;
+ }
+ return new Label(text);
+ }
+
+ @Override
+ protected void printItem(Label item, StringBuilder sb) {
+ sb.append(item.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Label;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/ListSection.java b/base/src/com/google/idea/blaze/base/projectview/section/ListSection.java
new file mode 100644
index 0000000..40ec7da
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/ListSection.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.projectview.section.sections.ItemOrTextBlock;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlock;
+import java.util.Collection;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * List value. Eg.
+ *
+ * <p>my_attribute: value0 value1 value2 ...
+ */
+public final class ListSection<T> extends Section<T> {
+ private static final long serialVersionUID = 2L;
+
+ private final ImmutableList<ItemOrTextBlock<T>> itemsOrComments;
+
+ ListSection(
+ SectionKey<T, ? extends ListSection<T>> sectionKey, ImmutableList<ItemOrTextBlock<T>> items) {
+ super(sectionKey);
+ this.itemsOrComments = items;
+ }
+
+ public Collection<T> items() {
+ return itemsOrComments
+ .stream()
+ .map(item -> item.item)
+ .filter(item -> item != null)
+ .collect(Collectors.toList());
+ }
+
+ public ImmutableList<ItemOrTextBlock<T>> itemsOrComments() {
+ return itemsOrComments;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ ListSection<?> that = (ListSection<?>) o;
+ return Objects.equal(itemsOrComments, that.itemsOrComments);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), itemsOrComments);
+ }
+
+ public static <T> Builder<T> builder(SectionKey<T, ListSection<T>> sectionKey) {
+ return new Builder<>(sectionKey, null);
+ }
+
+ public static <T> Builder<T> update(
+ SectionKey<T, ListSection<T>> sectionKey, @Nullable ListSection<T> section) {
+ return new Builder<>(sectionKey, section);
+ }
+
+ /** Builder for list sections */
+ public static class Builder<T> extends SectionBuilder<T, ListSection<T>> {
+ private final ImmutableList.Builder<ItemOrTextBlock<T>> items = ImmutableList.builder();
+
+ public Builder(SectionKey<T, ListSection<T>> sectionKey, @Nullable ListSection<T> section) {
+ super(sectionKey);
+ if (section != null) {
+ items.addAll(section.itemsOrComments);
+ }
+ }
+
+ public final Builder<T> add(T item) {
+ items.add(new ItemOrTextBlock<>(item));
+ return this;
+ }
+
+ public final Builder<T> add(TextBlock textBlock) {
+ items.add(new ItemOrTextBlock<T>(textBlock));
+ return this;
+ }
+
+ @Override
+ public final ListSection<T> build() {
+ return new ListSection<>(getSectionKey(), items.build());
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/ListSectionParser.java b/base/src/com/google/idea/blaze/base/projectview/section/ListSectionParser.java
new file mode 100644
index 0000000..a95b230
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/ListSectionParser.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.sections.ItemOrTextBlock;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlock;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** List section parser base class. */
+public abstract class ListSectionParser<T> extends SectionParser {
+ private final SectionKey<T, ListSection<T>> key;
+
+ protected ListSectionParser(SectionKey<T, ListSection<T>> key) {
+ this.key = key;
+ }
+
+ @Override
+ public SectionKey<T, ListSection<T>> getSectionKey() {
+ return key;
+ }
+
+ @Nullable
+ @Override
+ public final ListSection<T> parse(ProjectViewParser parser, ParseContext parseContext) {
+ if (parseContext.atEnd()) {
+ return null;
+ }
+
+ String name = getName();
+ if (!parseContext.current().text.equals(name + ':')) {
+ return null;
+ }
+ parseContext.consume();
+
+ ImmutableList.Builder<ItemOrTextBlock<T>> builder = ImmutableList.builder();
+
+ boolean correctIndentationRun = true;
+ List<ItemOrTextBlock<T>> savedTextBlocks = Lists.newArrayList();
+ while (!parseContext.atEnd()) {
+ boolean isIndented = parseContext.current().indent == SectionParser.INDENT;
+ if (!isIndented && correctIndentationRun) {
+ parseContext.savePosition();
+ }
+ correctIndentationRun = isIndented;
+
+ ItemOrTextBlock<T> itemOrTextBlock = null;
+ TextBlock textBlock = TextBlockSection.parseTextBlock(parseContext);
+ if (textBlock != null) {
+ itemOrTextBlock = new ItemOrTextBlock<>(textBlock);
+ } else if (isIndented) {
+ T item = parseItem(parser, parseContext);
+ if (item != null) {
+ parseContext.consume();
+ itemOrTextBlock = new ItemOrTextBlock<>(item);
+ }
+ }
+
+ if (itemOrTextBlock == null) {
+ break;
+ }
+
+ if (isIndented) {
+ builder.addAll(savedTextBlocks);
+ builder.add(itemOrTextBlock);
+ savedTextBlocks.clear();
+ parseContext.clearSavedPosition();
+ } else {
+ savedTextBlocks.add(new ItemOrTextBlock<>(textBlock));
+ }
+ }
+ parseContext.resetToSavedPosition();
+
+ ImmutableList<ItemOrTextBlock<T>> items = builder.build();
+ if (items.isEmpty()) {
+ parseContext.addError(String.format("Empty section: '%s'", name));
+ }
+
+ return new ListSection<>(key, items);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final void print(StringBuilder sb, Section<?> section) {
+ ListSection<T> listSection = (ListSection<T>) section;
+
+ // Omit empty sections completely
+ if (listSection.itemsOrComments().isEmpty()) {
+ return;
+ }
+
+ sb.append(getName()).append(':').append('\n');
+ for (ItemOrTextBlock<T> item : listSection.itemsOrComments()) {
+ if (item.item != null) {
+ for (int i = 0; i < SectionParser.INDENT; ++i) {
+ sb.append(' ');
+ }
+ printItem(item.item, sb);
+ sb.append('\n');
+ } else if (item.textBlock != null) {
+ item.textBlock.print(sb);
+ }
+ }
+ }
+
+ @Nullable
+ protected abstract T parseItem(ProjectViewParser parser, ParseContext parseContext);
+
+ protected abstract void printItem(T item, StringBuilder sb);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/ScalarSection.java b/base/src/com/google/idea/blaze/base/projectview/section/ScalarSection.java
new file mode 100644
index 0000000..0b5b903
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/ScalarSection.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.base.Objects;
+
+/** Scalar value. */
+public final class ScalarSection<T> extends Section<T> {
+ private static final long serialVersionUID = 1L;
+
+ private final T value;
+
+ public ScalarSection(SectionKey<T, ScalarSection<T>> sectionKey, T value) {
+ super(sectionKey);
+ this.value = value;
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ ScalarSection<?> that = (ScalarSection<?>) o;
+ return Objects.equal(value, that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), value);
+ }
+
+ public static <T> Builder<T> builder(SectionKey<T, ScalarSection<T>> sectionKey) {
+ return new Builder<>(sectionKey);
+ }
+
+ /** Builder for scalar sections */
+ public static class Builder<T> extends SectionBuilder<T, ScalarSection<T>> {
+ private T value;
+
+ public Builder(SectionKey<T, ScalarSection<T>> sectionKey) {
+ super(sectionKey);
+ }
+
+ public Builder<T> set(T value) {
+ this.value = value;
+ return this;
+ }
+
+ @Override
+ public ScalarSection<T> build() {
+ return new ScalarSection<>(getSectionKey(), value);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/ScalarSectionParser.java b/base/src/com/google/idea/blaze/base/projectview/section/ScalarSectionParser.java
new file mode 100644
index 0000000..dbe2e6a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/ScalarSectionParser.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import javax.annotation.Nullable;
+
+/** Parses scalar values */
+public abstract class ScalarSectionParser<T> extends SectionParser {
+
+ private final SectionKey<T, ScalarSection<T>> key;
+ private final char divider;
+
+ protected ScalarSectionParser(SectionKey<T, ScalarSection<T>> key, char divider) {
+ this.key = key;
+ this.divider = divider;
+ }
+
+ @Override
+ public SectionKey<T, ScalarSection<T>> getSectionKey() {
+ return key;
+ }
+
+ @Nullable
+ @Override
+ public final ScalarSection<T> parse(ProjectViewParser parser, ParseContext parseContext) {
+ if (parseContext.atEnd()) {
+ return null;
+ }
+
+ String name = getName();
+ ParseContext.Line line = parseContext.current();
+
+ if (!line.text.startsWith(name + divider)) {
+ return null;
+ }
+ String rest = line.text.substring(name.length() + 1).trim();
+ parseContext.consume();
+ T item = parseItem(parser, parseContext, rest);
+ return item != null ? new ScalarSection<>(key, item) : null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final void print(StringBuilder sb, Section<?> section) {
+ sb.append(getName()).append(divider);
+ if (divider != ' ') {
+ sb.append(' ');
+ }
+ printItem(sb, ((ScalarSection<T>) section).getValue());
+ sb.append('\n');
+ }
+
+ /** Used by psi-parser for validation. */
+ public char getDivider() {
+ return divider;
+ }
+
+ @Nullable
+ protected abstract T parseItem(ProjectViewParser parser, ParseContext parseContext, String rest);
+
+ protected abstract void printItem(StringBuilder sb, T value);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/Section.java b/base/src/com/google/idea/blaze/base/projectview/section/Section.java
new file mode 100644
index 0000000..f4f2740
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/Section.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.base.Objects;
+import java.io.Serializable;
+
+/**
+ * A section is a part of an project view file. For instance:
+ *
+ * <p>directories java/com/a java/com/b
+ *
+ * <p>Is a directory section with two items.
+ */
+public abstract class Section<T> implements Serializable {
+ private static final long serialVersionUID = 2L;
+ private final String sectionName;
+
+ protected Section(SectionKey<T, ?> key) {
+ this.sectionName = key.getName();
+ }
+
+ public boolean isSectionType(SectionKey<?, ?> key) {
+ return this.sectionName.equals(key.getName());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Section<?> section = (Section<?>) o;
+ return Objects.equal(sectionName, section.sectionName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(sectionName);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/SectionBuilder.java b/base/src/com/google/idea/blaze/base/projectview/section/SectionBuilder.java
new file mode 100644
index 0000000..444ea03
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/SectionBuilder.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+/** Builder base class. */
+public abstract class SectionBuilder<T, SectionType extends Section<T>> {
+ private final SectionKey<T, SectionType> sectionKey;
+
+ protected SectionBuilder(SectionKey<T, SectionType> sectionKey) {
+ this.sectionKey = sectionKey;
+ }
+
+ public abstract SectionType build();
+
+ public final SectionKey<T, SectionType> getSectionKey() {
+ return sectionKey;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/SectionKey.java b/base/src/com/google/idea/blaze/base/projectview/section/SectionKey.java
new file mode 100644
index 0000000..e7910dc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/SectionKey.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.common.base.Objects;
+import java.io.Serializable;
+
+/** Key to a section of type T. */
+public final class SectionKey<T, SectionType extends Section<T>> implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final String name;
+
+ public SectionKey(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static <T, SectionType extends Section<T>> SectionKey<T, SectionType> of(String name) {
+ return new SectionKey<>(name);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SectionKey<?, ?> that = (SectionKey<?, ?>) o;
+ return Objects.equal(name, that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java b/base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java
new file mode 100644
index 0000000..6d1164b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section;
+
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import javax.annotation.Nullable;
+
+/** Parses a section. */
+public abstract class SectionParser {
+
+ public static final int INDENT = 2;
+
+ /** The type of item(s) in this section */
+ public enum ItemType {
+ FileSystemItem, // files, directories, globs
+ Label, // a blaze label
+ Other, // anything else
+ }
+
+ public String getName() {
+ return getSectionKey().getName();
+ }
+
+ public abstract SectionKey<?, ?> getSectionKey();
+
+ @Nullable
+ public abstract Section<?> parse(ProjectViewParser parser, ParseContext parseContext);
+
+ public abstract void print(StringBuilder sb, Section<?> section);
+
+ public boolean isDeprecated() {
+ return false;
+ }
+
+ /** The type of item(s) in this section. */
+ public abstract ItemType getItemType();
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/AdditionalLanguagesSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/AdditionalLanguagesSection.java
new file mode 100644
index 0000000..d9dc894
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/AdditionalLanguagesSection.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import javax.annotation.Nullable;
+
+/** Allows users to set the rule classes they want to be imported */
+public class AdditionalLanguagesSection {
+ public static final SectionKey<LanguageClass, ListSection<LanguageClass>> KEY =
+ SectionKey.of("additional_languages");
+ public static final SectionParser PARSER = new AdditionalLanguagesSectionParser();
+
+ private static class AdditionalLanguagesSectionParser extends ListSectionParser<LanguageClass> {
+ public AdditionalLanguagesSectionParser() {
+ super(KEY);
+ }
+
+ @Nullable
+ @Override
+ protected LanguageClass parseItem(ProjectViewParser parser, ParseContext parseContext) {
+ String text = parseContext.current().text;
+ LanguageClass language = LanguageClass.fromString(text);
+ if (language == null) {
+ parseContext.addError("Invalid language: " + text);
+ return null;
+ }
+ return language;
+ }
+
+ @Override
+ protected void printItem(LanguageClass item, StringBuilder sb) {
+ sb.append(item.getName());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/BuildFlagsSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/BuildFlagsSection.java
new file mode 100644
index 0000000..588d289
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/BuildFlagsSection.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import javax.annotation.Nullable;
+
+/** Section for blaze_flags */
+public class BuildFlagsSection {
+ public static final SectionKey<String, ListSection<String>> KEY = SectionKey.of("build_flags");
+ public static final SectionParser PARSER = new BuildFlagsSectionParser();
+
+ static class BuildFlagsSectionParser extends ListSectionParser<String> {
+ protected BuildFlagsSectionParser() {
+ super(KEY);
+ }
+
+ @Nullable
+ @Override
+ protected String parseItem(ProjectViewParser parser, ParseContext parseContext) {
+ return parseContext.current().text;
+ }
+
+ @Override
+ protected void printItem(String item, StringBuilder sb) {
+ sb.append(item);
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/DirectoryEntry.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/DirectoryEntry.java
new file mode 100644
index 0000000..0744eea
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/DirectoryEntry.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.base.Objects;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import java.io.Serializable;
+
+/** An entry in the directory section. */
+public class DirectoryEntry implements Serializable {
+ private static final long serialVersionUID = 1L;
+ public final WorkspacePath directory;
+ public final boolean included;
+
+ public DirectoryEntry(WorkspacePath directory, boolean included) {
+ this.directory = directory;
+ this.included = included;
+ }
+
+ public static DirectoryEntry include(WorkspacePath directory) {
+ return new DirectoryEntry(directory, true);
+ }
+
+ public static DirectoryEntry exclude(WorkspacePath directory) {
+ return new DirectoryEntry(directory, false);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DirectoryEntry that = (DirectoryEntry) o;
+ return Objects.equal(included, that.included) && Objects.equal(directory, that.directory);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(directory, included);
+ }
+
+ @Override
+ public String toString() {
+ return (included ? "" : "-") + directoryString();
+ }
+
+ private String directoryString() {
+ if (directory.isWorkspaceRoot()) {
+ return ".";
+ }
+ return directory.relativePath();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/DirectorySection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/DirectorySection.java
new file mode 100644
index 0000000..0163e24
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/DirectorySection.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import com.intellij.util.PathUtil;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
+
+/** "directories" section. */
+public class DirectorySection {
+ public static final SectionKey<DirectoryEntry, ListSection<DirectoryEntry>> KEY =
+ SectionKey.of("directories");
+ public static final SectionParser PARSER = new DirectorySectionParser();
+
+ private static class DirectorySectionParser extends ListSectionParser<DirectoryEntry> {
+ public DirectorySectionParser() {
+ super(KEY);
+ }
+
+ @Nullable
+ @Override
+ protected DirectoryEntry parseItem(ProjectViewParser parser, ParseContext parseContext) {
+ String text = parseContext.current().text;
+ boolean excluded = text.startsWith("-");
+ text = excluded ? text.substring(1) : text;
+
+ text = PathUtil.getCanonicalPath(text);
+
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!WorkspacePath.validate(text, errors)) {
+ parseContext.addErrors(errors);
+ return null;
+ }
+ return new DirectoryEntry(new WorkspacePath(text), !excluded);
+ }
+
+ @Override
+ protected void printItem(@NotNull DirectoryEntry item, @NotNull StringBuilder sb) {
+ sb.append(item.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.FileSystemItem;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludeTargetSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludeTargetSection.java
new file mode 100644
index 0000000..9a30791
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludeTargetSection.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.section.LabelSectionParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** Excludes a target. */
+public class ExcludeTargetSection {
+ public static final SectionKey<Label, ListSection<Label>> KEY = SectionKey.of("exclude_target");
+ public static final SectionParser PARSER = new LabelSectionParser(KEY);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludedSourceSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludedSourceSection.java
new file mode 100644
index 0000000..de6081f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludedSourceSection.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.GlobSectionParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** Section for excluding source files. */
+@Deprecated
+public class ExcludedSourceSection {
+ public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("excluded_sources");
+ public static final SectionParser PARSER =
+ new GlobSectionParser(KEY) {
+ @Override
+ public boolean isDeprecated() {
+ return true;
+ }
+ };
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/ImportSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/ImportSection.java
new file mode 100644
index 0000000..e377b09
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/ImportSection.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.io.File;
+import java.util.List;
+import org.jetbrains.annotations.Nullable;
+
+/** "import" section. */
+public class ImportSection {
+ public static final SectionKey<WorkspacePath, ScalarSection<WorkspacePath>> KEY =
+ SectionKey.of("import");
+ public static final SectionParser PARSER = new ImportSectionParser();
+
+ private static class ImportSectionParser extends ScalarSectionParser<WorkspacePath> {
+ public ImportSectionParser() {
+ super(KEY, ' ');
+ }
+
+ @Nullable
+ @Override
+ protected WorkspacePath parseItem(
+ ProjectViewParser parser, ParseContext parseContext, String text) {
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ if (!WorkspacePath.validate(text, errors)) {
+ parseContext.addErrors(errors);
+ return null;
+ }
+
+ WorkspacePath workspacePath = new WorkspacePath(text);
+ if (parser.isRecursive()) {
+ File projectViewFile = parseContext.getWorkspacePathResolver().resolveToFile(workspacePath);
+ if (projectViewFile != null) {
+ parser.parseProjectView(projectViewFile);
+ } else {
+ parseContext.addError("Could not resolve import: " + workspacePath);
+ }
+ }
+ return workspacePath;
+ }
+
+ @Override
+ protected void printItem(StringBuilder sb, WorkspacePath section) {
+ sb.append(section.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.FileSystemItem;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/ImportTargetOutputSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/ImportTargetOutputSection.java
new file mode 100644
index 0000000..95d343b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/ImportTargetOutputSection.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.section.LabelSectionParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** Forces target output import of mentioned targets. */
+public class ImportTargetOutputSection {
+ public static final SectionKey<Label, ListSection<Label>> KEY =
+ SectionKey.of("import_target_output");
+ public static final SectionParser PARSER = new LabelSectionParser(KEY);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/ItemOrTextBlock.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/ItemOrTextBlock.java
new file mode 100644
index 0000000..1f75a44
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/ItemOrTextBlock.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.base.Objects;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Union of an item or comment block */
+public class ItemOrTextBlock<T> implements Serializable {
+ private static final long serialVersionUID = 2L;
+ @Nullable public final T item;
+ @Nullable public final TextBlock textBlock;
+
+ public ItemOrTextBlock(T item) {
+ this(item, null);
+ }
+
+ public ItemOrTextBlock(TextBlock comment) {
+ this(null, comment);
+ }
+
+ private ItemOrTextBlock(@Nullable T item, @Nullable TextBlock comment) {
+ this.item = item;
+ this.textBlock = comment;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ItemOrTextBlock<?> that = (ItemOrTextBlock<?>) o;
+ return Objects.equal(item, that.item) && Objects.equal(textBlock, that.textBlock);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(item, textBlock);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/MetricsProjectSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/MetricsProjectSection.java
new file mode 100644
index 0000000..3a0d6c8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/MetricsProjectSection.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.intellij.openapi.util.text.StringUtil;
+import javax.annotation.Nullable;
+
+/** Sets the metrics project to allow monitoring of individual projects */
+public class MetricsProjectSection {
+ public static final SectionKey<String, ScalarSection<String>> KEY =
+ SectionKey.of("metrics_project");
+ public static final SectionParser PARSER = new MetricsProjectSectionParser();
+
+ private static class MetricsProjectSectionParser extends ScalarSectionParser<String> {
+ public MetricsProjectSectionParser() {
+ super(KEY, ':');
+ }
+
+ @Nullable
+ @Override
+ protected String parseItem(ProjectViewParser parser, ParseContext parseContext, String rest) {
+ return StringUtil.unquoteString(rest);
+ }
+
+ @Override
+ protected void printItem(StringBuilder sb, String value) {
+ sb.append(value);
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/Sections.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/Sections.java
new file mode 100644
index 0000000..93b2fd9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/Sections.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** List of available sections. */
+public class Sections {
+ private static final List<SectionParser> PARSERS =
+ Lists.newArrayList(
+ TextBlockSection.PARSER,
+ ImportSection.PARSER,
+ DirectorySection.PARSER,
+ TargetSection.PARSER,
+ WorkspaceTypeSection.PARSER,
+ AdditionalLanguagesSection.PARSER,
+ TestSourceSection.PARSER,
+ BuildFlagsSection.PARSER,
+ ImportTargetOutputSection.PARSER,
+ ExcludeTargetSection.PARSER,
+ ExcludedSourceSection.PARSER,
+ MetricsProjectSection.PARSER);
+
+ public static List<SectionParser> getParsers() {
+ List<SectionParser> parsers = Lists.newArrayList(PARSERS);
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ parsers.addAll(syncPlugin.getSections());
+ }
+ return parsers;
+ }
+
+ public static List<SectionParser> getUndeprecatedParsers() {
+ return getParsers().stream().filter(p -> !p.isDeprecated()).collect(Collectors.toList());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/TargetSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/TargetSection.java
new file mode 100644
index 0000000..5bd3361
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/TargetSection.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** "targets" section. */
+public class TargetSection {
+ public static final SectionKey<TargetExpression, ListSection<TargetExpression>> KEY =
+ SectionKey.of("targets");
+ public static final SectionParser PARSER = new TargetSectionParser();
+
+ private static class TargetSectionParser extends ListSectionParser<TargetExpression> {
+ public TargetSectionParser() {
+ super(KEY);
+ }
+
+ @Override
+ protected TargetExpression parseItem(ProjectViewParser parser, ParseContext parseContext) {
+ String text = parseContext.current().text;
+ return TargetExpression.fromString(text);
+ }
+
+ @Override
+ protected void printItem(TargetExpression item, StringBuilder sb) {
+ sb.append(item.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Label;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/TestSourceSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/TestSourceSection.java
new file mode 100644
index 0000000..44da7b0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/TestSourceSection.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.GlobSectionParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** Section for configuring test sources. */
+public class TestSourceSection {
+ public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("test_sources");
+ public static final SectionParser PARSER = new GlobSectionParser(KEY);
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/TextBlock.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/TextBlock.java
new file mode 100644
index 0000000..351b0c4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/TextBlock.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import java.io.Serializable;
+
+/**
+ * A block of text, like comments or whitespace.
+ *
+ * <p>A text block will be entirely of one type (comment/whitespace), and should all have the same
+ * indentation.
+ */
+public class TextBlock implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private final ImmutableList<String> lines;
+
+ public TextBlock(ImmutableList<String> lines) {
+ this.lines = lines;
+ }
+
+ /** Returns raw lines, including any indentation and surrounding whitespace */
+ public ImmutableList<String> lines() {
+ return lines;
+ }
+
+ public static TextBlock of(String... lines) {
+ return new TextBlock(ImmutableList.<String>builder().add(lines).build());
+ }
+
+ /** A text block that is a single newline */
+ public static TextBlock newLine() {
+ return new TextBlock(ImmutableList.of(""));
+ }
+
+ public void print(StringBuilder sb) {
+ for (String line : lines) {
+ sb.append(line);
+ sb.append('\n');
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TextBlock textBlock = (TextBlock) o;
+ return Objects.equal(lines, textBlock.lines);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(lines);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ print(sb);
+ return sb.toString();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/TextBlockSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/TextBlockSection.java
new file mode 100644
index 0000000..b12b781
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/TextBlockSection.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.Section;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** Section with a text block. */
+public final class TextBlockSection extends Section<TextBlock> {
+ public static final SectionKey<TextBlock, TextBlockSection> KEY = SectionKey.of("textblock");
+ public static final TextBlockSectionParser PARSER = new TextBlockSectionParser();
+
+ private final TextBlock textBlock;
+
+ public TextBlockSection(TextBlock textBlock) {
+ super(KEY);
+ this.textBlock = textBlock;
+ }
+
+ public TextBlock getTextBlock() {
+ return textBlock;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ if (!super.equals(o)) {
+ return false;
+ }
+ TextBlockSection that = (TextBlockSection) o;
+ return Objects.equal(textBlock, that.textBlock);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), textBlock);
+ }
+
+ public static TextBlockSection of(TextBlock textBlock) {
+ return new TextBlockSection(textBlock);
+ }
+
+ /** Parses a single text block with equal indentation. */
+ public static TextBlock parseTextBlock(ParseContext parseContext) {
+ return TextBlockSectionParser.parseTextBlock(parseContext);
+ }
+
+ /** Text block section. */
+ private static final class TextBlockSectionParser extends SectionParser {
+ private static final Pattern COMMENT_REGEX = Pattern.compile("^\\s*#.*$");
+ private static final Pattern WHITESPACE_REGEX = Pattern.compile("^\\s*$");
+ private static final Pattern[] REGEXES = {COMMENT_REGEX, WHITESPACE_REGEX};
+
+ @Override
+ public SectionKey<TextBlock, TextBlockSection> getSectionKey() {
+ return KEY;
+ }
+
+ @Nullable
+ @Override
+ public Section<?> parse(ProjectViewParser parser, ParseContext parseContext) {
+ TextBlock textBlock = parseTextBlock(parseContext);
+ if (textBlock == null) {
+ return null;
+ }
+ return new TextBlockSection(textBlock);
+ }
+
+ @Nullable
+ private static TextBlock parseTextBlock(ParseContext parseContext) {
+ for (Pattern regex : REGEXES) {
+ TextBlock textBlock = parseTextBlock(parseContext, regex);
+ if (textBlock != null) {
+ return textBlock;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static TextBlock parseTextBlock(ParseContext parseContext, Pattern regex) {
+ ImmutableList.Builder<String> lines = null;
+ int indent = -1;
+ while (!parseContext.atEnd()) {
+ if (indent >= 0 && parseContext.current().indent != indent) {
+ break;
+ }
+ if (!regex.matcher(parseContext.currentRawLine()).matches()) {
+ break;
+ }
+ // First line we match?
+ if (lines == null) {
+ lines = ImmutableList.builder();
+ indent = parseContext.current().indent;
+ }
+ lines.add(parseContext.currentRawLine());
+ parseContext.consume();
+ }
+ if (lines == null) {
+ return null;
+ }
+ return new TextBlock(lines.build());
+ }
+
+ @Override
+ public void print(StringBuilder sb, Section<?> section) {
+ TextBlockSection textBlockSection = (TextBlockSection) section;
+ textBlockSection.getTextBlock().print(sb);
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/WorkspaceTypeSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/WorkspaceTypeSection.java
new file mode 100644
index 0000000..b59266e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/WorkspaceTypeSection.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.section.sections;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** The type of your workspace. */
+public class WorkspaceTypeSection {
+ public static final SectionKey<WorkspaceType, ScalarSection<WorkspaceType>> KEY =
+ SectionKey.of("workspace_type");
+ public static final SectionParser PARSER = new WorkspaceTypeSectionParser();
+
+ private static class WorkspaceTypeSectionParser extends ScalarSectionParser<WorkspaceType> {
+ public WorkspaceTypeSectionParser() {
+ super(KEY, ':');
+ }
+
+ @Override
+ @Nullable
+ protected WorkspaceType parseItem(
+ ProjectViewParser parser, ParseContext parseContext, String text) {
+ List<BlazeValidationError> errors = Lists.newArrayList();
+ WorkspaceType workspaceType = WorkspaceType.fromString(text);
+ if (workspaceType == null) {
+ parseContext.addError("Invalid workspace type: " + text);
+ }
+ parseContext.addErrors(errors);
+ return workspaceType;
+ }
+
+ @Override
+ protected void printItem(StringBuilder sb, WorkspaceType item) {
+ sb.append(item.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/rulemaps/ReverseDependencyMap.java b/base/src/com/google/idea/blaze/base/rulemaps/ReverseDependencyMap.java
new file mode 100644
index 0000000..0a55a8e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/rulemaps/ReverseDependencyMap.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.rulemaps;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Iterables;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Label;
+
+/** Handy class to create an reverse dep map of all rules */
+public class ReverseDependencyMap {
+ public static ImmutableMultimap<Label, Label> createRdepsMap(RuleMap ruleMap) {
+ ImmutableMultimap.Builder<Label, Label> builder = ImmutableMultimap.builder();
+ for (RuleIdeInfo rule : ruleMap.rules()) {
+ Label label = rule.label;
+ for (Label dep : Iterables.concat(rule.dependencies, rule.runtimeDeps)) {
+ if (ruleMap.contains(dep)) {
+ builder.put(dep, label);
+ }
+ }
+ }
+ return builder.build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMap.java b/base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMap.java
new file mode 100644
index 0000000..6fcf01e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMap.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.rulemaps;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+
+/** Maps source files to their respective targets */
+public interface SourceToRuleMap {
+
+ static SourceToRuleMap getInstance(Project project) {
+ return ServiceManager.getService(project, SourceToRuleMap.class);
+ }
+
+ ImmutableCollection<Label> getTargetsForSourceFile(File file);
+}
diff --git a/base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMapImpl.java b/base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMapImpl.java
new file mode 100644
index 0000000..56fd32f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMapImpl.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.rulemaps;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.sync.SyncListener;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Maps source files to their respective targets */
+public class SourceToRuleMapImpl implements SourceToRuleMap {
+ private final Project project;
+ private ImmutableMultimap<File, Label> sourceToTargetMap;
+
+ public static SourceToRuleMapImpl getImpl(Project project) {
+ return (SourceToRuleMapImpl) ServiceManager.getService(project, SourceToRuleMap.class);
+ }
+
+ public SourceToRuleMapImpl(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public ImmutableCollection<Label> getTargetsForSourceFile(File file) {
+ ImmutableMultimap<File, Label> sourceToTargetMap = getSourceToTargetMap();
+ return sourceToTargetMap != null ? sourceToTargetMap.get(file) : ImmutableList.of();
+ }
+
+ @Nullable
+ private synchronized ImmutableMultimap<File, Label> getSourceToTargetMap() {
+ if (this.sourceToTargetMap == null) {
+ this.sourceToTargetMap = initSourceToTargetMap();
+ }
+ return this.sourceToTargetMap;
+ }
+
+ private synchronized void clearSourceToTargetMap() {
+ this.sourceToTargetMap = null;
+ }
+
+ @Nullable
+ private ImmutableMultimap<File, Label> initSourceToTargetMap() {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return null;
+ }
+ ImmutableMultimap.Builder<File, Label> sourceToTargetMap = ImmutableMultimap.builder();
+ for (RuleIdeInfo rule : blazeProjectData.ruleMap.rules()) {
+ Label label = rule.label;
+ for (ArtifactLocation sourceArtifact : rule.sources) {
+ sourceToTargetMap.put(sourceArtifact.getFile(), label);
+ }
+ }
+ return sourceToTargetMap.build();
+ }
+
+ static class ClearSourceToTargetMap extends SyncListener.Adapter {
+ @Override
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
+ getImpl(project).clearSourceToTargetMap();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeBeforeRunTaskProvider.java b/base/src/com/google/idea/blaze/base/run/BlazeBeforeRunTaskProvider.java
new file mode 100644
index 0000000..aa9d617
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeBeforeRunTaskProvider.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.execution.BeforeRunTask;
+import com.intellij.execution.BeforeRunTaskProvider;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.util.Key;
+import icons.BlazeIcons;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * Provides a before run task provider that immediately transfers control to {@link
+ * com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler}
+ */
+public final class BlazeBeforeRunTaskProvider
+ extends BeforeRunTaskProvider<BlazeBeforeRunTaskProvider.Task> {
+
+ public static final Key<Task> ID = Key.create("Blaze.BeforeRunTask");
+
+ static class Task extends BeforeRunTask<Task> {
+ private Task() {
+ super(ID);
+ setEnabled(true);
+ }
+ }
+
+ @Override
+ public Key<Task> getId() {
+ return ID;
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return BlazeIcons.Blaze;
+ }
+
+ @Nullable
+ @Override
+ public Icon getTaskIcon(Task task) {
+ return BlazeIcons.Blaze;
+ }
+
+ @Override
+ public String getName() {
+ return Blaze.guessBuildSystemName() + " before-run task";
+ }
+
+ @Override
+ public String getDescription(Task task) {
+ return Blaze.guessBuildSystemName() + " before-run task";
+ }
+
+ @Override
+ public boolean isConfigurable() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public Task createTask(RunConfiguration config) {
+ if (config instanceof BlazeCommandRunConfiguration) {
+ return new Task();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean configureTask(RunConfiguration runConfiguration, Task task) {
+ return false;
+ }
+
+ @Override
+ public boolean canExecuteTask(RunConfiguration configuration, Task task) {
+ return configuration instanceof BlazeCommandRunConfiguration;
+ }
+
+ @Override
+ public boolean executeTask(
+ final DataContext dataContext,
+ final RunConfiguration configuration,
+ final ExecutionEnvironment env,
+ Task task) {
+ if (!canExecuteTask(configuration, task)) {
+ return false;
+ }
+ BlazeCommandRunConfiguration config = (BlazeCommandRunConfiguration) configuration;
+ return config.getHandler().executeBeforeRunTask(env);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java
new file mode 100644
index 0000000..4d53ff5
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.common.base.Strings;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerEditor;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+import com.google.idea.blaze.base.run.confighandler.BlazeUnknownRunConfigurationHandler;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.RunManager;
+import com.intellij.execution.RunnerIconProvider;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.LocatableConfigurationBase;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationError;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.components.JBTextField;
+import com.intellij.util.ui.UIUtil;
+import javax.annotation.Nullable;
+import javax.swing.Box;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+/** A run configuration which executes Blaze commands. */
+public class BlazeCommandRunConfiguration extends LocatableConfigurationBase
+ implements BlazeRunConfiguration, RunnerIconProvider {
+ private static final Logger LOG = Logger.getInstance(BlazeCommandRunConfiguration.class);
+
+ private static final String HANDLER_ATTR = "handler-id";
+ private static final String TARGET_TAG = "blaze-target";
+ private static final String KIND_ATTR = "kind";
+
+ // Null for configurations created since restart.
+ @Nullable private Element externalElementBackup;
+ // Null when there is no target.
+ @Nullable private TargetExpression target;
+ // Null if the target is null, not a Label, or not a known rule.
+ @Nullable private Kind targetKind;
+ private BlazeCommandRunConfigurationHandler handler;
+ // Null if the handler is BlazeUnknownRunConfigurationHandler.
+ @Nullable private BlazeCommandRunConfigurationHandlerProvider handlerProvider;
+
+ public BlazeCommandRunConfiguration(Project project, ConfigurationFactory factory, String name) {
+ super(project, factory, name);
+ handler = new BlazeUnknownRunConfigurationHandler(this);
+ }
+
+ /** @return The configuration's {@link BlazeCommandRunConfigurationHandler}. */
+ @NotNull
+ public BlazeCommandRunConfigurationHandler getHandler() {
+ return handler;
+ }
+
+ /**
+ * Gets the configuration's {@link BlazeCommandRunConfigurationHandler} if it is an instance of
+ * the given class; otherwise returns null.
+ */
+ @Nullable
+ public <T extends BlazeCommandRunConfigurationHandler> T getHandlerIfType(Class<T> type) {
+ if (type.isInstance(handler)) {
+ return type.cast(handler);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ @Nullable
+ public TargetExpression getTarget() {
+ return target;
+ }
+
+ public void setTarget(@Nullable TargetExpression target) {
+ this.target = target;
+ RuleIdeInfo rule = getRuleForTarget();
+ targetKind = rule != null ? rule.kind : null;
+
+ BlazeCommandRunConfigurationHandlerProvider handlerProvider =
+ BlazeCommandRunConfigurationHandlerProvider.findHandlerProvider(targetKind);
+ setHandlerIfDifferentProvider(handlerProvider);
+ }
+
+ private void setHandlerIfDifferentProvider(
+ BlazeCommandRunConfigurationHandlerProvider newProvider) {
+ // Only change the handler if the provider has changed.
+ if (handlerProvider != newProvider) {
+ handlerProvider = newProvider;
+ handler = newProvider.createHandler(this);
+ }
+ }
+
+ /**
+ * Returns the single blaze target corresponding to the configuration's target expression, if one
+ * exists. Returns null if the target expression points to multiple blaze targets, or wasn't
+ * included in the latest sync.
+ */
+ @Nullable
+ public RuleIdeInfo getRuleForTarget() {
+ if (target instanceof Label) {
+ return RuleFinder.getInstance().ruleForTarget(getProject(), (Label) target);
+ }
+ return null;
+ }
+
+ /**
+ * @return The {@link Kind} name, if the target is a known rule. Otherwise, "target pattern" if it
+ * is a general {@link TargetExpression}, "unknown rule" if it is a {@link Label} without a
+ * known rule, and "unknown target" if there is no target.
+ */
+ public String getTargetKindName() {
+ RuleIdeInfo rule = getRuleForTarget();
+ if (rule != null) {
+ return rule.kind.toString();
+ } else if (target instanceof Label) {
+ return "unknown rule";
+ } else if (target != null) {
+ return "target pattern";
+ } else {
+ return "unknown target";
+ }
+ }
+
+ // TODO This method can be private after BlazeCommandRunConfigurationUpdater is removed.
+ void loadExternalElementBackup() {
+ if (externalElementBackup != null) {
+ try {
+ handler.readExternal(externalElementBackup);
+ } catch (InvalidDataException e) {
+ // This is what IntelliJ does when getting this exception while loading a configuration.
+ LOG.error(e);
+ }
+ }
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ // Our handler check and its quick fix are not valid when we don't have BlazeProjectData.
+ if (BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData() == null) {
+ throw new RuntimeConfigurationError(
+ "Configuration cannot be used or modified while project is syncing.");
+ }
+ if (isConfigurationInvalidated()) {
+ throw new RuntimeConfigurationError(
+ "A property of the target unexpectedly changed. The configuration must be updated. "
+ + "Some configuration settings may be lost.",
+ () -> {
+ BlazeCommandRunConfigurationHandler oldHandler = handler;
+ setTarget(target);
+ if (handler != oldHandler) {
+ loadExternalElementBackup();
+ }
+ });
+ }
+ if (target == null) {
+ throw new RuntimeConfigurationError(
+ String.format(
+ "You must specify a %s target expression.", Blaze.buildSystemName(getProject())));
+ }
+ if (!target.toString().startsWith("//")) {
+ throw new RuntimeConfigurationError(
+ "You must specify the full target expression, starting with //");
+ }
+ handler.checkConfiguration();
+ }
+
+ private boolean isConfigurationInvalidated() {
+ boolean configurationInvalidated = handler instanceof BlazeUnknownRunConfigurationHandler;
+ if (!configurationInvalidated) {
+ RuleIdeInfo rule = getRuleForTarget();
+ Kind expectedKind = rule != null ? rule.kind : null;
+ configurationInvalidated = targetKind != expectedKind;
+ }
+ if (!configurationInvalidated) {
+ configurationInvalidated =
+ handlerProvider
+ != BlazeCommandRunConfigurationHandlerProvider.findHandlerProvider(targetKind);
+ }
+ return configurationInvalidated;
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ super.readExternal(element);
+ externalElementBackup = element.clone();
+ // Target is persisted as a tag to permit multiple targets in the future.
+ Element targetElement = element.getChild(TARGET_TAG);
+ if (targetElement != null && !Strings.isNullOrEmpty(targetElement.getTextTrim())) {
+ target = TargetExpression.fromString(targetElement.getTextTrim());
+ targetKind = Kind.fromString(targetElement.getAttributeValue(KIND_ATTR));
+ } else {
+ // Legacy: Added in 1.9 to support reading target as an attribute so
+ // BlazeAndroid(Binary/Test)RunConfiguration elements can be read.
+ // TODO remove in 2.1 once BlazeAndroidBinaryRunConfigurationType and
+ // BlazeAndroidTestRunConfigurationType have been removed.
+ String targetString =
+ element.getAttributeValue(
+ TARGET_TAG); // The attribute ID happens to be identical to the tag ID.
+ if (targetString != null) {
+ target = TargetExpression.fromString(targetString);
+ // Once the above is removed, 'target = null;' should be
+ // the only thing in the outer else clause.
+ } else {
+ target = null;
+ }
+ }
+ // Because BlazeProjectData is not available when configurations are loading,
+ // we can't call setTarget and have it find the appropriate handler provider.
+ // So instead, we use the stored provider ID.
+ String providerId = element.getAttributeValue(HANDLER_ATTR);
+ BlazeCommandRunConfigurationHandlerProvider handlerProvider =
+ BlazeCommandRunConfigurationHandlerProvider.getHandlerProvider(providerId);
+ if (handlerProvider != null) {
+ setHandlerIfDifferentProvider(handlerProvider);
+ }
+ handler.readExternal(element);
+ }
+
+ @Override
+ @SuppressWarnings("ThrowsUncheckedException")
+ public void writeExternal(Element element) throws WriteExternalException {
+ super.writeExternal(element);
+ // We can't write externalElementBackup contents; doing so would cause the configuration
+ // xml to retain duplicate elements and grow across reopenings.
+ // We also can't use the approach in BlazeUnknownRunConfigurationHandler;
+ // this can revive intentionally deleted attributes/elements such as user flags.
+ if (target != null) {
+ // Target is persisted as a tag to permit multiple targets in the future.
+ Element targetElement = new Element(TARGET_TAG);
+ targetElement.setText(target.toString());
+ if (targetKind != null) {
+ targetElement.setAttribute(KIND_ATTR, targetKind.toString());
+ }
+ element.addContent(targetElement);
+ }
+ if (handlerProvider != null) {
+ element.setAttribute(HANDLER_ATTR, handlerProvider.getId());
+ }
+ handler.writeExternal(element);
+ }
+
+ @Override
+ public BlazeCommandRunConfiguration clone() {
+ final BlazeCommandRunConfiguration configuration = (BlazeCommandRunConfiguration) super.clone();
+ if (externalElementBackup != null) {
+ configuration.externalElementBackup = externalElementBackup.clone();
+ }
+ configuration.target = target;
+ configuration.targetKind = targetKind;
+ configuration.handler = handler.cloneFor(configuration);
+ configuration.handlerProvider = handlerProvider;
+ return configuration;
+ }
+
+ @Override
+ @Nullable
+ public RunProfileState getState(
+ @NotNull Executor executor, @NotNull ExecutionEnvironment environment)
+ throws ExecutionException {
+ return handler.getState(executor, environment);
+ }
+
+ @Override
+ @Nullable
+ public String suggestedName() {
+ return handler.suggestedName();
+ }
+
+ @Override
+ public boolean isGeneratedName() {
+ return handler.isGeneratedName(super.isGeneratedName());
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(@NotNull RunConfiguration configuration, @NotNull Executor executor) {
+ return handler.getExecutorIcon(configuration, executor);
+ }
+
+ @Override
+ @NotNull
+ public SettingsEditor<? extends BlazeCommandRunConfiguration> getConfigurationEditor() {
+ return new BlazeCommandRunConfigurationSettingsEditor(this);
+ }
+
+ static class BlazeCommandRunConfigurationSettingsEditor
+ extends SettingsEditor<BlazeCommandRunConfiguration> {
+ @Nullable private BlazeCommandRunConfigurationHandlerProvider handlerProvider;
+ private BlazeCommandRunConfigurationHandlerEditor handlerEditor;
+ @Nullable private JComponent handlerComponent;
+
+ private final Box editor;
+ private final JBLabel targetExpressionLabel;
+ private final JBTextField targetField = new JBTextField(1);
+
+ private boolean isEditable;
+
+ public BlazeCommandRunConfigurationSettingsEditor(BlazeCommandRunConfiguration config) {
+ targetExpressionLabel = new JBLabel(UIUtil.ComponentStyle.LARGE);
+ editor = UiUtil.createBox(targetExpressionLabel, targetField);
+ targetField.getEmptyText().setText("Full target expression starting with //");
+ updateTargetExpressionLabel(config);
+ updateHandlerEditor(config);
+ setEditable(isConfigurationEditable(config));
+ }
+
+ private static boolean isConfigurationEditable(BlazeCommandRunConfiguration config) {
+ RunConfiguration template =
+ RunManager.getInstance(config.getProject())
+ .getConfigurationTemplate(config.getFactory())
+ .getConfiguration();
+ if (config == template) {
+ return true; // The default template is always editable.
+ }
+ return BlazeProjectDataManager.getInstance(config.getProject()).getBlazeProjectData() != null
+ && !config.isConfigurationInvalidated();
+ }
+
+ private void setEditable(boolean editable) {
+ isEditable = editable;
+ targetField.setEnabled(isEditable);
+ if (handlerComponent != null) {
+ handlerComponent.setVisible(isEditable);
+ }
+ }
+
+ private void updateTargetExpressionLabel(BlazeCommandRunConfiguration config) {
+ targetExpressionLabel.setText(
+ String.format(
+ "Target expression (%s handled by %s):",
+ config.getTargetKindName(), config.handler.getHandlerName()));
+ }
+
+ private void updateHandlerEditor(BlazeCommandRunConfiguration config) {
+ handlerProvider = config.handlerProvider;
+ handlerEditor = config.handler.getHandlerEditor();
+
+ if (handlerComponent != null) {
+ editor.remove(handlerComponent);
+ }
+ handlerComponent = handlerEditor.createEditor();
+ if (handlerComponent != null) {
+ editor.add(handlerComponent);
+ }
+ }
+
+ @Override
+ @NotNull
+ protected JComponent createEditor() {
+ return editor;
+ }
+
+ @Override
+ protected void resetEditorFrom(BlazeCommandRunConfiguration config) {
+ updateTargetExpressionLabel(config);
+ if (config.handlerProvider != handlerProvider) {
+ updateHandlerEditor(config);
+ }
+ setEditable(isConfigurationEditable(config));
+ targetField.setText(config.target == null ? null : config.target.toString());
+ handlerEditor.resetEditorFrom(config.handler);
+ }
+
+ @Override
+ protected void applyEditorTo(BlazeCommandRunConfiguration config) {
+ if (!isEditable) {
+ return;
+ }
+ applyTarget(config);
+ updateTargetExpressionLabel(config);
+ if (config.handlerProvider != handlerProvider) {
+ updateHandlerEditor(config);
+ handlerEditor.resetEditorFrom(config.handler);
+ } else {
+ handlerEditor.applyEditorTo(config.handler);
+ }
+ }
+
+ private void applyTarget(BlazeCommandRunConfiguration config) {
+ String targetString = targetField.getText();
+ BlazeCommandRunConfigurationHandler oldHandler = config.handler;
+ config.setTarget(
+ Strings.isNullOrEmpty(targetString) ? null : TargetExpression.fromString(targetString));
+ if (config.handler != oldHandler) {
+ config.loadExternalElementBackup();
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationType.java b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationType.java
new file mode 100644
index 0000000..83ac98d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationType.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.execution.BeforeRunTask;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.ConfigurationTypeUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import icons.BlazeIcons;
+import javax.swing.Icon;
+import org.jetbrains.annotations.NotNull;
+
+/** A type for run configurations that execute Blaze commands. */
+public class BlazeCommandRunConfigurationType implements ConfigurationType {
+ @NotNull
+ private final BlazeCommandRunConfigurationFactory factory =
+ new BlazeCommandRunConfigurationFactory(this);
+
+ /** A run configuration factory */
+ public static class BlazeCommandRunConfigurationFactory extends ConfigurationFactory {
+ protected BlazeCommandRunConfigurationFactory(@NotNull ConfigurationType type) {
+ super(type);
+ }
+
+ @Override
+ public boolean isApplicable(@NotNull Project project) {
+ return Blaze.isBlazeProject(project);
+ }
+
+ @Override
+ public BlazeCommandRunConfiguration createTemplateConfiguration(Project project) {
+ return new BlazeCommandRunConfiguration(project, this, "Unnamed");
+ }
+
+ @Override
+ public void configureBeforeRunTaskDefaults(
+ Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
+ task.setEnabled(providerID.equals(BlazeBeforeRunTaskProvider.ID));
+ }
+
+ @Override
+ public boolean isConfigurationSingletonByDefault() {
+ return true;
+ }
+ }
+
+ @NotNull
+ public static BlazeCommandRunConfigurationType getInstance() {
+ return ConfigurationTypeUtil.findConfigurationType(BlazeCommandRunConfigurationType.class);
+ }
+
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return Blaze.defaultBuildSystemName() + " Command";
+ }
+
+ @NotNull
+ @Override
+ public String getConfigurationTypeDescription() {
+ return String.format(
+ "Configuration for launching arbitrary %s commands.", Blaze.guessBuildSystemName());
+ }
+
+ @NotNull
+ @Override
+ public Icon getIcon() {
+ return BlazeIcons.Blaze;
+ }
+
+ @NotNull
+ @Override
+ public String getId() {
+ return "BlazeCommandRunConfigurationType";
+ }
+
+ @NotNull
+ @Override
+ public BlazeCommandRunConfigurationFactory[] getConfigurationFactories() {
+ return new BlazeCommandRunConfigurationFactory[] {factory};
+ }
+
+ @NotNull
+ public BlazeCommandRunConfigurationFactory getFactory() {
+ return factory;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationUpdater.java b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationUpdater.java
new file mode 100644
index 0000000..c04c988
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationUpdater.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.run.confighandler.BlazeUnknownRunConfigurationHandler;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.sync.SyncListener;
+import com.intellij.execution.RunManager;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.project.Project;
+
+/**
+ * Added in 1.9 to facilitate updating existing configurations to include the new handler-id and
+ * kind attributes. To be removed in 2.1.
+ */
+public class BlazeCommandRunConfigurationUpdater extends SyncListener.Adapter {
+ @Override
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
+ final RunManager runManager = RunManager.getInstance(project);
+ for (RunConfiguration configuration : runManager.getAllConfigurationsList()) {
+ if (configuration instanceof BlazeCommandRunConfiguration) {
+ BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) configuration;
+ // Only update configurations with unknown handlers, as this will
+ // reset any changes made to the handler data since the project loaded.
+ if (blazeConfig.getHandler() instanceof BlazeUnknownRunConfigurationHandler
+ // Also skip unresolved Label targets; these cannot safely be defaulted
+ // to the generic handler and should continue to display an error instead.
+ // If the Blaze cache is invalidated, all Labels can be unresolved;
+ // blindly updating them would result in loss of handler settings.
+ && !(blazeConfig.getTarget() instanceof Label
+ && blazeConfig.getRuleForTarget() == null)) {
+ blazeConfig.setTarget(blazeConfig.getTarget());
+ blazeConfig.loadExternalElementBackup();
+ }
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeConfigurationNameBuilder.java b/base/src/com/google/idea/blaze/base/run/BlazeConfigurationNameBuilder.java
new file mode 100644
index 0000000..4b7c9d0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeConfigurationNameBuilder.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import java.util.Arrays;
+
+/**
+ * Utility class for creating Blaze configuration names of the form "{build system name} {command
+ * name} {target string}", where each component is optional.
+ */
+public class BlazeConfigurationNameBuilder {
+ private String buildSystemName;
+ private String commandName;
+ private String targetString;
+
+ public BlazeConfigurationNameBuilder() {}
+
+ /**
+ * Use the passed {@code configuration} to initialize the build system name, command name, and
+ * target string. If the configuration's command name is null, this will default to "command". If
+ * the configuration's target is null, target string will also be null.
+ */
+ public BlazeConfigurationNameBuilder(BlazeCommandRunConfiguration configuration) {
+ setBuildSystemName(configuration.getProject());
+
+ String commandName = configuration.getHandler().getCommandName();
+ setCommandName((commandName == null) ? "command" : commandName);
+
+ TargetExpression targetExpression = configuration.getTarget();
+ if (targetExpression != null) {
+ setTargetString(targetExpression);
+ }
+ }
+
+ /**
+ * Sets the build system name to the name of the build system used by {@code project}, e.g.
+ * "Blaze" or "Bazel".
+ */
+ public BlazeConfigurationNameBuilder setBuildSystemName(Project project) {
+ buildSystemName = Blaze.buildSystemName(project);
+ return this;
+ }
+
+ /** Sets the command name to {@code commandName}. */
+ public BlazeConfigurationNameBuilder setCommandName(String commandName) {
+ this.commandName = commandName;
+ return this;
+ }
+
+ /** Sets the target string to {@code targetString}. */
+ public BlazeConfigurationNameBuilder setTargetString(String targetString) {
+ this.targetString = targetString;
+ return this;
+ }
+
+ /**
+ * Sets the target string to a string of the form "{package}:{target}", where 'target' is {@code
+ * label}'s target, and the 'package' is the containing package. For example, the {@link Label}
+ * "//javatests/com/google/foo/bar/baz:FooTest" will set the target string to "baz:FooTest".
+ */
+ public BlazeConfigurationNameBuilder setTargetString(Label label) {
+ this.targetString =
+ String.format("%s:%s", getImmediatePackage(label), label.ruleName().toString());
+ return this;
+ }
+
+ /**
+ * If {@code targetExpression} is a {@link Label}, this is equivalent to {@link
+ * #setTargetString(Label)}. Otherwise, the target string is set to the string value of {@code
+ * targetExpression}.
+ */
+ public BlazeConfigurationNameBuilder setTargetString(TargetExpression targetExpression) {
+ if (targetExpression instanceof Label) {
+ return setTargetString((Label) targetExpression);
+ }
+ return setTargetString(targetExpression.toString());
+ }
+
+ /**
+ * Get the portion of a label between the colon and the preceding slash. Example:
+ * "//javatests/com/google/foo/bar/baz:FooTest" -> "baz".
+ */
+ private static String getImmediatePackage(Label label) {
+ String labelString = label.toString();
+ int colonIndex = labelString.lastIndexOf(':');
+ assert colonIndex >= 0;
+ int slashIndex = labelString.lastIndexOf('/', colonIndex);
+ assert slashIndex >= 0;
+ return labelString.substring(slashIndex + 1, colonIndex);
+ }
+
+ /**
+ * Builds a name of the form "{build system name} {command name} {target string}". Any null
+ * components are omitted, and there is always one space inserted between each included component.
+ */
+ public String build() {
+ // Use this instead of String.join to omit null terms.
+ return StringUtil.join(Arrays.asList(buildSystemName, commandName, targetString), " ");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeRuleConfigurationFactory.java b/base/src/com/google/idea/blaze/base/run/BlazeRuleConfigurationFactory.java
new file mode 100644
index 0000000..f430596
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeRuleConfigurationFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.execution.RunManager;
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+
+/** A factory creating run configurations based on Blaze rules. */
+public abstract class BlazeRuleConfigurationFactory {
+ public static final ExtensionPointName<BlazeRuleConfigurationFactory> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.RuleConfigurationFactory");
+
+ /** Returns whether this factory can handle a rule. */
+ public abstract boolean handlesRule(
+ WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule);
+
+ /**
+ * Returns whether this factory can initialize a configuration. <br>
+ * The default implementation simply checks that the configuration has the same {@link
+ * com.intellij.execution.configurations.ConfigurationType} as the type of {@link
+ * #getConfigurationFactory()}.
+ */
+ public boolean handlesConfiguration(RunConfiguration configuration) {
+ return getConfigurationFactory().getType().equals(configuration.getType());
+ }
+
+ /** Constructs and initializes {@link RunnerAndConfigurationSettings} for the given rule. */
+ public RunnerAndConfigurationSettings createForRule(
+ Project project, RunManager runManager, RuleIdeInfo rule) {
+ ConfigurationFactory factory = getConfigurationFactory();
+ RunConfiguration configuration = factory.createTemplateConfiguration(project, runManager);
+ setupConfiguration(configuration, rule);
+ return runManager.createConfiguration(configuration, factory);
+ }
+
+ /** The factory used to create configurations. */
+ protected abstract ConfigurationFactory getConfigurationFactory();
+
+ /** Initialize the configuration for the given rule. */
+ public abstract void setupConfiguration(RunConfiguration configuration, RuleIdeInfo rule);
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java b/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
new file mode 100644
index 0000000..f3409af
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import org.jetbrains.annotations.Nullable;
+
+/** Marker interface for all run configurations */
+public interface BlazeRunConfiguration {
+ @Nullable
+ TargetExpression getTarget();
+}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java b/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
new file mode 100755
index 0000000..ea4aae6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.sync.SyncListener;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.execution.RunManager;
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.ui.UIUtil;
+import java.util.List;
+import java.util.Set;
+
+/** Creates run configurations for project view targets, where appropriate. */
+public class BlazeRunConfigurationSyncListener extends SyncListener.Adapter {
+
+ @Override
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
+
+ UIUtil.invokeAndWaitIfNeeded(
+ (Runnable)
+ () -> {
+ Set<Label> labelsWithConfigs = labelsWithConfigs(project);
+ Set<TargetExpression> targetExpressions =
+ Sets.newHashSet(projectViewSet.listItems(TargetSection.KEY));
+ for (RuleIdeInfo rule : blazeProjectData.ruleMap.rules()) {
+ maybeAddRunConfiguration(
+ project,
+ blazeProjectData.workspaceLanguageSettings,
+ targetExpressions,
+ labelsWithConfigs,
+ rule);
+ }
+ });
+ }
+
+ /** Collects a set of all the Blaze labels that have an associated run configuration. */
+ private static Set<Label> labelsWithConfigs(Project project) {
+ List<RunConfiguration> configurations =
+ RunManager.getInstance(project).getAllConfigurationsList();
+ Set<Label> labelsWithConfigs = Sets.newHashSet();
+ for (RunConfiguration configuration : configurations) {
+ if (configuration instanceof BlazeRunConfiguration) {
+ BlazeRunConfiguration blazeRunConfiguration = (BlazeRunConfiguration) configuration;
+ TargetExpression target = blazeRunConfiguration.getTarget();
+ if (target instanceof Label) {
+ labelsWithConfigs.add((Label) target);
+ }
+ }
+ }
+ return labelsWithConfigs;
+ }
+
+ /**
+ * Adds a run configuration for an android_binary target if there is not already a configuration
+ * for that target.
+ */
+ private static void maybeAddRunConfiguration(
+ Project project,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ Set<TargetExpression> importTargets,
+ Set<Label> labelsWithConfigs,
+ RuleIdeInfo rule) {
+ Label label = rule.label;
+ // We only auto-generate configurations for rules listed in the project view.
+ if (!importTargets.contains(label) || labelsWithConfigs.contains(label)) {
+ return;
+ }
+ labelsWithConfigs.add(label);
+ final RunManager runManager = RunManager.getInstance(project);
+
+ for (BlazeRuleConfigurationFactory configurationFactory :
+ BlazeRuleConfigurationFactory.EP_NAME.getExtensions()) {
+ if (configurationFactory.handlesRule(workspaceLanguageSettings, rule)) {
+ final RunnerAndConfigurationSettings settings =
+ configurationFactory.createForRule(project, runManager, rule);
+ runManager.addConfiguration(settings, false /* isShared */);
+ if (runManager.getSelectedConfiguration() == null) {
+ // TODO(joshgiles): Better strategy for picking initially selected config.
+ runManager.setSelectedConfiguration(settings);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/RuleNameHeuristic.java b/base/src/com/google/idea/blaze/base/run/RuleNameHeuristic.java
new file mode 100644
index 0000000..8f92d75
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/RuleNameHeuristic.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.intellij.openapi.util.io.FileUtil;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Looks for a test rule with rule name matching the source file. */
+public class RuleNameHeuristic implements TestRuleHeuristic {
+
+ @Override
+ public boolean matchesSource(RuleIdeInfo rule, File sourceFile, @Nullable TestSize testSize) {
+ String sourceName = FileUtil.getNameWithoutExtension(sourceFile);
+ return sourceName.equals(rule.label.ruleName().toString());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/TestRuleFinder.java b/base/src/com/google/idea/blaze/base/run/TestRuleFinder.java
new file mode 100644
index 0000000..4049462
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/TestRuleFinder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+
+/** Locates test rules for a given file. */
+public interface TestRuleFinder {
+
+ static TestRuleFinder getInstance(Project project) {
+ return ServiceManager.getService(project, TestRuleFinder.class);
+ }
+
+ /**
+ * Finds all test rules 'reachable' from source file (i.e. with source included in srcs, deps or
+ * runtime_deps).
+ */
+ Collection<RuleIdeInfo> testTargetsForSourceFile(File sourceFile);
+
+}
diff --git a/base/src/com/google/idea/blaze/base/run/TestRuleHeuristic.java b/base/src/com/google/idea/blaze/base/run/TestRuleHeuristic.java
new file mode 100644
index 0000000..67e6813
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/TestRuleHeuristic.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.io.File;
+import java.util.Collection;
+import javax.annotation.Nullable;
+
+/** Heuristic to match test rules to source files. */
+public interface TestRuleHeuristic {
+
+ ExtensionPointName<TestRuleHeuristic> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.TestRuleHeuristic");
+
+ /**
+ * Given a source file and all test rules reachable from that file, chooses a test rule based on
+ * available filters, falling back to choosing the first one if there is no match.
+ */
+ @Nullable
+ static Label chooseTestTargetForSourceFile(
+ File sourceFile, Collection<RuleIdeInfo> rules, @Nullable TestIdeInfo.TestSize testSize) {
+
+ for (TestRuleHeuristic filter : EP_NAME.getExtensions()) {
+ RuleIdeInfo match =
+ rules
+ .stream()
+ .filter(rule -> filter.matchesSource(rule, sourceFile, testSize))
+ .findFirst()
+ .orElse(null);
+
+ if (match != null) {
+ return match.label;
+ }
+ }
+ return rules.isEmpty() ? null : rules.iterator().next().label;
+ }
+
+ /** Returns true if the rule and source file match, according to this heuristic. */
+ boolean matchesSource(RuleIdeInfo rule, File sourceFile, @Nullable TestIdeInfo.TestSize testSize);
+}
diff --git a/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java b/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java
new file mode 100644
index 0000000..1e1b56d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Matches source files to test rules based on size annotations/tags. */
+public class TestSizeHeuristic implements TestRuleHeuristic {
+
+ @Override
+ public boolean matchesSource(RuleIdeInfo rule, File sourceFile, @Nullable TestSize testSize) {
+ // If testSize == null then prefer small
+ // Some test runners will assume no size annotation == small and filter on that, others will not
+ TestSize size = testSize != null ? testSize : TestIdeInfo.DEFAULT_NON_ANNOTATED_TEST_SIZE;
+ return TestIdeInfo.getTestSize(rule) == size;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandler.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandler.java
new file mode 100644
index 0000000..97a9aaa
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandler.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.processhandler.LineProcessingProcessAdapter;
+import com.google.idea.blaze.base.run.processhandler.ScopedBlazeProcessHandler;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.CommandLineState;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationError;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.process.ProcessListener;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.ui.components.JBTextField;
+import com.intellij.util.execution.ParametersListUtil;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.ScrollPaneConstants;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Generic handler for {@link BlazeCommandRunConfiguration}s, used as a fallback in the case where
+ * no other handlers are more relevant.
+ */
+public class BlazeCommandGenericRunConfigurationHandler
+ implements BlazeCommandRunConfigurationHandler {
+ private static final String COMMAND_ATTR = "blaze-command";
+ private static final String USER_BLAZE_FLAG_TAG = "blaze-user-flag";
+ private static final String USER_EXE_FLAG_TAG = "blaze-user-exe-flag";
+ private static final String BLAZE_BINARY_TAG = "blaze-binary";
+
+ /** The configuration this handler is for. */
+ protected final BlazeCommandRunConfiguration configuration;
+
+ @Nullable private BlazeCommandName command;
+ @Nullable private String blazeBinary;
+ private ImmutableList<String> blazeFlags = ImmutableList.of();
+ private ImmutableList<String> exeFlags = ImmutableList.of();
+
+ public BlazeCommandGenericRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ protected BlazeCommandGenericRunConfigurationHandler(
+ BlazeCommandGenericRunConfigurationHandler other,
+ BlazeCommandRunConfiguration configuration) {
+ this(configuration);
+ command = other.command;
+ blazeFlags = other.blazeFlags;
+ exeFlags = other.exeFlags;
+ blazeBinary = other.blazeBinary;
+ }
+
+ @Nullable
+ public BlazeCommandName getCommand() {
+ return command;
+ }
+
+ /** @return The list of blaze flags that the user specified manually. */
+ public List<String> getBlazeFlags() {
+ return blazeFlags;
+ }
+
+ /** @return The list of executable flags the user specified manually. */
+ public List<String> getExeFlags() {
+ return exeFlags;
+ }
+
+ /**
+ * @return The list of all flags to be used on the Blaze command line for blaze. Subclasses should
+ * override this method to add flags for higher-level settings (e.g. "run locally").
+ */
+ public List<String> getAllBlazeFlags() {
+ return getBlazeFlags();
+ }
+
+ @Nullable
+ public String getBlazeBinary() {
+ return blazeBinary;
+ }
+
+ /**
+ * @return The list of all flags to be used for the executable on the Blaze command line.
+ * Subclasses should override this method to add flags if desired.
+ */
+ public List<String> getAllExeFlags() {
+ return getExeFlags();
+ }
+
+ public void setCommand(@Nullable BlazeCommandName command) {
+ this.command = command;
+ }
+
+ public final void setBlazeFlags(List<String> flags) {
+ this.blazeFlags = ImmutableList.copyOf(flags);
+ }
+
+ public final void setExeFlags(List<String> flags) {
+ this.exeFlags = ImmutableList.copyOf(flags);
+ }
+
+ public void setBlazeBinary(@Nullable String blazeBinary) {
+ this.blazeBinary = blazeBinary;
+ }
+
+ /** Searches through all blaze flags for the first one beginning with '--test_filter' */
+ @Nullable
+ public String getTestFilterFlag() {
+ for (String flag : getAllBlazeFlags()) {
+ if (flag.startsWith(BlazeFlags.TEST_FILTER)) {
+ return flag;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ if (command == null) {
+ throw new RuntimeConfigurationError("You must specify a command.");
+ }
+ if (blazeBinary != null && !(new File(blazeBinary).exists())) {
+ throw new RuntimeConfigurationError(
+ Blaze.buildSystemName(configuration.getProject()) + " binary does not exist");
+ }
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ String commandString = element.getAttributeValue(COMMAND_ATTR);
+ command =
+ Strings.isNullOrEmpty(commandString) ? null : BlazeCommandName.fromString(commandString);
+ blazeFlags = loadUserFlags(element, USER_BLAZE_FLAG_TAG);
+ exeFlags = loadUserFlags(element, USER_EXE_FLAG_TAG);
+ blazeBinary = element.getAttributeValue(BLAZE_BINARY_TAG);
+ }
+
+ private static ImmutableList<String> loadUserFlags(Element root, String tag) {
+ ImmutableList.Builder<String> flagsBuilder = ImmutableList.builder();
+ for (Element e : root.getChildren(tag)) {
+ String flag = e.getTextTrim();
+ if (flag != null && !flag.isEmpty()) {
+ flagsBuilder.add(flag);
+ }
+ }
+ return flagsBuilder.build();
+ }
+
+ @Override
+ public void writeExternal(Element element) {
+ if (command != null) {
+ element.setAttribute(COMMAND_ATTR, command.toString());
+ }
+ saveUserFlags(element, blazeFlags, USER_BLAZE_FLAG_TAG);
+ saveUserFlags(element, exeFlags, USER_EXE_FLAG_TAG);
+ if (!Strings.isNullOrEmpty(blazeBinary)) {
+ element.setAttribute(BLAZE_BINARY_TAG, blazeBinary);
+ }
+ }
+
+ private static void saveUserFlags(Element root, List<String> flags, String tag) {
+ for (String flag : flags) {
+ Element child = new Element(tag);
+ child.setText(flag);
+ root.addContent(child);
+ }
+ }
+
+ @Override
+ public BlazeCommandGenericRunConfigurationHandler cloneFor(
+ BlazeCommandRunConfiguration configuration) {
+ return new BlazeCommandGenericRunConfigurationHandler(this, configuration);
+ }
+
+ @Override
+ public RunProfileState getState(Executor executor, ExecutionEnvironment environment) {
+ return new BlazeCommandGenericRunConfigurationHandler.BlazeCommandRunProfileState(environment);
+ }
+
+ @Override
+ public boolean executeBeforeRunTask(ExecutionEnvironment environment) {
+ // Don't execute any tasks.
+ return true;
+ }
+
+ @Override
+ @Nullable
+ public String suggestedName() {
+ if (configuration.getTarget() == null) {
+ return null;
+ }
+ return new BlazeConfigurationNameBuilder(configuration).build();
+ }
+
+ @Override
+ @Nullable
+ public String getCommandName() {
+ return command != null ? command.toString() : null;
+ }
+
+ @Override
+ public boolean isGeneratedName(boolean hasGeneratedFlag) {
+ return hasGeneratedFlag;
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "Generic Handler";
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(RunConfiguration configuration, Executor executor) {
+ return null;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandlerEditor getHandlerEditor() {
+ return new BlazeCommandGenericRunConfigurationHandler
+ .BlazeCommandGenericRunConfigurationHandlerEditor(this);
+ }
+
+ /** {@link RunProfileState} for generic blaze commands. */
+ private static class BlazeCommandRunProfileState extends CommandLineState {
+ private final BlazeCommandRunConfiguration configuration;
+ private final BlazeCommandGenericRunConfigurationHandler handler;
+
+ BlazeCommandRunProfileState(ExecutionEnvironment environment) {
+ super(environment);
+ RunProfile runProfile = environment.getRunProfile();
+ configuration = (BlazeCommandRunConfiguration) runProfile;
+ handler = (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+ }
+
+ @Override
+ @NotNull
+ protected ProcessHandler startProcess() throws ExecutionException {
+ Project project = configuration.getProject();
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ assert importSettings != null;
+
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ assert projectViewSet != null;
+
+ BlazeCommand blazeCommand =
+ BlazeCommand.builder(Blaze.getBuildSystem(project), handler.getCommand())
+ .setBlazeBinary(handler.getBlazeBinary())
+ .addTargets(configuration.getTarget())
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
+ .addBlazeFlags(handler.getAllBlazeFlags())
+ .addExeFlags(handler.getAllExeFlags())
+ .build();
+
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
+ return new ScopedBlazeProcessHandler(
+ project,
+ blazeCommand,
+ workspaceRoot,
+ new ScopedBlazeProcessHandler.ScopedProcessHandlerDelegate() {
+ @Override
+ public void onBlazeContextStart(BlazeContext context) {
+ context
+ .push(new LoggedTimingScope(project, Action.BLAZE_COMMAND_USAGE))
+ .push(new IssuesScope(project))
+ .push(new IdeaLogScope());
+ }
+
+ @Override
+ public ImmutableList<ProcessListener> createProcessListeners(BlazeContext context) {
+ LineProcessingOutputStream outputStream =
+ LineProcessingOutputStream.of(
+ new IssueOutputLineProcessor(project, context, workspaceRoot));
+ return ImmutableList.of(new LineProcessingProcessAdapter(outputStream));
+ }
+ });
+ }
+ }
+
+ /** {@link BlazeCommandRunConfigurationHandlerEditor} for generic blaze commands. */
+ static class BlazeCommandGenericRunConfigurationHandlerEditor
+ implements BlazeCommandRunConfigurationHandlerEditor {
+ private final String buildSystemName;
+
+ private final ComboBox commandCombo;
+ private final JTextArea blazeFlagsField = new JTextArea(5, 1);
+ private final JTextArea exeFlagsField = new JTextArea(5, 1);
+ private final JBTextField blazeBinaryField = new JBTextField(1);
+
+ public BlazeCommandGenericRunConfigurationHandlerEditor(
+ BlazeCommandGenericRunConfigurationHandler handler) {
+ buildSystemName = Blaze.buildSystemName(handler.configuration.getProject());
+ commandCombo =
+ new ComboBox(new DefaultComboBoxModel(BlazeCommandName.knownCommands().toArray()));
+ // Allow the user to manually specify an unlisted command.
+ commandCombo.setEditable(true);
+ blazeBinaryField.getEmptyText().setText("(Use global)");
+ }
+
+ private static String makeArgString(List<String> arguments) {
+ StringBuilder flagString = new StringBuilder();
+ for (String flag : arguments) {
+ if (flagString.length() > 0) {
+ flagString.append('\n');
+ }
+ if (flag.isEmpty() || flag.contains(" ") || flag.contains("|")) {
+ flagString.append('"');
+ flagString.append(flag);
+ flagString.append('"');
+ } else {
+ flagString.append(flag);
+ }
+ }
+ return flagString.toString();
+ }
+
+ @Override
+ public void resetEditorFrom(BlazeCommandRunConfigurationHandler h) {
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) h;
+
+ commandCombo.setSelectedItem(handler.command);
+
+ // Normally we could just use ParametersListUtils.join, but that will only space-delimit args
+ blazeFlagsField.setText(makeArgString(handler.getBlazeFlags()));
+ exeFlagsField.setText(makeArgString(handler.getExeFlags()));
+
+ blazeBinaryField.setText(Strings.nullToEmpty(handler.blazeBinary));
+ }
+
+ @Override
+ public void applyEditorTo(BlazeCommandRunConfigurationHandler h) {
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) h;
+ Object selectedCommand = commandCombo.getSelectedItem();
+ if (selectedCommand instanceof BlazeCommandName) {
+ handler.command = (BlazeCommandName) selectedCommand;
+ } else {
+ handler.command =
+ Strings.isNullOrEmpty((String) selectedCommand)
+ ? null
+ : BlazeCommandName.fromString(selectedCommand.toString());
+ }
+ handler.blazeFlags =
+ ImmutableList.copyOf(
+ ParametersListUtil.parse(Strings.nullToEmpty(blazeFlagsField.getText())));
+ handler.exeFlags =
+ ImmutableList.copyOf(
+ ParametersListUtil.parse(Strings.nullToEmpty(exeFlagsField.getText())));
+
+ String blazeBinary = blazeBinaryField.getText();
+ handler.blazeBinary = Strings.emptyToNull(blazeBinary);
+ }
+
+ @Override
+ @NotNull
+ public JComponent createEditor() {
+ return UiUtil.createBox(
+ new JLabel(buildSystemName + " command:"),
+ commandCombo,
+ new JLabel(buildSystemName + " flags:"),
+ new JScrollPane(
+ blazeFlagsField,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
+ new JLabel("Executable flags:"),
+ new JScrollPane(
+ exeFlagsField,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
+ new JLabel(buildSystemName + " binary:"),
+ blazeBinaryField);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandlerProvider.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..f993c45
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandlerProvider.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+
+/**
+ * Generic handler provider for {@link BlazeCommandRunConfiguration}s, used as a fallback in the
+ * case where no other handler providers are more relevant.
+ */
+public class BlazeCommandGenericRunConfigurationHandlerProvider
+ implements BlazeCommandRunConfigurationHandlerProvider {
+
+ public static BlazeCommandGenericRunConfigurationHandlerProvider getInstance() {
+ return BlazeCommandRunConfigurationHandlerProvider.EP_NAME.findExtension(
+ BlazeCommandGenericRunConfigurationHandlerProvider.class);
+ }
+
+ @Override
+ public boolean canHandleKind(Kind kind) {
+ return true;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config) {
+ return new BlazeCommandGenericRunConfigurationHandler(config);
+ }
+
+ @Override
+ public String getId() {
+ return "BlazeCommandGenericRunConfigurationHandlerProvider";
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandler.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandler.java
new file mode 100644
index 0000000..7d88a7e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandler.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+import org.jdom.Element;
+
+/**
+ * Supports the run configuration flow for {@link BlazeCommandRunConfiguration}s.
+ *
+ * <p>Provides rule-specific configuration state, editor, name, RunProfileState, and
+ * before-run-tasks.
+ */
+public interface BlazeCommandRunConfigurationHandler {
+
+ /**
+ * Checks whether the handler settings are valid.
+ *
+ * @throws RuntimeConfigurationException for configuration errors the user should be warned about.
+ */
+ void checkConfiguration() throws RuntimeConfigurationException;
+
+ /** Loads this handler's state from the external data. */
+ void readExternal(Element element) throws InvalidDataException;
+
+ /** Writes this handler's state to the element. */
+ @SuppressWarnings("ThrowsUncheckedException")
+ void writeExternal(Element element) throws WriteExternalException;
+
+ /**
+ * Creates a clone of this handler for the specified configuration.
+ *
+ * @return A new BlazeCommandRunConfigurationHandler with the same state as this one, except its
+ * configuration is the specified {@code configuration}.
+ */
+ BlazeCommandRunConfigurationHandler cloneFor(BlazeCommandRunConfiguration configuration);
+
+ /** @return the RunProfileState corresponding to the given environment. */
+ RunProfileState getState(Executor executor, ExecutionEnvironment environment)
+ throws ExecutionException;
+
+ /**
+ * Executes any required before run tasks.
+ *
+ * @return true if no task exists or the task was successfully completed. Otherwise returns false
+ * if the task either failed or was cancelled.
+ */
+ boolean executeBeforeRunTask(ExecutionEnvironment environment);
+
+ /**
+ * @return The default name of the run configuration based on its settings and this handler's
+ * state.
+ */
+ @Nullable
+ String suggestedName();
+
+ /**
+ * Allows overriding the default behavior of {@link
+ * com.intellij.execution.configurations.LocatableConfiguration#isGeneratedName()}. Return {@code
+ * hasGeneratedFlag} to keep the default behavior.
+ *
+ * @param hasGeneratedFlag Whether the configuration reports its name is generated.
+ * @return Whether the run configuration's name should be treated as generated (allowing
+ * regenerating it when settings change).
+ */
+ boolean isGeneratedName(boolean hasGeneratedFlag);
+
+ /**
+ * @return The name of the Blaze command associated with this handler. May be null if no command
+ * is appropriate.
+ */
+ @Nullable
+ String getCommandName();
+
+ /** @return The name of this handler. Shown in the UI. */
+ String getHandlerName();
+
+ /**
+ * Allows overriding the default behavior of {@link
+ * com.intellij.execution.RunnerIconProvider#getExecutorIcon(RunConfiguration, Executor)}. Return
+ * null to keep the default behavior.
+ */
+ @Nullable
+ Icon getExecutorIcon(RunConfiguration configuration, Executor executor);
+
+ /** @return A {@link BlazeCommandRunConfigurationHandlerEditor} for this handler. */
+ BlazeCommandRunConfigurationHandlerEditor getHandlerEditor();
+}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandlerEditor.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandlerEditor.java
new file mode 100644
index 0000000..0c9bce7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandlerEditor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import javax.swing.JComponent;
+import org.jetbrains.annotations.Nullable;
+
+/** Provides support for editing {@link BlazeCommandRunConfigurationHandler}s. */
+public interface BlazeCommandRunConfigurationHandlerEditor {
+ /** Reset the editor based on the state of the given handler. */
+ void resetEditorFrom(BlazeCommandRunConfigurationHandler handler);
+
+ /** Update the given handler's state based on the editor. */
+ void applyEditorTo(BlazeCommandRunConfigurationHandler handler);
+
+ /** @return A component to display for the editor. */
+ @Nullable
+ JComponent createEditor();
+}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandlerProvider.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..af67362
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandRunConfigurationHandlerProvider.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import javax.annotation.Nullable;
+
+/**
+ * Provides a {@link BlazeCommandRunConfigurationHandler} corresponding to a given {@link
+ * BlazeCommandRunConfiguration}.
+ */
+public interface BlazeCommandRunConfigurationHandlerProvider {
+
+ ExtensionPointName<BlazeCommandRunConfigurationHandlerProvider> EP_NAME =
+ ExtensionPointName.create(
+ "com.google.idea.blaze.BlazeCommandRunConfigurationHandlerProvider");
+
+ /**
+ * Find a BlazeCommandRunConfigurationHandlerProvider applicable to the given kind. If no provider
+ * is more relevant, {@link BlazeCommandGenericRunConfigurationHandlerProvider} is returned.
+ */
+ static BlazeCommandRunConfigurationHandlerProvider findHandlerProvider(Kind kind) {
+ for (BlazeCommandRunConfigurationHandlerProvider handlerProvider : EP_NAME.getExtensions()) {
+ if (handlerProvider.canHandleKind(kind)) {
+ return handlerProvider;
+ }
+ }
+ // BlazeCommandGenericRunConfigurationHandlerProvider can handle any kind,
+ // and will be returned by this point.
+ assert false;
+ return null;
+ }
+
+ /** Get the BlazeCommandRunConfigurationHandlerProvider with the given ID, if one exists. */
+ @Nullable
+ static BlazeCommandRunConfigurationHandlerProvider getHandlerProvider(@Nullable String id) {
+ for (BlazeCommandRunConfigurationHandlerProvider handlerProvider : EP_NAME.getExtensions()) {
+ if (handlerProvider.getId().equals(id)) {
+ return handlerProvider;
+ }
+ }
+ return null;
+ }
+
+ /** Whether this extension is applicable to the kind. */
+ boolean canHandleKind(Kind kind);
+
+ /** Returns the corresponding {@link BlazeCommandRunConfigurationHandler}. */
+ BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config);
+
+ /**
+ * Returns the unique ID of this {@link BlazeCommandRunConfigurationHandlerProvider}. The ID is
+ * used to store configuration settings and must not change between plugin versions.
+ */
+ String getId();
+}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeUnknownRunConfigurationHandler.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeUnknownRunConfigurationHandler.java
new file mode 100644
index 0000000..e968860
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeUnknownRunConfigurationHandler.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.util.InvalidDataException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import org.jdom.Attribute;
+import org.jdom.Element;
+
+/**
+ * Fallback handler for {@link BlazeCommandRunConfiguration}s with uninitialized targets or unknown
+ * handler providers.
+ *
+ * <p>Cannot be run and provides no editor. Writes all attributes and elements it initially read,
+ * except those with names matching existing content written by the configuration itself.
+ */
+public class BlazeUnknownRunConfigurationHandler implements BlazeCommandRunConfigurationHandler {
+
+ private final BlazeCommandRunConfiguration configuration;
+
+ @Nullable private Element externalElementBackup;
+
+ public BlazeUnknownRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ // No need to throw anything here; BlazeCommandRunConfiguration's
+ // check will already detect any config with this handler as invalid
+ // because its provider is null and all targets are handled by some provider.
+ assert false;
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ externalElementBackup = element.clone();
+ }
+
+ @Override
+ public void writeExternal(Element element) {
+ // Write back attributes and elements from externalElementBackup,
+ // but take care not to write any which exist in the passed element.
+ // Such attributes and elements belong to the configuration, not the handler!
+ if (externalElementBackup != null) {
+ Set<String> configurationAttributeNames = new HashSet<>();
+ for (Attribute attribute : element.getAttributes()) {
+ configurationAttributeNames.add(attribute.getName());
+ }
+ Set<String> configurationElementNames = new HashSet<>();
+ for (Element child : element.getChildren()) {
+ configurationElementNames.add(child.getName());
+ }
+
+ for (Attribute attribute : externalElementBackup.getAttributes()) {
+ if (!configurationAttributeNames.contains(attribute.getName())) {
+ element.setAttribute(attribute.clone());
+ }
+ }
+ for (Element child : externalElementBackup.getChildren()) {
+ if (!configurationElementNames.contains(child.getName())) {
+ element.addContent(child.clone());
+ }
+ }
+ }
+ }
+
+ @Override
+ public BlazeUnknownRunConfigurationHandler cloneFor(BlazeCommandRunConfiguration configuration) {
+ return new BlazeUnknownRunConfigurationHandler(configuration);
+ }
+
+ @Override
+ public RunProfileState getState(Executor executor, ExecutionEnvironment environment)
+ throws ExecutionException {
+ return null;
+ }
+
+ @Override
+ public boolean executeBeforeRunTask(ExecutionEnvironment environment) {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public String suggestedName() {
+ return String.format(
+ "Unknown %s Configuration", Blaze.buildSystemName(configuration.getProject()));
+ }
+
+ @Override
+ public boolean isGeneratedName(boolean hasGeneratedFlag) {
+ return hasGeneratedFlag;
+ }
+
+ @Nullable
+ @Override
+ public String getCommandName() {
+ return null;
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "no handler";
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(RunConfiguration configuration, Executor executor) {
+ return null;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandlerEditor getHandlerEditor() {
+ return new BlazeCommandRunConfigurationHandlerEditor() {
+ @Override
+ public void resetEditorFrom(BlazeCommandRunConfigurationHandler handler) {}
+
+ @Override
+ public void applyEditorTo(BlazeCommandRunConfigurationHandler handler) {}
+
+ @Override
+ @Nullable
+ public JComponent createEditor() {
+ // Note: currently this will never be displayed,
+ // as the handler editor is not shown for invalidated configurations.
+ //return new JBLabel("Configuration could not be loaded "
+ // + "because its handler could not be found.");
+ return null;
+ }
+ };
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/processhandler/LineProcessingProcessAdapter.java b/base/src/com/google/idea/blaze/base/run/processhandler/LineProcessingProcessAdapter.java
new file mode 100644
index 0000000..891f19f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/processhandler/LineProcessingProcessAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.processhandler;
+
+import com.google.common.base.Charsets;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.openapi.util.Key;
+import java.io.IOException;
+
+/** Writes output from a process to a stream */
+public final class LineProcessingProcessAdapter extends ProcessAdapter {
+ private final LineProcessingOutputStream myOutputStream;
+
+ public LineProcessingProcessAdapter(LineProcessingOutputStream outputStream) {
+ myOutputStream = outputStream;
+ }
+
+ @Override
+ public void onTextAvailable(ProcessEvent event, Key outputType) {
+ String text = event.getText();
+ if (text != null) {
+ try {
+ myOutputStream.write(text.getBytes(Charsets.UTF_8));
+ } catch (IOException e) {
+ // Ignore -- cannot happen
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/processhandler/ScopedBlazeProcessHandler.java b/base/src/com/google/idea/blaze/base/run/processhandler/ScopedBlazeProcessHandler.java
new file mode 100644
index 0000000..7cd3050
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/processhandler/ScopedBlazeProcessHandler.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.processhandler;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.filecache.FileCaches;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.process.KillableColoredProcessHandler;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessListener;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+
+/**
+ * Scoped process handler.
+ *
+ * <p>A context is created during construction and is ended when the process is terminated.
+ */
+public final class ScopedBlazeProcessHandler extends KillableColoredProcessHandler {
+ /**
+ * Methods to give the caller of {@link ScopedBlazeProcessHandler} hooks after the context is
+ * created.
+ */
+ public interface ScopedProcessHandlerDelegate {
+ /**
+ * This method is called when the process starts. Any context setup (like pushing scopes on the
+ * context) should be done here.
+ */
+ void onBlazeContextStart(BlazeContext context);
+
+ /** Get a list of process listeners to add to the process. */
+ ImmutableList<ProcessListener> createProcessListeners(BlazeContext context);
+ }
+
+ private final ScopedProcessHandlerDelegate scopedProcessHandlerDelegate;
+ private final BlazeContext context;
+
+ /**
+ * Construct a process handler and a context to be used for the life of the process.
+ *
+ * @param blazeCommand the blaze command to run
+ * @param workspaceRoot workspace root
+ * @param scopedProcessHandlerDelegate delegate methods that will be run with the process's
+ * context.
+ * @throws ExecutionException
+ */
+ public ScopedBlazeProcessHandler(
+ Project project,
+ BlazeCommand blazeCommand,
+ WorkspaceRoot workspaceRoot,
+ ScopedProcessHandlerDelegate scopedProcessHandlerDelegate)
+ throws ExecutionException {
+ super(
+ new GeneralCommandLine(blazeCommand.toList())
+ .withWorkDirectory(workspaceRoot.directory().getPath()));
+
+ this.scopedProcessHandlerDelegate = scopedProcessHandlerDelegate;
+ this.context = new BlazeContext();
+ // The context is released in the ScopedProcessHandlerListener.
+ this.context.hold();
+
+ for (ProcessListener processListener :
+ scopedProcessHandlerDelegate.createProcessListeners(context)) {
+ addProcessListener(processListener);
+ }
+ addProcessListener(new ScopedProcessHandlerListener(project));
+ }
+
+ @Override
+ public void coloredTextAvailable(String text, Key attributes) {
+ // Change blaze's stderr output to normal color, otherwise
+ // test output looks red
+ if (attributes == ProcessOutputTypes.STDERR) {
+ attributes = ProcessOutputTypes.STDOUT;
+ }
+
+ super.coloredTextAvailable(text, attributes);
+ }
+
+ /**
+ * Handle the {@link BlazeContext} held in a {@link ScopedBlazeProcessHandler}. This class will
+ * take care of calling methods when the process starts and freeing the context when the process
+ * terminates.
+ */
+ private class ScopedProcessHandlerListener extends ProcessAdapter {
+
+ private final Project project;
+
+ ScopedProcessHandlerListener(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public void startNotified(ProcessEvent event) {
+ scopedProcessHandlerDelegate.onBlazeContextStart(context);
+ }
+
+ @Override
+ public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
+ FileCaches.refresh(project);
+ context.release();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/producers/AllInPackageBlazeConfigurationProducer.java b/base/src/com/google/idea/blaze/base/run/producers/AllInPackageBlazeConfigurationProducer.java
new file mode 100644
index 0000000..e3746f3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/producers/AllInPackageBlazeConfigurationProducer.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.producers;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/** Runs tests in all packages below selected directory */
+public class AllInPackageBlazeConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ public AllInPackageBlazeConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+
+ PsiDirectory dir = getTestDirectory(context);
+ if (dir == null) {
+ return false;
+ }
+ WorkspaceRoot root = WorkspaceRoot.fromProject(context.getModule().getProject());
+ WorkspacePath packagePath = getWorkspaceRelativeDirectoryPath(root, dir);
+ if (packagePath == null) {
+ return false;
+ }
+ sourceElement.set(dir);
+
+ configuration.setTarget(TargetExpression.allFromPackageRecursive(packagePath));
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ handler.setCommand(BlazeCommandName.TEST);
+ configuration.setGeneratedName();
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+
+ PsiDirectory dir = getTestDirectory(context);
+ if (dir == null) {
+ return false;
+ }
+ WorkspaceRoot root = WorkspaceRoot.fromProject(context.getModule().getProject());
+ WorkspacePath packagePath = getWorkspaceRelativeDirectoryPath(root, dir);
+ if (packagePath == null) {
+ return false;
+ }
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ return Objects.equals(handler.getCommand(), BlazeCommandName.TEST)
+ && Objects.equals(
+ configuration.getTarget(), TargetExpression.allFromPackageRecursive(packagePath));
+ }
+
+ @Nullable
+ private static PsiDirectory getTestDirectory(ConfigurationContext context) {
+ WorkspaceRoot root = WorkspaceRoot.fromProject(context.getModule().getProject());
+ PsiElement location = context.getPsiLocation();
+ if (location instanceof PsiDirectory) {
+ PsiDirectory dir = (PsiDirectory) location;
+ if (isInWorkspace(root, dir)) {
+ return dir;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static WorkspacePath getWorkspaceRelativeDirectoryPath(
+ WorkspaceRoot root, PsiDirectory dir) {
+ VirtualFile file = dir.getVirtualFile();
+ if (isInWorkspace(root, dir)) {
+ return root.workspacePathFor(file);
+ }
+ return null;
+ }
+
+ private static boolean isInWorkspace(WorkspaceRoot root, PsiDirectory dir) {
+ return root.isInWorkspace(dir.getVirtualFile());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/producers/BlazeBuildFileRunConfigurationProducer.java b/base/src/com/google/idea/blaze/base/run/producers/BlazeBuildFileRunConfigurationProducer.java
new file mode 100644
index 0000000..a28b644
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/producers/BlazeBuildFileRunConfigurationProducer.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.producers;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/** Creates run configurations from a BUILD file targets. */
+public class BlazeBuildFileRunConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ private static class BuildTarget {
+ private final FuncallExpression rule;
+ private final String ruleType;
+ private final Label label;
+ @Nullable private final RuleIdeInfo ruleIdeInfo;
+
+ public BuildTarget(
+ FuncallExpression rule, String ruleType, Label label, @Nullable RuleIdeInfo ruleIdeInfo) {
+ this.rule = rule;
+ this.ruleType = ruleType;
+ this.label = label;
+ this.ruleIdeInfo = ruleIdeInfo;
+ }
+ }
+
+ public BlazeBuildFileRunConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(configuration.getProject()).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return false;
+ }
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ blazeProjectData.workspaceLanguageSettings;
+ BuildTarget target = getBuildTarget(context);
+ if (target == null) {
+ return false;
+ }
+ sourceElement.set(target.rule);
+ setupConfiguration(configuration, workspaceLanguageSettings, target);
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+ BuildTarget target = getBuildTarget(context);
+ if (target == null) {
+ return false;
+ }
+ if (!Objects.equals(configuration.getTarget(), target.label)) {
+ return false;
+ }
+
+ // We don't know any details about how the various factories set up configurations from here.
+ // Simply returning true at this point would be overly broad
+ // (all configs with a matching target would be identified).
+ // A complete equality check, meanwhile, would be too restrictive
+ // (things like config name and user flags shouldn't count)
+ // - not to mention we lack the equals() implementations needed to perform such a check!
+
+ // So we compromise: if the target, suggested name, and command name match,
+ // we consider it close enough. The suggested name is checked because it tends
+ // to cover what the handler considers important,
+ // and ignores changes the user may have made to the name.
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(configuration.getProject()).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return false;
+ }
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ blazeProjectData.workspaceLanguageSettings;
+ BlazeCommandRunConfiguration generatedConfiguration =
+ new BlazeCommandRunConfiguration(
+ configuration.getProject(), configuration.getFactory(), configuration.getName());
+ setupConfiguration(generatedConfiguration, workspaceLanguageSettings, target);
+
+ // TODO This check should be removed once isTestRule is in a RuleFactory and
+ // test rules' suggestedName is modified to account for test filter flags.
+ if (isTestRule(target.ruleType)) {
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler != null && handler.getTestFilterFlag() != null) {
+ return false;
+ }
+ }
+ // End-TODO
+
+ return Objects.equals(configuration.suggestedName(), generatedConfiguration.suggestedName())
+ && Objects.equals(
+ configuration.getHandler().getCommandName(),
+ generatedConfiguration.getHandler().getCommandName());
+ }
+
+ @Nullable
+ private static BuildTarget getBuildTarget(ConfigurationContext context) {
+ FuncallExpression rule =
+ PsiTreeUtil.getNonStrictParentOfType(context.getPsiLocation(), FuncallExpression.class);
+ if (rule == null) {
+ return null;
+ }
+ String ruleType = rule.getFunctionName();
+ Label label = rule.resolveBuildLabel();
+ if (ruleType == null || label == null) {
+ return null;
+ }
+ RuleIdeInfo ruleIdeInfo = RuleFinder.getInstance().ruleForTarget(context.getProject(), label);
+ return new BuildTarget(rule, ruleType, label, ruleIdeInfo);
+ }
+
+ private static void setupConfiguration(
+ BlazeCommandRunConfiguration configuration,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BuildTarget target) {
+ // First see if a BlazeRuleConfigurationFactory can give us a specialized setup.
+ if (target.ruleIdeInfo != null) {
+ for (BlazeRuleConfigurationFactory configurationFactory :
+ BlazeRuleConfigurationFactory.EP_NAME.getExtensions()) {
+ if (configurationFactory.handlesRule(workspaceLanguageSettings, target.ruleIdeInfo)
+ && configurationFactory.handlesConfiguration(configuration)) {
+ configurationFactory.setupConfiguration(configuration, target.ruleIdeInfo);
+ return;
+ }
+ }
+ }
+
+ // If no factory exists, directly set up the configuration.
+ configuration.setTarget(target.label);
+ // Try to make it a 'blaze build' command, if applicable.
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler != null) {
+ // TODO move the old test rule functionality to a BlazeRuleConfigurationFactory
+ handler.setCommand(
+ isTestRule(target.ruleType) ? BlazeCommandName.TEST : BlazeCommandName.BUILD);
+ }
+ configuration.setGeneratedName();
+ }
+
+ // TODO this functionality should be moved to a BlazeRuleConfigurationFactory
+ private static boolean isTestRule(String ruleType) {
+ return isTestSuite(ruleType) || ruleType.endsWith("_test");
+ }
+
+ private static boolean isTestSuite(String ruleType) {
+ return "test_suite".equals(ruleType);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/producers/BlazeRunConfigurationProducer.java b/base/src/com/google/idea/blaze/base/run/producers/BlazeRunConfigurationProducer.java
new file mode 100644
index 0000000..c4b50fc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/producers/BlazeRunConfigurationProducer.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.producers;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.util.NullUtils;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiElement;
+
+/** Base class for Blaze run configuration producers. */
+public abstract class BlazeRunConfigurationProducer<T extends RunConfiguration>
+ extends RunConfigurationProducer<T> {
+
+ protected BlazeRunConfigurationProducer(ConfigurationType configurationType) {
+ super(configurationType);
+ }
+
+ @Override
+ public boolean isPreferredConfiguration(
+ ConfigurationFromContext self, ConfigurationFromContext other) {
+ return Blaze.isBlazeProject(self.getConfiguration().getProject());
+ }
+
+ @Override
+ public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) {
+ return Blaze.isBlazeProject(self.getConfiguration().getProject())
+ && !other.isProducedBy(BlazeRunConfigurationProducer.class);
+ }
+
+ @Override
+ protected final boolean setupConfigurationFromContext(
+ T configuration, ConfigurationContext context, Ref<PsiElement> sourceElement) {
+ if (NullUtils.hasNull(configuration, context, sourceElement)) {
+ return false;
+ }
+ if (!validContext(context)) {
+ return false;
+ }
+ return doSetupConfigFromContext(configuration, context, sourceElement);
+ }
+
+ protected abstract boolean doSetupConfigFromContext(
+ T configuration, ConfigurationContext context, Ref<PsiElement> sourceElement);
+
+ @Override
+ public final boolean isConfigurationFromContext(T configuration, ConfigurationContext context) {
+ if (NullUtils.hasNull(configuration, context)) {
+ return false;
+ }
+ if (!validContext(context)) {
+ return false;
+ }
+ return doIsConfigFromContext(configuration, context);
+ }
+
+ protected abstract boolean doIsConfigFromContext(T configuration, ConfigurationContext context);
+
+ private static boolean validContext(ConfigurationContext context) {
+ Module module = context.getModule();
+ if (module == null) {
+ return false;
+ }
+ if (!isBlazeContext(context)) {
+ return false;
+ }
+ return true;
+ }
+
+ private static boolean isBlazeContext(ConfigurationContext context) {
+ return Blaze.isBlazeProject(context.getProject());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinder.java b/base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinder.java
new file mode 100644
index 0000000..1b1b858
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinder.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.rulefinder;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Searches BlazeProjectData for matching rules. */
+public abstract class RuleFinder {
+ public static RuleFinder getInstance() {
+ return ServiceManager.getService(RuleFinder.class);
+ }
+
+ @Nullable
+ public RuleIdeInfo ruleForTarget(Project project, final Label target) {
+ return findRule(project, input -> input.label.equals(target));
+ }
+
+ public ImmutableList<RuleIdeInfo> rulesOfKinds(Project project, final Kind... kinds) {
+ return rulesOfKinds(project, Arrays.asList(kinds));
+ }
+
+ public ImmutableList<RuleIdeInfo> rulesOfKinds(Project project, final List<Kind> kinds) {
+ return ImmutableList.copyOf(findRules(project, input -> input.kindIsOneOf(kinds)));
+ }
+
+ @Nullable
+ public RuleIdeInfo firstRuleOfKinds(Project project, Kind... kinds) {
+ return Iterables.getFirst(rulesOfKinds(project, kinds), null);
+ }
+
+ @Nullable
+ public RuleIdeInfo firstRuleOfKinds(Project project, List<Kind> kinds) {
+ return Iterables.getFirst(rulesOfKinds(project, kinds), null);
+ }
+
+ @Nullable
+ private RuleIdeInfo findRule(Project project, Predicate<RuleIdeInfo> predicate) {
+ List<RuleIdeInfo> results = findRules(project, predicate);
+ assert results.size() <= 1;
+ return Iterables.getFirst(results, null);
+ }
+
+ @Nullable
+ public RuleIdeInfo findFirstRule(Project project, Predicate<RuleIdeInfo> predicate) {
+ return Iterables.getFirst(findRules(project, predicate), null);
+ }
+
+ public abstract List<RuleIdeInfo> findRules(Project project, Predicate<RuleIdeInfo> predicate);
+}
diff --git a/base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinderImpl.java b/base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinderImpl.java
new file mode 100644
index 0000000..bc547d7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinderImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.rulefinder;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.openapi.project.Project;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** Implementation of RuleFinder. */
+class RuleFinderImpl extends RuleFinder {
+ @Override
+ public List<RuleIdeInfo> findRules(
+ @NotNull Project project, @NotNull Predicate<RuleIdeInfo> predicate) {
+ BlazeProjectData projectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (projectData == null) {
+ return ImmutableList.of();
+ }
+
+ ImmutableList.Builder<RuleIdeInfo> resultList = ImmutableList.builder();
+ for (RuleIdeInfo rule : projectData.ruleMap.rules()) {
+ if (predicate.apply(rule)) {
+ resultList.add(rule);
+ }
+ }
+ return resultList.build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/testmap/TestRuleFinderImpl.java b/base/src/com/google/idea/blaze/base/run/testmap/TestRuleFinderImpl.java
new file mode 100644
index 0000000..258f059
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/testmap/TestRuleFinderImpl.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.testmap;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Queues;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.run.TestRuleFinder;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.sync.SyncListener;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Queue;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * Used to locate tests from source files for things like right-clicks.
+ *
+ * <p>It's essentially a map from source file -> reachable test rules.
+ */
+public class TestRuleFinderImpl implements TestRuleFinder {
+
+ private final Project project;
+ @Nullable private TestMap testMap;
+
+ static class TestMap {
+ private final Project project;
+ private final Multimap<File, Label> rootsMap;
+ private final RuleMap ruleMap;
+
+ TestMap(Project project, RuleMap ruleMap) {
+ this.project = project;
+ this.rootsMap = createRootsMap(ruleMap.rules());
+ this.ruleMap = ruleMap;
+ }
+
+ private Collection<RuleIdeInfo> testTargetsForSourceFile(File sourceFile) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData != null) {
+ return testRulesForSourceFile(blazeProjectData.reverseDependencies, sourceFile);
+ }
+ return ImmutableList.of();
+ }
+
+ @VisibleForTesting
+ Collection<Label> testTargetsForSourceFile(
+ ImmutableMultimap<Label, Label> rdepsMap, File sourceFile) {
+ return testRulesForSourceFile(rdepsMap, sourceFile)
+ .stream()
+ .map((rule) -> rule.label)
+ .collect(Collectors.toList());
+ }
+
+ Collection<RuleIdeInfo> testRulesForSourceFile(
+ ImmutableMultimap<Label, Label> rdepsMap, File sourceFile) {
+ List<RuleIdeInfo> result = Lists.newArrayList();
+ Collection<Label> roots = rootsMap.get(sourceFile);
+
+ Queue<Label> todo = Queues.newArrayDeque();
+ for (Label label : roots) {
+ todo.add(label);
+ }
+ Set<Label> seen = Sets.newHashSet();
+ while (!todo.isEmpty()) {
+ Label label = todo.remove();
+ if (!seen.add(label)) {
+ continue;
+ }
+
+ RuleIdeInfo rule = ruleMap.get(label);
+ if (isTestRule(rule)) {
+ result.add(rule);
+ }
+ for (Label rdep : rdepsMap.get(label)) {
+ todo.add(rdep);
+ }
+ }
+ return result;
+ }
+
+ static Multimap<File, Label> createRootsMap(Collection<RuleIdeInfo> rules) {
+ Multimap<File, Label> result = ArrayListMultimap.create();
+ for (RuleIdeInfo ruleIdeInfo : rules) {
+ for (ArtifactLocation source : ruleIdeInfo.sources) {
+ result.put(source.getFile(), ruleIdeInfo.label);
+ }
+ }
+ return result;
+ }
+
+ private static boolean isTestRule(@Nullable RuleIdeInfo rule) {
+ return rule != null
+ && rule.kind != null
+ && rule.kind.isOneOf(
+ Kind.ANDROID_ROBOLECTRIC_TEST,
+ Kind.ANDROID_TEST,
+ Kind.JAVA_TEST,
+ Kind.GWT_TEST,
+ Kind.CC_TEST);
+ }
+ }
+
+ public TestRuleFinderImpl(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public Collection<RuleIdeInfo> testTargetsForSourceFile(File sourceFile) {
+ TestMap testMap = getTestMap();
+ if (testMap == null) {
+ return ImmutableList.of();
+ }
+ return testMap.testTargetsForSourceFile(sourceFile);
+ }
+
+ private synchronized TestMap getTestMap() {
+ if (testMap == null) {
+ testMap = initTestMap();
+ }
+ return testMap;
+ }
+
+ @Nullable
+ private TestMap initTestMap() {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return null;
+ }
+ return new TestMap(project, blazeProjectData.ruleMap);
+ }
+
+ private synchronized void clearMapData() {
+ this.testMap = null;
+ }
+
+ static class ClearTestMap extends SyncListener.Adapter {
+ @Override
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
+ TestRuleFinder testRuleFinder = TestRuleFinder.getInstance(project);
+ ((TestRuleFinderImpl) testRuleFinder).clearMapData();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/BlazeContext.java b/base/src/com/google/idea/blaze/base/scope/BlazeContext.java
new file mode 100644
index 0000000..82568ae
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/BlazeContext.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Scoped operation context. */
+public class BlazeContext {
+ @Nullable private BlazeContext parentContext;
+
+ @NotNull private final List<BlazeScope> scopes = Lists.newArrayList();
+
+ @NotNull
+ private final ArrayListMultimap<Class<? extends Output>, OutputSink<?>> outputSinks =
+ ArrayListMultimap.create();
+
+ boolean isEnding;
+
+ boolean isCancelled;
+
+ private int holdCount;
+
+ private boolean hasErrors;
+
+ private boolean propagatesErrors = true;
+
+ public BlazeContext() {
+ this(null);
+ }
+
+ public BlazeContext(@Nullable BlazeContext parentContext) {
+ this.parentContext = parentContext;
+ }
+
+ public BlazeContext push(@NotNull BlazeScope scope) {
+ scopes.add(scope);
+ scope.onScopeBegin(this);
+ return this;
+ }
+
+ /** Ends the context scope. */
+ public void endScope() {
+ if (isEnding || holdCount > 0) {
+ return;
+ }
+ isEnding = true;
+ for (int i = scopes.size() - 1; i >= 0; i--) {
+ scopes.get(i).onScopeEnd(this);
+ }
+
+ if (parentContext != null && hasErrors && propagatesErrors) {
+ parentContext.setHasError();
+ }
+ }
+
+ /**
+ * Requests cancellation of the operation.
+ *
+ * <p>
+ *
+ * <p>Each context holder must handle cancellation individually.
+ */
+ public void setCancelled() {
+ if (isEnding || isCancelled) {
+ return;
+ }
+
+ isCancelled = true;
+
+ if (parentContext != null) {
+ parentContext.setCancelled();
+ }
+ }
+
+ public void hold() {
+ ++holdCount;
+ }
+
+ public void release() {
+ if (--holdCount == 0) {
+ endScope();
+ }
+ }
+
+ public boolean isEnding() {
+ return isEnding;
+ }
+
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ @Nullable
+ public <T extends BlazeScope> T getScope(@NotNull Class<T> scopeClass) {
+ return getScope(scopeClass, scopes.size());
+ }
+
+ @Nullable
+ private <T extends BlazeScope> T getScope(@NotNull Class<T> scopeClass, int endIndex) {
+ for (int i = endIndex - 1; i >= 0; i--) {
+ if (scopes.get(i).getClass() == scopeClass) {
+ return scopeClass.cast(scopes.get(i));
+ }
+ }
+ if (parentContext != null) {
+ return parentContext.getScope(scopeClass);
+ }
+ return null;
+ }
+
+ @Nullable
+ public <T extends BlazeScope> T getParentScope(@NotNull T scope) {
+ int index = scopes.indexOf(scope);
+ if (index == -1) {
+ throw new IllegalArgumentException("Scope does not belong to this context.");
+ }
+ @SuppressWarnings("unchecked")
+ Class<T> scopeClass = (Class<T>) scope.getClass();
+ return getScope(scopeClass, index);
+ }
+
+ /**
+ * Find all instances of {@param scopeClass} that are on the stack starting with this context.
+ * That includes this context and all parent contexts recursively.
+ *
+ * @param scopeClass type of scopes to locate
+ * @return The ordered list of all scopes of type {@param scopeClass}, ordered from {@param
+ * startingScope} to the root.
+ */
+ @NotNull
+ public <T extends BlazeScope> List<T> getScopes(@NotNull Class<T> scopeClass) {
+ List<T> scopesCollector = Lists.newArrayList();
+ getScopes(scopesCollector, scopeClass, scopes.size());
+ return scopesCollector;
+ }
+
+ /**
+ * Find all instances of {@param scopeClass} that are above {@param startingScope} on the stack.
+ * That includes this context and all parent contexts recursively. {@param startingScope} must be
+ * in the this {@link BlazeContext}.
+ *
+ * @param scopeClass type of scopes to locate
+ * @param startingScope scope to start our search from
+ * @return If {@param startingScope} is in this context, the ordered list of all scopes of type
+ * {@param scopeClass}, ordered from {@param startingScope} to the root. Otherwise, an empty
+ * list.
+ */
+ @NotNull
+ public <T extends BlazeScope> List<T> getScopes(
+ @NotNull Class<T> scopeClass, @NotNull BlazeScope startingScope) {
+ List<T> scopesCollector = Lists.newArrayList();
+ int index = scopes.indexOf(startingScope);
+ if (index == -1) {
+ return scopesCollector;
+ }
+
+ // index + 1 so we include startingScope
+ getScopes(scopesCollector, scopeClass, index + 1);
+ return scopesCollector;
+ }
+
+ /** Add matching scopes to {@param scopesCollector}. Search from {@param maxIndex} - 1 to 0. */
+ @VisibleForTesting
+ <T extends BlazeScope> void getScopes(
+ @NotNull List<T> scopesCollector, @NotNull Class<T> scopeClass, int maxIndex) {
+ for (int i = maxIndex - 1; i >= 0; --i) {
+ BlazeScope scope = scopes.get(i);
+ if (scope.getClass() == scopeClass) {
+ scopesCollector.add((T) scope);
+ }
+ }
+ if (parentContext != null) {
+ parentContext.getScopes(scopesCollector, scopeClass, parentContext.scopes.size());
+ }
+ }
+
+ public <T extends Output> BlazeContext addOutputSink(
+ @NotNull Class<T> outputClass, @NotNull OutputSink<T> outputSink) {
+ outputSinks.put(outputClass, outputSink);
+ return this;
+ }
+
+ /** Produces output by sending it to any registered sinks. */
+ @SuppressWarnings("unchecked")
+ public synchronized <T extends Output> void output(@NotNull T output) {
+ Class<? extends Output> outputClass = output.getClass();
+ List<OutputSink<?>> outputSinks = this.outputSinks.get(outputClass);
+
+ boolean continuePropagation = true;
+ for (int i = outputSinks.size() - 1; i >= 0; --i) {
+ OutputSink<?> outputSink = outputSinks.get(i);
+ OutputSink.Propagation propagation = ((OutputSink<T>) outputSink).onOutput(output);
+ continuePropagation = propagation == OutputSink.Propagation.Continue;
+ if (!continuePropagation) {
+ break;
+ }
+ }
+ if (continuePropagation && parentContext != null) {
+ parentContext.output(output);
+ }
+ }
+
+ /**
+ * Sets the error state.
+ *
+ * <p>
+ *
+ * <p>The error state will be propagated to any parents.
+ */
+ public void setHasError() {
+ this.hasErrors = true;
+ }
+
+ /** Returns true if there were errors */
+ public boolean hasErrors() {
+ return hasErrors;
+ }
+
+ public boolean isRoot() {
+ return parentContext == null;
+ }
+
+ /** Returns true if no errors and isn't cancelled. */
+ public boolean shouldContinue() {
+ return !hasErrors() && !isCancelled();
+ }
+
+ /** Sets whether errors are propagated to the parent context. */
+ public void setPropagatesErrors(boolean propagatesErrors) {
+ this.propagatesErrors = propagatesErrors;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/BlazeScope.java b/base/src/com/google/idea/blaze/base/scope/BlazeScope.java
new file mode 100644
index 0000000..3c60543
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/BlazeScope.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A scoped facet of a scoped operation.
+ *
+ * <p>
+ *
+ * <p>Attaches to a blaze context and starts and ends with it.
+ */
+public interface BlazeScope {
+ /** Called when the scope is added to the context. */
+ void onScopeBegin(@NotNull BlazeContext context);
+
+ /** Called when the context scope is ending. */
+ void onScopeEnd(@NotNull BlazeContext context);
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/Output.java b/base/src/com/google/idea/blaze/base/scope/Output.java
new file mode 100644
index 0000000..86af670
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/Output.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+/** A base interface for contextual output operations. */
+public interface Output {}
diff --git a/base/src/com/google/idea/blaze/base/scope/OutputSink.java b/base/src/com/google/idea/blaze/base/scope/OutputSink.java
new file mode 100644
index 0000000..8d8a51e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/OutputSink.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An output sink registered with a context.
+ *
+ * <p>
+ *
+ * <p>Register these via a ScopeExtension.
+ */
+public interface OutputSink<T extends Output> {
+ /** Whether to continue propagation */
+ enum Propagation {
+ Continue,
+ Stop
+ }
+
+ /**
+ * Called when an Output of the correct type goes through the scope.
+ *
+ * @return Whether to continue propagation of this input.
+ */
+ Propagation onOutput(@NotNull T output);
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/Result.java b/base/src/com/google/idea/blaze/base/scope/Result.java
new file mode 100644
index 0000000..383f67c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/Result.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+/** Helper class to be used when you want to return a result or error in a scoped function. */
+public class Result<T> {
+ public final T result;
+ public final Throwable error;
+
+ public Result(T result) {
+ this.result = result;
+ this.error = null;
+ }
+
+ public Result(Throwable error) {
+ this.result = null;
+ this.error = error;
+ }
+
+ public static <T> Result<T> of(T result) {
+ return new Result<T>(result);
+ }
+
+ public static <T> Result<T> error(Throwable t) {
+ return new Result<T>(t);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/Scope.java b/base/src/com/google/idea/blaze/base/scope/Scope.java
new file mode 100644
index 0000000..bb0c98d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/Scope.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import com.intellij.openapi.diagnostic.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Helper methods to run scoped functions and operations in a scoped context. */
+public final class Scope {
+ private static final Logger LOG = Logger.getInstance(Scope.class);
+
+ /** Runs a scoped function in a new root scope. */
+ public static <T> T root(@NotNull ScopedFunction<T> scopedFunction) {
+ return push(null, scopedFunction);
+ }
+
+ /** Runs a scoped function in a new nested scope. */
+ public static <T> T push(
+ @Nullable BlazeContext parentContext, @NotNull ScopedFunction<T> scopedFunction) {
+ BlazeContext context = new BlazeContext(parentContext);
+ try {
+ return scopedFunction.execute(context);
+ } catch (RuntimeException e) {
+ context.setHasError();
+ LOG.error(e);
+ throw e;
+ } finally {
+ context.endScope();
+ }
+ }
+
+ /** Runs a scoped operation in a new root scope. */
+ public static void root(@NotNull ScopedOperation scopedOperation) {
+ push(null, scopedOperation);
+ }
+
+ /** Runs a scoped operation in a new nested scope. */
+ public static void push(
+ @Nullable BlazeContext parentContext, @NotNull ScopedOperation scopedOperation) {
+ BlazeContext context = new BlazeContext(parentContext);
+ try {
+ scopedOperation.execute(context);
+ } catch (RuntimeException e) {
+ context.setHasError();
+ LOG.error(e);
+ throw e;
+ } finally {
+ context.endScope();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/ScopedFunction.java b/base/src/com/google/idea/blaze/base/scope/ScopedFunction.java
new file mode 100644
index 0000000..47c6365
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/ScopedFunction.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import org.jetbrains.annotations.NotNull;
+
+/** A scoped operation that can return a result to its caller. */
+public interface ScopedFunction<T> {
+ T execute(@NotNull BlazeContext context);
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/ScopedOperation.java b/base/src/com/google/idea/blaze/base/scope/ScopedOperation.java
new file mode 100644
index 0000000..1a704aa
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/ScopedOperation.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import org.jetbrains.annotations.NotNull;
+
+/** A scoped operation. */
+public interface ScopedOperation {
+ void execute(@NotNull BlazeContext context);
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/ScopedTask.java b/base/src/com/google/idea/blaze/base/scope/ScopedTask.java
new file mode 100644
index 0000000..725bf2f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/ScopedTask.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import com.google.idea.blaze.base.scope.scopes.ProgressIndicatorScope;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Progressive;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Wrapper between an IntelliJ Task and a BlazeContext */
+public abstract class ScopedTask implements Progressive {
+ @Nullable final BlazeContext parentContext;
+
+ public ScopedTask() {
+ this(null /* parentContext */);
+ }
+
+ public ScopedTask(@Nullable BlazeContext parentContext) {
+ this.parentContext = parentContext;
+ }
+
+ @Override
+ public void run(@NotNull final ProgressIndicator indicator) {
+ Scope.push(
+ parentContext,
+ new ScopedOperation() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ context.push(new ProgressIndicatorScope(indicator));
+ ScopedTask.this.execute(context);
+ }
+ });
+ }
+
+ protected abstract void execute(@NotNull BlazeContext context);
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java b/base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java
new file mode 100644
index 0000000..e3bc15a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.output;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Output;
+import com.intellij.pom.Navigatable;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** An issue in a blaze operation. */
+public class IssueOutput implements Output {
+
+ public static final int NO_LINE = -1;
+ public static final int NO_COLUMN = -1;
+
+ @Nullable private final File file;
+ private final int line;
+ private final int column;
+ @NotNull private final Category category;
+ @NotNull private final String message;
+ @Nullable Navigatable navigatable;
+ @Nullable IssueData issueData;
+
+ /** Base class for issue data */
+ public static class IssueData {}
+
+ /** Issue category */
+ public enum Category {
+ ERROR,
+ WARNING,
+ STATISTICS,
+ INFORMATION
+ }
+
+ @NotNull
+ public static Builder issue(@NotNull Category category, @NotNull String message) {
+ return new Builder(category, message);
+ }
+
+ @NotNull
+ public static Builder error(@NotNull String message) {
+ return new Builder(Category.ERROR, message);
+ }
+
+ @NotNull
+ public static Builder warn(@NotNull String message) {
+ return new Builder(Category.WARNING, message);
+ }
+
+ /** Builder for an issue */
+ public static class Builder {
+ @NotNull private final Category category;
+ @NotNull private final String message;
+ @Nullable private File file;
+ private int line = NO_LINE;
+ private int column = NO_COLUMN;
+ @Nullable Navigatable navigatable;
+ @Nullable IssueData issueData;
+
+ public Builder(@NotNull Category category, @NotNull String message) {
+ this.category = category;
+ this.message = message;
+ }
+
+ @NotNull
+ public Builder inFile(@Nullable File file) {
+ this.file = file;
+ return this;
+ }
+
+ @NotNull
+ public Builder onLine(int line) {
+ this.line = line;
+ return this;
+ }
+
+ @NotNull
+ public Builder inColumn(int column) {
+ this.column = column;
+ return this;
+ }
+
+ @NotNull
+ public Builder withData(@Nullable IssueData issueData) {
+ this.issueData = issueData;
+ return this;
+ }
+
+ @NotNull
+ public Builder navigatable(@Nullable Navigatable navigatable) {
+ this.navigatable = navigatable;
+ return this;
+ }
+
+ public IssueOutput build() {
+ return new IssueOutput(file, line, column, navigatable, category, message, issueData);
+ }
+
+ public void submit(@NotNull BlazeContext context) {
+ context.output(build());
+ if (category == Category.ERROR) {
+ context.setHasError();
+ }
+ }
+ }
+
+ private IssueOutput(
+ @Nullable File file,
+ int line,
+ int column,
+ @Nullable Navigatable navigatable,
+ @NotNull Category category,
+ @NotNull String message,
+ @Nullable IssueData issueData) {
+ this.file = file;
+ this.line = line;
+ this.column = column;
+ this.navigatable = navigatable;
+ this.category = category;
+ this.message = message;
+ this.issueData = issueData;
+ }
+
+ @Nullable
+ public File getFile() {
+ return file;
+ }
+
+ public int getLine() {
+ return line;
+ }
+
+ public int getColumn() {
+ return column;
+ }
+
+ @Nullable
+ public Navigatable getNavigatable() {
+ return navigatable;
+ }
+
+ @NotNull
+ public Category getCategory() {
+ return category;
+ }
+
+ @NotNull
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public String toString() {
+ return message;
+ }
+
+ @Nullable
+ public IssueData getIssueData() {
+ return issueData;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/output/PerformanceWarning.java b/base/src/com/google/idea/blaze/base/scope/output/PerformanceWarning.java
new file mode 100644
index 0000000..006875d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/output/PerformanceWarning.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.output;
+
+import com.google.idea.blaze.base.scope.Output;
+
+/** Output that is collected when running in performance collection mode. */
+public class PerformanceWarning implements Output {
+ public final String text;
+
+ public PerformanceWarning(String text) {
+ this.text = text;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/output/PrintOutput.java b/base/src/com/google/idea/blaze/base/scope/output/PrintOutput.java
new file mode 100644
index 0000000..7e9e8af
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/output/PrintOutput.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.output;
+
+import com.google.idea.blaze.base.scope.Output;
+import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.openapi.util.Key;
+import org.jetbrains.annotations.NotNull;
+
+/** Output that can be printed to a log. */
+public class PrintOutput implements Output {
+
+ @NotNull private final String text;
+
+ @NotNull private final OutputType outputType;
+
+ /** The output type */
+ public enum OutputType {
+ NORMAL,
+ LOGGED,
+ ERROR;
+
+ public static OutputType fromProcessOutputKey(Key outputKey) {
+ return outputKey == ProcessOutputTypes.STDERR ? ERROR : NORMAL;
+ }
+ }
+
+ public PrintOutput(@NotNull String text, @NotNull OutputType outputType) {
+ this.text = text;
+ this.outputType = outputType;
+ }
+
+ public PrintOutput(@NotNull String text) {
+ this(text, OutputType.NORMAL);
+ }
+
+ @NotNull
+ public String getText() {
+ return text;
+ }
+
+ @NotNull
+ public OutputType getOutputType() {
+ return outputType;
+ }
+
+ public static PrintOutput output(String text) {
+ return new PrintOutput(text);
+ }
+
+ public static PrintOutput log(String text) {
+ return new PrintOutput(text, OutputType.LOGGED);
+ }
+
+ public static PrintOutput error(String text) {
+ return new PrintOutput(text, OutputType.ERROR);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/output/StatusOutput.java b/base/src/com/google/idea/blaze/base/scope/output/StatusOutput.java
new file mode 100644
index 0000000..ea3bc3d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/output/StatusOutput.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.output;
+
+import com.google.idea.blaze.base.scope.Output;
+import org.jetbrains.annotations.NotNull;
+
+/** Status message output. */
+public class StatusOutput implements Output {
+ @NotNull String status;
+
+ public StatusOutput(@NotNull String status) {
+ this.status = status;
+ }
+
+ @NotNull
+ public String getStatus() {
+ return status;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java
new file mode 100644
index 0000000..19205cf
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.idea.blaze.base.console.BlazeConsoleService;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.OutputSink;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.PrintOutput.OutputType;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Moves print output to the blaze console. */
+public class BlazeConsoleScope implements BlazeScope {
+
+ /** Builder for blaze console scope */
+ public static class Builder {
+ private Project project;
+ private ProgressIndicator progressIndicator;
+ private boolean suppressConsole = false;
+
+ public Builder(@NotNull Project project) {
+ this(project, null);
+ }
+
+ public Builder(@NotNull Project project, ProgressIndicator progressIndicator) {
+ this.project = project;
+ this.progressIndicator = progressIndicator;
+ }
+
+ public Builder setSuppressConsole(boolean suppressConsole) {
+ this.suppressConsole = suppressConsole;
+ return this;
+ }
+
+ public BlazeConsoleScope build() {
+ return new BlazeConsoleScope(project, progressIndicator, suppressConsole);
+ }
+ }
+
+ @NotNull private final Project project;
+
+ @NotNull private final BlazeConsoleService blazeConsoleService;
+
+ @Nullable private final ProgressIndicator progressIndicator;
+
+ private final boolean showDialogOnChange;
+ private boolean activated;
+
+ private OutputSink<PrintOutput> printSink =
+ (output) -> {
+ @NotNull String text = output.getText();
+ @NotNull
+ ConsoleViewContentType contentType =
+ output.getOutputType() == OutputType.ERROR
+ ? ConsoleViewContentType.ERROR_OUTPUT
+ : ConsoleViewContentType.NORMAL_OUTPUT;
+ print(text, contentType);
+ return OutputSink.Propagation.Continue;
+ };
+
+ private OutputSink<StatusOutput> statusSink =
+ (output) -> {
+ @NotNull String text = output.getStatus();
+ @NotNull ConsoleViewContentType contentType = ConsoleViewContentType.NORMAL_OUTPUT;
+ print(text, contentType);
+ return OutputSink.Propagation.Continue;
+ };
+
+ private BlazeConsoleScope(
+ @NotNull Project project,
+ @Nullable ProgressIndicator progressIndicator,
+ boolean suppressConsole) {
+ this.project = project;
+ this.blazeConsoleService = BlazeConsoleService.getInstance(project);
+ this.progressIndicator = progressIndicator;
+ this.showDialogOnChange = !suppressConsole;
+ }
+
+ private void print(String text, ConsoleViewContentType contentType) {
+ blazeConsoleService.print(text + "\n", contentType);
+
+ if (showDialogOnChange && !activated) {
+ activated = true;
+ ApplicationManager.getApplication()
+ .invokeLater(() -> blazeConsoleService.activateConsoleWindow());
+ }
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull final BlazeContext context) {
+ context.addOutputSink(PrintOutput.class, printSink);
+ context.addOutputSink(StatusOutput.class, statusSink);
+ blazeConsoleService.clear();
+ blazeConsoleService.setStopHandler(
+ () -> {
+ if (progressIndicator != null) {
+ progressIndicator.cancel();
+ }
+ context.setCancelled();
+ });
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ blazeConsoleService.setStopHandler(null);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/IdeaLogScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/IdeaLogScope.java
new file mode 100644
index 0000000..4a1130c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/IdeaLogScope.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.OutputSink;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.intellij.openapi.diagnostic.Logger;
+import org.jetbrains.annotations.NotNull;
+
+/** Scope that captures relevant output to the IntelliJ log file. */
+public class IdeaLogScope implements BlazeScope {
+
+ private static final Logger LOG = Logger.getInstance(IdeaLogScope.class);
+
+ private static final OutputSink<IssueOutput> issueSink =
+ (output) -> {
+ LOG.warn(output.toString());
+ return OutputSink.Propagation.Continue;
+ };
+
+ private static final OutputSink<PrintOutput> printSink =
+ (output) -> {
+ switch (output.getOutputType()) {
+ case NORMAL:
+ break;
+ case LOGGED:
+ LOG.info(output.getText());
+ break;
+ case ERROR:
+ LOG.warn(output.getText());
+ break;
+ }
+ return OutputSink.Propagation.Continue;
+ };
+
+ private static final OutputSink<StatusOutput> statusSink =
+ (output) -> {
+ LOG.info(output.getStatus());
+ return OutputSink.Propagation.Continue;
+ };
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ context.addOutputSink(IssueOutput.class, issueSink);
+ context.addOutputSink(PrintOutput.class, printSink);
+ context.addOutputSink(StatusOutput.class, statusSink);
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {}
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/IssuesScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/IssuesScope.java
new file mode 100644
index 0000000..fc02ee0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/IssuesScope.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.OutputSink;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.ui.BlazeProblemsView;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowManager;
+import java.util.UUID;
+import org.jetbrains.annotations.NotNull;
+
+/** Shows the compiler output. */
+public class IssuesScope implements BlazeScope, OutputSink<IssueOutput> {
+
+ private final Project project;
+ private final UUID sessionId;
+ private int issuesCount;
+
+ public IssuesScope(@NotNull Project project) {
+ this.project = project;
+ this.sessionId = UUID.randomUUID();
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ context.addOutputSink(IssueOutput.class, this);
+ BlazeProblemsView blazeProblemsView = BlazeProblemsView.getInstance(project);
+ if (blazeProblemsView != null) {
+ blazeProblemsView.clearOldMessages(sessionId);
+ }
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ if (issuesCount > 0) {
+ ApplicationManager.getApplication()
+ .invokeLater(
+ new Runnable() {
+ @Override
+ public void run() {
+ focusProblemsView();
+ }
+ });
+ }
+ }
+
+ private void focusProblemsView() {
+ ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
+ ToolWindow toolWindow = toolWindowManager.getToolWindow("Problems");
+ if (toolWindow != null) {
+ toolWindow.activate(null, false, false);
+ }
+ }
+
+ @Override
+ public Propagation onOutput(@NotNull IssueOutput output) {
+ BlazeProblemsView blazeProblemsView = BlazeProblemsView.getInstance(project);
+ if (blazeProblemsView != null) {
+ blazeProblemsView.addMessage(output, sessionId);
+ }
+ ++issuesCount;
+ return Propagation.Continue;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/LoggedTimingScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/LoggedTimingScope.java
new file mode 100644
index 0000000..3b34acd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/LoggedTimingScope.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.common.base.Stopwatch;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.metrics.LoggingService;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.intellij.openapi.project.Project;
+import java.util.concurrent.TimeUnit;
+
+/** Timing scope where the results are sent to a logging service */
+public class LoggedTimingScope implements BlazeScope {
+ // It is not guaranteed that the threading model will be sane during the entirety of this scope,
+ // so we use wall clock time and not ThreadMXBean where we could get user/system time.
+
+ Project project;
+ private final Action action;
+ private Stopwatch timer;
+
+ /** @param action The action we will be reporting a time for to the logging service */
+ public LoggedTimingScope(Project project, Action action) {
+ this.project = project;
+ this.action = action;
+ this.timer = Stopwatch.createUnstarted();
+ }
+
+ @Override
+ public void onScopeBegin(BlazeContext context) {
+ timer.start();
+ }
+
+ @Override
+ public void onScopeEnd(BlazeContext context) {
+ if (!context.isCancelled()) {
+ long totalMS = timer.elapsed(TimeUnit.MILLISECONDS);
+ LoggingService.reportEvent(project, action, totalMS);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/NotificationScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/NotificationScope.java
new file mode 100644
index 0000000..5557e4e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/NotificationScope.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.SystemNotifications;
+import org.jetbrains.annotations.NotNull;
+
+/** Notifies the user with a system notification when the scope ends. */
+public class NotificationScope implements BlazeScope {
+
+ private static final long NOTIFICATION_THRESHOLD_MS = 0;
+
+ @NotNull private Project project;
+
+ @NotNull private final String notificationName;
+
+ @NotNull private final String notificationTitle;
+
+ @NotNull private final String notificationText;
+
+ @NotNull private final String notificationErrorText;
+
+ private long startTime;
+
+ public NotificationScope(
+ @NotNull Project project,
+ @NotNull String notificationName,
+ @NotNull String notificationTitle,
+ @NotNull String notificationText,
+ @NotNull String notificationErrorText) {
+ this.project = project;
+ this.notificationName = notificationName;
+ this.notificationTitle = notificationTitle;
+ this.notificationText = notificationText;
+ this.notificationErrorText = notificationErrorText;
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ startTime = System.currentTimeMillis();
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ if (project.isDisposed()) {
+ return;
+ }
+ if (context.isCancelled()) {
+ context.output(new StatusOutput(notificationName + " cancelled"));
+ return;
+ }
+ long duration = System.currentTimeMillis() - startTime;
+ if (duration < NOTIFICATION_THRESHOLD_MS) {
+ return;
+ }
+
+ String notificationText =
+ !context.hasErrors() ? this.notificationText : this.notificationErrorText;
+
+ SystemNotifications.getInstance().notify(notificationName, notificationTitle, notificationText);
+
+ if (context.hasErrors()) {
+ context.output(PrintOutput.error(notificationName + " failed"));
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/PerformanceWarningScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/PerformanceWarningScope.java
new file mode 100644
index 0000000..38a2dc0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/PerformanceWarningScope.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.OutputSink;
+import com.google.idea.blaze.base.scope.output.PerformanceWarning;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import java.util.List;
+
+/** Shows performance warnings. */
+public class PerformanceWarningScope implements BlazeScope, OutputSink<PerformanceWarning> {
+
+ private final List<PerformanceWarning> outputs = Lists.newArrayList();
+
+ @Override
+ public void onScopeBegin(BlazeContext context) {
+ context.addOutputSink(PerformanceWarning.class, this);
+ }
+
+ @Override
+ public void onScopeEnd(BlazeContext context) {
+ if (outputs.isEmpty()) {
+ return;
+ }
+ context.output(new PrintOutput("\n===== PERFORMANCE WARNINGS =====\n"));
+ context.output(new PrintOutput("Your IDE isn't as fast as it could be."));
+ context.output(
+ new PrintOutput("You can turn these off via Blaze > Show Performance Warnings."));
+ context.output(new PrintOutput(""));
+ for (PerformanceWarning output : outputs) {
+ context.output(new PrintOutput(output.text));
+ }
+ }
+
+ @Override
+ public Propagation onOutput(PerformanceWarning output) {
+ outputs.add(output);
+ return Propagation.Continue;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/ProgressIndicatorScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/ProgressIndicatorScope.java
new file mode 100644
index 0000000..faa3a7b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/ProgressIndicatorScope.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.OutputSink;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase;
+import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Progress indicator scope.
+ *
+ * <p>
+ *
+ * <p>Channels status outputs to the progress indicator text.
+ *
+ * <p>Cancels the scope if the user presses cancel on the progress indicator.
+ */
+public class ProgressIndicatorScope extends AbstractProgressIndicatorExBase
+ implements BlazeScope, OutputSink<StatusOutput> {
+
+ private final ProgressIndicator progressIndicator;
+ private BlazeContext context;
+
+ public ProgressIndicatorScope(@NotNull ProgressIndicator progressIndicator) {
+ this.progressIndicator = progressIndicator;
+
+ if (progressIndicator instanceof ProgressIndicatorEx) {
+ ((ProgressIndicatorEx) progressIndicator).addStateDelegate(this);
+ }
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ this.context = context;
+ context.addOutputSink(StatusOutput.class, this);
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {}
+
+ @Override
+ public void cancel() {
+ context.setCancelled();
+ }
+
+ @Override
+ public Propagation onOutput(@NotNull StatusOutput output) {
+ progressIndicator.setText(output.getStatus());
+ return Propagation.Continue;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/ProjectCloseScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/ProjectCloseScope.java
new file mode 100644
index 0000000..da1bc16
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/ProjectCloseScope.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.project.ProjectManagerListener;
+import com.intellij.openapi.ui.Messages;
+import org.jetbrains.annotations.NotNull;
+
+/** Prevents the user from closing the project while the scope is open. */
+public class ProjectCloseScope implements ProjectManagerListener, BlazeScope {
+
+ @NotNull private final Project project;
+
+ private boolean isApplicationExitingOrProjectClosing;
+
+ public ProjectCloseScope(@NotNull Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.addProjectManagerListener(project, this);
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.removeProjectManagerListener(project, this);
+ }
+
+ @Override
+ public void projectOpened(Project project) {}
+
+ @Override
+ public boolean canCloseProject(Project project) {
+ if (!project.equals(this.project)) {
+ return true;
+ }
+ if (shouldPromptUser()) {
+ askUserToWait();
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public void projectClosed(Project project) {}
+
+ @Override
+ public void projectClosing(Project project) {
+ if (project.equals(this.project)) {
+ isApplicationExitingOrProjectClosing = true;
+ }
+ }
+
+ private boolean shouldPromptUser() {
+ return !isApplicationExitingOrProjectClosing;
+ }
+
+ private void askUserToWait() {
+ String buildSystem = Blaze.buildSystemName(project);
+ Messages.showMessageDialog(
+ project,
+ String.format("Please wait until %s command execution finishes", buildSystem),
+ buildSystem + " Running",
+ null);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java b/base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java
new file mode 100644
index 0000000..d3dcad0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope.scopes;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.BlazeScope;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Prints timing information as output. */
+public class TimingScope implements BlazeScope {
+
+ @NotNull private final String name;
+
+ private long startTime;
+
+ private double duration;
+
+ @Nullable private TimingScope parentScope;
+
+ @NotNull private List<TimingScope> children = Lists.newArrayList();
+
+ public TimingScope(@NotNull String name) {
+ this.name = name;
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ startTime = System.currentTimeMillis();
+ parentScope = context.getParentScope(this);
+
+ if (parentScope != null) {
+ parentScope.children.add(this);
+ }
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ if (context.isCancelled()) {
+ return;
+ }
+
+ long elapsedTime = System.currentTimeMillis() - startTime;
+ duration = (double) elapsedTime / 1000.0;
+
+ if (parentScope == null) {
+ outputReport(context);
+ }
+ }
+
+ private void outputReport(@NotNull BlazeContext context) {
+ context.output(PrintOutput.log("\n==== TIMING REPORT ====\n"));
+ outputReport(context, this, 0);
+ }
+
+ private static void outputReport(
+ @NotNull BlazeContext context, @NotNull TimingScope timingScope, int depth) {
+ String selfString = "";
+
+ // Self time trivially 100% if no children
+ if (timingScope.children.size() > 0) {
+ // Calculate self time as <my duration> - <sum child duration>
+ double selfTime = timingScope.duration;
+ for (TimingScope child : timingScope.children) {
+ selfTime -= child.duration;
+ }
+
+ selfString = selfTime > 0.1 ? String.format(" (%s)", durationStr(selfTime)) : "";
+ }
+
+ context.output(
+ PrintOutput.log(
+ String.format(
+ "%s%s: %s%s",
+ getIndentation(depth),
+ timingScope.name,
+ durationStr(timingScope.duration),
+ selfString)));
+
+ for (TimingScope child : timingScope.children) {
+ outputReport(context, child, depth + 1);
+ }
+ }
+
+ private static String durationStr(double time) {
+ return time >= 1.0 ? String.format("%.1fs", time) : String.format("%dms", (int) (time * 1000));
+ }
+
+ private static String getIndentation(int depth) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < depth; ++i) {
+ sb.append(" ");
+ }
+ return sb.toString();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/Blaze.java b/base/src/com/google/idea/blaze/base/settings/Blaze.java
new file mode 100644
index 0000000..d9e5537
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/Blaze.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings;
+
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import javax.annotation.Nullable;
+import javax.swing.SwingUtilities;
+
+/** Blaze project utilities. */
+public class Blaze {
+
+ /** Build system enum */
+ public enum BuildSystem {
+ Blaze,
+ Bazel;
+
+ /** The build system name, capitalized. */
+ public String getName() {
+ return name();
+ }
+
+ /** The build system name, capitalized. */
+ public String getLowerCaseName() {
+ return name().toLowerCase();
+ }
+ }
+
+ private Blaze() {}
+
+ public static boolean isBlazeProjectOpen() {
+ for (Project project : ProjectManager.getInstance().getOpenProjects()) {
+ if (isBlazeProject(project)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Returns whether this project was imported from blaze. */
+ public static boolean isBlazeProject(Project project) {
+ return BlazeImportSettingsManager.getInstance(project).getImportSettings() != null;
+ }
+
+ /**
+ * Returns the build system associated with this project, or falls back to the default blaze build
+ * system if the project is null or not a blaze project.
+ */
+ public static BuildSystem getBuildSystem(@Nullable Project project) {
+ BlazeImportSettings importSettings =
+ project == null
+ ? null
+ : BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings == null) {
+ return BuildSystemProvider.defaultBuildSystem().buildSystem();
+ }
+ return importSettings.getBuildSystem();
+ }
+
+ /**
+ * Returns the build system provider associated with this project, or falls back to the default
+ * blaze build system if the project is null or not a blaze project.
+ */
+ public static BuildSystemProvider getBuildSystemProvider(@Nullable Project project) {
+ return BuildSystemProvider.getBuildSystemProvider(getBuildSystem(project));
+ }
+
+ /**
+ * The name of the build system associated with the given project, or falls back to the default
+ * blaze build system if the project is null or not a blaze project.
+ */
+ public static String buildSystemName(@Nullable Project project) {
+ return getBuildSystem(project).getName();
+ }
+
+ /** The default build system */
+ public static BuildSystem defaultBuildSystem() {
+ return BuildSystemProvider.defaultBuildSystem().buildSystem();
+ }
+
+ /**
+ * The name of the application-wide build system default. This should only be used in situations
+ * where it doesn't make sense to use the build system associated with the current project (e.g.
+ * the import project action).
+ */
+ public static String defaultBuildSystemName() {
+ return BuildSystemProvider.defaultBuildSystem().buildSystem().getName();
+ }
+
+ /**
+ * Tries to guess the current project, and uses that to determine the build system name.<br>
+ * Should only be used in situations where the current project is not accessible.
+ */
+ public static String guessBuildSystemName() {
+ Project project = guessCurrentProject();
+ return buildSystemName(project);
+ }
+
+ private static Project guessCurrentProject() {
+ Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
+ if (openProjects.length == 1) {
+ return openProjects[0];
+ }
+ if (SwingUtilities.isEventDispatchThread()) {
+ return (Project) DataManager.getInstance().getDataContext().getData("project");
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
new file mode 100644
index 0000000..7f0ea60
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings;
+
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.util.xmlb.annotations.Tag;
+import javax.annotation.Nullable;
+
+// The tag here is for legacy migration support.
+// No longer needed and can be removed with {@link BlazeImportSettingsManagerLegacy}
+/** Project settings that are set at import time. */
+@Tag("BlazeProjectSettings")
+public final class BlazeImportSettings {
+
+ private String workspaceRoot = "";
+
+ private String projectName = "";
+
+ private String projectDataDirectory = "";
+
+ private String locationHash = "";
+
+ private String projectViewFile;
+
+ private BuildSystem buildSystem =
+ BuildSystem.Blaze; // default for backwards compatibility with existing projects.
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ BlazeImportSettings() {}
+
+ public BlazeImportSettings(
+ String workspaceRoot,
+ String projectName,
+ String projectDataDirectory,
+ String locationHash,
+ String projectViewFile,
+ BuildSystem buildSystem) {
+ this.workspaceRoot = workspaceRoot;
+ this.projectName = projectName;
+ this.projectDataDirectory = projectDataDirectory;
+ this.locationHash = locationHash;
+ this.projectViewFile = projectViewFile;
+ this.buildSystem = buildSystem;
+ }
+
+ @SuppressWarnings("unused")
+ public String getWorkspaceRoot() {
+ return workspaceRoot;
+ }
+
+ @SuppressWarnings("unused")
+ public String getProjectName() {
+ return projectName;
+ }
+
+ @SuppressWarnings("unused")
+ public String getProjectDataDirectory() {
+ return projectDataDirectory;
+ }
+
+ /** Hash used to give the project a unique directory in the system directory. */
+ @SuppressWarnings("unused")
+ public String getLocationHash() {
+ return locationHash;
+ }
+
+ /** The user's local project view file */
+ @SuppressWarnings("unused")
+ public String getProjectViewFile() {
+ return projectViewFile;
+ }
+
+ /** The build system used for the project. */
+ @SuppressWarnings("unused")
+ public BuildSystem getBuildSystem() {
+ return buildSystem;
+ }
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ public void setWorkspaceRoot(String workspaceRoot) {
+ this.workspaceRoot = workspaceRoot;
+ }
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ public void setProjectName(String projectName) {
+ this.projectName = projectName;
+ }
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ public void setProjectDataDirectory(String projectDataDirectory) {
+ this.projectDataDirectory = projectDataDirectory;
+ }
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ public void setLocationHash(String locationHash) {
+ this.locationHash = locationHash;
+ }
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ public void setProjectViewFile(@Nullable String projectViewFile) {
+ this.projectViewFile = projectViewFile;
+ }
+
+ // Used by bean serialization -- legacy import support
+ @SuppressWarnings("unused")
+ public void setAsProjectFile(@Nullable String projectViewFile) {
+ this.projectViewFile = projectViewFile;
+ }
+
+ // Used by bean serialization
+ @SuppressWarnings("unused")
+ public void setBuildSystem(BuildSystem buildSystem) {
+ this.buildSystem = buildSystem;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
new file mode 100644
index 0000000..a45b08e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings;
+
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.components.StoragePathMacros;
+import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Manages storage for the project's {@link BlazeImportSettings}. */
+@State(name = "BlazeImportSettings", storages = @Storage(file = StoragePathMacros.WORKSPACE_FILE))
+public class BlazeImportSettingsManager implements PersistentStateComponent<BlazeImportSettings> {
+
+ @Nullable private BlazeImportSettings importSettings;
+
+ private Project project;
+
+ public BlazeImportSettingsManager(@NotNull Project project) {
+ this.project = project;
+ }
+
+ public static BlazeImportSettingsManager getInstance(Project project) {
+ return ServiceManager.getService(project, BlazeImportSettingsManager.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ @Override
+ public BlazeImportSettings getState() {
+ return importSettings;
+ }
+
+ @Override
+ public void loadState(BlazeImportSettings importSettings) {
+ this.importSettings = importSettings;
+ }
+
+ @Nullable
+ public BlazeImportSettings getImportSettings() {
+ if (importSettings == null) {
+ importSettings =
+ BlazeImportSettingsManagerLegacy.getInstance(project).migrateImportSettings();
+ }
+
+ return importSettings;
+ }
+
+ public void setImportSettings(@NotNull BlazeImportSettings importSettings) {
+ this.importSettings = importSettings;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManagerLegacy.java b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManagerLegacy.java
new file mode 100644
index 0000000..fec7d1d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManagerLegacy.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings;
+
+import com.google.common.collect.Lists;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.components.StoragePathMacros;
+import com.intellij.openapi.components.StorageScheme;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.xmlb.annotations.AbstractCollection;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Legacy storage for BlazeImportSettings. Introduced in 1.8, can be removed around ~2.2. Removal of
+ * this class will cause old projects to stop loading.
+ */
+@State(
+ name = "BlazeSettings",
+ storages = {
+ @Storage(file = StoragePathMacros.PROJECT_FILE),
+ @Storage(
+ file = StoragePathMacros.PROJECT_CONFIG_DIR + "/blaze.xml",
+ scheme = StorageScheme.DIRECTORY_BASED
+ )
+ }
+)
+public class BlazeImportSettingsManagerLegacy
+ implements PersistentStateComponent<BlazeImportSettingsManagerLegacy.State> {
+
+ @Nullable private BlazeImportSettings importSettings;
+
+ @NotNull private Project project;
+
+ public BlazeImportSettingsManagerLegacy(@NotNull Project project) {
+ this.project = project;
+ }
+
+ @NotNull
+ public static BlazeImportSettingsManagerLegacy getInstance(@NotNull Project project) {
+ return ServiceManager.getService(project, BlazeImportSettingsManagerLegacy.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Nullable
+ @Override
+ public State getState() {
+ if (importSettings == null) {
+ return null;
+ }
+ State state = new State();
+ List<BlazeImportSettings> value = Lists.newArrayList();
+ value.add(importSettings);
+ state.setLinkedExternalProjectsSettings(value);
+ return state;
+ }
+
+ @Override
+ public void loadState(State state) {
+ if (state == null) {
+ importSettings = null;
+ return;
+ }
+
+ Collection<BlazeImportSettings> settings = state.getLinkedExternalProjectsSettings();
+ if (settings != null && !settings.isEmpty()) {
+ importSettings = settings.iterator().next();
+ } else {
+ importSettings = null;
+ }
+ }
+
+ @Nullable
+ BlazeImportSettings migrateImportSettings() {
+ BlazeImportSettings importSettings = this.importSettings;
+ this.importSettings = null;
+ return importSettings;
+ }
+
+ /** State class for the Blaze settings. */
+ static class State {
+
+ private List<BlazeImportSettings> importSettings = Lists.newArrayList();
+
+ @AbstractCollection(
+ surroundWithTag = false,
+ elementTypes = {BlazeImportSettings.class}
+ )
+ public List<BlazeImportSettings> getLinkedExternalProjectsSettings() {
+ return importSettings;
+ }
+
+ public void setLinkedExternalProjectsSettings(List<BlazeImportSettings> settings) {
+ importSettings = settings;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/BlazeUserSettings.java b/base/src/com/google/idea/blaze/base/settings/BlazeUserSettings.java
new file mode 100644
index 0000000..1e74ef4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/BlazeUserSettings.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings;
+
+import com.google.idea.blaze.base.sync.status.BlazeSyncStatus;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.util.xmlb.XmlSerializerUtil;
+import javax.annotation.Nullable;
+
+/** Stores blaze view settings. */
+@State(
+ name = "BlazeUserSettings",
+ storages = {
+ @Storage("blaze.user.settings.xml"),
+ @Storage(value = "blaze.view.xml", deprecated = true)
+ }
+)
+public class BlazeUserSettings implements PersistentStateComponent<BlazeUserSettings> {
+
+ public boolean suppressConsoleForRunAction = false;
+ private boolean resyncAutomatically = false;
+ private boolean syncStatusPopupShown = false;
+ private boolean expandSyncToWorkingSet = true;
+ private boolean showPerformanceWarnings = false;
+ private boolean attachSourcesByDefault = false;
+ private boolean attachSourcesOnDemand = false;
+ private boolean collapseProjectView = true;
+ private String blazeBinaryPath = "/usr/bin/blaze";
+ @Nullable private String bazelBinaryPath;
+
+ public static BlazeUserSettings getInstance() {
+ return ServiceManager.getService(BlazeUserSettings.class);
+ }
+
+ @Override
+ public BlazeUserSettings getState() {
+ return this;
+ }
+
+ @Override
+ public void loadState(BlazeUserSettings state) {
+ XmlSerializerUtil.copyBean(state, this);
+ }
+
+ /**
+ * Also kicks off an incremental sync if we're now syncing automatically, and the project is
+ * currently dirty.
+ */
+ public void setResyncAutomatically(boolean resyncAutomatically) {
+ if (this.resyncAutomatically == resyncAutomatically) {
+ return;
+ }
+ this.resyncAutomatically = resyncAutomatically;
+ ProjectManager projectManager =
+ ApplicationManager.getApplication().getComponent(ProjectManager.class);
+ Project[] openProjects = projectManager.getOpenProjects();
+ for (Project project : openProjects) {
+ if (Blaze.isBlazeProject(project)) {
+ BlazeSyncStatus.getInstance(project).queueAutomaticSyncIfDirty();
+ }
+ }
+ }
+
+ public boolean getResyncAutomatically() {
+ return resyncAutomatically;
+ }
+
+ public boolean getSuppressConsoleForRunAction() {
+ return suppressConsoleForRunAction;
+ }
+
+ public void setSuppressConsoleForRunAction(boolean suppressConsoleForRunAction) {
+ this.suppressConsoleForRunAction = suppressConsoleForRunAction;
+ }
+
+ public boolean getSyncStatusPopupShown() {
+ return syncStatusPopupShown;
+ }
+
+ public void setSyncStatusPopupShown(boolean syncStatusPopupShown) {
+ this.syncStatusPopupShown = syncStatusPopupShown;
+ }
+
+ public boolean getExpandSyncToWorkingSet() {
+ return expandSyncToWorkingSet;
+ }
+
+ public void setExpandSyncToWorkingSet(boolean expandSyncToWorkingSet) {
+ this.expandSyncToWorkingSet = expandSyncToWorkingSet;
+ }
+
+ public boolean getShowPerformanceWarnings() {
+ return showPerformanceWarnings;
+ }
+
+ public void setShowPerformanceWarnings(boolean showPerformanceWarnings) {
+ this.showPerformanceWarnings = showPerformanceWarnings;
+ }
+
+ public String getBlazeBinaryPath() {
+ return blazeBinaryPath;
+ }
+
+ public void setBlazeBinaryPath(String blazeBinaryPath) {
+ this.blazeBinaryPath = blazeBinaryPath;
+ }
+
+ @Nullable
+ public String getBazelBinaryPath() {
+ return bazelBinaryPath;
+ }
+
+ public void setBazelBinaryPath(String bazelBinaryPath) {
+ this.bazelBinaryPath = bazelBinaryPath;
+ }
+
+ public boolean getCollapseProjectView() {
+ return collapseProjectView;
+ }
+
+ public void setCollapseProjectView(boolean collapseProjectView) {
+ this.collapseProjectView = collapseProjectView;
+ }
+
+ // Deprecated -- use BlazeJavaUserSettings
+ @Deprecated
+ @SuppressWarnings("unused") // Used by bean serialization
+ public boolean getAttachSourcesByDefault() {
+ return attachSourcesByDefault;
+ }
+
+ // Deprecated -- use BlazeJavaUserSettings
+ @Deprecated
+ @SuppressWarnings("unused") // Used by bean serialization
+ public void setAttachSourcesByDefault(boolean attachSourcesByDefault) {
+ this.attachSourcesByDefault = attachSourcesByDefault;
+ }
+
+ // Deprecated -- use BlazeJavaUserSettings
+ @Deprecated
+ @SuppressWarnings("unused") // Used by bean serialization
+ public boolean getAttachSourcesOnDemand() {
+ return attachSourcesOnDemand;
+ }
+
+ // Deprecated -- use BlazeJavaUserSettings
+ @Deprecated
+ @SuppressWarnings("unused") // Used by bean serialization
+ public void setAttachSourcesOnDemand(boolean attachSourcesOnDemand) {
+ this.attachSourcesOnDemand = attachSourcesOnDemand;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/IsBlazeProjectCondition.java b/base/src/com/google/idea/blaze/base/settings/IsBlazeProjectCondition.java
new file mode 100644
index 0000000..23da190
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/IsBlazeProjectCondition.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+
+/** Condition for enabling features (e.g. Blaze and Crow consoles) only in Blaze projects. */
+public class IsBlazeProjectCondition implements Condition<Project> {
+
+ @Override
+ public boolean value(Project project) {
+ return project != null && Blaze.isBlazeProject(project);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsConfigurable.java b/base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsConfigurable.java
new file mode 100644
index 0000000..d541dc9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsConfigurable.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings.ui;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.ui.FileSelectorWithStoredHistory;
+import com.intellij.openapi.options.BaseConfigurable;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.project.Project;
+import com.intellij.uiDesigner.core.GridConstraints;
+import com.intellij.uiDesigner.core.GridLayoutManager;
+import com.intellij.uiDesigner.core.Spacer;
+import java.awt.Insets;
+import java.util.Collection;
+import javax.annotation.Nullable;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+/** Blaze console view settings */
+public class BlazeUserSettingsConfigurable extends BaseConfigurable
+ implements SearchableConfigurable {
+
+ private static final String BLAZE_BINARY_PATH_KEY = "blaze.binary.path";
+ public static final String BAZEL_BINARY_PATH_KEY = "bazel.binary.path";
+
+ private final BuildSystem buildSystem;
+ private final Collection<BlazeUserSettingsContributor> settingsContributors;
+
+ private JPanel myMainPanel;
+ private JCheckBox suppressConsoleForRunAction;
+ private JCheckBox resyncAutomatically;
+ private JCheckBox collapseProjectView;
+ private FileSelectorWithStoredHistory blazeBinaryPathField;
+ private FileSelectorWithStoredHistory bazelBinaryPathField;
+
+ public BlazeUserSettingsConfigurable(Project project) {
+ this.buildSystem = Blaze.getBuildSystem(project);
+ this.settingsContributors = Lists.newArrayList();
+ for (BlazeUserSettingsContributor.Provider provider :
+ BlazeUserSettingsContributor.Provider.EP_NAME.getExtensions()) {
+ settingsContributors.add(provider.getContributor());
+ }
+
+ setupUI();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return buildSystem.getName() + " View Settings";
+ }
+
+ @Nullable
+ @Override
+ public String getHelpTopic() {
+ return null;
+ }
+
+ @Override
+ public void apply() throws ConfigurationException {
+ BlazeUserSettings settings = BlazeUserSettings.getInstance();
+ settings.setSuppressConsoleForRunAction(suppressConsoleForRunAction.isSelected());
+ settings.setResyncAutomatically(resyncAutomatically.isSelected());
+ settings.setCollapseProjectView(collapseProjectView.isSelected());
+ settings.setBlazeBinaryPath(Strings.nullToEmpty(blazeBinaryPathField.getText()));
+ settings.setBazelBinaryPath(Strings.nullToEmpty(bazelBinaryPathField.getText()));
+
+ for (BlazeUserSettingsContributor settingsContributor : settingsContributors) {
+ settingsContributor.apply();
+ }
+ }
+
+ @Override
+ public void reset() {
+ BlazeUserSettings settings = BlazeUserSettings.getInstance();
+ suppressConsoleForRunAction.setSelected(settings.getSuppressConsoleForRunAction());
+ resyncAutomatically.setSelected(settings.getResyncAutomatically());
+ collapseProjectView.setSelected(settings.getCollapseProjectView());
+ blazeBinaryPathField.setTextWithHistory(settings.getBlazeBinaryPath());
+ bazelBinaryPathField.setTextWithHistory(settings.getBazelBinaryPath());
+
+ for (BlazeUserSettingsContributor settingsContributor : settingsContributors) {
+ settingsContributor.reset();
+ }
+ }
+
+ @Nullable
+ @Override
+ public JComponent createComponent() {
+ return myMainPanel;
+ }
+
+ @Override
+ public boolean isModified() {
+ BlazeUserSettings settings = BlazeUserSettings.getInstance();
+ boolean isModified =
+ !Objects.equal(
+ suppressConsoleForRunAction.isSelected(), settings.getSuppressConsoleForRunAction())
+ || !Objects.equal(resyncAutomatically.isSelected(), settings.getResyncAutomatically())
+ || !Objects.equal(collapseProjectView.isSelected(), settings.getCollapseProjectView())
+ || !Objects.equal(blazeBinaryPathField.getText(), settings.getBlazeBinaryPath())
+ || !Objects.equal(bazelBinaryPathField.getText(), settings.getBazelBinaryPath());
+
+ for (BlazeUserSettingsContributor settingsContributor : settingsContributors) {
+ isModified |= settingsContributor.isModified();
+ }
+ return isModified;
+ }
+
+ @Override
+ public void disposeUIResources() {}
+
+ @Override
+ public String getId() {
+ return "blaze.view.settings";
+ }
+
+ @Nullable
+ @Override
+ public Runnable enableSearch(String option) {
+ return null;
+ }
+
+ /** Initially generated by IntelliJ from a .form file. */
+ private void setupUI() {
+ int contributorRowCount = 0;
+ for (BlazeUserSettingsContributor contributor : settingsContributors) {
+ contributorRowCount += contributor.getRowCount();
+ }
+
+ final int totalRowSize = 5 + contributorRowCount;
+ int rowi = 0;
+
+ myMainPanel = new JPanel();
+ myMainPanel.setLayout(new GridLayoutManager(totalRowSize, 2, new Insets(0, 0, 0, 0), -1, -1));
+ suppressConsoleForRunAction = new JCheckBox();
+ suppressConsoleForRunAction.setText(
+ String.format("Suppress %s console for Run/Debug actions", buildSystem));
+ suppressConsoleForRunAction.setVerticalAlignment(SwingConstants.CENTER);
+ myMainPanel.add(
+ suppressConsoleForRunAction,
+ new GridConstraints(
+ rowi++,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_NORTHWEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ resyncAutomatically = new JCheckBox();
+ resyncAutomatically.setSelected(false);
+ resyncAutomatically.setText("Automatically re-sync project when BUILD files change");
+ myMainPanel.add(
+ resyncAutomatically,
+ new GridConstraints(
+ rowi++,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_NORTHWEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ collapseProjectView = new JCheckBox();
+ collapseProjectView.setSelected(false);
+ collapseProjectView.setText("Collapse project view directory roots");
+ myMainPanel.add(
+ collapseProjectView,
+ new GridConstraints(
+ rowi++,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_NORTHWEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ for (BlazeUserSettingsContributor contributor : settingsContributors) {
+ rowi = contributor.addComponents(myMainPanel, rowi);
+ }
+
+ blazeBinaryPathField =
+ FileSelectorWithStoredHistory.create(
+ BLAZE_BINARY_PATH_KEY, "Specify the blaze binary path");
+ bazelBinaryPathField =
+ FileSelectorWithStoredHistory.create(
+ BAZEL_BINARY_PATH_KEY, "Specify the bazel binary path");
+
+ JLabel pathLabel;
+ JComponent pathPanel;
+ if (buildSystem == BuildSystem.Blaze) {
+ pathPanel = blazeBinaryPathField;
+ pathLabel = new JLabel("Blaze binary location");
+ } else {
+ pathPanel = bazelBinaryPathField;
+ pathLabel = new JLabel("Bazel binary location");
+ }
+ pathLabel.setLabelFor(pathPanel);
+ myMainPanel.add(
+ pathLabel,
+ new GridConstraints(
+ rowi,
+ 0,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_FIXED,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ myMainPanel.add(
+ pathPanel,
+ new GridConstraints(
+ rowi,
+ 1,
+ 1,
+ 1,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_HORIZONTAL,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ rowi++;
+
+ myMainPanel.add(
+ new Spacer(),
+ new GridConstraints(
+ rowi,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_CENTER,
+ GridConstraints.FILL_VERTICAL,
+ 1,
+ GridConstraints.SIZEPOLICY_WANT_GROW,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsContributor.java b/base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsContributor.java
new file mode 100644
index 0000000..7ebe8b7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsContributor.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings.ui;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import javax.swing.JPanel;
+
+/** Allows other modules to contribute user settings. */
+public interface BlazeUserSettingsContributor {
+ /** Apply UI to settings. */
+ void apply();
+
+ /** Reset UI from settings. */
+ void reset();
+
+ /** @return Whether any settings in the UI is modified. */
+ boolean isModified();
+
+ /** Return the number of components you intend to add. */
+ int getRowCount();
+
+ /**
+ * Return all components. They will be added to the user settings page.
+ *
+ * @param panel The panel to add the components to
+ * @param rowi The row index to start adding components to.
+ * @return The next free row index
+ */
+ int addComponents(JPanel panel, int rowi);
+
+ /** A provider of user settings. Bind one of these to provide settings. */
+ interface Provider {
+ ExtensionPointName<Provider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BlazeUserSettingsContributor");
+
+ BlazeUserSettingsContributor getContributor();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/ui/EditProjectViewAction.java b/base/src/com/google/idea/blaze/base/settings/ui/EditProjectViewAction.java
new file mode 100644
index 0000000..b2e86be
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/ui/EditProjectViewAction.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings.ui;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+
+/** Opens all the user's project views. */
+public class EditProjectViewAction extends BlazeAction {
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return;
+ }
+ for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
+ File file = projectViewFile.projectViewFile;
+ if (file != null) {
+ VirtualFile virtualFile = VfsUtil.findFileByIoFile(file, true);
+ if (virtualFile != null) {
+ OpenFileDescriptor descriptor = new OpenFileDescriptor(project, virtualFile);
+ FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
+ }
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java b/base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java
new file mode 100644
index 0000000..8e763f1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings.ui;
+
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataProvider;
+import com.intellij.openapi.project.Project;
+import java.awt.LayoutManager;
+import javax.annotation.Nullable;
+import javax.swing.JPanel;
+
+/**
+ * A normal JPanel which implements DataProvider, providing the specified IntelliJ Project.
+ *
+ * <p>This is used by IntelliJ's action system to determine the relevant project associated with a
+ * UI component.
+ */
+public class JPanelProvidingProject extends JPanel implements DataProvider {
+
+ private final Project project;
+
+ public JPanelProvidingProject(Project project, LayoutManager layoutManager) {
+ super(layoutManager);
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public Object getData(String dataId) {
+ return CommonDataKeys.PROJECT.is(dataId) ? project : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java b/base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java
new file mode 100644
index 0000000..85df043
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.settings.ui;
+
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.scope.OutputSink;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
+import com.intellij.openapi.command.undo.UndoUtil;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.EditorSettings;
+import com.intellij.openapi.editor.colors.EditorColors;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.impl.DocumentImpl;
+import com.intellij.openapi.editor.impl.EditorFactoryImpl;
+import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.project.impl.ProjectImpl;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.impl.PsiManagerEx;
+import com.intellij.psi.impl.file.impl.FileManager;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.ui.components.JBLabel;
+import java.awt.Dimension;
+import java.awt.KeyboardFocusManager;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+import javax.swing.UIManager;
+import org.jetbrains.annotations.NotNull;
+import org.picocontainer.MutablePicoContainer;
+
+/** UI for changing the ProjectView. */
+public class ProjectViewUi {
+
+ private static final String USE_SHARED_PROJECT_VIEW = "Use shared project view file";
+
+ private final Disposable parentDisposable;
+ private EditorEx projectViewEditor;
+ private JCheckBox useShared;
+
+ private WorkspaceRoot workspaceRoot;
+ private boolean useSharedProjectView;
+ private boolean allowEditShared;
+ private String sharedProjectViewText;
+ private boolean settingsInitialized;
+
+ public ProjectViewUi(Disposable parentDisposable) {
+ this.parentDisposable = parentDisposable;
+ }
+
+ /**
+ * To support the custom language features, we need a ProjectImpl, and it's not desirable to
+ * create one from scratch.<br>
+ *
+ * @return the current, non-default project, if one exists, else the default project.
+ */
+ public static Project getProject() {
+ Project project = (Project) DataManager.getInstance().getDataContext().getData("project");
+ if (project != null && project instanceof ProjectImpl) {
+ return project;
+ }
+ return ProjectManager.getInstance().getDefaultProject();
+ }
+
+ public static Dimension getMinimumSize() {
+ return new Dimension(1000, 550);
+ }
+
+ private static EditorEx createEditor(String tooltip) {
+ Project project = getProject();
+ LightVirtualFile virtualFile =
+ new LightVirtualFile("mockProjectViewFile", ProjectViewLanguage.INSTANCE, "");
+ final Document document =
+ ((EditorFactoryImpl) EditorFactory.getInstance()).createDocument(true);
+ ((DocumentImpl) document).setAcceptSlashR(true);
+ FileDocumentManagerImpl.registerDocument(document, virtualFile);
+
+ FileManager fileManager = ((PsiManagerEx) PsiManager.getInstance(project)).getFileManager();
+ fileManager.setViewProvider(virtualFile, fileManager.createFileViewProvider(virtualFile, true));
+
+ if (project.isDefault()) {
+ // Undo-redo doesn't work with the default project.
+ // Explicitly turn it off to avoid error dialogs.
+ UndoUtil.disableUndoFor(document);
+ }
+
+ EditorEx editor =
+ (EditorEx)
+ EditorFactory.getInstance()
+ .createEditor(document, project, ProjectViewFileType.INSTANCE, false);
+ final EditorSettings settings = editor.getSettings();
+ settings.setLineNumbersShown(false);
+ settings.setLineMarkerAreaShown(false);
+ settings.setFoldingOutlineShown(false);
+ settings.setRightMarginShown(false);
+ settings.setAdditionalPageAtBottom(false);
+ editor.getComponent().setMinimumSize(getMinimumSize());
+ editor.getComponent().setPreferredSize(getMinimumSize());
+ editor.getComponent().setToolTipText(tooltip);
+ editor.getComponent().setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
+ editor.getComponent().setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
+ return editor;
+ }
+
+ public void fillUi(JPanel canvas, int indentLevel) {
+ String tooltip =
+ "Enter a project view descriptor file."
+ + (Blaze.defaultBuildSystem() == BuildSystem.Blaze
+ ? " See 'go/intellij/docs/project-views.md' for more information."
+ : "");
+
+ projectViewEditor = createEditor(tooltip);
+ projectViewEditor
+ .getColorsScheme()
+ .setColor(EditorColors.READONLY_BACKGROUND_COLOR, UIManager.getColor("Label.background"));
+ Disposer.register(
+ parentDisposable, () -> EditorFactory.getInstance().releaseEditor(projectViewEditor));
+
+ JBLabel labelsLabel = new JBLabel("Project View");
+ labelsLabel.setToolTipText(tooltip);
+ canvas.add(labelsLabel, UiUtil.getFillLineConstraints(indentLevel));
+
+ canvas.add(projectViewEditor.getComponent(), UiUtil.getFillLineConstraints(indentLevel));
+
+ useShared = new JCheckBox(USE_SHARED_PROJECT_VIEW);
+ useShared.addActionListener(
+ e -> {
+ useSharedProjectView = useShared.isSelected();
+ if (useSharedProjectView) {
+ setProjectViewText(sharedProjectViewText);
+ }
+ updateTextAreasEnabled();
+ });
+ canvas.add(useShared, UiUtil.getFillLineConstraints(indentLevel));
+ }
+
+ public void init(
+ WorkspaceRoot workspaceRoot,
+ String projectViewText,
+ @Nullable String sharedProjectViewText,
+ @Nullable File sharedProjectViewFile,
+ boolean useSharedProjectView,
+ boolean allowEditShared) {
+ this.workspaceRoot = workspaceRoot;
+ this.useSharedProjectView = useSharedProjectView;
+ this.allowEditShared = allowEditShared;
+ this.sharedProjectViewText = sharedProjectViewText;
+
+ assert !(useSharedProjectView && sharedProjectViewText == null);
+
+ if (sharedProjectViewFile != null) {
+ WorkspacePath workspacePath = workspaceRoot.workspacePathFor(sharedProjectViewFile);
+ useShared.setText(USE_SHARED_PROJECT_VIEW + ": " + workspacePath.relativePath());
+ }
+
+ useShared.setSelected(useSharedProjectView);
+
+ if (sharedProjectViewText == null) {
+ useShared.setEnabled(false);
+ }
+
+ setDummyWorkspacePathResolverProvider(workspaceRoot);
+ setProjectViewText(projectViewText);
+ settingsInitialized = true;
+ }
+
+ private void setDummyWorkspacePathResolverProvider(WorkspaceRoot workspaceRoot) {
+ MutablePicoContainer container = (MutablePicoContainer) getProject().getPicoContainer();
+ Class<WorkspacePathResolverProvider> key = WorkspacePathResolverProvider.class;
+ Object oldProvider = container.getComponentInstance(key);
+ container.unregisterComponent(key.getName());
+ container.registerComponentInstance(
+ key.getName(),
+ (WorkspacePathResolverProvider) () -> new WorkspacePathResolverImpl(workspaceRoot));
+ if (!settingsInitialized) {
+ Disposer.register(
+ parentDisposable,
+ () -> {
+ container.unregisterComponent(key.getName());
+ if (oldProvider != null) {
+ container.registerComponentInstance(key.getName(), oldProvider);
+ }
+ });
+ }
+ }
+
+ private void setProjectViewText(String projectViewText) {
+ new WriteAction() {
+ @Override
+ protected void run(@NotNull Result result) throws Throwable {
+ projectViewEditor.getDocument().setReadOnly(false);
+ projectViewEditor.getDocument().setText(projectViewText);
+ }
+ }.execute();
+ updateTextAreasEnabled();
+ }
+
+ private void updateTextAreasEnabled() {
+ boolean editEnabled = allowEditShared || !useSharedProjectView;
+ projectViewEditor.setViewer(!editEnabled);
+ projectViewEditor.getDocument().setReadOnly(!editEnabled);
+ projectViewEditor.reinitSettings();
+ }
+
+ public ProjectViewSet parseProjectView(final List<IssueOutput> issues) {
+ final String projectViewText = projectViewEditor.getDocument().getText();
+ final OutputSink<IssueOutput> issueCollector =
+ output -> {
+ issues.add(output);
+ return OutputSink.Propagation.Continue;
+ };
+ return Scope.root(
+ context -> {
+ context.addOutputSink(IssueOutput.class, issueCollector);
+ ProjectViewParser projectViewParser =
+ new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot));
+ projectViewParser.parseProjectView(projectViewText);
+ return projectViewParser.getResult();
+ });
+ }
+
+ public boolean getUseSharedProjectView() {
+ return this.useSharedProjectView;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncManager.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncManager.java
new file mode 100644
index 0000000..db3cba2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncManager.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.startup.StartupManager;
+import org.jetbrains.annotations.NotNull;
+
+/** Manages syncing and its listeners. */
+public class BlazeSyncManager {
+
+ @NotNull private final Project project;
+
+ public BlazeSyncManager(@NotNull Project project) {
+ this.project = project;
+ }
+
+ public static BlazeSyncManager getInstance(@NotNull Project project) {
+ return ServiceManager.getService(project, BlazeSyncManager.class);
+ }
+
+ /** Requests a project sync with Blaze. */
+ public void requestProjectSync(@NotNull final BlazeSyncParams syncParams) {
+ StartupManager.getInstance(project)
+ .runWhenProjectIsInitialized(
+ new Runnable() {
+ @Override
+ public void run() {
+ final BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings == null) {
+ throw new IllegalStateException(
+ String.format(
+ "Attempt to sync non-%s project.", Blaze.buildSystemName(project)));
+ }
+
+ final BlazeSyncTask syncTask =
+ new BlazeSyncTask(project, importSettings, syncParams);
+
+ BlazeExecutor.submitTask(project, syncTask);
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncParams.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncParams.java
new file mode 100644
index 0000000..0f904fc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncParams.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import java.util.Collection;
+import javax.annotation.concurrent.Immutable;
+
+/** Parameters that control the sync. */
+@Immutable
+public final class BlazeSyncParams {
+
+ /** The kind of sync. */
+ public enum SyncMode {
+ RESTORE_EPHEMERAL_STATE,
+ INCREMENTAL,
+ FULL
+ }
+
+ /** Builder for sync params */
+ public static final class Builder {
+ private String title;
+ private SyncMode syncMode;
+ private boolean backgroundSync;
+ private boolean addProjectViewTargets;
+ private boolean addWorkingSet;
+ private ImmutableList.Builder<TargetExpression> targetExpressions = ImmutableList.builder();
+
+ public Builder(String title, SyncMode syncMode) {
+ this.title = title;
+ this.syncMode = syncMode;
+ }
+
+ public Builder setBackgroundSync(boolean backgroundSync) {
+ this.backgroundSync = backgroundSync;
+ return this;
+ }
+
+ public Builder addProjectViewTargets(boolean addProjectViewTargets) {
+ this.addProjectViewTargets = addProjectViewTargets;
+ return this;
+ }
+
+ public Builder addTargetExpression(TargetExpression targetExpression) {
+ this.targetExpressions.add(targetExpression);
+ return this;
+ }
+
+ public Builder addTargetExpressions(Collection<TargetExpression> targets) {
+ this.targetExpressions.addAll(targets);
+ return this;
+ }
+
+ public Builder addWorkingSet(boolean addWorkingSet) {
+ this.addWorkingSet = addWorkingSet;
+ return this;
+ }
+
+ public BlazeSyncParams build() {
+ return new BlazeSyncParams(
+ title,
+ syncMode,
+ backgroundSync,
+ addProjectViewTargets,
+ addWorkingSet,
+ targetExpressions.build());
+ }
+ }
+
+ public final String title;
+ public final SyncMode syncMode;
+ public final boolean backgroundSync;
+ public final boolean addProjectViewTargets;
+ public final boolean addWorkingSet;
+ public final ImmutableList<TargetExpression> targetExpressions;
+
+ private BlazeSyncParams(
+ String title,
+ SyncMode syncMode,
+ boolean backgroundSync,
+ boolean addProjectViewTargets,
+ boolean addWorkingSet,
+ ImmutableList<TargetExpression> targetExpressions) {
+ this.title = title;
+ this.syncMode = syncMode;
+ this.backgroundSync = backgroundSync;
+ this.addProjectViewTargets = addProjectViewTargets;
+ this.addWorkingSet = addWorkingSet;
+ this.targetExpressions = targetExpressions;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
new file mode 100644
index 0000000..985ff17
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import java.util.Collection;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/** Can plug into the blaze sync system. */
+public interface BlazeSyncPlugin {
+ ExtensionPointName<BlazeSyncPlugin> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.SyncPlugin");
+
+ /**
+ * May be used by the plugin to create/edit modules.
+ *
+ * <p>Using this ensures that the blaze plugin is aware of the modules, won't garbage collect
+ * them, and that all module modifications happen in a single transaction.
+ */
+ interface ModuleEditor {
+ /** Creates a new module and registers it with the module editor. */
+ Module createModule(String moduleName, ModuleType moduleType);
+
+ /**
+ * Edits a module. It will be committed when commit is called.
+ *
+ * <p>The module will be returned in a cleared state. You should not call this method multiple
+ * times.
+ */
+ ModifiableRootModel editModule(Module module);
+
+ /**
+ * Registers a module. This prevents garbage collection of the module upon commit.
+ *
+ * @return True if the module exists and was registered.
+ */
+ boolean registerModule(String moduleName);
+
+ /** Finds a module by name. This doesn't register the module. */
+ @Nullable
+ Module findModule(String moduleName);
+
+ /** Commits the module editor without garbage collection. */
+ void commit();
+ }
+
+ /** @return The default workspace type recommended by this plugin. */
+ @Nullable
+ WorkspaceType getDefaultWorkspaceType();
+
+ /** @return The module type for the workspace given the workspace type. */
+ @Nullable
+ ModuleType getWorkspaceModuleType(WorkspaceType workspaceType);
+
+ /** @return The set of supported languages under this workspace type. */
+ Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType);
+
+ /** Given the rule map, update the sync state for this plugin. Should not have side effects. */
+ void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState);
+
+ /** Updates the sdk. */
+ void updateSdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData);
+
+ /**
+ * Modify the project content entries. There will be one content entry per project directory from
+ * the project view set.
+ */
+ void updateContentEntries(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<ContentEntry> contentEntries);
+
+ /** Modifies the IDE project structure in accordance with the sync data. */
+ void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel);
+
+ /** Validates the project. */
+ boolean validate(Project project, BlazeContext context, BlazeProjectData blazeProjectData);
+
+ /**
+ * Validates the project view.
+ *
+ * @return True for success, false for fatal error.
+ */
+ boolean validateProjectView(
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings);
+
+ /** Returns any custom sections that this plugin supports. */
+ Collection<SectionParser> getSections();
+
+ /** Returns whether this plugin requires resolving ide artifacts to function. */
+ boolean requiresResolveIdeArtifacts();
+
+ /** Convenience adapter to help stubbing out methods. */
+ class Adapter implements BlazeSyncPlugin {
+
+ @Nullable
+ @Override
+ public WorkspaceType getDefaultWorkspaceType() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
+ return null;
+ }
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {}
+
+ @Override
+ public void updateSdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData) {}
+
+ @Override
+ public void updateContentEntries(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<ContentEntry> contentEntries) {}
+
+ @Override
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {}
+
+ @Override
+ public boolean validate(
+ Project project, BlazeContext context, BlazeProjectData blazeProjectData) {
+ return true;
+ }
+
+ @Override
+ public boolean validateProjectView(
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
+ return true;
+ }
+
+ @Override
+ public Collection<SectionParser> getSections() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean requiresResolveIdeArtifacts() {
+ return false;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncStartupActivity.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncStartupActivity.java
new file mode 100644
index 0000000..5b6a8ee
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncStartupActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.startup.StartupActivity;
+import org.jetbrains.annotations.NotNull;
+
+/** Syncs the project upon startup. */
+public class BlazeSyncStartupActivity implements StartupActivity {
+
+ @Override
+ public void runActivity(@NotNull final Project project) {
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+
+ if (importSettings != null) {
+ BlazeSyncManager.getInstance(project).requestProjectSync(getSyncParams());
+ }
+ }
+
+ private static BlazeSyncParams getSyncParams() {
+ if (BlazeUserSettings.getInstance().getResyncAutomatically()) {
+ return new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build();
+ }
+ return new BlazeSyncParams.Builder(
+ "Sync Project", BlazeSyncParams.SyncMode.RESTORE_EPHEMERAL_STATE)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
new file mode 100755
index 0000000..a49b8bf
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.async.AsyncUtil;
+import com.google.idea.blaze.base.async.FutureUtil;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.experiments.ExperimentScope;
+import com.google.idea.blaze.base.filecache.FileCaches;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.prefetch.PrefetchService;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.ProjectViewVerifier;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.rulemaps.ReverseDependencyMap;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.scope.scopes.NotificationScope;
+import com.google.idea.blaze.base.scope.scopes.PerformanceWarningScope;
+import com.google.idea.blaze.base.scope.scopes.ProgressIndicatorScope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin.ModuleEditor;
+import com.google.idea.blaze.base.sync.SyncListener.SyncResult;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface.BuildResult;
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManagerImpl;
+import com.google.idea.blaze.base.sync.projectstructure.ContentEntryEditor;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorImpl;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
+import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.google.idea.blaze.base.util.SaveUtil;
+import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Progressive;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.StandardFileSystems;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** Syncs the project with blaze. */
+final class BlazeSyncTask implements Progressive {
+
+ private static final Logger LOG = Logger.getInstance(BlazeSyncTask.class);
+
+ private final Project project;
+ private final BlazeImportSettings importSettings;
+ private final WorkspaceRoot workspaceRoot;
+ private final BlazeSyncParams syncParams;
+ private final boolean showPerformanceWarnings;
+ private long syncStartTime;
+
+ BlazeSyncTask(
+ Project project, BlazeImportSettings importSettings, final BlazeSyncParams syncParams) {
+ this.project = project;
+ this.importSettings = importSettings;
+ this.workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
+ this.syncParams = syncParams;
+ this.showPerformanceWarnings = BlazeUserSettings.getInstance().getShowPerformanceWarnings();
+ }
+
+ @Override
+ public void run(final ProgressIndicator indicator) {
+ Scope.root(
+ (BlazeContext context) -> {
+ context.push(new ExperimentScope());
+ if (showPerformanceWarnings) {
+ context.push(new PerformanceWarningScope());
+ }
+ context
+ .push(new ProgressIndicatorScope(indicator))
+ .push(new TimingScope("Sync"))
+ .push(new LoggedTimingScope(project, Action.SYNC_TOTAL_TIME));
+
+ if (!syncParams.backgroundSync) {
+ context
+ .push(new BlazeConsoleScope.Builder(project, indicator).build())
+ .push(new IssuesScope(project))
+ .push(new IdeaLogScope())
+ .push(
+ new NotificationScope(
+ project, "Sync", "Sync project", "Sync successful", "Sync failed"));
+ }
+
+ context.output(new StatusOutput("Syncing project..."));
+ syncProject(context);
+ });
+ }
+
+ /** Returns true if sync successfully completed */
+ @VisibleForTesting
+ boolean syncProject(BlazeContext context) {
+ SyncResult syncResult = SyncResult.FAILURE;
+ try {
+ SaveUtil.saveAllFiles();
+ onSyncStart(project);
+ syncResult = doSyncProject(context);
+ } catch (AssertionError | Exception e) {
+ LOG.error(e);
+ IssueOutput.error("Internal error: " + e.getMessage()).submit(context);
+ } finally {
+ afterSync(project, syncResult);
+ }
+ return syncResult == SyncResult.SUCCESS || syncResult == SyncResult.PARTIAL_SUCCESS;
+ }
+
+ /** @return true if sync successfully completed */
+ private SyncResult doSyncProject(final BlazeContext context) {
+ this.syncStartTime = System.currentTimeMillis();
+
+ if (importSettings.getProjectViewFile() == null) {
+ IssueOutput.error(
+ "This project looks like it's been opened from an old version of ASwB. "
+ + "That is unfortunately not supported. Please reimport your project.")
+ .submit(context);
+ return SyncResult.FAILURE;
+ }
+
+ @Nullable BlazeProjectData oldBlazeProjectData = null;
+ if (syncParams.syncMode != SyncMode.FULL) {
+ oldBlazeProjectData =
+ BlazeProjectDataManagerImpl.getImpl(project).loadProjectRoot(context, importSettings);
+ }
+
+ BlazeVcsHandler vcsHandler = null;
+ for (BlazeVcsHandler candidate : BlazeVcsHandler.EP_NAME.getExtensions()) {
+ if (candidate.handlesProject(Blaze.getBuildSystem(project), workspaceRoot)) {
+ vcsHandler = candidate;
+ break;
+ }
+ }
+ if (vcsHandler == null) {
+ IssueOutput.error("Could not find a VCS handler").submit(context);
+ return SyncResult.FAILURE;
+ }
+
+ ListeningExecutorService executor = BlazeExecutor.getInstance().getExecutor();
+ ListenableFuture<BlazeRoots> blazeRootsFuture =
+ BlazeRoots.compute(project, workspaceRoot, context);
+ ListenableFuture<WorkingSet> workingSetFuture =
+ vcsHandler.getWorkingSet(project, context, workspaceRoot, executor);
+
+ BlazeRoots blazeRoots =
+ FutureUtil.waitForFuture(context, blazeRootsFuture)
+ .timed(Blaze.buildSystemName(project) + "Roots")
+ .withProgressMessage(
+ String.format("Running %s info...", Blaze.buildSystemName(project)))
+ .onError(String.format("Could not get %s roots", Blaze.buildSystemName(project)))
+ .run()
+ .result();
+ if (blazeRoots == null) {
+ return SyncResult.FAILURE;
+ }
+
+ WorkspacePathResolverAndProjectView workspacePathResolverAndProjectView =
+ computeWorkspacePathResolverAndProjectView(context, blazeRoots, vcsHandler, executor);
+ if (workspacePathResolverAndProjectView == null) {
+ return SyncResult.FAILURE;
+ }
+ WorkspacePathResolver workspacePathResolver =
+ workspacePathResolverAndProjectView.workspacePathResolver;
+ ProjectViewSet projectViewSet = workspacePathResolverAndProjectView.projectViewSet;
+
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ if (workspaceLanguageSettings == null) {
+ return SyncResult.FAILURE;
+ }
+
+ if (!ProjectViewVerifier.verifyProjectView(
+ context, workspaceRoot, projectViewSet, workspaceLanguageSettings)) {
+ return SyncResult.FAILURE;
+ }
+
+ final BlazeProjectData newBlazeProjectData;
+
+ WorkingSet workingSet =
+ FutureUtil.waitForFuture(context, workingSetFuture)
+ .timed("WorkingSet")
+ .withProgressMessage("Computing VCS working set...")
+ .onError("Could not compute working set")
+ .run()
+ .result();
+ if (context.isCancelled()) {
+ return SyncResult.CANCELLED;
+ }
+ if (context.hasErrors()) {
+ return SyncResult.FAILURE;
+ }
+
+ if (workingSet != null) {
+ printWorkingSet(context, workingSet);
+ }
+
+ BuildResult ideInfoResult = BuildResult.SUCCESS;
+ BuildResult ideResolveResult = BuildResult.SUCCESS;
+ if (syncParams.syncMode != SyncMode.RESTORE_EPHEMERAL_STATE || oldBlazeProjectData == null) {
+ SyncState.Builder syncStateBuilder = new SyncState.Builder();
+ SyncState previousSyncState =
+ oldBlazeProjectData != null ? oldBlazeProjectData.syncState : null;
+
+ boolean syncPluginRequiresBuild = false;
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ syncPluginRequiresBuild |= syncPlugin.requiresResolveIdeArtifacts();
+ }
+
+ List<TargetExpression> targets = Lists.newArrayList();
+ if (syncParams.addProjectViewTargets || oldBlazeProjectData == null) {
+ targets.addAll(projectViewSet.listItems(TargetSection.KEY));
+ }
+ if (syncParams.addWorkingSet && workingSet != null) {
+ targets.addAll(getWorkingSetTargets(workingSet));
+ }
+ targets.addAll(syncParams.targetExpressions);
+
+ boolean mergeWithOldState = !syncParams.addProjectViewTargets;
+ BlazeIdeInterface.IdeResult ideQueryResult =
+ getIdeQueryResult(
+ project,
+ context,
+ projectViewSet,
+ targets,
+ workspaceLanguageSettings,
+ new ArtifactLocationDecoder(blazeRoots, workspacePathResolver),
+ syncStateBuilder,
+ previousSyncState,
+ mergeWithOldState);
+ if (context.isCancelled()) {
+ return SyncResult.CANCELLED;
+ }
+ if (ideQueryResult.ruleMap == null || ideQueryResult.buildResult == BuildResult.FATAL_ERROR) {
+ context.setHasError();
+ return SyncResult.FAILURE;
+ }
+
+ RuleMap ruleMap = ideQueryResult.ruleMap;
+ ideInfoResult = ideQueryResult.buildResult;
+
+ ListenableFuture<ImmutableMultimap<Label, Label>> reverseDependenciesFuture =
+ BlazeExecutor.getInstance().submit(() -> ReverseDependencyMap.createRdepsMap(ruleMap));
+
+ boolean doResolve = syncPluginRequiresBuild || oldBlazeProjectData == null;
+ if (doResolve) {
+ ideResolveResult =
+ resolveIdeArtifacts(project, context, workspaceRoot, projectViewSet, targets);
+ if (ideResolveResult == BuildResult.FATAL_ERROR) {
+ context.setHasError();
+ return SyncResult.FAILURE;
+ }
+ }
+ if (context.isCancelled()) {
+ return SyncResult.CANCELLED;
+ }
+
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("UpdateSyncState"));
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ syncPlugin.updateSyncState(
+ project,
+ childContext,
+ workspaceRoot,
+ projectViewSet,
+ workspaceLanguageSettings,
+ blazeRoots,
+ workingSet,
+ workspacePathResolver,
+ ruleMap,
+ syncStateBuilder,
+ previousSyncState);
+ }
+ });
+
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ FutureUtil.waitForFuture(context, reverseDependenciesFuture)
+ .timed("ReverseDependencies")
+ .onError("Failed to compute reverse dependency map")
+ .run()
+ .result();
+ if (reverseDependencies == null) {
+ return SyncResult.FAILURE;
+ }
+
+ newBlazeProjectData =
+ new BlazeProjectData(
+ syncStartTime,
+ ruleMap,
+ blazeRoots,
+ workingSet,
+ workspacePathResolver,
+ workspaceLanguageSettings,
+ syncStateBuilder.build(),
+ reverseDependencies,
+ vcsHandler.getVcsName());
+ } else {
+ // Restore project based on old blaze project data
+ newBlazeProjectData = oldBlazeProjectData;
+ }
+
+ FileCaches.onSync(project, context, projectViewSet, newBlazeProjectData, syncParams.syncMode);
+ ListenableFuture<?> prefetch =
+ PrefetchService.getInstance().prefetchProjectFiles(project, newBlazeProjectData);
+ FutureUtil.waitForFuture(context, prefetch)
+ .withProgressMessage("Prefetching files...")
+ .timed("PrefetchFiles")
+ .onError("Prefetch failed")
+ .run();
+
+ boolean success =
+ updateProject(project, context, projectViewSet, oldBlazeProjectData, newBlazeProjectData);
+ if (!success) {
+ return SyncResult.FAILURE;
+ }
+
+ SyncResult syncResult = SyncResult.SUCCESS;
+
+ if (ideInfoResult == BuildResult.BUILD_ERROR || ideResolveResult == BuildResult.BUILD_ERROR) {
+ final String errorType =
+ ideInfoResult == BuildResult.BUILD_ERROR ? "BUILD file errors" : "compilation errors";
+
+ String message =
+ String.format(
+ "Sync was successful, but there were %s. "
+ + "The project may not be fully updated or resolve until fixed. "
+ + "If the errors are from your working set, please uncheck "
+ + "'Blaze > Expand Sync to Working Set' and try again.",
+ errorType);
+ context.output(PrintOutput.error(message));
+ IssueOutput.warn(message).submit(context);
+ syncResult = SyncResult.PARTIAL_SUCCESS;
+ }
+
+ onSyncComplete(project, context, projectViewSet, newBlazeProjectData, syncResult);
+ return syncResult;
+ }
+
+ static class WorkspacePathResolverAndProjectView {
+ final WorkspacePathResolver workspacePathResolver;
+ final ProjectViewSet projectViewSet;
+
+ public WorkspacePathResolverAndProjectView(
+ WorkspacePathResolver workspacePathResolver, ProjectViewSet projectViewSet) {
+ this.workspacePathResolver = workspacePathResolver;
+ this.projectViewSet = projectViewSet;
+ }
+ }
+
+ private WorkspacePathResolverAndProjectView computeWorkspacePathResolverAndProjectView(
+ BlazeContext context,
+ BlazeRoots blazeRoots,
+ BlazeVcsHandler vcsHandler,
+ ListeningExecutorService executor) {
+ context.output(new StatusOutput("Updating VCS..."));
+
+ for (int i = 0; i < 3; ++i) {
+ WorkspacePathResolver vcsWorkspacePathResolver = null;
+ BlazeVcsHandler.BlazeVcsSyncHandler vcsSyncHandler =
+ vcsHandler.createSyncHandler(project, workspaceRoot);
+ if (vcsSyncHandler != null) {
+ boolean ok =
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("UpdateVcs"));
+ return vcsSyncHandler.update(context, blazeRoots, executor);
+ });
+ if (!ok) {
+ return null;
+ }
+ vcsWorkspacePathResolver = vcsSyncHandler.getWorkspacePathResolver();
+ }
+
+ WorkspacePathResolver workspacePathResolver =
+ vcsWorkspacePathResolver != null
+ ? vcsWorkspacePathResolver
+ : new WorkspacePathResolverImpl(workspaceRoot, blazeRoots);
+
+ ProjectViewSet projectViewSet =
+ ProjectViewManager.getInstance(project).reloadProjectView(context, workspacePathResolver);
+ if (projectViewSet == null) {
+ return null;
+ }
+
+ if (vcsSyncHandler != null) {
+ BlazeVcsHandler.BlazeVcsSyncHandler.ValidationResult validationResult =
+ vcsSyncHandler.validateProjectView(context, projectViewSet);
+ switch (validationResult) {
+ case OK:
+ // Fall-through and return
+ break;
+ case Error:
+ return null;
+ case RestartSync:
+ continue;
+ default:
+ // Cannot happen
+ return null;
+ }
+ }
+
+ return new WorkspacePathResolverAndProjectView(workspacePathResolver, projectViewSet);
+ }
+ return null;
+ }
+
+ private void printWorkingSet(BlazeContext context, WorkingSet workingSet) {
+ List<String> messages = Lists.newArrayList();
+ messages.addAll(
+ workingSet
+ .addedFiles
+ .stream()
+ .map(file -> file.relativePath() + " (added)")
+ .collect(Collectors.toList()));
+ messages.addAll(
+ workingSet
+ .modifiedFiles
+ .stream()
+ .map(file -> file.relativePath() + " (modified)")
+ .collect(Collectors.toList()));
+ Collections.sort(messages);
+
+ if (messages.isEmpty()) {
+ context.output(PrintOutput.log("Your working set is empty"));
+ return;
+ }
+ int maxFiles = 20;
+ for (String message : Iterables.limit(messages, maxFiles)) {
+ context.output(PrintOutput.log(" " + message));
+ }
+ if (messages.size() > maxFiles) {
+ context.output(PrintOutput.log(String.format(" (and %d more)", messages.size() - maxFiles)));
+ }
+ }
+
+ private Collection<? extends TargetExpression> getWorkingSetTargets(WorkingSet workingSet) {
+ List<TargetExpression> result = Lists.newArrayList();
+ for (WorkspacePath workspacePath :
+ Iterables.concat(workingSet.addedFiles, workingSet.modifiedFiles)) {
+ File buildFile = workspaceRoot.fileForPath(workspacePath);
+ if (buildFile.getName().equals("BUILD")) {
+ result.add(
+ TargetExpression.allFromPackageNonRecursive(
+ workspaceRoot.workspacePathFor(buildFile.getParentFile())));
+ }
+ }
+ return result;
+ }
+
+ private BlazeIdeInterface.IdeResult getIdeQueryResult(
+ Project project,
+ BlazeContext parentContext,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState,
+ boolean mergeWithOldState) {
+
+ return Scope.push(
+ parentContext,
+ context -> {
+ context.push(new TimingScope("IdeQuery"));
+ context.output(new StatusOutput("Building IDE info files..."));
+ context.setPropagatesErrors(false);
+
+ BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
+ return blazeIdeInterface.updateRuleMap(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ targets,
+ workspaceLanguageSettings,
+ artifactLocationDecoder,
+ syncStateBuilder,
+ previousSyncState,
+ mergeWithOldState);
+ });
+ }
+
+ private static BuildResult resolveIdeArtifacts(
+ Project project,
+ BlazeContext parentContext,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targetExpressions) {
+ return Scope.push(
+ parentContext,
+ context -> {
+ context
+ .push(new LoggedTimingScope(project, Action.BLAZE_BUILD_DURING_SYNC))
+ .push(new TimingScope(Blaze.buildSystemName(project) + "Build"));
+ context.output(new StatusOutput("Building IDE resolve files..."));
+
+ // We don't want IDE resolve errors to fail the whole sync
+ context.setPropagatesErrors(false);
+
+ if (targetExpressions.isEmpty()) {
+ return BuildResult.SUCCESS;
+ }
+ BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
+ return blazeIdeInterface.resolveIdeArtifacts(
+ project, context, workspaceRoot, projectViewSet, targetExpressions);
+ });
+ }
+
+ private boolean updateProject(
+ Project project,
+ BlazeContext parentContext,
+ ProjectViewSet projectViewSet,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ BlazeProjectData newBlazeProjectData) {
+ return Scope.push(
+ parentContext,
+ context -> {
+ context
+ .push(new LoggedTimingScope(project, Action.SYNC_IMPORT_DATA_TIME))
+ .push(new TimingScope("UpdateProjectStructure"));
+ context.output(new StatusOutput("Committing project structure..."));
+
+ try {
+ AsyncUtil.executeProjectChangeAction(
+ () ->
+ ProjectRootManagerEx.getInstanceEx(this.project)
+ .mergeRootsChangesDuring(
+ () -> {
+ updateSdk(context, projectViewSet, newBlazeProjectData);
+ updateProjectStructure(
+ context,
+ importSettings,
+ projectViewSet,
+ newBlazeProjectData,
+ oldBlazeProjectData);
+ }));
+ } catch (Throwable t) {
+ IssueOutput.error("Internal error. Error: " + t).submit(context);
+ LOG.error(t);
+ return false;
+ }
+
+ BlazeProjectDataManagerImpl.getImpl(this.project)
+ .saveProject(importSettings, newBlazeProjectData);
+ return true;
+ });
+ }
+
+ private void updateSdk(
+ BlazeContext context, ProjectViewSet projectViewSet, BlazeProjectData newBlazeProjectData) {
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ syncPlugin.updateSdk(project, context, projectViewSet, newBlazeProjectData);
+ }
+ }
+
+ private void updateProjectStructure(
+ BlazeContext context,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData newBlazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData) {
+
+ ModuleEditorImpl moduleEditor =
+ ModuleEditorProvider.getInstance().getModuleEditor(project, importSettings);
+
+ ModuleType workspaceModuleType = null;
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ workspaceModuleType =
+ syncPlugin.getWorkspaceModuleType(
+ newBlazeProjectData.workspaceLanguageSettings.getWorkspaceType());
+ if (workspaceModuleType != null) {
+ break;
+ }
+ }
+ if (workspaceModuleType == null) {
+ workspaceModuleType = ModuleType.EMPTY;
+ IssueOutput.warn("Could not set module type for workspace module.").submit(context);
+ }
+
+ Module workspaceModule = moduleEditor.createModule(".workspace", workspaceModuleType);
+ ModifiableRootModel workspaceModifiableModel = moduleEditor.editModule(workspaceModule);
+
+ ContentEntryEditor.createContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ newBlazeProjectData,
+ workspaceModifiableModel);
+
+ for (BlazeSyncPlugin blazeSyncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ blazeSyncPlugin.updateProjectStructure(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ newBlazeProjectData,
+ oldBlazeProjectData,
+ moduleEditor,
+ workspaceModule,
+ workspaceModifiableModel);
+ }
+
+ createProjectDataDirectoryModule(
+ moduleEditor, new File(importSettings.getProjectDataDirectory()), workspaceModuleType);
+
+ moduleEditor.commitWithGc(context);
+ }
+
+ /**
+ * Creates a module that includes the user's data directory.
+ *
+ * <p>This is useful to be able to edit the project view without IntelliJ complaining it's outside
+ * the project.
+ */
+ private void createProjectDataDirectoryModule(
+ ModuleEditor moduleEditor, File projectDataDirectory, ModuleType moduleType) {
+ Module module = moduleEditor.createModule(".project-data-dir", moduleType);
+ ModifiableRootModel modifiableModel = moduleEditor.editModule(module);
+ ContentEntry rootContentEntry =
+ modifiableModel.addContentEntry(pathToUrl(projectDataDirectory));
+ rootContentEntry.addExcludeFolder(pathToUrl(new File(projectDataDirectory, ".idea")));
+ rootContentEntry.addExcludeFolder(
+ pathToUrl(BlazeDataStorage.getProjectDataDir(importSettings)));
+ }
+
+ private static String pathToUrl(File path) {
+ String filePath = FileUtil.toSystemIndependentName(path.getPath());
+ return VirtualFileManager.constructUrl(StandardFileSystems.FILE_PROTOCOL, filePath);
+ }
+
+ private static void onSyncStart(Project project) {
+ final SyncListener[] syncListeners = SyncListener.EP_NAME.getExtensions();
+ for (SyncListener syncListener : syncListeners) {
+ syncListener.onSyncStart(project);
+ }
+ }
+
+ private static void afterSync(Project project, SyncResult syncResult) {
+ final SyncListener[] syncListeners = SyncListener.EP_NAME.getExtensions();
+ for (SyncListener syncListener : syncListeners) {
+ syncListener.afterSync(project, syncResult);
+ }
+ }
+
+ private void onSyncComplete(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {
+ validate(project, context, blazeProjectData);
+
+ final SyncListener[] syncListeners = SyncListener.EP_NAME.getExtensions();
+ for (SyncListener syncListener : syncListeners) {
+ syncListener.onSyncComplete(
+ project, importSettings, projectViewSet, blazeProjectData, syncResult);
+ }
+ }
+
+ private static void validate(
+ Project project, BlazeContext context, BlazeProjectData blazeProjectData) {
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ syncPlugin.validate(project, context, blazeProjectData);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/SyncListener.java b/base/src/com/google/idea/blaze/base/sync/SyncListener.java
new file mode 100644
index 0000000..6445b14
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/SyncListener.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+
+/** Extension interface for listening to syncs. */
+public interface SyncListener {
+ ExtensionPointName<SyncListener> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.SyncListener");
+
+ /** Result of the sync operation */
+ enum SyncResult {
+ /** Full success */
+ SUCCESS,
+ /** The user has errors in their BUILD files or compilation errors */
+ PARTIAL_SUCCESS,
+ /** The user cancelled */
+ CANCELLED,
+ /** Failure -- sync could not complete */
+ FAILURE,
+ }
+
+ /** Called after open documents have been saved, prior to starting the blaze sync. */
+ void onSyncStart(Project project);
+
+ /** Called on successful (or partially successful) completion of a sync */
+ void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult);
+
+ /** Guaranteed to be called once per sync, regardless of whether it successfully completed */
+ void afterSync(Project project, SyncResult syncResult);
+
+ /** Convenience adapter class. */
+ abstract class Adapter implements SyncListener {
+
+ @Override
+ public void onSyncStart(Project project) {}
+
+ @Override
+ public void onSyncComplete(
+ Project project,
+ BlazeImportSettings importSettings,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ SyncResult syncResult) {}
+
+ @Override
+ public void afterSync(Project project, SyncResult syncResult) {}
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/actions/ExpandSyncToWorkingSetAction.java b/base/src/com/google/idea/blaze/base/sync/actions/ExpandSyncToWorkingSetAction.java
new file mode 100644
index 0000000..0509cca
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/actions/ExpandSyncToWorkingSetAction.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.actions;
+
+import com.google.idea.blaze.base.actions.BlazeToggleAction;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+
+/** Manages a tick box of whether to expand the sync targets to the working set. */
+public class ExpandSyncToWorkingSetAction extends BlazeToggleAction {
+ @Override
+ public boolean isSelected(AnActionEvent e) {
+ return BlazeUserSettings.getInstance().getExpandSyncToWorkingSet();
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean state) {
+ BlazeUserSettings.getInstance().setExpandSyncToWorkingSet(state);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/actions/FullSyncProjectAction.java b/base/src/com/google/idea/blaze/base/sync/actions/FullSyncProjectAction.java
new file mode 100644
index 0000000..2c1f625
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/actions/FullSyncProjectAction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.actions;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+
+/** Re-imports (syncs) an Android-Blaze project, without showing the "Import Project" wizard. */
+public class FullSyncProjectAction extends BlazeAction {
+
+ public FullSyncProjectAction() {
+ super("Non-Incrementally Sync Project with BUILD Files");
+ }
+
+ @Override
+ public void actionPerformed(final AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabled(false);
+ try {
+ BlazeSyncParams syncParams =
+ new BlazeSyncParams.Builder("Full Sync", SyncMode.FULL)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build();
+ BlazeSyncManager.getInstance(project).requestProjectSync(syncParams);
+ } finally {
+ presentation.setEnabled(true);
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/actions/IncrementalSyncProjectAction.java b/base/src/com/google/idea/blaze/base/sync/actions/IncrementalSyncProjectAction.java
new file mode 100644
index 0000000..134acfb
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/actions/IncrementalSyncProjectAction.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.actions;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.google.idea.blaze.base.sync.status.BlazeSyncStatus;
+import com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationDisplayType;
+import com.intellij.notification.NotificationGroup;
+import com.intellij.notification.NotificationType;
+import com.intellij.notification.Notifications;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import icons.BlazeIcons;
+import javax.swing.Icon;
+
+/** Re-imports (syncs) an Android-Blaze project, without showing the "Import Project" wizard. */
+public class IncrementalSyncProjectAction extends BlazeAction {
+
+ public IncrementalSyncProjectAction() {
+ super("Sync Project with BUILD Files");
+ }
+
+ @Override
+ public void actionPerformed(final AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ BlazeSyncManager.getInstance(project)
+ .requestProjectSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build());
+ updateIcon(e);
+ }
+ }
+
+ @Override
+ protected void doUpdate(AnActionEvent e) {
+ super.doUpdate(e);
+ updateIcon(e);
+ }
+
+ private static void updateIcon(AnActionEvent e) {
+ Project project = e.getProject();
+ Presentation presentation = e.getPresentation();
+ if (project == null) {
+ presentation.setIcon(BlazeIcons.Blaze);
+ presentation.setEnabled(true);
+ return;
+ }
+ BlazeSyncStatusImpl statusHelper = BlazeSyncStatusImpl.getImpl(project);
+ BlazeSyncStatus.SyncStatus status = statusHelper.getStatus();
+ presentation.setIcon(getIcon(status));
+ presentation.setEnabled(!statusHelper.syncInProgress.get());
+
+ if (status == BlazeSyncStatus.SyncStatus.DIRTY
+ && !BlazeUserSettings.getInstance().getSyncStatusPopupShown()) {
+ BlazeUserSettings.getInstance().setSyncStatusPopupShown(true);
+ showPopupNotification(project);
+ }
+ }
+
+ private static Icon getIcon(BlazeSyncStatus.SyncStatus status) {
+ switch (status) {
+ case FAILED:
+ return BlazeIcons.BlazeFailed;
+ case DIRTY:
+ return BlazeIcons.BlazeDirty;
+ case CLEAN:
+ return BlazeIcons.BlazeClean;
+ default:
+ return BlazeIcons.Blaze;
+ }
+ }
+
+ private static final NotificationGroup NOTIFICATION_GROUP =
+ new NotificationGroup("Changes since last blaze sync", NotificationDisplayType.BALLOON, true);
+
+ private static void showPopupNotification(Project project) {
+ String msg =
+ "Some relevant files (e.g. BUILD files, .blazeproject file) have changed "
+ + "since the last sync. Please press the 'Sync' button in the toolbar to "
+ + "re-sync your IntelliJ project.";
+ Notification notification =
+ new Notification(
+ NOTIFICATION_GROUP.getDisplayId(),
+ String.format("Changes since last %s sync", Blaze.buildSystemName(project)),
+ msg,
+ NotificationType.INFORMATION);
+ notification.setImportant(true);
+ Notifications.Bus.notify(notification, project);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/actions/PartialSyncAction.java b/base/src/com/google/idea/blaze/base/sync/actions/PartialSyncAction.java
new file mode 100644
index 0000000..2d6512b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/actions/PartialSyncAction.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.actions;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Allows a partial sync of the project depending on what's been selected. */
+public class PartialSyncAction extends BlazeAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ List<TargetExpression> targetExpressions = Lists.newArrayList();
+ getTargets(e, targetExpressions);
+
+ BlazeSyncParams syncParams =
+ new BlazeSyncParams.Builder("Partial Sync", BlazeSyncParams.SyncMode.INCREMENTAL)
+ .addTargetExpressions(targetExpressions)
+ .build();
+
+ BlazeSyncManager.getInstance(project).requestProjectSync(syncParams);
+ }
+ }
+
+ @Override
+ protected void doUpdate(AnActionEvent e) {
+ super.doUpdate(e);
+ List<TargetExpression> targets = Lists.newArrayList();
+ String objectName = getTargets(e, targets);
+
+ boolean enabled = objectName != null && !targets.isEmpty();
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabled(enabled);
+
+ if (enabled) {
+ presentation.setText(
+ String.format("Partially Sync %s with %s", objectName, buildSystemName(e.getProject())));
+ } else {
+ presentation.setText(String.format("Partial %s Sync", buildSystemName(e.getProject())));
+ }
+ }
+
+ private static String buildSystemName(@Nullable Project project) {
+ return Blaze.buildSystemName(project);
+ }
+
+ @Nullable
+ private String getTargets(AnActionEvent e, List<TargetExpression> targets) {
+ Project project = e.getProject();
+ VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
+ if (project == null || virtualFile == null || !virtualFile.isInLocalFileSystem()) {
+ return null;
+ }
+
+ String objectName = null;
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+
+ if (virtualFile.isDirectory()) {
+ if (workspaceRoot.isInWorkspace(virtualFile)) {
+ targets.add(
+ TargetExpression.allFromPackageRecursive(workspaceRoot.workspacePathFor(virtualFile)));
+ }
+ objectName = "Package";
+ } else {
+ targets.addAll(
+ SourceToRuleMap.getInstance(project)
+ .getTargetsForSourceFile(new File(virtualFile.getPath())));
+
+ // If empty, try to build parent package
+ if (targets.isEmpty()) {
+ VirtualFile parent = virtualFile.getParent();
+ if (parent.isDirectory()) {
+ if (workspaceRoot.isInWorkspace(parent)) {
+ targets.add(
+ TargetExpression.allFromPackageNonRecursive(
+ workspaceRoot.workspacePathFor(parent)));
+ }
+ }
+ }
+ objectName = "File";
+ }
+
+ return objectName;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/actions/ShowPerformanceWarningsToggleAction.java b/base/src/com/google/idea/blaze/base/sync/actions/ShowPerformanceWarningsToggleAction.java
new file mode 100644
index 0000000..d7c6e96
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/actions/ShowPerformanceWarningsToggleAction.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.actions;
+
+import com.google.idea.blaze.base.actions.BlazeToggleAction;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+
+/** Manages a tick box of whether to show performance warnings. */
+public class ShowPerformanceWarningsToggleAction extends BlazeToggleAction {
+ @Override
+ public boolean isSelected(AnActionEvent e) {
+ return BlazeUserSettings.getInstance().getShowPerformanceWarnings();
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean state) {
+ BlazeUserSettings.getInstance().setShowPerformanceWarnings(state);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/actions/SyncWorkingSetAction.java b/base/src/com/google/idea/blaze/base/sync/actions/SyncWorkingSetAction.java
new file mode 100644
index 0000000..530f819
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/actions/SyncWorkingSetAction.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.actions;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+
+/** Allows a partial sync of the project depending on what's been selected. */
+public class SyncWorkingSetAction extends BlazeAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ BlazeSyncParams syncParams =
+ new BlazeSyncParams.Builder("Sync Working Set", BlazeSyncParams.SyncMode.INCREMENTAL)
+ .addWorkingSet(true)
+ .build();
+
+ BlazeSyncManager.getInstance(project).requestProjectSync(syncParams);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/AspectStrategy.java b/base/src/com/google/idea/blaze/base/sync/aspects/AspectStrategy.java
new file mode 100644
index 0000000..7755abd
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/AspectStrategy.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
+import com.google.repackaged.protobuf.TextFormat;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/** Indirection for our various ways of calling the aspect. */
+public interface AspectStrategy {
+
+ String getName();
+
+ void modifyIdeInfoCommand(BlazeCommand.Builder blazeCommandBuilder);
+
+ void modifyIdeResolveCommand(BlazeCommand.Builder blazeCommandBuilder);
+
+ String getAspectOutputFileExtension();
+
+ AndroidStudioIdeInfo.RuleIdeInfo readAspectFile(File file) throws IOException;
+
+ AspectStrategy NATIVE_ASPECT =
+ new AspectStrategy() {
+ @Override
+ public String getName() {
+ return "NativeAspect";
+ }
+
+ @Override
+ public void modifyIdeInfoCommand(BlazeCommand.Builder blazeCommandBuilder) {
+ blazeCommandBuilder
+ .addBlazeFlags("--aspects=AndroidStudioInfoAspect")
+ .addBlazeFlags("--output_groups=ide-info");
+ }
+
+ @Override
+ public void modifyIdeResolveCommand(BlazeCommand.Builder blazeCommandBuilder) {
+ blazeCommandBuilder
+ .addBlazeFlags("--aspects=AndroidStudioInfoAspect")
+ .addBlazeFlags("--output_groups=ide-resolve");
+ }
+
+ @Override
+ public String getAspectOutputFileExtension() {
+ return ".aswb-build";
+ }
+
+ @Override
+ public AndroidStudioIdeInfo.RuleIdeInfo readAspectFile(File file) throws IOException {
+ try (InputStream inputStream = new FileInputStream(file)) {
+ return AndroidStudioIdeInfo.RuleIdeInfo.parseFrom(inputStream);
+ }
+ }
+ };
+
+ AspectStrategy SKYLARK_ASPECT =
+ new AspectStrategy() {
+ @Override
+ public String getName() {
+ return "SkylarkAspect";
+ }
+
+ private void addAspectFlag(BlazeCommand.Builder blazeCommandBuilder) {
+ blazeCommandBuilder.addBlazeFlags(
+ "--aspects=//third_party/bazel/src/test/java/com/google/devtools/build/lib/ideinfo/intellij_info.bzl%intellij_info_aspect");
+ }
+
+ @Override
+ public void modifyIdeInfoCommand(BlazeCommand.Builder blazeCommandBuilder) {
+ addAspectFlag(blazeCommandBuilder);
+ blazeCommandBuilder.addBlazeFlags("--output_groups=ide-info-text");
+ }
+
+ @Override
+ public void modifyIdeResolveCommand(BlazeCommand.Builder blazeCommandBuilder) {
+ addAspectFlag(blazeCommandBuilder);
+ blazeCommandBuilder.addBlazeFlags("--output_groups=ide-resolve");
+ }
+
+ @Override
+ public String getAspectOutputFileExtension() {
+ return ".intellij-build.txt";
+ }
+
+ @Override
+ public AndroidStudioIdeInfo.RuleIdeInfo readAspectFile(File file) throws IOException {
+ try (InputStream inputStream = new FileInputStream(file)) {
+ AndroidStudioIdeInfo.RuleIdeInfo.Builder builder =
+ AndroidStudioIdeInfo.RuleIdeInfo.newBuilder();
+ TextFormat.Parser parser =
+ TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build();
+ parser.merge(new InputStreamReader(inputStream), builder);
+ return builder.build();
+ }
+ }
+ };
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java b/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java
new file mode 100644
index 0000000..d46ac4a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Indirection between ide_build_info and aspect style IDE info. */
+public interface BlazeIdeInterface {
+
+ static BlazeIdeInterface getInstance() {
+ return ServiceManager.getService(BlazeIdeInterface.class);
+ }
+
+ /** The result of a blaze operation */
+ enum BuildResult {
+ SUCCESS, // Success
+ BUILD_ERROR, // Return code 1, a build error
+ FATAL_ERROR; // Some other failure
+
+ public static BuildResult fromExitCode(int exitCode) {
+ if (exitCode == 0) {
+ return SUCCESS;
+ } else if (exitCode == 1) {
+ return BUILD_ERROR;
+ }
+ return FATAL_ERROR;
+ }
+ }
+
+ /** The result of the ide operation */
+ class IdeResult {
+ @Nullable public final RuleMap ruleMap;
+ public final BuildResult buildResult;
+
+ public IdeResult(@Nullable RuleMap ruleMap, BuildResult buildResult) {
+ this.ruleMap = ruleMap;
+ this.buildResult = buildResult;
+ }
+ }
+
+ /**
+ * Queries blaze to update the rule map for the given targets.
+ *
+ * @param mergeWithOldState If true, we overlay the given targets to the current rule map.
+ * @return A tuple of the latest updated rule map and the result of the operation.
+ */
+ IdeResult updateRuleMap(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState,
+ boolean mergeWithOldState);
+
+ /**
+ * Attempts to resolve the requested ide artifacts.
+ *
+ * <p>Amounts to a build of the ide-resolve output group.
+ */
+ BuildResult resolveIdeArtifacts(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets);
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java b/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java
new file mode 100644
index 0000000..1b4be0e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.async.FutureUtil;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.async.process.ExternalTask;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.command.ExperimentalShowArtifactsLineProcessor;
+import com.google.idea.blaze.base.filecache.FileDiffer;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.prefetch.PrefetchService;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Result;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.ScopedFunction;
+import com.google.idea.blaze.base.scope.output.PerformanceWarning;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.Nullable;
+
+/** Implementation of BlazeIdeInterface based on aspects. */
+public class BlazeIdeInterfaceAspectsImpl implements BlazeIdeInterface {
+
+ private static final Logger LOG = Logger.getInstance(BlazeIdeInterfaceAspectsImpl.class);
+ private static final BoolExperiment USE_SKYLARK_ASPECT =
+ new BoolExperiment("use.skylark.aspect", false);
+ private static final BoolExperiment IDE_INFO_KEEP_GOING =
+ new BoolExperiment("ide.info.keep.going", true);
+
+ static class State implements Serializable {
+ private static final long serialVersionUID = 13L;
+ RuleMap ruleMap;
+ ImmutableMap<File, Long> fileState = null;
+ Map<File, Label> fileToLabel = Maps.newHashMap();
+ WorkspaceLanguageSettings workspaceLanguageSettings;
+ String aspectStrategyName;
+ }
+
+ @Override
+ public IdeResult updateRuleMap(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState,
+ boolean mergeWithOldState) {
+ State prevState = previousSyncState != null ? previousSyncState.get(State.class) : null;
+
+ // If the language filter has changed, redo everything from scratch
+ if (prevState != null
+ && !prevState.workspaceLanguageSettings.equals(workspaceLanguageSettings)) {
+ prevState = null;
+ }
+
+ // If the aspect strategy has changed, redo everything from scratch
+ final AspectStrategy aspectStrategy = getAspectStrategy(project);
+ if (prevState != null
+ && !Objects.equal(prevState.aspectStrategyName, aspectStrategy.getName())) {
+ prevState = null;
+ }
+
+ IdeInfoResult ideInfoResult =
+ getIdeInfo(project, context, workspaceRoot, projectViewSet, targets, aspectStrategy);
+ if (ideInfoResult.buildResult == BuildResult.FATAL_ERROR) {
+ return new IdeResult(prevState != null ? prevState.ruleMap : null, BuildResult.FATAL_ERROR);
+ }
+ // If there was a partial error, make a best-effort attempt to sync. Retain
+ // any old state that we have in an attempt not to lose too much code.
+ if (ideInfoResult.buildResult == BuildResult.BUILD_ERROR) {
+ mergeWithOldState = true;
+ }
+
+ List<File> fileList = ideInfoResult.files;
+ List<File> updatedFiles = Lists.newArrayList();
+ List<File> removedFiles = Lists.newArrayList();
+ ImmutableMap<File, Long> fileState =
+ FileDiffer.updateFiles(
+ prevState != null ? prevState.fileState : null, fileList, updatedFiles, removedFiles);
+ if (fileState == null) {
+ return new IdeResult(prevState != null ? prevState.ruleMap : null, BuildResult.FATAL_ERROR);
+ }
+
+ context.output(
+ PrintOutput.log(
+ String.format(
+ "Total rules: %d, new/changed: %d, removed: %d",
+ fileList.size(), updatedFiles.size(), removedFiles.size())));
+
+ ListenableFuture<?> prefetchFuture =
+ PrefetchService.getInstance().prefetchFiles(project, updatedFiles);
+ if (!FutureUtil.waitForFuture(context, prefetchFuture)
+ .timed("FetchAspectOutput")
+ .withProgressMessage("Reading IDE info result...")
+ .run()
+ .success()) {
+ return new IdeResult(prevState != null ? prevState.ruleMap : null, BuildResult.FATAL_ERROR);
+ }
+
+ State state =
+ updateState(
+ context,
+ prevState,
+ fileState,
+ workspaceLanguageSettings,
+ artifactLocationDecoder,
+ aspectStrategy,
+ updatedFiles,
+ removedFiles,
+ mergeWithOldState);
+ if (state == null) {
+ return new IdeResult(prevState != null ? prevState.ruleMap : null, BuildResult.FATAL_ERROR);
+ }
+ syncStateBuilder.put(State.class, state);
+ return new IdeResult(state.ruleMap, ideInfoResult.buildResult);
+ }
+
+ private static class IdeInfoResult {
+ private final List<File> files;
+ private final BuildResult buildResult;
+
+ IdeInfoResult(List<File> files, BuildResult buildResult) {
+ this.files = files;
+ this.buildResult = buildResult;
+ }
+ }
+
+ private static IdeInfoResult getIdeInfo(
+ Project project,
+ BlazeContext parentContext,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets,
+ AspectStrategy aspectStrategy) {
+ return Scope.push(
+ parentContext,
+ context -> {
+ context.push(
+ new TimingScope(String.format("Execute%sCommand", Blaze.buildSystemName(project))));
+
+ List<File> result = Lists.newArrayList();
+
+ BuildSystem buildSystem = Blaze.getBuildSystem(project);
+ BlazeCommand.Builder blazeCommandBuilder =
+ BlazeCommand.builder(buildSystem, BlazeCommandName.BUILD);
+ blazeCommandBuilder.addTargets(targets);
+ if (IDE_INFO_KEEP_GOING.getValue()) {
+ blazeCommandBuilder.addBlazeFlags(BlazeFlags.KEEP_GOING);
+ }
+ blazeCommandBuilder
+ .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS)
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet));
+
+ aspectStrategy.modifyIdeInfoCommand(blazeCommandBuilder);
+
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(blazeCommandBuilder.build())
+ .context(context)
+ .stderr(
+ LineProcessingOutputStream.of(
+ new ExperimentalShowArtifactsLineProcessor(
+ result, aspectStrategy.getAspectOutputFileExtension()),
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
+
+ BuildResult buildResult = BuildResult.fromExitCode(retVal);
+
+ // If the experiment is turned off, upgrade any build errors to fatal errors
+ if (buildResult == BuildResult.BUILD_ERROR && !IDE_INFO_KEEP_GOING.getValue()) {
+ buildResult = BuildResult.FATAL_ERROR;
+ }
+
+ return new IdeInfoResult(result, buildResult);
+ });
+ }
+
+ private static class RuleIdeInfoPair {
+ private final File file;
+ private final RuleIdeInfo ruleIdeInfo;
+
+ RuleIdeInfoPair(File file, RuleIdeInfo ruleIdeInfo) {
+ this.file = file;
+ this.ruleIdeInfo = ruleIdeInfo;
+ }
+ }
+
+ @Nullable
+ static State updateState(
+ BlazeContext parentContext,
+ @Nullable State prevState,
+ ImmutableMap<File, Long> fileState,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ AspectStrategy aspectStrategy,
+ List<File> newFiles,
+ List<File> removedFiles,
+ boolean mergeWithOldState) {
+ Result<State> result =
+ Scope.push(
+ parentContext,
+ (ScopedFunction<Result<State>>)
+ context -> {
+ context.push(new TimingScope("UpdateRuleMap"));
+
+ // If we're not removing we have to merge the old state
+ // into the new one or we'll miss file removes next time
+ ImmutableMap<File, Long> nextFileState = fileState;
+ if (mergeWithOldState && prevState != null) {
+ ImmutableMap.Builder<File, Long> fileStateBuilder =
+ ImmutableMap.<File, Long>builder().putAll(fileState);
+ for (Map.Entry<File, Long> entry : prevState.fileState.entrySet()) {
+ if (!fileState.containsKey(entry.getKey())) {
+ fileStateBuilder.put(entry);
+ }
+ }
+ nextFileState = fileStateBuilder.build();
+ }
+
+ State state = new State();
+ state.fileState = nextFileState;
+ state.workspaceLanguageSettings = workspaceLanguageSettings;
+ state.aspectStrategyName = aspectStrategy.getName();
+
+ Map<Label, RuleIdeInfo> ruleMap = Maps.newHashMap();
+ Map<Label, RuleIdeInfo> updatedRules = Maps.newHashMap();
+ if (prevState != null) {
+ ruleMap.putAll(prevState.ruleMap.map());
+ state.fileToLabel.putAll(prevState.fileToLabel);
+ }
+
+ // Update removed unless we're merging with the old state
+ if (!mergeWithOldState) {
+ for (File removedFile : removedFiles) {
+ Label label = state.fileToLabel.remove(removedFile);
+ if (label != null) {
+ ruleMap.remove(label);
+ }
+ }
+ }
+
+ AtomicLong totalSizeLoaded = new AtomicLong(0);
+
+ ListeningExecutorService executor = BlazeExecutor.getInstance().getExecutor();
+
+ // Read protos from any new files
+ List<ListenableFuture<RuleIdeInfoPair>> futures = Lists.newArrayList();
+ for (File file : newFiles) {
+ futures.add(
+ executor.submit(
+ () -> {
+ totalSizeLoaded.addAndGet(file.length());
+
+ AndroidStudioIdeInfo.RuleIdeInfo ruleProto =
+ aspectStrategy.readAspectFile(file);
+ RuleIdeInfo ruleIdeInfo =
+ IdeInfoFromProtobuf.makeRuleIdeInfo(
+ workspaceLanguageSettings,
+ artifactLocationDecoder,
+ ruleProto);
+ return new RuleIdeInfoPair(file, ruleIdeInfo);
+ }));
+ }
+
+ // Update state with result from proto files
+ int duplicateRuleLabels = 0;
+ try {
+ for (RuleIdeInfoPair ruleIdeInfoOrSdkInfo : Futures.allAsList(futures).get()) {
+ if (ruleIdeInfoOrSdkInfo.ruleIdeInfo != null) {
+ File file = ruleIdeInfoOrSdkInfo.file;
+ Label label = ruleIdeInfoOrSdkInfo.ruleIdeInfo.label;
+ RuleIdeInfo previousRule =
+ updatedRules.putIfAbsent(label, ruleIdeInfoOrSdkInfo.ruleIdeInfo);
+ if (previousRule == null) {
+ state.fileToLabel.put(file, label);
+ } else {
+ duplicateRuleLabels++;
+ }
+ }
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return Result.error(null);
+ } catch (ExecutionException e) {
+ return Result.error(e);
+ }
+ ruleMap.putAll(updatedRules);
+
+ context.output(
+ PrintOutput.log(
+ String.format(
+ "Loaded %d aspect files, total size %dkB",
+ newFiles.size(), totalSizeLoaded.get() / 1024)));
+ if (duplicateRuleLabels > 0) {
+ context.output(
+ new PerformanceWarning(
+ String.format(
+ "There were %d duplicate rules. "
+ + "You may be including multiple configurations in your build. "
+ + "Your IDE sync is slowed down by ~%d%%.",
+ duplicateRuleLabels,
+ (100 * duplicateRuleLabels / ruleMap.size()))));
+ }
+
+ state.ruleMap = new RuleMap(ImmutableMap.copyOf(ruleMap));
+ return Result.of(state);
+ });
+
+ if (result.error != null) {
+ LOG.error(result.error);
+ return null;
+ }
+ return result.result;
+ }
+
+ @Override
+ public BuildResult resolveIdeArtifacts(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets) {
+ AspectStrategy aspectStrategy = getAspectStrategy(project);
+
+ BlazeCommand.Builder blazeCommandBuilder =
+ BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD)
+ .addTargets(targets)
+ .addBlazeFlags()
+ .addBlazeFlags(BlazeFlags.KEEP_GOING)
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet));
+
+ aspectStrategy.modifyIdeResolveCommand(blazeCommandBuilder);
+
+ BlazeCommand blazeCommand = blazeCommandBuilder.build();
+
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(blazeCommand)
+ .context(context)
+ .stderr(
+ LineProcessingOutputStream.of(
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
+
+ return BuildResult.fromExitCode(retVal);
+ }
+
+ private AspectStrategy getAspectStrategy(Project project) {
+ BuildSystem buildSystem = Blaze.getBuildSystem(project);
+ if (buildSystem == BuildSystem.Bazel) {
+ return AspectStrategy.NATIVE_ASPECT;
+ }
+ return USE_SKYLARK_ASPECT.getValue()
+ ? AspectStrategy.SKYLARK_ASPECT
+ : AspectStrategy.NATIVE_ASPECT;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java b/base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java
new file mode 100644
index 0000000..4f1e622
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.CRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.JavaToolchainIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.ProtoLibraryLegacyInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
+import com.google.repackaged.protobuf.ProtocolStringList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Conversion functions from new aspect-style Bazel IDE info to ASWB internal classes. */
+public class IdeInfoFromProtobuf {
+
+ @Nullable
+ public static RuleIdeInfo makeRuleIdeInfo(
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ ArtifactLocationDecoder decoder,
+ AndroidStudioIdeInfo.RuleIdeInfo message) {
+ Kind kind = getKind(message);
+ if (kind == null) {
+ return null;
+ }
+ if (!workspaceLanguageSettings.isLanguageActive(kind.getLanguageClass())) {
+ return null;
+ }
+
+ Label label = new Label(message.getLabel());
+ ArtifactLocation buildFile = getBuildFile(decoder, message);
+
+ Collection<Label> dependencies = makeLabelListFromProtobuf(message.getDependenciesList());
+ Collection<Label> runtimeDeps = makeLabelListFromProtobuf(message.getRuntimeDepsList());
+ Collection<String> tags = ImmutableList.copyOf(message.getTagsList());
+
+ Collection<ArtifactLocation> sources = Lists.newArrayList();
+ CRuleIdeInfo cRuleIdeInfo = null;
+ if (message.hasCRuleIdeInfo()) {
+ cRuleIdeInfo = makeCRuleIdeInfo(decoder, message.getCRuleIdeInfo());
+ sources.addAll(cRuleIdeInfo.sources);
+ }
+ CToolchainIdeInfo cToolchainIdeInfo = null;
+ if (message.hasCToolchainIdeInfo()) {
+ cToolchainIdeInfo = makeCToolchainIdeInfo(message.getCToolchainIdeInfo());
+ }
+ JavaRuleIdeInfo javaRuleIdeInfo = null;
+ if (message.hasJavaRuleIdeInfo()) {
+ javaRuleIdeInfo = makeJavaRuleIdeInfo(decoder, message.getJavaRuleIdeInfo());
+ Collection<ArtifactLocation> javaSources =
+ makeArtifactLocationList(decoder, message.getJavaRuleIdeInfo().getSourcesList());
+ sources.addAll(javaSources);
+ }
+ AndroidRuleIdeInfo androidRuleIdeInfo = null;
+ if (message.hasAndroidRuleIdeInfo()) {
+ androidRuleIdeInfo = makeAndroidRuleIdeInfo(decoder, message.getAndroidRuleIdeInfo());
+ }
+ TestIdeInfo testIdeInfo = null;
+ if (message.hasTestInfo()) {
+ testIdeInfo = makeTestIdeInfo(message.getTestInfo());
+ }
+ ProtoLibraryLegacyInfo protoLibraryLegacyInfo = null;
+ if (message.hasProtoLibraryLegacyJavaIdeInfo()) {
+ protoLibraryLegacyInfo =
+ makeProtoLibraryLegacyInfo(decoder, message.getProtoLibraryLegacyJavaIdeInfo());
+ }
+ JavaToolchainIdeInfo javaToolchainIdeInfo = null;
+ if (message.hasJavaToolchainIdeInfo()) {
+ javaToolchainIdeInfo = makeJavaToolchainIdeInfo(message.getJavaToolchainIdeInfo());
+ }
+
+ return new RuleIdeInfo(
+ label,
+ kind,
+ buildFile,
+ dependencies,
+ runtimeDeps,
+ tags,
+ sources,
+ cRuleIdeInfo,
+ cToolchainIdeInfo,
+ javaRuleIdeInfo,
+ androidRuleIdeInfo,
+ testIdeInfo,
+ protoLibraryLegacyInfo,
+ javaToolchainIdeInfo);
+ }
+
+ @Nullable
+ private static ArtifactLocation getBuildFile(
+ ArtifactLocationDecoder decoder, AndroidStudioIdeInfo.RuleIdeInfo message) {
+ if (message.hasBuildFileArtifactLocation()) {
+ return makeArtifactLocation(decoder, message.getBuildFileArtifactLocation());
+ }
+ return null;
+ }
+
+ private static CRuleIdeInfo makeCRuleIdeInfo(
+ ArtifactLocationDecoder decoder, AndroidStudioIdeInfo.CRuleIdeInfo cRuleIdeInfo) {
+ List<ArtifactLocation> sources =
+ makeArtifactLocationList(decoder, cRuleIdeInfo.getSourceList());
+ List<ExecutionRootPath> transitiveIncludeDirectories =
+ makeExecutionRootPathList(cRuleIdeInfo.getTransitiveIncludeDirectoryList());
+ List<ExecutionRootPath> transitiveQuoteIncludeDirectories =
+ makeExecutionRootPathList(cRuleIdeInfo.getTransitiveQuoteIncludeDirectoryList());
+ List<ExecutionRootPath> transitiveSystemIncludeDirectories =
+ makeExecutionRootPathList(cRuleIdeInfo.getTransitiveSystemIncludeDirectoryList());
+
+ CRuleIdeInfo.Builder builder =
+ CRuleIdeInfo.builder()
+ .addSources(sources)
+ .addTransitiveIncludeDirectories(transitiveIncludeDirectories)
+ .addTransitiveQuoteIncludeDirectories(transitiveQuoteIncludeDirectories)
+ .addTransitiveDefines(cRuleIdeInfo.getTransitiveDefineList())
+ .addTransitiveSystemIncludeDirectories(transitiveSystemIncludeDirectories);
+
+ return builder.build();
+ }
+
+ private static List<ExecutionRootPath> makeExecutionRootPathList(Iterable<String> relativePaths) {
+ List<ExecutionRootPath> workspacePaths = Lists.newArrayList();
+ for (String relativePath : relativePaths) {
+ workspacePaths.add(new ExecutionRootPath(relativePath));
+ }
+ return workspacePaths;
+ }
+
+ private static CToolchainIdeInfo makeCToolchainIdeInfo(
+ AndroidStudioIdeInfo.CToolchainIdeInfo cToolchainIdeInfo) {
+ Collection<ExecutionRootPath> builtInIncludeDirectories =
+ makeExecutionRootPathList(cToolchainIdeInfo.getBuiltInIncludeDirectoryList());
+ ExecutionRootPath cppExecutable = new ExecutionRootPath(cToolchainIdeInfo.getCppExecutable());
+ ExecutionRootPath preprocessorExecutable =
+ new ExecutionRootPath(cToolchainIdeInfo.getPreprocessorExecutable());
+
+ UnfilteredCompilerOptions unfilteredCompilerOptions =
+ new UnfilteredCompilerOptions(cToolchainIdeInfo.getUnfilteredCompilerOptionList());
+
+ CToolchainIdeInfo.Builder builder =
+ CToolchainIdeInfo.builder()
+ .addBaseCompilerOptions(cToolchainIdeInfo.getBaseCompilerOptionList())
+ .addCCompilerOptions(cToolchainIdeInfo.getCOptionList())
+ .addCppCompilerOptions(cToolchainIdeInfo.getCppOptionList())
+ .addLinkOptions(cToolchainIdeInfo.getLinkOptionList())
+ .addBuiltInIncludeDirectories(builtInIncludeDirectories)
+ .setCppExecutable(cppExecutable)
+ .setPreprocessorExecutable(preprocessorExecutable)
+ .setTargetName(cToolchainIdeInfo.getTargetName())
+ .addUnfilteredCompilerOptions(unfilteredCompilerOptions.getToolchainFlags())
+ .addUnfilteredToolchainSystemIncludes(
+ unfilteredCompilerOptions.getToolchainSysIncludes());
+
+ return builder.build();
+ }
+
+ private static JavaRuleIdeInfo makeJavaRuleIdeInfo(
+ ArtifactLocationDecoder decoder, AndroidStudioIdeInfo.JavaRuleIdeInfo javaRuleIdeInfo) {
+ return new JavaRuleIdeInfo(
+ makeLibraryArtifactList(decoder, javaRuleIdeInfo.getJarsList()),
+ makeLibraryArtifactList(decoder, javaRuleIdeInfo.getGeneratedJarsList()),
+ javaRuleIdeInfo.hasFilteredGenJar()
+ ? makeLibraryArtifact(decoder, javaRuleIdeInfo.getFilteredGenJar())
+ : null,
+ javaRuleIdeInfo.hasPackageManifest()
+ ? makeArtifactLocation(decoder, javaRuleIdeInfo.getPackageManifest())
+ : null,
+ javaRuleIdeInfo.hasJdeps()
+ ? makeArtifactLocation(decoder, javaRuleIdeInfo.getJdeps())
+ : null);
+ }
+
+ private static AndroidRuleIdeInfo makeAndroidRuleIdeInfo(
+ ArtifactLocationDecoder decoder, AndroidStudioIdeInfo.AndroidRuleIdeInfo androidRuleIdeInfo) {
+ return new AndroidRuleIdeInfo(
+ makeArtifactLocationList(decoder, androidRuleIdeInfo.getResourcesList()),
+ androidRuleIdeInfo.getJavaPackage(),
+ androidRuleIdeInfo.getGenerateResourceClass(),
+ androidRuleIdeInfo.hasManifest()
+ ? makeArtifactLocation(decoder, androidRuleIdeInfo.getManifest())
+ : null,
+ androidRuleIdeInfo.hasIdlJar()
+ ? makeLibraryArtifact(decoder, androidRuleIdeInfo.getIdlJar())
+ : null,
+ androidRuleIdeInfo.hasResourceJar()
+ ? makeLibraryArtifact(decoder, androidRuleIdeInfo.getResourceJar())
+ : null,
+ androidRuleIdeInfo.getHasIdlSources(),
+ !Strings.isNullOrEmpty(androidRuleIdeInfo.getLegacyResources())
+ ? new Label(androidRuleIdeInfo.getLegacyResources())
+ : null);
+ }
+
+ private static TestIdeInfo makeTestIdeInfo(AndroidStudioIdeInfo.TestInfo testInfo) {
+ String size = testInfo.getSize();
+ TestIdeInfo.TestSize testSize = TestIdeInfo.DEFAULT_RULE_TEST_SIZE;
+ if (!Strings.isNullOrEmpty(size)) {
+ switch (size) {
+ case "small":
+ testSize = TestIdeInfo.TestSize.SMALL;
+ break;
+ case "medium":
+ testSize = TestIdeInfo.TestSize.MEDIUM;
+ break;
+ case "large":
+ testSize = TestIdeInfo.TestSize.LARGE;
+ break;
+ case "enormous":
+ testSize = TestIdeInfo.TestSize.ENORMOUS;
+ break;
+ default:
+ break;
+ }
+ }
+ return new TestIdeInfo(testSize);
+ }
+
+ private static ProtoLibraryLegacyInfo makeProtoLibraryLegacyInfo(
+ ArtifactLocationDecoder decoder,
+ AndroidStudioIdeInfo.ProtoLibraryLegacyJavaIdeInfo protoLibraryLegacyJavaIdeInfo) {
+ final ProtoLibraryLegacyInfo.ApiFlavor apiFlavor;
+ if (protoLibraryLegacyJavaIdeInfo.getApiVersion() == 1) {
+ apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1;
+ } else {
+ switch (protoLibraryLegacyJavaIdeInfo.getApiFlavor()) {
+ case MUTABLE:
+ apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.MUTABLE;
+ break;
+ case IMMUTABLE:
+ apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE;
+ break;
+ case BOTH:
+ apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.BOTH;
+ break;
+ default:
+ apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.NONE;
+ break;
+ }
+ }
+ return new ProtoLibraryLegacyInfo(
+ apiFlavor,
+ makeLibraryArtifactList(decoder, protoLibraryLegacyJavaIdeInfo.getJars1List()),
+ makeLibraryArtifactList(decoder, protoLibraryLegacyJavaIdeInfo.getJarsMutableList()),
+ makeLibraryArtifactList(decoder, protoLibraryLegacyJavaIdeInfo.getJarsImmutableList()));
+ }
+
+ private static JavaToolchainIdeInfo makeJavaToolchainIdeInfo(
+ AndroidStudioIdeInfo.JavaToolchainIdeInfo javaToolchainIdeInfo) {
+ return new JavaToolchainIdeInfo(
+ javaToolchainIdeInfo.getSourceVersion(), javaToolchainIdeInfo.getTargetVersion());
+ }
+
+ private static Collection<LibraryArtifact> makeLibraryArtifactList(
+ ArtifactLocationDecoder decoder, List<AndroidStudioIdeInfo.LibraryArtifact> jarsList) {
+ ImmutableList.Builder<LibraryArtifact> builder = ImmutableList.builder();
+ for (AndroidStudioIdeInfo.LibraryArtifact libraryArtifact : jarsList) {
+ LibraryArtifact lib = makeLibraryArtifact(decoder, libraryArtifact);
+ if (lib != null) {
+ builder.add(lib);
+ }
+ }
+ return builder.build();
+ }
+
+ @Nullable
+ private static LibraryArtifact makeLibraryArtifact(
+ ArtifactLocationDecoder decoder, AndroidStudioIdeInfo.LibraryArtifact libraryArtifact) {
+ ArtifactLocation classJar =
+ libraryArtifact.hasJar() ? makeArtifactLocation(decoder, libraryArtifact.getJar()) : null;
+ ArtifactLocation iJar =
+ libraryArtifact.hasInterfaceJar()
+ ? makeArtifactLocation(decoder, libraryArtifact.getInterfaceJar())
+ : null;
+ ArtifactLocation sourceJar =
+ libraryArtifact.hasSourceJar()
+ ? makeArtifactLocation(decoder, libraryArtifact.getSourceJar())
+ : null;
+ if (iJar == null && classJar == null) {
+ // Failed to find ArtifactLocation file --
+ // presumably because it was removed from file system since blaze build
+ return null;
+ }
+ return new LibraryArtifact(iJar, classJar, sourceJar);
+ }
+
+ private static List<ArtifactLocation> makeArtifactLocationList(
+ ArtifactLocationDecoder decoder, List<AndroidStudioIdeInfo.ArtifactLocation> sourcesList) {
+ ImmutableList.Builder<ArtifactLocation> builder = ImmutableList.builder();
+ for (AndroidStudioIdeInfo.ArtifactLocation pbArtifactLocation : sourcesList) {
+ ArtifactLocation loc = makeArtifactLocation(decoder, pbArtifactLocation);
+ if (loc != null) {
+ builder.add(loc);
+ }
+ }
+ return builder.build();
+ }
+
+ @Nullable
+ private static ArtifactLocation makeArtifactLocation(
+ ArtifactLocationDecoder decoder, AndroidStudioIdeInfo.ArtifactLocation pbArtifactLocation) {
+ if (pbArtifactLocation == null) {
+ return null;
+ }
+ return decoder.decode(pbArtifactLocation);
+ }
+
+ private static Collection<Label> makeLabelListFromProtobuf(ProtocolStringList dependenciesList) {
+ ImmutableList.Builder<Label> dependenciesBuilder = ImmutableList.builder();
+ for (String dependencyLabel : dependenciesList) {
+ dependenciesBuilder.add(new Label(dependencyLabel));
+ }
+ return dependenciesBuilder.build();
+ }
+
+ @Nullable
+ private static Kind getKind(AndroidStudioIdeInfo.RuleIdeInfo rule) {
+ String kindString = rule.getKindString();
+ if (!Strings.isNullOrEmpty(kindString)) {
+ return Kind.fromString(kindString);
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java b/base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java
new file mode 100644
index 0000000..8509647
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import java.util.List;
+
+/**
+ * unfilteredCompilerOptions is a grab bag of options passed to the compiler. Do minimal parsing to
+ * extract what we need.
+ */
+final class UnfilteredCompilerOptions {
+ private enum NextOption {
+ ISYSTEM,
+ FLAG
+ }
+
+ private final List<ExecutionRootPath> toolchainSysIncludes;
+ private final List<String> toolchainFlags;
+
+ public UnfilteredCompilerOptions(Iterable<String> unfilteredOptions) {
+ List<String> toolchainSystemIncludePaths = Lists.newArrayList();
+ toolchainFlags = Lists.newArrayList();
+ splitUnfilteredCompilerOptions(unfilteredOptions, toolchainSystemIncludePaths, toolchainFlags);
+
+ toolchainSysIncludes = Lists.newArrayList();
+ for (String systemInclude : toolchainSystemIncludePaths) {
+ toolchainSysIncludes.add(new ExecutionRootPath(systemInclude));
+ }
+ }
+
+ public List<String> getToolchainFlags() {
+ return toolchainFlags;
+ }
+
+ public List<ExecutionRootPath> getToolchainSysIncludes() {
+ return toolchainSysIncludes;
+ }
+
+ @VisibleForTesting
+ static void splitUnfilteredCompilerOptions(
+ Iterable<String> unfilteredOptions,
+ List<String> toolchainSysIncludes,
+ List<String> toolchainFlags) {
+ NextOption nextOption = NextOption.FLAG;
+ for (String unfilteredOption : unfilteredOptions) {
+ // We are looking for either the flag pair
+ // "-isystem /path/to/dir" or the flag "-isystem/path/to/dir"
+ //
+ // blaze emits isystem flags in both formats.
+ // The latter isn't ideal but apparently it is accepted by GCC and will be emitted by
+ // blaze under certain circumstances.
+ if (nextOption == NextOption.ISYSTEM) {
+ toolchainSysIncludes.add(unfilteredOption);
+ nextOption = NextOption.FLAG;
+ } else {
+ if (unfilteredOption.equals("-isystem")) {
+ nextOption = NextOption.ISYSTEM;
+ } else if (unfilteredOption.startsWith("-isystem")) {
+ String iSystemIncludePath = unfilteredOption.substring("-isystem".length());
+ toolchainSysIncludes.add(iSystemIncludePath);
+ } else {
+ toolchainFlags.add(unfilteredOption);
+ nextOption = NextOption.FLAG;
+ }
+ }
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/data/BlazeDataStorage.java b/base/src/com/google/idea/blaze/base/sync/data/BlazeDataStorage.java
new file mode 100644
index 0000000..2a9fca8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/data/BlazeDataStorage.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.data;
+
+import com.google.common.base.Strings;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+
+/** Defines where we store our blaze project data. */
+public class BlazeDataStorage {
+ private static final String DATA_SUBDIRECTORY = ".blaze";
+
+ public static File getProjectDataDir(BlazeImportSettings importSettings) {
+ return new File(importSettings.getProjectDataDirectory(), DATA_SUBDIRECTORY);
+ }
+
+ public static File getProjectCacheDir(Project project, BlazeImportSettings importSettings) {
+ String locationHash = importSettings.getLocationHash();
+
+ // Legacy support: The location hash used to be just the project hash
+ if (Strings.isNullOrEmpty(locationHash)) {
+ locationHash = project.getLocationHash();
+ }
+
+ return new File(getProjectConfigurationDir(), locationHash);
+ }
+
+ private static File getProjectConfigurationDir() {
+ return new File(PathManager.getSystemPath(), "blaze/projects").getAbsoluteFile();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManager.java b/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManager.java
new file mode 100644
index 0000000..f92cf85
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManager.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.data;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Stores a cache of blaze project data. */
+public interface BlazeProjectDataManager {
+ static BlazeProjectDataManager getInstance(Project project) {
+ return ServiceManager.getService(project, BlazeProjectDataManager.class);
+ }
+
+ @Nullable
+ BlazeProjectData getBlazeProjectData();
+
+ BlazeSyncPlugin.ModuleEditor editModules();
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java b/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java
new file mode 100644
index 0000000..821109d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.data;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
+import com.google.idea.blaze.base.util.SerializationUtil;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Stores a cache of blaze project data and issues any side effects when that data is updated. */
+public class BlazeProjectDataManagerImpl implements BlazeProjectDataManager {
+
+ private static final Logger LOG = Logger.getInstance(BlazeProjectDataManagerImpl.class.getName());
+
+ private final Project project;
+
+ @Nullable private volatile BlazeProjectData blazeProjectData;
+
+ private final Object saveLock = new Object();
+
+ public static BlazeProjectDataManagerImpl getImpl(Project project) {
+ return (BlazeProjectDataManagerImpl) BlazeProjectDataManager.getInstance(project);
+ }
+
+ public BlazeProjectDataManagerImpl(Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ public BlazeProjectData loadProjectRoot(
+ BlazeContext context, BlazeImportSettings importSettings) {
+ BlazeProjectData projectData = blazeProjectData;
+ if (projectData != null) {
+ return projectData;
+ }
+ synchronized (this) {
+ projectData = blazeProjectData;
+ return projectData != null ? projectData : loadProject(context, importSettings);
+ }
+ }
+
+ @Override
+ @Nullable
+ public BlazeProjectData getBlazeProjectData() {
+ return blazeProjectData;
+ }
+
+ @Override
+ public BlazeSyncPlugin.ModuleEditor editModules() {
+ return ModuleEditorProvider.getInstance()
+ .getModuleEditor(
+ project, BlazeImportSettingsManager.getInstance(project).getImportSettings());
+ }
+
+ @Nullable
+ private synchronized BlazeProjectData loadProject(
+ BlazeContext context, BlazeImportSettings importSettings) {
+ BlazeProjectData blazeProjectData = null;
+ try {
+ File file = getCacheFile(project, importSettings);
+
+ List<ClassLoader> classLoaders = Lists.newArrayList();
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ classLoaders.add(syncPlugin.getClass().getClassLoader());
+ }
+ classLoaders.add(getClass().getClassLoader());
+ classLoaders.add(Thread.currentThread().getContextClassLoader());
+
+ blazeProjectData = (BlazeProjectData) SerializationUtil.loadFromDisk(file, classLoaders);
+ } catch (IOException e) {
+ String buildSystemName = importSettings.getBuildSystem().getLowerCaseName();
+ context.output(
+ new StatusOutput(
+ String.format("Stale %s project cache, sync will be needed", buildSystemName)));
+ LOG.info(e);
+ }
+
+ this.blazeProjectData = blazeProjectData;
+ return blazeProjectData;
+ }
+
+ public void saveProject(
+ final BlazeImportSettings importSettings, final BlazeProjectData blazeProjectData) {
+ this.blazeProjectData = blazeProjectData;
+
+ // Can only run one save operation per project at a time
+ synchronized (saveLock) {
+ BlazeExecutor.submitTask(
+ project,
+ "Saving sync data...",
+ (ProgressIndicator indicator) -> {
+ try {
+ File file = getCacheFile(project, importSettings);
+ SerializationUtil.saveToDisk(file, blazeProjectData);
+ } catch (IOException e) {
+ LOG.error(
+ "Could not save cache data file to disk. Please resync project. Error: "
+ + e.getMessage());
+ }
+ });
+ }
+ }
+
+ private static File getCacheFile(Project project, BlazeImportSettings importSettings) {
+ return new File(BlazeDataStorage.getProjectCacheDir(project, importSettings), "cache.dat");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java
new file mode 100644
index 0000000..e3e4357
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectstructure;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.util.io.URLUtil;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+/** Modifies content entries based on project data. */
+public class ContentEntryEditor {
+
+ public static void createContentEntries(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ ModifiableRootModel modifiableRootModel) {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
+ .add(projectViewSet)
+ .build();
+ Collection<WorkspacePath> rootDirectories = importRoots.rootDirectories();
+ Collection<WorkspacePath> excludeDirectories = importRoots.excludeDirectories();
+ Multimap<WorkspacePath, WorkspacePath> excludesByRootDirectory =
+ sortExcludesByRootDirectory(rootDirectories, excludeDirectories);
+
+ List<ContentEntry> contentEntries = Lists.newArrayList();
+ for (WorkspacePath rootDirectory : rootDirectories) {
+ File root = workspaceRoot.fileForPath(rootDirectory);
+ ContentEntry contentEntry = modifiableRootModel.addContentEntry(pathToUrl(root.getPath()));
+ contentEntries.add(contentEntry);
+
+ for (WorkspacePath exclude : excludesByRootDirectory.get(rootDirectory)) {
+ File excludeFolder = workspaceRoot.fileForPath(exclude);
+ contentEntry.addExcludeFolder(pathToIdeaUrl(excludeFolder));
+ }
+ }
+
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ syncPlugin.updateContentEntries(
+ project, context, workspaceRoot, projectViewSet, blazeProjectData, contentEntries);
+ }
+ }
+
+ private static Multimap<WorkspacePath, WorkspacePath> sortExcludesByRootDirectory(
+ Collection<WorkspacePath> rootDirectories, Collection<WorkspacePath> excludedDirectories) {
+
+ Multimap<WorkspacePath, WorkspacePath> result = ArrayListMultimap.create();
+ for (WorkspacePath exclude : excludedDirectories) {
+ WorkspacePath foundWorkspacePath =
+ rootDirectories
+ .stream()
+ .filter(rootDirectory -> isUnderRootDirectory(rootDirectory, exclude.relativePath()))
+ .findFirst()
+ .orElse(null);
+ if (foundWorkspacePath != null) {
+ result.put(foundWorkspacePath, exclude);
+ }
+ }
+ return result;
+ }
+
+ private static boolean isUnderRootDirectory(WorkspacePath rootDirectory, String relativePath) {
+ if (rootDirectory.isWorkspaceRoot()) {
+ return true;
+ }
+ String rootDirectoryString = rootDirectory.toString();
+ return relativePath.startsWith(rootDirectoryString)
+ && (relativePath.length() == rootDirectoryString.length()
+ || (relativePath.charAt(rootDirectoryString.length()) == '/'));
+ }
+
+ @NotNull
+ private static String pathToUrl(@NotNull String filePath) {
+ filePath = FileUtil.toSystemIndependentName(filePath);
+ if (filePath.endsWith(".srcjar") || filePath.endsWith(".jar")) {
+ return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR + filePath + URLUtil.JAR_SEPARATOR;
+ } else if (filePath.contains("src.jar!")) {
+ return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR + filePath;
+ } else {
+ return VfsUtilCore.pathToUrl(filePath);
+ }
+ }
+
+ @NotNull
+ private static String pathToIdeaUrl(@NotNull File path) {
+ return pathToUrl(toSystemIndependentName(path.getPath()));
+ }
+
+ @NotNull
+ private static String toSystemIndependentName(@NonNls @NotNull String aFileName) {
+ return FileUtilRt.toSystemIndependentName(aFileName);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorImpl.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorImpl.java
new file mode 100644
index 0000000..2f05f68
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorImpl.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectstructure;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.intellij.ide.highlighter.ModuleFileType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.ModifiableModuleModel;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.CompilerModuleExtension;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/** Module editor implementation. */
+public class ModuleEditorImpl implements BlazeSyncPlugin.ModuleEditor {
+ private static final Logger LOG = Logger.getInstance(ModuleEditorImpl.class.getName());
+ private static final String EXTERNAL_SYSTEM_ID_KEY = "external.system.id";
+ private static final String EXTERNAL_SYSTEM_ID_VALUE = "Blaze";
+
+ private final Project project;
+ private final ModifiableModuleModel moduleModel;
+ private final File imlDirectory;
+ private final Set<String> moduleNames = Sets.newHashSet();
+ @VisibleForTesting public Collection<ModifiableRootModel> modifiableModels = Lists.newArrayList();
+
+ public ModuleEditorImpl(Project project, BlazeImportSettings importSettings) {
+ this.project = project;
+ this.moduleModel = ModuleManager.getInstance(project).getModifiableModel();
+
+ this.imlDirectory = getImlDirectory(importSettings);
+ if (!FileAttributeProvider.getInstance().exists(imlDirectory)) {
+ if (!imlDirectory.mkdirs()) {
+ LOG.error("Could not make directory: " + imlDirectory.getPath());
+ }
+ }
+ }
+
+ @Override
+ public boolean registerModule(String moduleName) {
+ boolean hasModule = moduleModel.findModuleByName(moduleName) != null;
+ if (hasModule) {
+ moduleNames.add(moduleName);
+ }
+ return hasModule;
+ }
+
+ @Override
+ public Module createModule(String moduleName, ModuleType moduleType) {
+ Module module = moduleModel.findModuleByName(moduleName);
+ if (module == null) {
+ File imlFile = new File(imlDirectory, moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION);
+ removeImlFile(imlFile);
+ module = moduleModel.newModule(imlFile.getPath(), moduleType.getId());
+ module.setOption(EXTERNAL_SYSTEM_ID_KEY, EXTERNAL_SYSTEM_ID_VALUE);
+ }
+ module.setOption(Module.ELEMENT_TYPE, moduleType.getId());
+ moduleNames.add(moduleName);
+ return module;
+ }
+
+ @Override
+ public ModifiableRootModel editModule(Module module) {
+ ModifiableRootModel modifiableModel =
+ ModuleRootManager.getInstance(module).getModifiableModel();
+ modifiableModels.add(modifiableModel);
+
+ modifiableModel.clear();
+ modifiableModel.inheritSdk();
+ CompilerModuleExtension compilerSettings =
+ modifiableModel.getModuleExtension(CompilerModuleExtension.class);
+ if (compilerSettings != null) {
+ compilerSettings.inheritCompilerOutputPath(false);
+ }
+
+ return modifiableModel;
+ }
+
+ @Override
+ @Nullable
+ public Module findModule(String moduleName) {
+ return moduleModel.findModuleByName(moduleName);
+ }
+
+ public void commitWithGc(BlazeContext context) {
+ List<Module> orphanModules = Lists.newArrayList();
+ for (Module module : ModuleManager.getInstance(project).getModules()) {
+ if (!moduleNames.contains(module.getName())) {
+ orphanModules.add(module);
+ }
+ }
+ if (orphanModules.size() > 0) {
+ context.output(
+ PrintOutput.log(String.format("Removing %d dead modules", orphanModules.size())));
+ for (Module module : orphanModules) {
+ if (module.isDisposed()) {
+ continue;
+ }
+ moduleModel.disposeModule(module);
+ File imlFile = new File(module.getModuleFilePath());
+ removeImlFile(imlFile);
+ }
+ }
+
+ context.output(
+ PrintOutput.log(String.format("Workspace has %s modules", modifiableModels.size())));
+
+ commit();
+ }
+
+ @Override
+ public void commit() {
+ ModifiableModelCommitter.multiCommit(modifiableModels, moduleModel);
+ }
+
+ private File getImlDirectory(BlazeImportSettings importSettings) {
+ return new File(BlazeDataStorage.getProjectDataDir(importSettings), "modules");
+ }
+
+ // Delete using the virtual file to ensure that IntelliJ properly updates its index.
+ // Otherwise, it is possible for IntelliJ to read the
+ // old IML file from its index and behave unpredictably
+ // (like failing to save the new IML files to disk).
+ private static void removeImlFile(final File imlFile) {
+ final VirtualFile imlVirtualFile = VfsUtil.findFileByIoFile(imlFile, true);
+ if (imlVirtualFile != null && imlVirtualFile.exists()) {
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ imlVirtualFile.delete(this);
+ } catch (IOException e) {
+ LOG.warn(
+ String.format(
+ "Could not delete file: %s, will try to continue anyway.",
+ imlVirtualFile.getPath()),
+ e);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProvider.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProvider.java
new file mode 100644
index 0000000..6280c37
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectstructure;
+
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+
+/**
+ * Provides a ModuleEditor. This indirection is required to avoid committing modules during
+ * integration tests of the sync process, as this is not allowed by LightPlatformTestCase.
+ */
+public interface ModuleEditorProvider {
+
+ static ModuleEditorProvider getInstance() {
+ return ServiceManager.getService(ModuleEditorProvider.class);
+ }
+
+ ModuleEditorImpl getModuleEditor(Project project, BlazeImportSettings importSettings);
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProviderImpl.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProviderImpl.java
new file mode 100644
index 0000000..8cfa34b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProviderImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectstructure;
+
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.intellij.openapi.project.Project;
+
+/**
+ * Provides a ModuleEditor. This indirection is required to avoid committing modules during
+ * integration tests of the sync process, as this is not allowed by LightPlatformTestCase.
+ */
+public class ModuleEditorProviderImpl implements ModuleEditorProvider {
+
+ @Override
+ public ModuleEditorImpl getModuleEditor(Project project, BlazeImportSettings importSettings) {
+ return new ModuleEditorImpl(project, importSettings);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java b/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java
new file mode 100644
index 0000000..5a73ef4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectview;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.util.io.FileUtil;
+import java.util.Collection;
+import java.util.Set;
+
+/** The roots to import. Derived from project view. */
+public final class ImportRoots {
+ /** Builder for import roots */
+ public static class Builder {
+ private final ImmutableCollection.Builder<WorkspacePath> rootDirectoriesBuilder =
+ ImmutableList.builder();
+ private final ImmutableSet.Builder<WorkspacePath> excludeDirectoriesBuilder =
+ ImmutableSet.builder();
+
+ private final WorkspaceRoot workspaceRoot;
+ private final BuildSystem buildSystem;
+
+ private Builder(WorkspaceRoot workspaceRoot, BuildSystem buildSystem) {
+ this.workspaceRoot = workspaceRoot;
+ this.buildSystem = buildSystem;
+ }
+
+ public Builder add(ProjectViewSet projectViewSet) {
+ for (DirectoryEntry entry : projectViewSet.listItems(DirectorySection.KEY)) {
+ add(entry);
+ }
+ return this;
+ }
+
+ @VisibleForTesting
+ public Builder add(DirectoryEntry entry) {
+ if (entry.included) {
+ rootDirectoriesBuilder.add(entry.directory);
+ } else {
+ excludeDirectoriesBuilder.add(entry.directory);
+ }
+ return this;
+ }
+
+ public ImportRoots build() {
+ ImmutableCollection<WorkspacePath> rootDirectories = rootDirectoriesBuilder.build();
+
+ // Remove any duplicates and any overlapping directories
+ ImmutableSet.Builder<WorkspacePath> minimalRootDirectories = ImmutableSet.builder();
+ for (WorkspacePath directory : rootDirectories) {
+ boolean ok = true;
+ for (WorkspacePath otherDirectory : rootDirectories) {
+ if (directory == otherDirectory) {
+ continue;
+ }
+ ok = ok && !isAncestor(otherDirectory.relativePath(), directory.relativePath());
+ }
+ if (ok) {
+ minimalRootDirectories.add(directory);
+ }
+ }
+
+ // for bazel projects, if we're including the workspace root,
+ // we force-exclude the bazel artifact directories
+ // (e.g. bazel-bin, bazel-genfiles).
+ if (buildSystem == BuildSystem.Bazel && hasWorkspaceRoot(rootDirectories)) {
+ excludeBuildSystemArtifacts();
+ }
+ return new ImportRoots(minimalRootDirectories.build(), excludeDirectoriesBuilder.build());
+ }
+
+ private void excludeBuildSystemArtifacts() {
+ for (String dir :
+ BuildSystemProvider.getBuildSystemProvider(buildSystem)
+ .buildArtifactDirectories(workspaceRoot)) {
+ excludeDirectoriesBuilder.add(new WorkspacePath(dir));
+ }
+ }
+
+ private static boolean hasWorkspaceRoot(ImmutableCollection<WorkspacePath> rootDirectories) {
+ return rootDirectories.stream().anyMatch(WorkspacePath::isWorkspaceRoot);
+ }
+ }
+
+ private final ImmutableCollection<WorkspacePath> rootDirectories;
+ private final ImmutableSet<WorkspacePath> excludeDirectories;
+
+ public static Builder builder(WorkspaceRoot workspaceRoot, BuildSystem buildSystem) {
+ return new Builder(workspaceRoot, buildSystem);
+ }
+
+ private ImportRoots(
+ ImmutableCollection<WorkspacePath> rootDirectories,
+ ImmutableSet<WorkspacePath> excludeDirectories) {
+ this.rootDirectories = rootDirectories;
+ this.excludeDirectories = excludeDirectories;
+ }
+
+ public Collection<WorkspacePath> rootDirectories() {
+ return rootDirectories;
+ }
+
+ public Set<WorkspacePath> excludeDirectories() {
+ return excludeDirectories;
+ }
+
+ /** Returns true if this rule should be imported as source. */
+ public boolean importAsSource(Label label) {
+ return containsLabel(label);
+ }
+
+ private boolean containsLabel(Label label) {
+ boolean included = false;
+ boolean excluded = false;
+ for (WorkspacePath workspacePath : rootDirectories()) {
+ included = included || matchesLabel(workspacePath, label);
+ }
+ for (WorkspacePath workspacePath : excludeDirectories()) {
+ excluded = excluded || matchesLabel(workspacePath, label);
+ }
+ return included && !excluded;
+ }
+
+ private static boolean matchesLabel(WorkspacePath workspacePath, Label label) {
+ if (workspacePath.isWorkspaceRoot()) {
+ return true;
+ }
+ String moduleLabelStr = label.toString();
+ int packagePrefixLength = "//".length();
+ int nextCharIndex = workspacePath.relativePath().length() + packagePrefixLength;
+ if (moduleLabelStr.startsWith(workspacePath.relativePath(), packagePrefixLength)
+ && moduleLabelStr.length() >= nextCharIndex) {
+ char c = moduleLabelStr.charAt(nextCharIndex);
+ return c == '/' || c == ':';
+ }
+ return false;
+ }
+
+ /** Returns true if 'path' is a strict child of 'ancestorPath'. */
+ private static boolean isAncestor(String ancestorPath, String path) {
+ // FileUtil.isAncestor has a bug in its handling of equal,
+ // empty paths (it ignores the 'strict' flag in this case).
+ if (ancestorPath.equals(path)) {
+ return false;
+ }
+ return FileUtil.isAncestor(ancestorPath, path, true);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java b/base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java
new file mode 100644
index 0000000..f0e43ab
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectview;
+
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection;
+import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.intellij.openapi.diagnostic.Logger;
+import java.util.Set;
+
+/** Reads the user's language preferences from the project view. */
+public class LanguageSupport {
+
+ private static final Logger LOG = Logger.getInstance(LanguageSupport.class);
+
+ public static WorkspaceLanguageSettings createWorkspaceLanguageSettings(
+ BlazeContext context, ProjectViewSet projectViewSet) {
+ WorkspaceType workspaceType = projectViewSet.getScalarValue(WorkspaceTypeSection.KEY);
+ if (workspaceType == null) {
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ WorkspaceType pluginWorkspaceType = syncPlugin.getDefaultWorkspaceType();
+ if (pluginWorkspaceType != null) {
+ if (workspaceType == null || workspaceType.ordinal() < pluginWorkspaceType.ordinal()) {
+ workspaceType = pluginWorkspaceType;
+ }
+ }
+ }
+ }
+
+ if (workspaceType == null) {
+ LOG.error("Could not find workspace type."); // Should never happen
+ return null;
+ }
+
+ Set<LanguageClass> activeLanguages = Sets.newHashSet();
+ for (LanguageClass languageClass : workspaceType.getLanguages()) {
+ activeLanguages.add(languageClass);
+ }
+ activeLanguages.addAll(projectViewSet.listItems(AdditionalLanguagesSection.KEY));
+
+ Set<LanguageClass> supportedLanguages = Sets.newHashSet();
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ supportedLanguages.addAll(syncPlugin.getSupportedLanguagesInWorkspace(workspaceType));
+ }
+
+ for (LanguageClass languageClass : activeLanguages) {
+ if (!supportedLanguages.contains(languageClass)) {
+ IssueOutput.error(
+ String.format(
+ "Language '%s' is not supported for this plugin with workspace type: '%s'",
+ languageClass.getName(), workspaceType.getName()))
+ .submit(context);
+ return null;
+ }
+ }
+
+ return new WorkspaceLanguageSettings(workspaceType, activeLanguages);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/ProjectViewRuleImportFilter.java b/base/src/com/google/idea/blaze/base/sync/projectview/ProjectViewRuleImportFilter.java
new file mode 100644
index 0000000..5cd8b16
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/ProjectViewRuleImportFilter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectview;
+
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.Tags;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.sections.ExcludeTargetSection;
+import com.google.idea.blaze.base.projectview.section.sections.ImportTargetOutputSection;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.project.Project;
+import java.util.Set;
+
+/** Filters rules into source/library depending on the project view. */
+public class ProjectViewRuleImportFilter {
+ private final ImportRoots importRoots;
+ private final Set<Label> importTargetOutputs;
+ private final Set<Label> excludedTargets;
+
+ public ProjectViewRuleImportFilter(
+ Project project, WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
+ this.importRoots =
+ ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
+ .add(projectViewSet)
+ .build();
+ this.importTargetOutputs =
+ Sets.newHashSet(projectViewSet.listItems(ImportTargetOutputSection.KEY));
+ this.excludedTargets = Sets.newHashSet(projectViewSet.listItems(ExcludeTargetSection.KEY));
+ }
+
+ public boolean isSourceRule(RuleIdeInfo rule) {
+ return importRoots.importAsSource(rule.label) && !importTargetOutput(rule);
+ }
+
+ private boolean importTargetOutput(RuleIdeInfo rule) {
+ return rule.tags.contains(Tags.RULE_TAG_IMPORT_TARGET_OUTPUT)
+ || rule.tags.contains(Tags.RULE_TAG_IMPORT_AS_LIBRARY_LEGACY)
+ || importTargetOutputs.contains(rule.label);
+ }
+
+ public boolean excludeTarget(RuleIdeInfo rule) {
+ return excludedTargets.contains(rule.label)
+ || rule.tags.contains(Tags.RULE_TAG_PROVIDED_BY_SDK)
+ || rule.tags.contains(Tags.RULE_TAG_EXCLUDE_TARGET);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/SourceTestConfig.java b/base/src/com/google/idea/blaze/base/sync/projectview/SourceTestConfig.java
new file mode 100644
index 0000000..018193e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/SourceTestConfig.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectview;
+
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.sections.TestSourceSection;
+
+/** Affects the way sources are imported. */
+public class SourceTestConfig {
+ private final Glob.GlobSet testSources;
+
+ public SourceTestConfig(ProjectViewSet projectViewSet) {
+ this.testSources = new Glob.GlobSet(projectViewSet.listItems(TestSourceSection.KEY));
+ }
+
+ /** Returns true if this artifact is a test artifact. */
+ public boolean isTestSource(String relativePath) {
+ return testSources.matches(relativePath);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java b/base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java
new file mode 100644
index 0000000..4ebde4d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.projectview;
+
+import com.google.common.base.Objects;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import java.io.Serializable;
+import java.util.Set;
+import javax.annotation.concurrent.Immutable;
+
+/** Contains the user's language preferences from the project view. */
+@Immutable
+public class WorkspaceLanguageSettings implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final WorkspaceType workspaceType;
+ private final Set<LanguageClass> activeLanguages;
+
+ public WorkspaceLanguageSettings(
+ WorkspaceType workspaceType, Set<LanguageClass> activeLanguages) {
+ this.workspaceType = workspaceType;
+ this.activeLanguages = activeLanguages;
+ }
+
+ public WorkspaceType getWorkspaceType() {
+ return workspaceType;
+ }
+
+ public boolean isWorkspaceType(WorkspaceType workspaceType) {
+ return this.workspaceType == workspaceType;
+ }
+
+ public boolean isWorkspaceType(WorkspaceType... workspaceTypes) {
+ for (WorkspaceType workspaceType : workspaceTypes) {
+ if (this.workspaceType == workspaceType) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isLanguageActive(LanguageClass languageClass) {
+ return activeLanguages.contains(languageClass);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ WorkspaceLanguageSettings that = (WorkspaceLanguageSettings) o;
+ return workspaceType == that.workspaceType
+ && Objects.equal(activeLanguages, that.activeLanguages);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(workspaceType, activeLanguages);
+ }
+
+ @Override
+ public String toString() {
+ return "WorkspaceLanguageSettings {"
+ + "\n"
+ + " workspaceType: "
+ + workspaceType
+ + "\n"
+ + " activeLanguages: "
+ + activeLanguages
+ + "\n"
+ + '}';
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sdk/DefaultSdkProvider.java b/base/src/com/google/idea/blaze/base/sync/sdk/DefaultSdkProvider.java
new file mode 100644
index 0000000..8777975
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sdk/DefaultSdkProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.sdk;
+
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** May download or otherwise provide default sdk locations for languages. */
+public interface DefaultSdkProvider {
+ ExtensionPointName<DefaultSdkProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.DefaultSdkProvider");
+
+ @Nullable
+ File provideSdkForLanguage(LanguageClass language);
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatus.java b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatus.java
new file mode 100644
index 0000000..aa98c7e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatus.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.status;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+
+/** Interface to tell blaze it might need to resync. */
+public interface BlazeSyncStatus {
+
+ /** The current sync status */
+ enum SyncStatus {
+ FAILED,
+ DIRTY,
+ CLEAN,
+ }
+
+ SyncStatus getStatus();
+
+ static BlazeSyncStatus getInstance(Project project) {
+ return ServiceManager.getService(project, BlazeSyncStatus.class);
+ }
+
+ void setDirty();
+
+ void queueAutomaticSyncIfDirty();
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java
new file mode 100644
index 0000000..a6b062b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.status;
+
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.google.idea.blaze.base.sync.SyncListener.SyncResult;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.FileEditorManagerAdapter;
+import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
+import com.intellij.openapi.fileEditor.FileEditorManagerListener;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileAdapter;
+import com.intellij.openapi.vfs.VirtualFileEvent;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.openapi.vfs.VirtualFileMoveEvent;
+import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Per-project listener for changes to BUILD files, and other changes requiring an incremental sync.
+ */
+public class BlazeSyncStatusImpl implements BlazeSyncStatus {
+
+ public static BlazeSyncStatusImpl getImpl(@NotNull Project project) {
+ return (BlazeSyncStatusImpl) BlazeSyncStatus.getInstance(project);
+ }
+
+ private static Logger log = Logger.getInstance(BlazeSyncStatusImpl.class);
+
+ private final Project project;
+
+ public final AtomicBoolean syncInProgress = new AtomicBoolean(false);
+ private final AtomicBoolean syncPending = new AtomicBoolean(false);
+
+ /** has a BUILD file changed since the last sync started */
+ private volatile boolean dirty = false;
+
+ private volatile boolean failedSync = false;
+
+ public BlazeSyncStatusImpl(Project project) {
+ this.project = project;
+ // listen for changes to the VFS
+ VirtualFileManager.getInstance().addVirtualFileListener(new FileListener(), project);
+
+ // trigger VFS updates whenever navigating away from an unsaved BUILD file
+ project
+ .getMessageBus()
+ .connect()
+ .subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileFocusListener());
+ }
+
+ private static boolean automaticSyncEnabled() {
+ return BlazeUserSettings.getInstance().getResyncAutomatically();
+ }
+
+ @Override
+ public SyncStatus getStatus() {
+ if (failedSync) {
+ return SyncStatus.FAILED;
+ }
+ return dirty ? SyncStatus.DIRTY : SyncStatus.CLEAN;
+ }
+
+ public void syncStarted() {
+ syncPending.set(false);
+ syncInProgress.set(true);
+ }
+
+ public void syncEnded(SyncResult syncResult) {
+ syncInProgress.set(false);
+ failedSync = syncResult == SyncResult.FAILURE;
+ if (syncResult == SyncResult.SUCCESS && !syncPending.get()) {
+ dirty = false;
+ } else if (syncResult == SyncResult.PARTIAL_SUCCESS || syncResult == SyncResult.CANCELLED) {
+ dirty = true;
+ }
+ }
+
+ @Override
+ public void setDirty() {
+ dirty = true;
+ queueIncrementalSync();
+ }
+
+ @Override
+ public void queueAutomaticSyncIfDirty() {
+ if (dirty) {
+ queueIncrementalSync();
+ }
+ }
+
+ private void queueIncrementalSync() {
+ if (automaticSyncEnabled() && syncPending.compareAndSet(false, true)) {
+ log.info("Automatic sync started");
+ BlazeSyncManager.getInstance(project)
+ .requestProjectSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .setBackgroundSync(true)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build());
+ }
+ }
+
+ /**
+ * Listens for changes to files which impact the sync process (BUILD files and project view files)
+ */
+ private class FileListener extends VirtualFileAdapter {
+ @Override
+ public void fileCreated(@NotNull VirtualFileEvent event) {
+ processEvent(event);
+ }
+
+ @Override
+ public void fileDeleted(@NotNull VirtualFileEvent event) {
+ processEvent(event);
+ // we (sometimes) only get one event when a directory is deleted, so check the children too.
+ checkChildren(event.getFile());
+ }
+
+ @Override
+ public void fileMoved(@NotNull VirtualFileMoveEvent event) {
+ processEvent(event);
+ }
+
+ @Override
+ public void contentsChanged(@NotNull VirtualFileEvent event) {
+ processEvent(event);
+ }
+
+ private void processEvent(@NotNull VirtualFileEvent event) {
+ if (isSyncSensitiveFile(event.getFile())) {
+ setDirty();
+ }
+ }
+
+ private void checkChildren(VirtualFile file) {
+ if (!(file instanceof NewVirtualFile)) {
+ return;
+ }
+ Collection<VirtualFile> children = ((NewVirtualFile) file).getCachedChildren();
+ for (VirtualFile child : children) {
+ if (isSyncSensitiveFile(child)) {
+ setDirty();
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Listens for changes to files which impact the sync process (BUILD files and project view files)
+ */
+ private static class FileFocusListener extends FileEditorManagerAdapter {
+ @Override
+ public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
+ processEvent(file);
+ }
+
+ @Override
+ public void selectionChanged(@NotNull FileEditorManagerEvent event) {
+ processEvent(event.getOldFile());
+ }
+
+ private void processEvent(@Nullable VirtualFile file) {
+ if (isSyncSensitiveFile(file)) {
+ FileDocumentManager manager = FileDocumentManager.getInstance();
+ Document doc = manager.getCachedDocument(file);
+ if (doc != null) {
+ manager.saveDocument(doc);
+ }
+ }
+ }
+ }
+
+ private static boolean isSyncSensitiveFile(@Nullable VirtualFile file) {
+ return file != null
+ && (isBuildFile(file) || ProjectViewStorageManager.isProjectViewFile(file.getPath()));
+ }
+
+ private static boolean isBuildFile(VirtualFile file) {
+ return file.getName().equals("BUILD");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusListener.java b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusListener.java
new file mode 100644
index 0000000..05ca578
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusListener.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.status;
+
+import com.google.idea.blaze.base.sync.SyncListener;
+import com.intellij.openapi.project.Project;
+
+/**
+ * Application-wide listener for blaze syncs. Notifies per-project status listener when they start
+ * and finish.
+ */
+public class BlazeSyncStatusListener extends SyncListener.Adapter {
+
+ @Override
+ public void onSyncStart(Project project) {
+ BlazeSyncStatusImpl.getImpl(project).syncStarted();
+ }
+
+ @Override
+ public void afterSync(Project project, SyncResult syncResult) {
+ BlazeSyncStatusImpl.getImpl(project).syncEnded(syncResult);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoder.java b/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoder.java
new file mode 100644
index 0000000..13fce58
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoder.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Decodes android_studio_ide_info.proto ArtifactLocation file paths */
+public class ArtifactLocationDecoder {
+
+ private final BlazeRoots blazeRoots;
+ private final WorkspacePathResolver pathResolver;
+
+ public ArtifactLocationDecoder(BlazeRoots blazeRoots, WorkspacePathResolver pathResolver) {
+ this.blazeRoots = blazeRoots;
+ this.pathResolver = pathResolver;
+ }
+
+ /**
+ * Decodes the ArtifactLocation proto, locates the absolute artifact file path. Returns null if
+ * the file can't be found (presumably because it was removed since the blaze build)
+ */
+ @Nullable
+ public ArtifactLocation decode(AndroidStudioIdeInfo.ArtifactLocation loc) {
+ return decode(
+ loc.getRootExecutionPathFragment(),
+ loc.getRelativePath(),
+ loc.getIsSource());
+ }
+
+ /**
+ * Decodes the ArtifactLocation proto, locates the absolute artifact file path. Returns null if
+ * the file can't be found (presumably because it was removed since the blaze build)
+ */
+ @Nullable
+ public ArtifactLocation decode(PackageManifestOuterClass.ArtifactLocation loc) {
+ return decode(
+ loc.getRootExecutionPathFragment(),
+ loc.getRelativePath(),
+ loc.getIsSource());
+ }
+
+ @Nullable
+ private ArtifactLocation decode(
+ String rootExecutionPathFragment, String relativePath, boolean isSource) {
+ File root;
+ if (isSource) {
+ root = pathResolver.findPackageRoot(relativePath);
+ } else {
+ root = new File(blazeRoots.executionRoot, rootExecutionPathFragment);
+ }
+ if (root == null) {
+ return null;
+ }
+ return ArtifactLocation.builder()
+ .setRootPath(root.toString())
+ .setRootExecutionPathFragment(rootExecutionPathFragment)
+ .setRelativePath(relativePath)
+ .setIsSource(isSource)
+ .build();
+ }
+
+ @Deprecated
+ private String deriveRootExecutionPathFragmentFromRoot(String rootPath) {
+ String execRoot = blazeRoots.executionRoot.toString();
+ if (rootPath.startsWith(execRoot)) {
+ return rootPath.substring(execRoot.length());
+ }
+ return "";
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java b/base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java
new file mode 100644
index 0000000..092fb48
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** The data output by BlazeInfo. */
+public class BlazeRoots implements Serializable {
+ public static final long serialVersionUID = 3L;
+ private static final Logger LOG = Logger.getInstance(BlazeRoots.class);
+
+ public static ListenableFuture<BlazeRoots> compute(
+ Project project, WorkspaceRoot workspaceRoot, BlazeContext context) {
+ BuildSystem buildSystem = Blaze.getBuildSystem(project);
+ ListenableFuture<ImmutableMap<String, String>> blazeInfoDataFuture =
+ BlazeInfo.getInstance()
+ .runBlazeInfo(context, buildSystem, workspaceRoot, ImmutableList.of());
+ return Futures.transform(
+ blazeInfoDataFuture,
+ new Function<ImmutableMap<String, String>, BlazeRoots>() {
+ @Nullable
+ @Override
+ public BlazeRoots apply(@Nullable ImmutableMap<String, String> blazeInfoData) {
+ // This method is supposed to throw if the input is null
+ // but the input is not allowed to be null.
+ if (blazeInfoData == null) {
+ throw new NullPointerException("blazeInfoData is not allowed to be null");
+ }
+ return build(
+ workspaceRoot,
+ getOrThrow(buildSystem, blazeInfoData, BlazeInfo.EXECUTION_ROOT_KEY),
+ getOrThrow(buildSystem, blazeInfoData, BlazeInfo.PACKAGE_PATH_KEY),
+ getOrThrow(buildSystem, blazeInfoData, BlazeInfo.blazeBinKey(buildSystem)),
+ getOrThrow(buildSystem, blazeInfoData, BlazeInfo.blazeGenfilesKey(buildSystem)));
+ }
+ });
+ }
+
+ private static String getOrThrow(
+ BuildSystem buildSystem, ImmutableMap<String, String> map, String key) {
+ String value = map.get(key);
+ if (value == null) {
+ throw new RuntimeException(
+ String.format("Could not locate %s in %s info", key, buildSystem.getLowerCaseName()));
+ }
+ return value;
+ }
+
+ private static BlazeRoots build(
+ WorkspaceRoot workspaceRoot,
+ String execRootString,
+ String packagePathString,
+ String blazeBinRoot,
+ String blazeGenfilesRoot) {
+ List<File> packagePaths = parsePackagePaths(workspaceRoot.toString(), packagePathString.trim());
+ File executionRoot = new File(execRootString.trim());
+ ExecutionRootPath blazeBinExecutionRootPath =
+ ExecutionRootPath.createAncestorRelativePath(executionRoot, new File(blazeBinRoot));
+ ExecutionRootPath blazeGenfilesExecutionRootPath =
+ ExecutionRootPath.createAncestorRelativePath(executionRoot, new File(blazeGenfilesRoot));
+ LOG.assertTrue(blazeBinExecutionRootPath != null);
+ LOG.assertTrue(blazeGenfilesExecutionRootPath != null);
+ return new BlazeRoots(
+ executionRoot, packagePaths, blazeBinExecutionRootPath, blazeGenfilesExecutionRootPath);
+ }
+
+ private static List<File> parsePackagePaths(String workspaceRoot, String packagePathString) {
+ String[] paths = packagePathString.split(":");
+ List<File> packagePaths = Lists.newArrayListWithCapacity(paths.length);
+ FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
+ for (String path : paths) {
+ File packagePath = new File(path.replace("%workspace%", workspaceRoot));
+ if (fileAttributeProvider.exists(packagePath)) {
+ packagePaths.add(packagePath);
+ }
+ }
+ return packagePaths;
+ }
+
+ public final File executionRoot;
+ public final List<File> packagePaths;
+ public final ExecutionRootPath blazeBinExecutionRootPath;
+ public final ExecutionRootPath blazeGenfilesExecutionRootPath;
+
+ @VisibleForTesting
+ public BlazeRoots(
+ File executionRoot,
+ List<File> packagePaths,
+ ExecutionRootPath blazeBinExecutionRootPath,
+ ExecutionRootPath blazeGenfilesExecutionRootPath) {
+ this.executionRoot = executionRoot;
+ this.packagePaths = packagePaths;
+ this.blazeBinExecutionRootPath = blazeBinExecutionRootPath;
+ this.blazeGenfilesExecutionRootPath = blazeGenfilesExecutionRootPath;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkingSet.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkingSet.java
new file mode 100644
index 0000000..614f5d3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkingSet.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import java.io.Serializable;
+
+/** Computes the working set of files of directories from source control. */
+public class WorkingSet implements Serializable {
+ private static final long serialVersionUID = 2L;
+
+ public final ImmutableList<WorkspacePath> addedFiles;
+ public final ImmutableList<WorkspacePath> modifiedFiles;
+ public final ImmutableList<WorkspacePath> deletedFiles;
+
+ public WorkingSet(
+ ImmutableList<WorkspacePath> addedFiles,
+ ImmutableList<WorkspacePath> modifiedFiles,
+ ImmutableList<WorkspacePath> deletedFiles) {
+ this.addedFiles = addedFiles;
+ this.modifiedFiles = modifiedFiles;
+ this.deletedFiles = deletedFiles;
+ }
+
+ public boolean isEmpty() {
+ return addedFiles.isEmpty() && modifiedFiles.isEmpty() && deletedFiles.isEmpty();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java
new file mode 100644
index 0000000..d01975d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import java.io.File;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/**
+ * Converts workspace-relative paths to absolute files with a minimum of file system calls
+ * (typically none).
+ */
+public interface WorkspacePathResolver extends Serializable {
+ /** Resolves a workspace path to an absolute file. */
+ @Nullable
+ default File resolveToFile(WorkspacePath workspacepath) {
+ return resolveToFile(workspacepath.relativePath());
+ }
+
+ /** Resolves a workspace relative path to an absolute file. */
+ @Nullable
+ default File resolveToFile(String workspaceRelativePath) {
+ File packageRoot = findPackageRoot(workspaceRelativePath);
+ return packageRoot != null ? new File(packageRoot, workspaceRelativePath) : null;
+ }
+
+ /**
+ * This method should be used for directories. Returns all workspace files corresponding to the
+ * given execution-root-relative path.
+ */
+ ImmutableList<File> resolveToIncludeDirectories(ExecutionRootPath executionRootPath);
+
+ /** Finds the package root directory that a workspace relative path is in. */
+ @Nullable
+ File findPackageRoot(String relativePath);
+
+ /**
+ * Given a resolved, absolute file, returns the corresponding {@link WorkspacePath}. Returns null
+ * if the file is not in the workspace.
+ */
+ @Nullable
+ WorkspacePath getWorkspacePath(File absoluteFile);
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java
new file mode 100644
index 0000000..5721b91
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Uses the package path locations to resolve a workspace path. */
+public class WorkspacePathResolverImpl implements WorkspacePathResolver {
+ private static final long serialVersionUID = 2L;
+
+ private final WorkspaceRoot workspaceRoot;
+ private final List<File> packagePaths;
+
+ public WorkspacePathResolverImpl(WorkspaceRoot workspaceRoot, BlazeRoots blazeRoots) {
+ this(workspaceRoot, blazeRoots.packagePaths);
+ }
+
+ public WorkspacePathResolverImpl(WorkspaceRoot workspaceRoot) {
+ this(workspaceRoot, ImmutableList.of(workspaceRoot.directory()));
+ }
+
+ public WorkspacePathResolverImpl(WorkspaceRoot workspaceRoot, List<File> packagePaths) {
+ this.workspaceRoot = workspaceRoot;
+ this.packagePaths = packagePaths;
+ }
+
+ @Override
+ public ImmutableList<File> resolveToIncludeDirectories(ExecutionRootPath executionRootPath) {
+ File trackedLocation = executionRootPath.getFileRootedAt(workspaceRoot.directory());
+ return ImmutableList.of(trackedLocation);
+ }
+
+ @Override
+ @Nullable
+ public File findPackageRoot(String relativePath) {
+ if (packagePaths.size() == 1) {
+ return packagePaths.get(0);
+ }
+ // fall back to manually checking each one
+ FileAttributeProvider existenceChecker = FileAttributeProvider.getInstance();
+ for (File pkg : packagePaths) {
+ if (existenceChecker.exists(new File(pkg, relativePath))) {
+ return pkg;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getWorkspacePath(File absoluteFile) {
+ return workspaceRoot.workspacePathForSafe(absoluteFile);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProvider.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProvider.java
new file mode 100644
index 0000000..62f419d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Provides a WorkspacePathResolver. */
+public interface WorkspacePathResolverProvider {
+
+ static WorkspacePathResolverProvider getInstance(Project project) {
+ return ServiceManager.getService(project, WorkspacePathResolverProvider.class);
+ }
+
+ /**
+ * Returns a WorkspacePathResolver for this project, or null if it's not a blaze/bazel project.
+ */
+ @Nullable
+ WorkspacePathResolver getPathResolver();
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProviderImpl.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProviderImpl.java
new file mode 100644
index 0000000..ff8941a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProviderImpl.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Provides a WorkspacePathResolver. */
+public class WorkspacePathResolverProviderImpl implements WorkspacePathResolverProvider {
+
+ private final Project project;
+
+ public WorkspacePathResolverProviderImpl(Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePathResolver getPathResolver() {
+ BlazeProjectData projectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ return projectData != null ? projectData.workspacePathResolver : null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryNode.java b/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryNode.java
new file mode 100644
index 0000000..755bb58
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryNode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.treeview;
+
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.ui.SimpleTextAttributes;
+import org.jetbrains.annotations.NotNull;
+
+/** A PsiDirectoryNode that doesn't render module names or source roots. */
+public class BlazePsiDirectoryNode extends PsiDirectoryNode {
+ public BlazePsiDirectoryNode(@NotNull PsiDirectoryNode original) {
+ this(original.getProject(), original.getValue(), original.getSettings());
+ }
+
+ public BlazePsiDirectoryNode(Project project, PsiDirectory directory, ViewSettings settings) {
+ super(project, directory, settings);
+ }
+
+ @Override
+ protected boolean shouldShowModuleName() {
+ return false;
+ }
+
+ @Override
+ protected boolean shouldShowSourcesRoot() {
+ return false;
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ super.updateImpl(data);
+ PsiDirectory psiDirectory = getValue();
+ assert psiDirectory != null;
+ String text = psiDirectory.getName();
+
+ data.setPresentableText(text);
+ data.clearText();
+ data.addText(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
+ data.setLocationString("");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNode.java b/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNode.java
new file mode 100644
index 0000000..4c061c3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNode.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.treeview;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.ui.SimpleTextAttributes;
+
+/**
+ * A PsiDirectoryNode that represents a directory root, rendering the whole directory name from the
+ * workspace root.
+ */
+public class BlazePsiDirectoryRootNode extends BlazePsiDirectoryNode {
+ public BlazePsiDirectoryRootNode(Project project, PsiDirectory directory, ViewSettings settings) {
+ super(project, directory, settings);
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ super.updateImpl(data);
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(getProject());
+ PsiDirectory psiDirectory = getValue();
+ assert psiDirectory != null;
+ WorkspacePath workspacePath = workspaceRoot.workspacePathFor(psiDirectory.getVirtualFile());
+ String text = workspacePath.relativePath();
+
+ for (BlazePsiDirectoryRootNodeNameModifier modifier :
+ BlazePsiDirectoryRootNodeNameModifier.EP_NAME.getExtensions()) {
+ text = modifier.modifyRootNodeName(text);
+ }
+
+ data.setPresentableText(text);
+ data.clearText();
+ data.addText(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
+ data.setLocationString("");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNodeNameModifier.java b/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNodeNameModifier.java
new file mode 100644
index 0000000..e15b85f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNodeNameModifier.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.treeview;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+
+/** Extension point to allow modifying the root node names. */
+public interface BlazePsiDirectoryRootNodeNameModifier {
+ ExtensionPointName<BlazePsiDirectoryRootNodeNameModifier> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BlazePsiDirectoryRootNodeNameModifier");
+
+ String modifyRootNodeName(String name);
+}
diff --git a/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java b/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
new file mode 100644
index 0000000..764e3b0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.treeview;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.ide.projectView.ProjectViewSettings;
+import com.intellij.ide.projectView.TreeStructureProvider;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.ExternalLibrariesNode;
+import com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode;
+import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiManager;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Modifies the project view:
+ *
+ * <p>- Replaces the root with a single workspace root - Removes rendering of module names and
+ * source roots
+ */
+public class BlazeTreeStructureProvider implements TreeStructureProvider, DumbAware {
+ @NotNull
+ @Override
+ public Collection<AbstractTreeNode> modify(
+ @NotNull AbstractTreeNode parent,
+ @NotNull Collection<AbstractTreeNode> children,
+ ViewSettings settings) {
+ Project project = parent.getProject();
+ if (project == null || !Blaze.isBlazeProject(project)) {
+ return children;
+ }
+
+ if (parent instanceof ProjectViewProjectNode) {
+ WorkspaceRootNode rootNode = createRootNode(project, settings);
+ if (rootNode == null) {
+ return children;
+ }
+
+ Collection<AbstractTreeNode> result = Lists.newArrayList();
+ result.add(rootNode);
+ for (AbstractTreeNode treeNode : children) {
+ if (treeNode instanceof ExternalLibrariesNode) {
+ result.add(treeNode);
+ }
+ }
+ return result;
+ } else {
+ List<AbstractTreeNode> result = Lists.newArrayList();
+ for (AbstractTreeNode treeNode : children) {
+ if (treeNode.getClass().equals(PsiDirectoryNode.class)) {
+ result.add(new BlazePsiDirectoryNode((PsiDirectoryNode) treeNode));
+ } else {
+ result.add(treeNode);
+ }
+ }
+ return result;
+ }
+ }
+
+ @Nullable
+ private WorkspaceRootNode createRootNode(
+ @NotNull Project project, @NotNull ViewSettings settings) {
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings != null) {
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
+ File fdir = workspaceRoot.directory();
+ VirtualFile vdir = LocalFileSystem.getInstance().findFileByIoFile(fdir);
+ if (vdir != null) {
+ final PsiManager psiManager = PsiManager.getInstance(project);
+ PsiDirectory directory = psiManager.findDirectory(vdir);
+ return new WorkspaceRootNode(project, workspaceRoot, directory, wrapViewSettings(settings));
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Object getData(Collection<AbstractTreeNode> selected, String dataName) {
+ return null;
+ }
+
+ private ViewSettings wrapViewSettings(@NotNull final ViewSettings original) {
+ return new ProjectViewSettings() {
+ @Override
+ public boolean isShowMembers() {
+ return original.isShowMembers();
+ }
+
+ @Override
+ public boolean isStructureView() {
+ return original.isStructureView();
+ }
+
+ @Override
+ public boolean isShowModules() {
+ return original.isShowModules();
+ }
+
+ @Override
+ public boolean isFlattenPackages() {
+ return false;
+ }
+
+ @Override
+ public boolean isAbbreviatePackageNames() {
+ return original.isAbbreviatePackageNames();
+ }
+
+ @Override
+ public boolean isHideEmptyMiddlePackages() {
+ return false;
+ }
+
+ @Override
+ public boolean isShowLibraryContents() {
+ return original.isShowLibraryContents();
+ }
+
+ @Override
+ public boolean isShowExcludedFiles() {
+ return true;
+ }
+ };
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/treeview/WorkspaceRootNode.java b/base/src/com/google/idea/blaze/base/treeview/WorkspaceRootNode.java
new file mode 100644
index 0000000..d0c504a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/treeview/WorkspaceRootNode.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.treeview;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiManager;
+import com.intellij.ui.SimpleTextAttributes;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Workspace root node.
+ *
+ * <p>
+ *
+ * <p>Customizes rendering of the workspace root node to cut out the full absolute path of the
+ * workspace directory.
+ */
+public class WorkspaceRootNode extends PsiDirectoryNode {
+
+ private static final BoolExperiment COLLAPSE_PROJECT_VIEW =
+ new BoolExperiment("collapse.project.view", true);
+
+ private final WorkspaceRoot workspaceRoot;
+
+ public WorkspaceRootNode(
+ Project project, WorkspaceRoot workspaceRoot, PsiDirectory value, ViewSettings viewSettings) {
+ super(project, value, viewSettings);
+ this.workspaceRoot = workspaceRoot;
+ }
+
+ @Override
+ public Collection<AbstractTreeNode> getChildrenImpl() {
+ if (!COLLAPSE_PROJECT_VIEW.getValue()) {
+ return super.getChildrenImpl();
+ }
+ if (!BlazeUserSettings.getInstance().getCollapseProjectView()) {
+ return super.getChildrenImpl();
+ }
+ Project project = getProject();
+ if (project == null) {
+ return super.getChildrenImpl();
+ }
+ List<AbstractTreeNode> children = Lists.newArrayList();
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return super.getChildrenImpl();
+ }
+
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
+ .add(projectViewSet)
+ .build();
+ if (importRoots.rootDirectories().stream().anyMatch(WorkspacePath::isWorkspaceRoot)) {
+ return super.getChildrenImpl();
+ }
+ for (WorkspacePath workspacePath : importRoots.rootDirectories()) {
+ VirtualFile virtualFile =
+ VfsUtil.findFileByIoFile(workspaceRoot.fileForPath(workspacePath), false);
+ if (virtualFile == null) {
+ continue;
+ }
+ PsiDirectory psiDirectory = PsiManager.getInstance(project).findDirectory(virtualFile);
+ if (psiDirectory == null) {
+ continue;
+ }
+ children.add(new BlazePsiDirectoryRootNode(project, psiDirectory, getSettings()));
+ }
+ if (children.isEmpty()) {
+ return super.getChildrenImpl();
+ }
+ return children;
+ }
+
+ @Override
+ protected void updateImpl(PresentationData data) {
+ super.updateImpl(data);
+ PsiDirectory psiDirectory = getValue();
+ assert psiDirectory != null;
+ String text = psiDirectory.getName();
+
+ data.setPresentableText(text);
+ data.clearText();
+ data.addText(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
+ data.setLocationString("");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/BlazeProblemsView.java b/base/src/com/google/idea/blaze/base/ui/BlazeProblemsView.java
new file mode 100644
index 0000000..53aefa6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/BlazeProblemsView.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import java.util.UUID;
+import javax.annotation.Nullable;
+
+/** An interface to the IntelliJ problems view */
+public interface BlazeProblemsView {
+ @Nullable
+ static BlazeProblemsView getInstance(Project project) {
+ return ServiceManager.getService(project, BlazeProblemsView.class);
+ }
+
+ void clearOldMessages(UUID sessionId);
+
+ void addMessage(IssueOutput issue, UUID sessionId);
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java b/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
new file mode 100644
index 0000000..452ae82
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import java.util.Collection;
+import javax.annotation.concurrent.Immutable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** An error occuring during a blaze validation */
+@Immutable
+public final class BlazeValidationError {
+
+ @NotNull private final String error;
+
+ public BlazeValidationError(@NotNull String validationFailure) {
+ this.error = validationFailure;
+ }
+
+ @NotNull
+ public String getError() {
+ return error;
+ }
+
+ public static void collect(
+ @Nullable Collection<BlazeValidationError> errors, @NotNull BlazeValidationError error) {
+ if (errors != null) {
+ errors.add(error);
+ }
+ }
+
+ public static void throwError(@NotNull Collection<BlazeValidationError> errors)
+ throws IllegalArgumentException {
+ BlazeValidationError error = !errors.isEmpty() ? errors.iterator().next() : null;
+ String errorMessage = error != null ? error.getError() : "Unknown validation error";
+ throw new IllegalArgumentException(errorMessage);
+ }
+
+ /**
+ * Shows an error dialog.
+ *
+ * @return true if there are no errors
+ */
+ public static boolean verify(
+ @NotNull Project project,
+ @NotNull String title,
+ @NotNull Collection<BlazeValidationError> errors) {
+ if (!errors.isEmpty()) {
+ BlazeValidationError error = errors.iterator().next();
+ Messages.showErrorDialog(project, error.getError(), title);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java b/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
new file mode 100644
index 0000000..4200003
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import org.jetbrains.annotations.Nullable;
+
+/** Pair of (success, validation error) */
+public class BlazeValidationResult {
+ public final boolean success;
+ @Nullable public final BlazeValidationError error;
+
+ private static final BlazeValidationResult SUCCESS = new BlazeValidationResult(true, null);
+
+ private BlazeValidationResult(boolean success, @Nullable BlazeValidationError error) {
+ this.success = success;
+ this.error = error;
+ }
+
+ public static BlazeValidationResult success() {
+ return SUCCESS;
+ }
+
+ public static BlazeValidationResult failure(BlazeValidationError error) {
+ return new BlazeValidationResult(false, error);
+ }
+
+ public static BlazeValidationResult failure(String error) {
+ return failure(new BlazeValidationError(error));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/ComboWrapper.java b/base/src/com/google/idea/blaze/base/ui/ComboWrapper.java
new file mode 100644
index 0000000..331cde0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/ComboWrapper.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.ui.ListCellRendererWrapper;
+import java.awt.event.ActionListener;
+import java.util.Collection;
+import javax.swing.DefaultComboBoxModel;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A simple wrapper for IDEA's {@link ComboBox} class adding type safety for the methods we commonly
+ * use.
+ */
+public final class ComboWrapper<T> {
+ @NotNull private final ComboBox combo;
+
+ public static <T> ComboWrapper<T> create() {
+ return new ComboWrapper<T>();
+ }
+
+ private ComboWrapper() {
+ combo = new ComboBox();
+ }
+
+ public void setItems(@NotNull Collection<T> values) {
+ combo.setModel(new DefaultComboBoxModel(values.toArray()));
+ }
+
+ public void setSelectedItem(T value) {
+ combo.setSelectedItem(value);
+ }
+
+ public T getSelectedItem() {
+ return (T) combo.getSelectedItem();
+ }
+
+ public void addActionListener(@NotNull ActionListener listener) {
+ combo.addActionListener(listener);
+ }
+
+ public void setRenderer(ListCellRendererWrapper<T> renderer) {
+ combo.setRenderer(renderer);
+ }
+
+ @NotNull
+ public ComboBox getCombo() {
+ return combo;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/FileSelectorWithStoredHistory.java b/base/src/com/google/idea/blaze/base/ui/FileSelectorWithStoredHistory.java
new file mode 100644
index 0000000..8636726
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/FileSelectorWithStoredHistory.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import com.intellij.ide.util.BrowseFilesListener;
+import com.intellij.openapi.ui.ComponentWithBrowseButton;
+import com.intellij.openapi.ui.TextComponentAccessor;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.TextFieldWithStoredHistory;
+import javax.annotation.Nullable;
+
+/** A file selector panel with text field, browse button and stored history. */
+public class FileSelectorWithStoredHistory
+ extends ComponentWithBrowseButton<TextFieldWithStoredHistory> {
+
+ public static FileSelectorWithStoredHistory create(String historyKey, String title) {
+ TextFieldWithStoredHistory textField = new TextFieldWithStoredHistory(historyKey);
+ return new FileSelectorWithStoredHistory(textField, title);
+ }
+
+ private FileSelectorWithStoredHistory(TextFieldWithStoredHistory textField, String title) {
+ super(textField, null);
+
+ addBrowseFolderListener(
+ title,
+ "",
+ null,
+ BrowseFilesListener.SINGLE_FILE_DESCRIPTOR,
+ TextComponentAccessor.TEXT_FIELD_WITH_STORED_HISTORY_WHOLE_TEXT);
+ }
+
+ /** Set the text without altering the history. */
+ public void setText(@Nullable String text) {
+ if (text == null) {
+ getChildComponent().reset();
+ } else {
+ getChildComponent().setText(text);
+ }
+ }
+
+ public void setTextWithHistory(@Nullable String text) {
+ setText(text);
+ if (text != null) {
+ getChildComponent().addCurrentTextToHistory();
+ }
+ }
+
+ @Nullable
+ public String getText() {
+ String text = getChildComponent().getText();
+ return StringUtil.nullize(text);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/IntegerTextField.java b/base/src/com/google/idea/blaze/base/ui/IntegerTextField.java
new file mode 100644
index 0000000..8a6e108
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/IntegerTextField.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import javax.swing.JFormattedTextField;
+import javax.swing.text.NumberFormatter;
+
+/** Naive extension of JTextField, accepting integers or null. */
+public class IntegerTextField extends JFormattedTextField {
+
+ private static final NumberFormatter integerFormatter =
+ new NumberFormatter(new NullableNumberFormat(NumberFormat.getIntegerInstance()));
+
+ static {
+ integerFormatter.setValueClass(Integer.class);
+ }
+
+ private static class NullableNumberFormat extends NumberFormat {
+
+ private final NumberFormat base;
+
+ private NullableNumberFormat(NumberFormat base) {
+ this.base = base;
+ }
+
+ @Override
+ public Object parseObject(String source) throws ParseException {
+ if (source == null || source.trim().isEmpty()) {
+ return null;
+ }
+ return super.parseObject(source);
+ }
+
+ @Override
+ public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
+ return base.format(number, toAppendTo, pos);
+ }
+
+ @Override
+ public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
+ return base.format(number, toAppendTo, pos);
+ }
+
+ @Override
+ public Number parse(String source, ParsePosition parsePosition) {
+ return base.parse(source, parsePosition);
+ }
+ }
+
+ private int minValue = Integer.MIN_VALUE;
+ private int maxValue = Integer.MAX_VALUE;
+
+ public IntegerTextField() {
+ super(integerFormatter);
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (value == null) {
+ super.setValue(value);
+ return;
+ }
+ Integer integer;
+ try {
+ integer = Integer.parseInt(getFormatter().valueToString(value));
+
+ } catch (ParseException | NumberFormatException e) {
+ return; // retain existing value if invalid
+ }
+ super.setValue(integer < minValue ? minValue : integer > maxValue ? maxValue : integer);
+ }
+
+ public IntegerTextField setMinValue(int minValue) {
+ this.minValue = minValue;
+ return this;
+ }
+
+ public IntegerTextField setMaxValue(int maxValue) {
+ this.maxValue = maxValue;
+ return this;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ui/UiUtil.java b/base/src/com/google/idea/blaze/base/ui/UiUtil.java
new file mode 100644
index 0000000..9f28ccb
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/UiUtil.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ui;
+
+import com.google.common.collect.Lists;
+import com.intellij.util.ui.GridBag;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import javax.swing.Box;
+import javax.swing.JComponent;
+import org.jetbrains.annotations.NotNull;
+
+/** A collection of UI utility methods. */
+public final class UiUtil {
+
+ public static final int INSETS = 7;
+
+ private UiUtil() {}
+
+ public static Box createBox(@NotNull Component... components) {
+ return createBox(Lists.newArrayList(components));
+ }
+
+ /** Puts all the given components in order in a box, aligned left. */
+ public static Box createBox(@NotNull Iterable<Component> components) {
+ Box box = Box.createVerticalBox();
+ box.setAlignmentX(0);
+ for (Component component : components) {
+ if (component instanceof JComponent) {
+ ((JComponent) component).setAlignmentX(0);
+ }
+ box.add(component);
+ }
+ return box;
+ }
+
+ /** Puts all the given components in order in a horizontal box. */
+ public static Box createHorizontalBox(int gap, @NotNull Component... components) {
+ return createHorizontalBox(gap, Lists.newArrayList(components));
+ }
+
+ public static Box createHorizontalBox(int gap, @NotNull Iterable<Component> components) {
+ Box box = Box.createHorizontalBox();
+ for (Component component : components) {
+ box.add(component);
+ box.add(Box.createRigidArea(new Dimension(gap, 0)));
+ }
+ return box;
+ }
+
+ @NotNull
+ public static GridBag getLabelConstraints(int indentLevel) {
+ Insets insets = new Insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS);
+ return new GridBag().anchor(GridBagConstraints.WEST).weightx(0).insets(insets);
+ }
+
+ @NotNull
+ public static GridBag getFillLineConstraints(int indentLevel) {
+ Insets insets = new Insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS);
+ return new GridBag()
+ .weightx(1)
+ .coverLine()
+ .fillCellHorizontally()
+ .anchor(GridBagConstraints.WEST)
+ .insets(insets);
+ }
+
+ public static void fillBottom(@NotNull JComponent component) {
+ component.add(
+ Box.createVerticalGlue(), new GridBag().weightx(1).weighty(1).fillCell().coverLine());
+ }
+
+ public static void setEnabledRecursive(Component component, boolean enabled) {
+ component.setEnabled(enabled);
+ if (component instanceof Container) {
+ for (Component child : ((Container) component).getComponents()) {
+ setEnabledRecursive(child, enabled);
+ }
+ }
+ }
+
+ public static void setPreferredWidth(JComponent component, int width) {
+ int height = component.getPreferredSize().height;
+ component.setPreferredSize(new Dimension(width, height));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/util/BlazeHelperBinaryUtil.java b/base/src/com/google/idea/blaze/base/util/BlazeHelperBinaryUtil.java
new file mode 100644
index 0000000..d89004e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/util/BlazeHelperBinaryUtil.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.util;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.io.URLUtil;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.HashMap;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Extracts binaries from the resource section of the jar for execution */
+public final class BlazeHelperBinaryUtil {
+
+ private static final Logger LOG = Logger.getInstance(BlazeHelperBinaryUtil.class);
+
+ private static final File tempDirectory = com.google.common.io.Files.createTempDir();
+ private static final Map<String, File> cachedFiles = new HashMap<>();
+
+ @Nullable
+ public static synchronized File getBlazeHelperBinary(@NotNull String binaryName) {
+ File file = cachedFiles.get(binaryName);
+ if (file != null) {
+ return file;
+ }
+ file = new File(tempDirectory, binaryName);
+ File directory = file.getParentFile();
+
+ if (!directory.mkdirs()) {
+ LOG.error("Could not create temporary dir: " + directory);
+ return null;
+ }
+
+ URL url = BlazeHelperBinaryUtil.class.getResource(binaryName);
+ if (url == null) {
+ LOG.error(String.format("Blaze binary '%s' was not found", binaryName));
+ return null;
+ }
+ try (InputStream inputStream = URLUtil.openResourceStream(url)) {
+ Files.copy(inputStream, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ file.setExecutable(true);
+ cachedFiles.put(binaryName, file);
+ return file;
+ } catch (IOException e) {
+ LOG.error(String.format("Error loading blaze binary '%s'", binaryName));
+ return null;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java b/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
new file mode 100644
index 0000000..e923236
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.util;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import org.jetbrains.annotations.NotNull;
+
+/** Calculates package prefix from workspace paths. */
+public final class PackagePrefixCalculator {
+
+ public static String packagePrefixOf(@NotNull WorkspacePath workspacePath) {
+ int skipIndex = 0;
+
+ skipIndex = skipIndex == 0 ? skip(workspacePath, "java/") : skipIndex;
+ skipIndex = skipIndex == 0 ? skip(workspacePath, "javatests/") : skipIndex;
+
+ return workspacePath.relativePath().substring(skipIndex).replace('/', '.');
+ }
+
+ private static int skip(@NotNull WorkspacePath workspacePath, @NotNull String skipString) {
+ if (workspacePath.relativePath().startsWith(skipString)) {
+ return skipString.length();
+ }
+ return 0;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/util/SaveUtil.java b/base/src/com/google/idea/blaze/base/util/SaveUtil.java
new file mode 100644
index 0000000..6454a7a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/util/SaveUtil.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.util;
+
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.util.ui.UIUtil;
+
+/** Utility for saving all files. */
+public class SaveUtil {
+ public static void saveAllFiles() {
+ UIUtil.invokeAndWaitIfNeeded(
+ new Runnable() {
+ @Override
+ public void run() {
+ FileDocumentManager.getInstance().saveAllDocuments();
+ }
+ });
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/util/SerializationUtil.java b/base/src/com/google/idea/blaze/base/util/SerializationUtil.java
new file mode 100644
index 0000000..51f46d4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/util/SerializationUtil.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.util;
+
+import com.google.common.io.Closeables;
+import com.intellij.CommonBundle;
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.Serializable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Utils for serialization. */
+public class SerializationUtil {
+ private static final Logger LOG = Logger.getInstance(SerializationUtil.class.getName());
+
+ public static void saveToDisk(@NotNull File file, @NotNull Serializable serializable)
+ throws IOException {
+ ensureExists(file.getParentFile());
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file);
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ try {
+ oos.writeObject(serializable);
+ } finally {
+ Closeables.close(oos, false);
+ }
+ } finally {
+ Closeables.close(fos, false);
+ }
+ }
+
+ @Nullable
+ public static Object loadFromDisk(
+ @NotNull File file, @NotNull final Iterable<ClassLoader> classLoaders) throws IOException {
+ try {
+ FileInputStream fin = null;
+ try {
+ if (!file.exists()) {
+ return null;
+ }
+ fin = new FileInputStream(file);
+ ObjectInputStream ois =
+ new ObjectInputStream(fin) {
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass desc)
+ throws IOException, ClassNotFoundException {
+ String name = desc.getName();
+ for (ClassLoader loader : classLoaders) {
+ try {
+ return Class.forName(name, false, loader);
+ } catch (ClassNotFoundException e) {
+ // Ignore - will throw eventually in super
+ }
+ }
+ return super.resolveClass(desc);
+ }
+ };
+ try {
+ return (Object) ois.readObject();
+ } finally {
+ Closeables.close(ois, false);
+ }
+ } finally {
+ Closeables.close(fin, false);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new IOException(e);
+ } catch (ClassCastException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private static void ensureExists(@NotNull File dir) throws IOException {
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new IOException(
+ CommonBundle.message("exception.directory.can.not.create", dir.getPath()));
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/vcs/BlazeVcsHandler.java b/base/src/com/google/idea/blaze/base/vcs/BlazeVcsHandler.java
new file mode 100644
index 0000000..16e6909
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/vcs/BlazeVcsHandler.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Provides a diff against the version control system. */
+public interface BlazeVcsHandler {
+ ExtensionPointName<BlazeVcsHandler> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.VcsHandler");
+
+ /** Returns the name of this VCS, eg. "git" or "hg" */
+ String getVcsName();
+
+ /** Returns whether this vcs handler can manage this project */
+ boolean handlesProject(BuildSystem buildSystem, WorkspaceRoot workspaceRoot);
+
+ /** Returns the working set of modified files compared to some "upstream". */
+ ListenableFuture<WorkingSet> getWorkingSet(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ListeningExecutorService executor);
+
+ /** Optionally creates a sync handler to perform vcs-specific computation during sync. */
+ @Nullable
+ BlazeVcsSyncHandler createSyncHandler(Project project, WorkspaceRoot workspaceRoot);
+
+ /** Sync handler that performs VCS specific computation. */
+ interface BlazeVcsSyncHandler {
+ enum ValidationResult {
+ OK,
+ Error,
+ RestartSync, // The sync process needs restarting
+ }
+
+ /**
+ * Updates the vcs state of the project.
+ *
+ * @return True for OK, false to abort the sync process.
+ */
+ boolean update(BlazeContext context, BlazeRoots blazeRoots, ListeningExecutorService executor);
+
+ /** Returns a custom workspace path resolver for this vcs. */
+ @Nullable
+ WorkspacePathResolver getWorkspacePathResolver();
+
+ /** Validates the project view. Can cause sync to fail or restart. */
+ ValidationResult validateProjectView(BlazeContext context, ProjectViewSet projectViewSet);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/vcs/FallbackBlazeVcsHandler.java b/base/src/com/google/idea/blaze/base/vcs/FallbackBlazeVcsHandler.java
new file mode 100644
index 0000000..a975203
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/vcs/FallbackBlazeVcsHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/**
+ * Used for bazel projects, when no other vcs handler can be found. Fallback to returning a null
+ * working set.
+ */
+public class FallbackBlazeVcsHandler implements BlazeVcsHandler {
+
+ @Override
+ public String getVcsName() {
+ return "Generic VCS Handler";
+ }
+
+ @Override
+ public boolean handlesProject(BuildSystem buildSystem, WorkspaceRoot workspaceRoot) {
+ return buildSystem == BuildSystem.Bazel;
+ }
+
+ @Override
+ public ListenableFuture<WorkingSet> getWorkingSet(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ListeningExecutorService executor) {
+ return Futures.immediateFuture(null);
+ }
+
+ @Nullable
+ @Override
+ public BlazeVcsSyncHandler createSyncHandler(Project project, WorkspaceRoot workspaceRoot) {
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/vcs/VcsWorkspacePathResolver.java b/base/src/com/google/idea/blaze/base/vcs/VcsWorkspacePathResolver.java
new file mode 100644
index 0000000..2b5516c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/vcs/VcsWorkspacePathResolver.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs;
+
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Created by tomlu on 5/13/16. */
+public interface VcsWorkspacePathResolver {
+
+ @Nullable
+ File findPackageRoot(String relativePath);
+}
diff --git a/base/src/com/google/idea/blaze/base/vcs/git/GitBlazeVcsHandler.java b/base/src/com/google/idea/blaze/base/vcs/git/GitBlazeVcsHandler.java
new file mode 100644
index 0000000..e1ffb78
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/vcs/git/GitBlazeVcsHandler.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs.git;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.async.process.ExternalTask;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Vcs diff provider for git */
+public class GitBlazeVcsHandler implements BlazeVcsHandler {
+
+ private static final Logger LOG = Logger.getInstance(GitBlazeVcsHandler.class);
+
+ @Override
+ public String getVcsName() {
+ return "git";
+ }
+
+ @Override
+ public boolean handlesProject(BuildSystem buildSystem, WorkspaceRoot workspaceRoot) {
+ return buildSystem == BuildSystem.Bazel
+ && isGitRepository(workspaceRoot)
+ && tracksRemote(workspaceRoot);
+ }
+
+ @Override
+ public ListenableFuture<WorkingSet> getWorkingSet(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ListeningExecutorService executor) {
+ return executor.submit(
+ () -> {
+ String upstreamSha = getUpstreamSha(workspaceRoot, false);
+ if (upstreamSha == null) {
+ return null;
+ }
+ return GitWorkingSetProvider.calculateWorkingSet(workspaceRoot, upstreamSha);
+ });
+ }
+
+ @Nullable
+ @Override
+ public BlazeVcsSyncHandler createSyncHandler(Project project, WorkspaceRoot workspaceRoot) {
+ return null;
+ }
+
+ private static boolean isGitRepository(WorkspaceRoot workspaceRoot) {
+ // TODO: What if the git repo root is a parent directory of the workspace root?
+ // Just call 'git rev-parse --is-inside-work-tree' or similar instead?
+ File gitDir = new File(workspaceRoot.directory(), ".git");
+ return FileAttributeProvider.getInstance().isDirectory(gitDir);
+ }
+
+ /**
+ * If we're not on a git branch which tracks a remote, we have no way of determining a WorkingSet.
+ */
+ private static boolean tracksRemote(WorkspaceRoot workspaceRoot) {
+ return getUpstreamSha(workspaceRoot, true) != null;
+ }
+
+ /**
+ * Returns the git commit SHA corresponding to the most recent commit in the current branch which
+ * matches a commit in the currently-tracked remote branch.
+ */
+ @Nullable
+ public static String getUpstreamSha(WorkspaceRoot workspaceRoot, boolean suppressErrors) {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .args("git", "rev-parse", "@{u}")
+ .stdout(stdout)
+ .stderr(stderr)
+ .build()
+ .run();
+ if (retVal != 0) {
+ if (!suppressErrors) {
+ LOG.error(stderr);
+ }
+ return null;
+ }
+ return StringUtil.trimEnd(stdout.toString(), "\n");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessor.java b/base/src/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessor.java
new file mode 100644
index 0000000..8c4952b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessor.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs.git;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.openapi.util.text.StringUtil;
+import java.io.File;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** Finds file modifications from git status output */
+public class GitStatusLineProcessor implements LineProcessingOutputStream.LineProcessor {
+
+ private static final Pattern REGEX = Pattern.compile("^(A|M|D)\\s*(.*?)$");
+
+ private final WorkspaceRoot workspaceRoot;
+ private final String gitRoot;
+
+ public final List<WorkspacePath> addedFiles = Lists.newArrayList();
+ public final List<WorkspacePath> modifiedFiles = Lists.newArrayList();
+ public final List<WorkspacePath> deletedFiles = Lists.newArrayList();
+
+ public GitStatusLineProcessor(WorkspaceRoot workspaceRoot, String gitRoot) {
+ this.workspaceRoot = workspaceRoot;
+ this.gitRoot = gitRoot;
+ }
+
+ @Override
+ public boolean processLine(String line) {
+ Matcher matcher = REGEX.matcher(line);
+ if (matcher.find()) {
+ String type = matcher.group(1);
+ String file = matcher.group(2);
+ file = StringUtil.trimEnd(file, '/');
+
+ WorkspacePath workspacePath = getWorkspacePath(file);
+ if (workspacePath == null) {
+ return true;
+ }
+ switch (type) {
+ case "A":
+ addedFiles.add(workspacePath);
+ break;
+ case "M":
+ modifiedFiles.add(workspacePath);
+ break;
+ case "D":
+ deletedFiles.add(workspacePath);
+ break;
+ }
+ }
+ return true;
+ }
+
+ @Nullable
+ private WorkspacePath getWorkspacePath(String gitPath) {
+ File absoluteFile = new File(gitRoot, gitPath);
+ return workspaceRoot.workspacePathForSafe(absoluteFile);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/vcs/git/GitWorkingSetProvider.java b/base/src/com/google/idea/blaze/base/vcs/git/GitWorkingSetProvider.java
new file mode 100644
index 0000000..cfef8c0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/vcs/git/GitWorkingSetProvider.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs.git;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.ExternalTask;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.text.StringUtil;
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** Vcs diff provider for git. */
+public class GitWorkingSetProvider {
+
+ private static final Logger LOG = Logger.getInstance(GitWorkingSetProvider.class);
+
+ /**
+ * Finds all changes between HEAD and the git commit specified by the provided SHA.<br>
+ * Returns null if an error occurred.
+ */
+ @Nullable
+ public static WorkingSet calculateWorkingSet(WorkspaceRoot workspaceRoot, String upstreamSha) {
+
+ String gitRoot = getConsoleOutput(workspaceRoot, "git", "rev-parse", "--show-toplevel");
+ if (gitRoot == null) {
+ return null;
+ }
+ GitStatusLineProcessor processor = new GitStatusLineProcessor(workspaceRoot, gitRoot);
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+
+ // Do a git diff to find all modified files we know about
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .args("git", "diff", "--name-status", "--no-renames", upstreamSha)
+ .stdout(LineProcessingOutputStream.of(processor))
+ .stderr(stderr)
+ .build()
+ .run();
+ if (retVal != 0) {
+ LOG.error(stderr);
+ return null;
+ }
+
+ // Finally list all untracked files, as they're not caught by the git diff step above
+ String untrackedFilesOutput =
+ getConsoleOutput(workspaceRoot, "git", "ls-files", "--others", "--exclude-standard");
+ if (untrackedFilesOutput == null) {
+ return null;
+ }
+
+ List<WorkspacePath> untrackedFiles =
+ Arrays.asList(untrackedFilesOutput.split("\n"))
+ .stream()
+ .filter(s -> !Strings.isNullOrEmpty(s))
+ .filter(WorkspacePath::validate)
+ .map(WorkspacePath::new)
+ .collect(Collectors.toList());
+
+ return new WorkingSet(
+ ImmutableList.<WorkspacePath>builder()
+ .addAll(processor.addedFiles)
+ .addAll(untrackedFiles)
+ .build(),
+ ImmutableList.copyOf(processor.modifiedFiles),
+ ImmutableList.copyOf(processor.deletedFiles));
+ }
+
+ /** @return the console output, in string form, or null if there was a non-zero exit code. */
+ @Nullable
+ private static String getConsoleOutput(WorkspaceRoot workspaceRoot, String... commands) {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .args(commands)
+ .stdout(stdout)
+ .stderr(stderr)
+ .build()
+ .run();
+ if (retVal != 0) {
+ LOG.error(stderr);
+ return null;
+ }
+ return StringUtil.trimEnd(stdout.toString(), "\n");
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BazelWizardOptionProvider.java b/base/src/com/google/idea/blaze/base/wizard2/BazelWizardOptionProvider.java
new file mode 100644
index 0000000..9e62e78
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BazelWizardOptionProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+
+/** Provides bazel options for the wizard. */
+public class BazelWizardOptionProvider implements BlazeWizardOptionProvider {
+
+ @Override
+ public Collection<BlazeSelectWorkspaceOption> getSelectWorkspaceOptions(
+ BlazeNewProjectBuilder builder) {
+ return ImmutableList.of(new UseExistingBazelWorkspaceOption(builder));
+ }
+
+ @Override
+ public Collection<BlazeSelectProjectViewOption> getSelectProjectViewOptions(
+ BlazeNewProjectBuilder builder) {
+ return ImmutableList.of(
+ new CreateFromScratchProjectViewOption(),
+ new ImportFromWorkspaceProjectViewOption(builder),
+ new GenerateFromBuildFileSelectProjectViewOption(builder),
+ new CopyExternalProjectViewOption(builder));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
new file mode 100644
index 0000000..ad36704
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.plugin.dependency.PluginDependencyHelper;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import java.io.File;
+import java.io.IOException;
+import java.util.UUID;
+
+/** Contains the state to build a new project throughout the new project wizard process. */
+public final class BlazeNewProjectBuilder {
+ private static final Logger LOG = Logger.getInstance(BlazeNewProjectBuilder.class);
+
+ // Stored in user settings as the last imported workspace
+ private static final String LAST_IMPORTED_BLAZE_WORKSPACE =
+ "blaze-wizard.last-imported-workspace";
+ private static final String LAST_IMPORTED_BAZEL_WORKSPACE =
+ "blaze-wizard.last-imported-bazel-workspace";
+
+ public static String lastImportedWorkspaceKey(BuildSystem buildSystem) {
+ switch (buildSystem) {
+ case Blaze:
+ return LAST_IMPORTED_BLAZE_WORKSPACE;
+ case Bazel:
+ return LAST_IMPORTED_BAZEL_WORKSPACE;
+ default:
+ throw new RuntimeException("Unrecognized build system type: " + buildSystem);
+ }
+ }
+
+ private final BlazeWizardUserSettings userSettings;
+ private BlazeSelectWorkspaceOption workspaceOption;
+ private BlazeSelectProjectViewOption projectViewOption;
+ private File projectViewFile;
+ private ProjectView projectView;
+ private ProjectViewSet projectViewSet;
+ private String projectName;
+ private String projectDataDirectory;
+ private WorkspaceRoot workspaceRoot;
+ private BuildSystem buildSystem;
+
+ public BlazeNewProjectBuilder() {
+ this.userSettings = BlazeWizardUserSettingsStorage.getInstance().copyUserSettings();
+ }
+
+ public BlazeWizardUserSettings getUserSettings() {
+ return userSettings;
+ }
+
+ public BlazeSelectWorkspaceOption getWorkspaceOption() {
+ return workspaceOption;
+ }
+
+ public BlazeSelectProjectViewOption getProjectViewOption() {
+ return projectViewOption;
+ }
+
+ public String getProjectName() {
+ return projectName;
+ }
+
+ public ProjectView getProjectView() {
+ return projectView;
+ }
+
+ public ProjectViewSet getProjectViewSet() {
+ return projectViewSet;
+ }
+
+ public String getProjectDataDirectory() {
+ return projectDataDirectory;
+ }
+
+ public BuildSystem getBuildSystem() {
+ return buildSystem;
+ }
+
+ public String getBuildSystemName() {
+ if (buildSystem != null) {
+ return buildSystem.getName();
+ }
+ return Blaze.defaultBuildSystemName();
+ }
+
+ public BlazeNewProjectBuilder setWorkspaceOption(BlazeSelectWorkspaceOption workspaceOption) {
+ this.workspaceOption = workspaceOption;
+ this.buildSystem = workspaceOption.getBuildSystemForWorkspace();
+ return this;
+ }
+
+ public BlazeNewProjectBuilder setProjectViewOption(
+ BlazeSelectProjectViewOption projectViewOption) {
+ this.projectViewOption = projectViewOption;
+ return this;
+ }
+
+ public BlazeNewProjectBuilder setProjectView(ProjectView projectView) {
+ this.projectView = projectView;
+ return this;
+ }
+
+ public BlazeNewProjectBuilder setProjectViewFile(File projectViewFile) {
+ this.projectViewFile = projectViewFile;
+ return this;
+ }
+
+ public BlazeNewProjectBuilder setProjectViewSet(ProjectViewSet projectViewSet) {
+ this.projectViewSet = projectViewSet;
+ return this;
+ }
+
+ public BlazeNewProjectBuilder setProjectName(String projectName) {
+ this.projectName = projectName;
+ return this;
+ }
+
+ public BlazeNewProjectBuilder setProjectDataDirectory(String projectDataDirectory) {
+ this.projectDataDirectory = projectDataDirectory;
+ return this;
+ }
+
+ /** Commits the project. May report errors. */
+ public void commit() throws BlazeProjectCommitException {
+ this.workspaceRoot = workspaceOption.getWorkspaceRoot();
+
+ workspaceOption.commit();
+ projectViewOption.commit();
+
+ String workspaceKey = lastImportedWorkspaceKey(workspaceOption.getBuildSystemForWorkspace());
+ userSettings.put(workspaceKey, workspaceRoot.toString());
+
+ if (!StringUtil.isEmpty(projectDataDirectory)) {
+ File projectDataDir = new File(projectDataDirectory);
+ if (!projectDataDir.exists()) {
+ if (!projectDataDir.mkdirs()) {
+ throw new BlazeProjectCommitException(
+ "Unable to create the project directory: " + projectDataDirectory);
+ }
+ }
+ }
+
+ try {
+ LOG.assertTrue(projectViewFile != null);
+ ProjectViewStorageManager.getInstance()
+ .writeProjectView(ProjectViewParser.projectViewToString(projectView), projectViewFile);
+ } catch (IOException e) {
+ throw new BlazeProjectCommitException("Could not create project view file", e);
+ }
+ }
+
+ /**
+ * Commits the project data. This method mustn't fail, because the project has already been
+ * created.
+ */
+ public void commitToProject(Project project) {
+ BlazeWizardUserSettingsStorage.getInstance().commit(userSettings);
+
+ BlazeImportSettings importSettings =
+ new BlazeImportSettings(
+ workspaceRoot.directory().getPath(),
+ projectName,
+ projectDataDirectory,
+ createLocationHash(projectName),
+ projectViewFile.getPath(),
+ buildSystem);
+
+ BlazeImportSettingsManager.getInstance(project).setImportSettings(importSettings);
+ PluginDependencyHelper.addDependencyOnSyncPlugin(project);
+ // Initial sync of the project happens in BlazeSyncStartupActivity
+ }
+
+ private static String createLocationHash(String projectName) {
+ String uuid = UUID.randomUUID().toString();
+ uuid = uuid.substring(0, Math.min(uuid.length(), 8));
+ return projectName.replaceAll("[^a-zA-Z0-9]", "") + "-" + uuid;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeProjectCommitException.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeProjectCommitException.java
new file mode 100644
index 0000000..a7011e8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeProjectCommitException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+/** Throws during the commit stage of the new project wizard. */
+public class BlazeProjectCommitException extends Exception {
+ public BlazeProjectCommitException(String message) {
+ super(message);
+ }
+
+ public BlazeProjectCommitException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public BlazeProjectCommitException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
new file mode 100644
index 0000000..348d657
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import javax.annotation.Nullable;
+
+/** Provides an option on the "Select .blazeproject" screen */
+public interface BlazeSelectProjectViewOption extends BlazeWizardOption {
+ @Nullable
+ WorkspacePath getSharedProjectView();
+
+ @Nullable
+ String getInitialProjectViewText();
+
+ void commit();
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java
new file mode 100644
index 0000000..1c8654d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+
+/** Provides an option on the "Select workspace" screen */
+public interface BlazeSelectWorkspaceOption extends BlazeWizardOption {
+ /** @return The workspace root that will be created after commit. */
+ WorkspaceRoot getWorkspaceRoot();
+
+ /** @return a location to use when browsing for workspace paths. */
+ WorkspaceRoot getTemporaryWorkspaceRoot();
+
+ /** @return the name of the workspace. Used to generate default project names. */
+ String getWorkspaceName();
+
+ BuildSystem getBuildSystemForWorkspace();
+
+ void commit() throws BlazeProjectCommitException;
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOption.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOption.java
new file mode 100644
index 0000000..775824f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOption.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.UiUtil;
+import javax.annotation.Nullable;
+import javax.swing.JComponent;
+
+/** Base class for the workspace and project view options. */
+public interface BlazeWizardOption {
+ int VERTICAL_LAYOUT_GAP = 10;
+ int HORIZONTAL_LAYOUT_GAP = 10;
+ int PREFERRED_COMPONENT_WIDTH = 700;
+
+ /** @return A stable option name, used to remember which option was selected. */
+ String getOptionName();
+
+ /** @return the option text, eg "Create workspace from scratch" */
+ String getOptionText();
+
+ /** @return a ui component to be added below the corresponding radio button */
+ @Nullable
+ JComponent getUiComponent();
+
+ BlazeValidationResult validate();
+
+ default void optionSelected() {
+ UiUtil.setEnabledRecursive(getUiComponent(), true);
+ }
+
+ default void optionDeselected() {
+ UiUtil.setEnabledRecursive(getUiComponent(), false);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOptionProvider.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOptionProvider.java
new file mode 100644
index 0000000..20a7e4d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOptionProvider.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.util.Collection;
+
+/** Provides options during the import process. */
+public interface BlazeWizardOptionProvider {
+ ExtensionPointName<BlazeWizardOptionProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BlazeWizardOptionProvider");
+
+ Collection<BlazeSelectWorkspaceOption> getSelectWorkspaceOptions(BlazeNewProjectBuilder builder);
+
+ Collection<BlazeSelectProjectViewOption> getSelectProjectViewOptions(
+ BlazeNewProjectBuilder builder);
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettings.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettings.java
new file mode 100644
index 0000000..7d3ba41
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettings.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
+import com.intellij.util.xmlb.annotations.MapAnnotation;
+import com.intellij.util.xmlb.annotations.Tag;
+import java.util.Map;
+
+/**
+ * A bundle of settings that are stored between invocations of the wizard.
+ *
+ * <p>It's the user's responsibility to appropriately namespace the keys.
+ */
+public class BlazeWizardUserSettings {
+ Map<String, String> values = Maps.newHashMap();
+
+ public BlazeWizardUserSettings() {}
+
+ public BlazeWizardUserSettings(BlazeWizardUserSettings state) {
+ values.putAll(state.getValues());
+ }
+
+ public String get(String key, String defaultValue) {
+ return values.getOrDefault(key, defaultValue);
+ }
+
+ public void put(String key, String value) {
+ values.put(key, value);
+ }
+
+ @SuppressWarnings("unused")
+ @Tag("settings")
+ @MapAnnotation(surroundWithTag = false)
+ public Map<String, String> getValues() {
+ return values;
+ }
+
+ @SuppressWarnings("unused")
+ public void setValues(Map<String, String> values) {
+ this.values = values;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ BlazeWizardUserSettings that = (BlazeWizardUserSettings) o;
+ return Objects.equal(values, that.values);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(values);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
new file mode 100644
index 0000000..2184d14
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import org.jetbrains.annotations.Nullable;
+
+/** Stores wizard user settings between runs. */
+@State(name = "BlazeWizardUserSettings", storages = @Storage("blaze.wizard.settings.xml"))
+public class BlazeWizardUserSettingsStorage
+ implements PersistentStateComponent<BlazeWizardUserSettings> {
+ private BlazeWizardUserSettings state = new BlazeWizardUserSettings();
+
+ static BlazeWizardUserSettingsStorage getInstance() {
+ return ServiceManager.getService(BlazeWizardUserSettingsStorage.class);
+ }
+
+ @Nullable
+ @Override
+ public BlazeWizardUserSettings getState() {
+ return state;
+ }
+
+ @Override
+ public void loadState(BlazeWizardUserSettings state) {
+ this.state = state;
+ }
+
+ BlazeWizardUserSettings copyUserSettings() {
+ return new BlazeWizardUserSettings(state);
+ }
+
+ void commit(BlazeWizardUserSettings userSettings) {
+ this.state = userSettings;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/CopyExternalProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/CopyExternalProjectViewOption.java
new file mode 100644
index 0000000..437f736
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/CopyExternalProjectViewOption.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDialog;
+import com.intellij.openapi.fileChooser.FileChooserFactory;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.awt.Dimension;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import javax.annotation.Nullable;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+class CopyExternalProjectViewOption implements BlazeSelectProjectViewOption {
+ private static final String LAST_WORKSPACE_PATH = "copy-external.last-project-view-path";
+
+ final BlazeWizardUserSettings userSettings;
+ final JComponent component;
+ final JTextField projectViewPathField;
+
+ CopyExternalProjectViewOption(BlazeNewProjectBuilder builder) {
+ this.userSettings = builder.getUserSettings();
+
+ String defaultWorkspacePath = userSettings.get(LAST_WORKSPACE_PATH, "");
+ this.projectViewPathField = new JTextField(defaultWorkspacePath);
+
+ JButton button = new JButton("...");
+ button.addActionListener(action -> chooseWorkspacePath());
+ int buttonSize = projectViewPathField.getPreferredSize().height;
+ button.setPreferredSize(new Dimension(buttonSize, buttonSize));
+
+ JComponent box =
+ UiUtil.createHorizontalBox(
+ HORIZONTAL_LAYOUT_GAP, new JLabel("Project view:"), projectViewPathField, button);
+ UiUtil.setPreferredWidth(box, PREFERRED_COMPONENT_WIDTH);
+ this.component = box;
+ }
+
+ @Override
+ public String getOptionName() {
+ return "copy-external";
+ }
+
+ @Override
+ public String getOptionText() {
+ return "Copy external";
+ }
+
+ @Override
+ public JComponent getUiComponent() {
+ return component;
+ }
+
+ @Override
+ public BlazeValidationResult validate() {
+ if (getProjectViewPath().isEmpty()) {
+ return BlazeValidationResult.failure("Path to project view file cannot be empty.");
+ }
+ File file = new File(getProjectViewPath());
+ if (!file.exists()) {
+ return BlazeValidationResult.failure("Project view file does not exist.");
+ }
+ return BlazeValidationResult.success();
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getSharedProjectView() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getInitialProjectViewText() {
+ try {
+ byte[] bytes = Files.readAllBytes(Paths.get(getProjectViewPath()));
+ return new String(bytes, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public void commit() {
+ userSettings.put(LAST_WORKSPACE_PATH, getProjectViewPath());
+ }
+
+ private String getProjectViewPath() {
+ return projectViewPathField.getText().trim();
+ }
+
+ private void chooseWorkspacePath() {
+ FileChooserDescriptor descriptor =
+ new FileChooserDescriptor(true, false, false, false, false, false)
+ .withShowHiddenFiles(true) // Show root project view file
+ .withHideIgnored(false)
+ .withTitle("Select Project View File")
+ .withDescription("Select a project view file to import.")
+ .withFileFilter(
+ virtualFile ->
+ ProjectViewStorageManager.isProjectViewFile(new File(virtualFile.getPath())));
+ FileChooserDialog chooser =
+ FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
+
+ File startingLocation = null;
+ String projectViewPath = getProjectViewPath();
+ if (!projectViewPath.isEmpty()) {
+ File fileLocation = new File(projectViewPath);
+ if (fileLocation.exists()) {
+ startingLocation = fileLocation;
+ }
+ }
+ final VirtualFile[] files;
+ if (startingLocation != null) {
+ VirtualFile toSelect =
+ LocalFileSystem.getInstance().refreshAndFindFileByPath(startingLocation.getPath());
+ files = chooser.choose(null, toSelect);
+ } else {
+ files = chooser.choose(null);
+ }
+ if (files.length == 0) {
+ return;
+ }
+ VirtualFile file = files[0];
+ projectViewPathField.setText(file.getPath());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/CreateFromScratchProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/CreateFromScratchProjectViewOption.java
new file mode 100644
index 0000000..d886175
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/CreateFromScratchProjectViewOption.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import javax.annotation.Nullable;
+import javax.swing.JComponent;
+
+class CreateFromScratchProjectViewOption implements BlazeSelectProjectViewOption {
+ @Override
+ public String getOptionName() {
+ return "create-from-scratch";
+ }
+
+ @Override
+ public String getOptionText() {
+ return "Create from scratch";
+ }
+
+ @Override
+ public JComponent getUiComponent() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getSharedProjectView() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getInitialProjectViewText() {
+ return "";
+ }
+
+ @Override
+ public void commit() {}
+
+ @Override
+ public BlazeValidationResult validate() {
+ return BlazeValidationResult.success();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
new file mode 100644
index 0000000..9826c2a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlock;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDialog;
+import com.intellij.openapi.fileChooser.FileChooserFactory;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.awt.Dimension;
+import java.io.File;
+import javax.annotation.Nullable;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+class GenerateFromBuildFileSelectProjectViewOption implements BlazeSelectProjectViewOption {
+ private static final String LAST_WORKSPACE_PATH = "generate-from-build-file.last-workspace-path";
+ private final BlazeNewProjectBuilder builder;
+ private final BlazeWizardUserSettings userSettings;
+ private final JTextField buildFilePathField;
+ private final JComponent component;
+
+ public GenerateFromBuildFileSelectProjectViewOption(BlazeNewProjectBuilder builder) {
+ this.builder = builder;
+ this.userSettings = builder.getUserSettings();
+
+ String defaultWorkspacePath = userSettings.get(LAST_WORKSPACE_PATH, "");
+ this.buildFilePathField = new JTextField(defaultWorkspacePath);
+
+ JButton button = new JButton("...");
+ button.addActionListener(action -> chooseWorkspacePath());
+ int buttonSize = buildFilePathField.getPreferredSize().height;
+ button.setPreferredSize(new Dimension(buttonSize, buttonSize));
+
+ JComponent box =
+ UiUtil.createHorizontalBox(
+ HORIZONTAL_LAYOUT_GAP, new JLabel("BUILD file:"), buildFilePathField, button);
+ UiUtil.setPreferredWidth(box, PREFERRED_COMPONENT_WIDTH);
+ this.component = box;
+ }
+
+ @Override
+ public String getOptionName() {
+ return "generate-from-build-file";
+ }
+
+ @Override
+ public String getOptionText() {
+ return "Generate from BUILD file";
+ }
+
+ @Override
+ public JComponent getUiComponent() {
+ return component;
+ }
+
+ @Override
+ public BlazeValidationResult validate() {
+ if (getBuildFilePath().isEmpty()) {
+ return BlazeValidationResult.failure("BUILD file field cannot be empty.");
+ }
+ WorkspaceRoot temporaryWorkspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
+ File file = temporaryWorkspaceRoot.fileForPath(new WorkspacePath(getBuildFilePath()));
+ if (!file.exists()) {
+ return BlazeValidationResult.failure("BUILD file does not exist.");
+ }
+
+ return BlazeValidationResult.success();
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getSharedProjectView() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getInitialProjectViewText() {
+ WorkspaceRoot temporaryWorkspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
+ WorkspacePath workspacePath = new WorkspacePath(getBuildFilePath());
+ return guessProjectViewFromLocation(
+ temporaryWorkspaceRoot,
+ temporaryWorkspaceRoot.workspacePathFor(
+ temporaryWorkspaceRoot.fileForPath(workspacePath).getParentFile()));
+ }
+
+ @Override
+ public void commit() {
+ userSettings.put(LAST_WORKSPACE_PATH, getBuildFilePath());
+ }
+
+ private static String guessProjectViewFromLocation(
+ WorkspaceRoot workspaceRoot, WorkspacePath workspacePath) {
+
+ WorkspacePath mainModuleWorkspaceRelativePath = workspacePath;
+ WorkspacePath testModuleWorkspaceRelativePath =
+ guessTestRelativePath(workspaceRoot, mainModuleWorkspaceRelativePath);
+
+ ListSection.Builder<DirectoryEntry> directorySectionBuilder =
+ ListSection.builder(DirectorySection.KEY);
+ directorySectionBuilder.add(DirectoryEntry.include(mainModuleWorkspaceRelativePath));
+ if (testModuleWorkspaceRelativePath != null) {
+ directorySectionBuilder.add(DirectoryEntry.include(testModuleWorkspaceRelativePath));
+ }
+
+ ListSection.Builder<TargetExpression> targetSectionBuilder =
+ ListSection.builder(TargetSection.KEY);
+ targetSectionBuilder.add(
+ TargetExpression.allFromPackageRecursive(mainModuleWorkspaceRelativePath));
+ if (testModuleWorkspaceRelativePath != null) {
+ targetSectionBuilder.add(
+ TargetExpression.allFromPackageRecursive(testModuleWorkspaceRelativePath));
+ }
+
+ return ProjectViewParser.projectViewToString(
+ ProjectView.builder()
+ .add(directorySectionBuilder)
+ .add(TextBlockSection.of(TextBlock.newLine()))
+ .add(targetSectionBuilder)
+ .build());
+ }
+
+ @Nullable
+ private static WorkspacePath guessTestRelativePath(
+ WorkspaceRoot workspaceRoot, WorkspacePath projectWorkspacePath) {
+ String projectRelativePath = projectWorkspacePath.relativePath();
+ String testBuildFileRelativePath = null;
+ if (projectRelativePath.startsWith("java/")) {
+ testBuildFileRelativePath = projectRelativePath.replaceFirst("java/", "javatests/");
+ } else if (projectRelativePath.contains("/java/")) {
+ testBuildFileRelativePath = projectRelativePath.replaceFirst("/java/", "/javatests/");
+ }
+ if (testBuildFileRelativePath != null) {
+ File testBuildFile = workspaceRoot.fileForPath(new WorkspacePath(testBuildFileRelativePath));
+ if (testBuildFile.exists()) {
+ return new WorkspacePath(testBuildFileRelativePath);
+ }
+ }
+ return null;
+ }
+
+ private String getBuildFilePath() {
+ return buildFilePathField.getText().trim();
+ }
+
+ private void chooseWorkspacePath() {
+ FileChooserDescriptor descriptor =
+ new FileChooserDescriptor(true, false, false, false, false, false)
+ .withShowHiddenFiles(true) // Show root project view file
+ .withHideIgnored(false)
+ .withTitle("Select BUILD File")
+ .withDescription("Select a BUILD file to synthesize a project view from.")
+ .withFileFilter(virtualFile -> virtualFile.getName().equals("BUILD"));
+ FileChooserDialog chooser =
+ FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
+
+ WorkspaceRoot temporaryWorkspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
+
+ File startingLocation = temporaryWorkspaceRoot.directory();
+ String buildFilePath = getBuildFilePath();
+ if (!buildFilePath.isEmpty()) {
+ File fileLocation = temporaryWorkspaceRoot.fileForPath(new WorkspacePath(buildFilePath));
+ if (fileLocation.exists()) {
+ startingLocation = fileLocation;
+ }
+ }
+ VirtualFile toSelect =
+ LocalFileSystem.getInstance().refreshAndFindFileByPath(startingLocation.getPath());
+ VirtualFile[] files = chooser.choose(null, toSelect);
+ if (files.length == 0) {
+ return;
+ }
+ VirtualFile file = files[0];
+ String newWorkspacePath =
+ FileUtil.getRelativePath(temporaryWorkspaceRoot.directory(), new File(file.getPath()));
+ buildFilePathField.setText(newWorkspacePath);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
new file mode 100644
index 0000000..1162d05
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDialog;
+import com.intellij.openapi.fileChooser.FileChooserFactory;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.awt.Dimension;
+import java.io.File;
+import javax.annotation.Nullable;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+class ImportFromWorkspaceProjectViewOption implements BlazeSelectProjectViewOption {
+ private static final String LAST_WORKSPACE_PATH = "import-from-workspace.last-workspace-path";
+
+ final BlazeNewProjectBuilder builder;
+ final BlazeWizardUserSettings userSettings;
+ final JComponent component;
+ final JTextField projectViewPathField;
+
+ ImportFromWorkspaceProjectViewOption(BlazeNewProjectBuilder builder) {
+ this.builder = builder;
+ this.userSettings = builder.getUserSettings();
+
+ String defaultWorkspacePath = userSettings.get(LAST_WORKSPACE_PATH, "");
+ this.projectViewPathField = new JTextField(defaultWorkspacePath);
+
+ JButton button = new JButton("...");
+ button.addActionListener(action -> chooseWorkspacePath());
+ int buttonSize = projectViewPathField.getPreferredSize().height;
+ button.setPreferredSize(new Dimension(buttonSize, buttonSize));
+
+ JComponent box =
+ UiUtil.createHorizontalBox(
+ HORIZONTAL_LAYOUT_GAP, new JLabel("Project view:"), projectViewPathField, button);
+ UiUtil.setPreferredWidth(box, PREFERRED_COMPONENT_WIDTH);
+ this.component = box;
+ }
+
+ @Override
+ public String getOptionName() {
+ return "import-from-workspace";
+ }
+
+ @Override
+ public String getOptionText() {
+ return "Import from workspace";
+ }
+
+ @Override
+ public JComponent getUiComponent() {
+ return component;
+ }
+
+ @Override
+ public BlazeValidationResult validate() {
+ if (getProjectViewPath().isEmpty()) {
+ return BlazeValidationResult.failure("Workspace path to project view file cannot be empty.");
+ }
+ WorkspaceRoot temporaryWorkspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
+ File file = temporaryWorkspaceRoot.fileForPath(getSharedProjectView());
+ if (!file.exists()) {
+ return BlazeValidationResult.failure("Project view file does not exist.");
+ }
+
+ return BlazeValidationResult.success();
+ }
+
+ @Nullable
+ @Override
+ public WorkspacePath getSharedProjectView() {
+ return new WorkspacePath(getProjectViewPath());
+ }
+
+ @Nullable
+ @Override
+ public String getInitialProjectViewText() {
+ return null;
+ }
+
+ @Override
+ public void commit() {
+ userSettings.put(LAST_WORKSPACE_PATH, getProjectViewPath());
+ }
+
+ private String getProjectViewPath() {
+ return projectViewPathField.getText().trim();
+ }
+
+ private void chooseWorkspacePath() {
+ FileChooserDescriptor descriptor =
+ new FileChooserDescriptor(true, false, false, false, false, false)
+ .withShowHiddenFiles(true) // Show root project view file
+ .withHideIgnored(false)
+ .withTitle("Select Project View File")
+ .withDescription("Select a project view file to import.")
+ .withFileFilter(
+ virtualFile ->
+ ProjectViewStorageManager.isProjectViewFile(new File(virtualFile.getPath())));
+ FileChooserDialog chooser =
+ FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
+
+ WorkspaceRoot temporaryWorkspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
+
+ File startingLocation = temporaryWorkspaceRoot.directory();
+ String projectViewPath = getProjectViewPath();
+ if (!projectViewPath.isEmpty()) {
+ // Avoid exception -- workspace paths cannot end with trailing slash
+ projectViewPath = StringUtil.trimEnd(projectViewPath, '/');
+
+ File fileLocation = temporaryWorkspaceRoot.fileForPath(new WorkspacePath(projectViewPath));
+ if (fileLocation.exists()) {
+ startingLocation = fileLocation;
+ }
+ }
+ VirtualFile toSelect =
+ LocalFileSystem.getInstance().refreshAndFindFileByPath(startingLocation.getPath());
+ VirtualFile[] files = chooser.choose(null, toSelect);
+ if (files.length == 0) {
+ return;
+ }
+ VirtualFile file = files[0];
+
+ if (!FileUtil.isAncestor(temporaryWorkspaceRoot.directory().getPath(), file.getPath(), true)) {
+ Messages.showErrorDialog(
+ String.format(
+ "You must choose a project view file under %s. "
+ + "To use an external project view, please use the 'Copy external' option.",
+ temporaryWorkspaceRoot.directory().getPath()),
+ "Cannot Use Project View File");
+ return;
+ }
+
+ String newWorkspacePath =
+ FileUtil.getRelativePath(temporaryWorkspaceRoot.directory(), new File(file.getPath()));
+ projectViewPathField.setText(newWorkspacePath);
+ }
+}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/README b/base/src/com/google/idea/blaze/base/wizard2/README
similarity index 100%
rename from blaze-base/src/com/google/idea/blaze/base/wizard2/README
rename to base/src/com/google/idea/blaze/base/wizard2/README
diff --git a/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java b/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
new file mode 100644
index 0000000..c810f64
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import icons.BlazeIcons;
+import java.io.File;
+import javax.swing.Icon;
+
+class UseExistingBazelWorkspaceOption extends UseExistingWorkspaceOption {
+
+ UseExistingBazelWorkspaceOption(BlazeNewProjectBuilder builder) {
+ super(builder, BuildSystem.Bazel);
+ }
+
+ @Override
+ protected boolean isWorkspaceRoot(File file) {
+ return BuildSystemProvider.getWorkspaceRootProvider(BuildSystem.Bazel).isWorkspaceRoot(file);
+ }
+
+ @Override
+ protected BlazeValidationResult validateWorkspaceRoot(File workspaceRoot) {
+ if (!isWorkspaceRoot(workspaceRoot)) {
+ return BlazeValidationResult.failure(
+ "Invalid workspace root: choose a bazel workspace directory "
+ + "(containing a WORKSPACE file)");
+ }
+ return BlazeValidationResult.success();
+ }
+
+ @Override
+ public String getOptionName() {
+ return "use-existing-bazel-workspace";
+ }
+
+ @Override
+ public String getOptionText() {
+ return "Use existing bazel workspace";
+ }
+
+ @Override
+ protected String getWorkspaceName(File workspaceRoot) {
+ return workspaceRoot.getName();
+ }
+
+ @Override
+ protected String fileChooserDescription() {
+ return "Select the directory of the workspace you want to use.";
+ }
+
+ @Override
+ protected Icon getBuildSystemIcon() {
+ return BlazeIcons.BazelLeaf;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/UseExistingWorkspaceOption.java b/base/src/com/google/idea/blaze/base/wizard2/UseExistingWorkspaceOption.java
new file mode 100644
index 0000000..9d18f4e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/UseExistingWorkspaceOption.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDialog;
+import com.intellij.openapi.fileChooser.FileChooserFactory;
+import com.intellij.openapi.util.IconLoader;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.awt.Dimension;
+import java.io.File;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+/** Option to use an existing workspace */
+public abstract class UseExistingWorkspaceOption implements BlazeSelectWorkspaceOption {
+
+ private final BlazeWizardUserSettings userSettings;
+ private final JComponent component;
+ private final JTextField directoryField;
+ private final BuildSystem buildSystem;
+
+ protected UseExistingWorkspaceOption(BlazeNewProjectBuilder builder, BuildSystem buildSystem) {
+ this.userSettings = builder.getUserSettings();
+ this.buildSystem = buildSystem;
+
+ String defaultDirectory =
+ userSettings.get(BlazeNewProjectBuilder.lastImportedWorkspaceKey(buildSystem), "");
+
+ this.directoryField = new JTextField(defaultDirectory);
+
+ JButton button = new JButton("...");
+ button.addActionListener(action -> chooseDirectory());
+ int buttonSize = directoryField.getPreferredSize().height;
+ button.setPreferredSize(new Dimension(buttonSize, buttonSize));
+
+ JComponent box =
+ UiUtil.createHorizontalBox(
+ HORIZONTAL_LAYOUT_GAP,
+ getIconComponent(),
+ new JLabel("Workspace:"),
+ directoryField,
+ button);
+ UiUtil.setPreferredWidth(box, PREFERRED_COMPONENT_WIDTH);
+ this.component = box;
+ }
+
+ protected abstract boolean isWorkspaceRoot(File file);
+
+ protected abstract BlazeValidationResult validateWorkspaceRoot(File workspaceRoot);
+
+ private boolean isWorkspaceRoot(VirtualFile file) {
+ return isWorkspaceRoot(new File(file.getPath()));
+ }
+
+ protected abstract String fileChooserDescription();
+
+ protected abstract Icon getBuildSystemIcon();
+
+ protected abstract String getWorkspaceName(File workspaceRoot);
+
+ @Override
+ public BuildSystem getBuildSystemForWorkspace() {
+ return buildSystem;
+ }
+
+ @Override
+ public JComponent getUiComponent() {
+ return component;
+ }
+
+ @Override
+ public void commit() throws BlazeProjectCommitException {}
+
+ @Override
+ public WorkspaceRoot getWorkspaceRoot() {
+ return new WorkspaceRoot(new File(getDirectory()));
+ }
+
+ @Nullable
+ @Override
+ public WorkspaceRoot getTemporaryWorkspaceRoot() {
+ return getWorkspaceRoot();
+ }
+
+ @Override
+ public String getWorkspaceName() {
+ File workspaceRoot = new File(getDirectory());
+ return getWorkspaceName(workspaceRoot);
+ }
+
+ @Override
+ public BlazeValidationResult validate() {
+ if (getDirectory().isEmpty()) {
+ return BlazeValidationResult.failure("Please select a workspace");
+ }
+
+ File workspaceRootFile = new File(getDirectory());
+ if (!workspaceRootFile.exists()) {
+ return BlazeValidationResult.failure("Workspace does not exist");
+ }
+
+ WorkspaceRoot workspaceRoot = new WorkspaceRoot(workspaceRootFile);
+ boolean hasVcsHandler =
+ Arrays.stream(BlazeVcsHandler.EP_NAME.getExtensions())
+ .anyMatch(vcsHandler -> vcsHandler.handlesProject(buildSystem, workspaceRoot));
+ if (!hasVcsHandler) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Workspace is not of a supported VCS type. ");
+ sb.append("VCS types considered were: ");
+ Joiner.on(", ")
+ .appendTo(
+ sb,
+ Arrays.stream(BlazeVcsHandler.EP_NAME.getExtensions())
+ .map(BlazeVcsHandler::getVcsName)
+ .collect(Collectors.toList()));
+ return BlazeValidationResult.failure(sb.toString());
+ }
+
+ return validateWorkspaceRoot(workspaceRootFile);
+ }
+
+ private String getDirectory() {
+ return directoryField.getText().trim();
+ }
+
+ private void chooseDirectory() {
+ FileChooserDescriptor descriptor =
+ new FileChooserDescriptor(false, true, false, false, false, false) {
+ @Override
+ public boolean isFileSelectable(VirtualFile file) {
+ // Default implementation doesn't filter directories,
+ // we want to make sure only workspace roots are selectable
+ return super.isFileSelectable(file) && isWorkspaceRoot(file);
+ }
+
+ @Override
+ public Icon getIcon(VirtualFile file) {
+ if (buildSystem == BuildSystem.Bazel) {
+ // isWorkspaceRoot requires file system calls -- it's too expensive
+ return super.getIcon(file);
+ }
+ if (isWorkspaceRoot(file)) {
+ return AllIcons.Nodes.SourceFolder;
+ }
+ return super.getIcon(file);
+ }
+ }.withHideIgnored(false)
+ .withTitle("Select Workspace Root")
+ .withDescription(fileChooserDescription())
+ .withFileFilter(this::isWorkspaceRoot);
+ FileChooserDialog chooser =
+ FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
+
+ final VirtualFile[] files;
+ File existingLocation = new File(getDirectory());
+ if (existingLocation.exists()) {
+ VirtualFile toSelect =
+ LocalFileSystem.getInstance().refreshAndFindFileByPath(existingLocation.getPath());
+ files = chooser.choose(null, toSelect);
+ } else {
+ files = chooser.choose(null);
+ }
+ if (files.length == 0) {
+ return;
+ }
+ VirtualFile file = files[0];
+ directoryField.setText(file.getPath());
+ }
+
+ private JComponent getIconComponent() {
+ JLabel iconPanel =
+ new JLabel(IconLoader.getIconSnapshot(getBuildSystemIcon())) {
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+ };
+ UiUtil.setPreferredWidth(iconPanel, 16);
+ return iconPanel;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java
new file mode 100644
index 0000000..de7e373
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2.ui;
+
+import com.google.common.collect.Lists;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hashing;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.sections.ImportSection;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.settings.ui.JPanelProvidingProject;
+import com.google.idea.blaze.base.settings.ui.ProjectViewUi;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.BlazeSelectProjectViewOption;
+import com.google.idea.blaze.base.wizard2.BlazeSelectWorkspaceOption;
+import com.intellij.ide.RecentProjectsManager;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationNamesInfo;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.ui.TextComponentAccessor;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.util.SystemProperties;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import org.jetbrains.annotations.Nullable;
+
+/** The UI control to collect project settings when importing a Blaze project. */
+public final class BlazeEditProjectViewControl {
+
+ private static final FileChooserDescriptor PROJECT_FOLDER_DESCRIPTOR =
+ new FileChooserDescriptor(false, true, false, false, false, false);
+ private static final Logger LOG = Logger.getInstance(BlazeEditProjectViewControl.class);
+
+ private final JPanel component;
+ private final String buildSystemName;
+ private final ProjectViewUi projectViewUi;
+
+ private TextFieldWithBrowseButton projectDataDirField;
+ private JTextField projectNameField;
+ private HashCode paramsHash;
+ private WorkspaceRoot workspaceRoot;
+
+ public BlazeEditProjectViewControl(BlazeNewProjectBuilder builder, Disposable parentDisposable) {
+ this.projectViewUi = new ProjectViewUi(parentDisposable);
+ JPanel component = new JPanelProvidingProject(ProjectViewUi.getProject(), new GridBagLayout());
+ fillUi(component, 0);
+ update(builder);
+ UiUtil.fillBottom(component);
+ this.component = component;
+ this.buildSystemName = builder.getBuildSystemName();
+ }
+
+ public Component getUiComponent() {
+ return component;
+ }
+
+ private void fillUi(JPanel canvas, int indentLevel) {
+ JLabel projectDataDirLabel = new JBLabel("Project data directory:");
+
+ Dimension minSize = ProjectViewUi.getMinimumSize();
+ // Add 120 pixels so we have room for our extra fields
+ minSize.setSize(minSize.width, minSize.height + 120);
+ canvas.setMinimumSize(minSize);
+ canvas.setPreferredSize(minSize);
+
+ projectDataDirField = new TextFieldWithBrowseButton();
+ projectDataDirField.addBrowseFolderListener(
+ "",
+ buildSystemName + " project data directory",
+ null,
+ PROJECT_FOLDER_DESCRIPTOR,
+ TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT,
+ false);
+ final String dataDirToolTipText =
+ "Directory in which to store the project's metadata. "
+ + "Choose a directory outside of your workspace.";
+ projectDataDirField.setToolTipText(dataDirToolTipText);
+ projectDataDirLabel.setToolTipText(dataDirToolTipText);
+
+ canvas.add(projectDataDirLabel, UiUtil.getLabelConstraints(indentLevel));
+ canvas.add(projectDataDirField, UiUtil.getFillLineConstraints(0));
+
+ JLabel projectNameLabel = new JLabel("Project name:");
+ projectNameField = new JTextField();
+ final String projectNameToolTipText = "Project display name.";
+ projectNameField.setToolTipText(projectNameToolTipText);
+ projectNameLabel.setToolTipText(projectNameToolTipText);
+ canvas.add(projectNameLabel, UiUtil.getLabelConstraints(indentLevel));
+ canvas.add(projectNameField, UiUtil.getFillLineConstraints(0));
+
+ projectViewUi.fillUi(canvas, indentLevel);
+ }
+
+ public void update(BlazeNewProjectBuilder builder) {
+ BlazeSelectWorkspaceOption workspaceOption = builder.getWorkspaceOption();
+ BlazeSelectProjectViewOption projectViewOption = builder.getProjectViewOption();
+ String workspaceName = workspaceOption.getWorkspaceName();
+ WorkspaceRoot workspaceRoot = workspaceOption.getWorkspaceRoot();
+ WorkspaceRoot temporaryWorkspaceRoot = workspaceOption.getTemporaryWorkspaceRoot();
+ WorkspacePath workspacePath = projectViewOption.getSharedProjectView();
+ String initialProjectViewText = projectViewOption.getInitialProjectViewText();
+
+ HashCode hashCode =
+ Hashing.md5()
+ .newHasher()
+ .putUnencodedChars(workspaceName)
+ .putUnencodedChars(workspaceRoot.toString())
+ .putUnencodedChars(temporaryWorkspaceRoot.toString())
+ .putUnencodedChars(workspacePath != null ? workspacePath.toString() : "")
+ .putUnencodedChars(initialProjectViewText != null ? initialProjectViewText : "")
+ .hash();
+
+ // If any params have changed, reinit the control
+ if (!hashCode.equals(paramsHash)) {
+ this.paramsHash = hashCode;
+ init(
+ workspaceName,
+ workspaceRoot,
+ temporaryWorkspaceRoot,
+ workspacePath,
+ initialProjectViewText);
+ }
+ }
+
+ private void init(
+ String workspaceName,
+ WorkspaceRoot workspaceRoot,
+ WorkspaceRoot temporaryWorkspaceRoot,
+ @Nullable WorkspacePath sharedProjectView,
+ @Nullable String initialProjectViewText) {
+ this.workspaceRoot = workspaceRoot;
+ projectNameField.setText(workspaceName);
+ String defaultDataDir = getDefaultProjectDataDirectory(workspaceName);
+ projectDataDirField.setText(defaultDataDir);
+
+ String projectViewText = "";
+ File sharedProjectViewFile = null;
+
+ if (sharedProjectView != null) {
+ sharedProjectViewFile = temporaryWorkspaceRoot.fileForPath(sharedProjectView);
+
+ try {
+ projectViewText =
+ ProjectViewStorageManager.getInstance().loadProjectView(sharedProjectViewFile);
+ if (projectViewText == null) {
+ LOG.error("Could not load project view: " + sharedProjectViewFile);
+ projectViewText = "";
+ }
+ } catch (IOException e) {
+ LOG.error(e);
+ }
+ } else {
+ projectViewText = initialProjectViewText;
+ LOG.assertTrue(projectViewText != null);
+ }
+
+ projectViewUi.init(
+ temporaryWorkspaceRoot,
+ projectViewText,
+ sharedProjectViewFile != null ? projectViewText : null,
+ sharedProjectViewFile,
+ sharedProjectViewFile != null,
+ false /* allowEditShared - not allowed during import */);
+ }
+
+ private static String getDefaultProjectDataDirectory(String projectName) {
+ File defaultDataDirectory = new File(getDefaultProjectsDirectory());
+ File desiredLocation = new File(defaultDataDirectory, projectName);
+ return newUniquePath(desiredLocation);
+ }
+
+ private static String getDefaultProjectsDirectory() {
+ final String lastProjectLocation =
+ RecentProjectsManager.getInstance().getLastProjectCreationLocation();
+ if (lastProjectLocation != null) {
+ return lastProjectLocation.replace('/', File.separatorChar);
+ }
+ final String userHome = SystemProperties.getUserHome();
+ String productName = ApplicationNamesInfo.getInstance().getLowercaseProductName();
+ return userHome.replace('/', File.separatorChar)
+ + File.separator
+ + productName.replace(" ", "")
+ + "Projects";
+ }
+
+ /** Returns a unique file path by appending numbers until a non-collision is found. */
+ private static String newUniquePath(File location) {
+ if (!location.exists()) {
+ return location.getAbsolutePath();
+ }
+
+ String name = location.getName();
+ File directory = location.getParentFile();
+ int tries = 0;
+ while (true) {
+ String candidateName = String.format("%s-%02d", name, tries);
+ File candidateFile = new File(directory, candidateName);
+ if (!candidateFile.exists()) {
+ return candidateFile.getAbsolutePath();
+ }
+ tries++;
+ }
+ }
+
+ public BlazeValidationResult validate() {
+ // Validate project settings fields
+ String projectName = projectNameField.getText().trim();
+ if (StringUtil.isEmpty(projectName)) {
+ return BlazeValidationResult.failure(
+ new BlazeValidationError("Project name is not specified"));
+ }
+ String projectDataDirPath = projectDataDirField.getText().trim();
+ if (StringUtil.isEmpty(projectDataDirPath)) {
+ return BlazeValidationResult.failure(
+ new BlazeValidationError("Project data directory is not specified"));
+ }
+ File projectDataDir = new File(projectDataDirPath);
+ if (!projectDataDir.isAbsolute()) {
+ return BlazeValidationResult.failure(
+ new BlazeValidationError("Project data directory is not valid"));
+ }
+ File workspaceRootDirectory = workspaceRoot.directory();
+ if (FileUtil.isAncestor(projectDataDir, workspaceRootDirectory, false)) {
+ return BlazeValidationResult.failure(
+ new BlazeValidationError(
+ "Project data directory must not contain the workspace. "
+ + "Please choose a directory outside your workspace."));
+ }
+ if (FileUtil.isAncestor(workspaceRootDirectory, projectDataDir, false)) {
+ return BlazeValidationResult.failure(
+ new BlazeValidationError(
+ "Project data directory cannot be inside your workspace. "
+ + "Please choose a directory outside your workspace."));
+ }
+
+ List<IssueOutput> issues = Lists.newArrayList();
+
+ projectViewUi.parseProjectView(issues);
+ BlazeValidationError projectViewParseError = validationErrorFromIssueList(issues);
+ if (projectViewParseError != null) {
+ return BlazeValidationResult.failure(projectViewParseError);
+ }
+
+ return BlazeValidationResult.success();
+ }
+
+ @Nullable
+ private static BlazeValidationError validationErrorFromIssueList(List<IssueOutput> issues) {
+ List<IssueOutput> errors =
+ issues
+ .stream()
+ .filter(issue -> issue.getCategory() == IssueOutput.Category.ERROR)
+ .collect(Collectors.toList());
+
+ if (!errors.isEmpty()) {
+ StringBuilder errorMessage = new StringBuilder();
+ errorMessage.append("The following issues were found:\n\n");
+ for (IssueOutput issue : errors) {
+ errorMessage.append(issue.getMessage());
+ errorMessage.append('\n');
+ }
+ return new BlazeValidationError(errorMessage.toString());
+ }
+ return null;
+ }
+
+ public void updateBuilder(BlazeNewProjectBuilder builder) {
+ String projectName = projectNameField.getText().trim();
+ String projectDataDirectory = projectDataDirField.getText().trim();
+ File localProjectViewFile =
+ ProjectViewStorageManager.getLocalProjectViewFileName(
+ builder.getBuildSystem(), new File(projectDataDirectory));
+
+ BlazeSelectProjectViewOption selectProjectViewOption = builder.getProjectViewOption();
+ boolean useSharedProjectView = projectViewUi.getUseSharedProjectView();
+
+ // If we're using a shared project view, synthesize a local one that imports the shared one
+ ProjectViewSet parseResult = projectViewUi.parseProjectView(Lists.newArrayList());
+
+ final ProjectView projectView;
+ final ProjectViewSet projectViewSet;
+ if (useSharedProjectView && selectProjectViewOption.getSharedProjectView() != null) {
+ projectView =
+ ProjectView.builder()
+ .add(
+ ScalarSection.builder(ImportSection.KEY)
+ .set(selectProjectViewOption.getSharedProjectView()))
+ .build();
+ projectViewSet =
+ ProjectViewSet.builder()
+ .addAll(parseResult.getProjectViewFiles())
+ .add(localProjectViewFile, projectView)
+ .build();
+ } else {
+ ProjectViewSet.ProjectViewFile projectViewFile = parseResult.getTopLevelProjectViewFile();
+ assert projectViewFile != null;
+ projectView = projectViewFile.projectView;
+ projectViewSet = parseResult;
+ }
+
+ builder
+ .setProjectView(projectView)
+ .setProjectViewFile(localProjectViewFile)
+ .setProjectViewSet(projectViewSet)
+ .setProjectName(projectName)
+ .setProjectDataDirectory(projectDataDirectory);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectOptionControl.java b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectOptionControl.java
new file mode 100644
index 0000000..a79644d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectOptionControl.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2.ui;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.settings.ui.ProjectViewUi;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.BlazeWizardOption;
+import com.google.idea.blaze.base.wizard2.BlazeWizardUserSettings;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.ui.components.panels.HorizontalLayout;
+import com.intellij.ui.components.panels.VerticalLayout;
+import java.awt.Dimension;
+import java.util.Collection;
+import javax.swing.ButtonGroup;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSeparator;
+import javax.swing.border.EmptyBorder;
+
+/** UI for selecting a client during the import process. */
+public abstract class BlazeSelectOptionControl<T extends BlazeWizardOption> {
+ private static final Logger LOG = Logger.getInstance(BlazeSelectOptionControl.class);
+
+ private final BlazeWizardUserSettings userSettings;
+ private final JPanel canvas;
+ private final JLabel titleLabel;
+ private final Collection<OptionUiEntry<T>> optionUiEntryList;
+
+ static class OptionUiEntry<T> {
+ final T option;
+ final JRadioButton radioButton;
+
+ OptionUiEntry(T option, JRadioButton radioButton) {
+ this.option = option;
+ this.radioButton = radioButton;
+ }
+ }
+
+ BlazeSelectOptionControl(BlazeNewProjectBuilder builder, Collection<T> options) {
+ if (options == null) {
+ LOG.error("No options on select screen '" + getTitle() + "'");
+ }
+
+ this.userSettings = builder.getUserSettings();
+
+ JPanel canvas = new JPanel(new VerticalLayout(4));
+
+ Dimension minSize = ProjectViewUi.getMinimumSize();
+ canvas.setPreferredSize(minSize);
+
+ titleLabel = new JLabel(getTitle());
+ canvas.add(titleLabel);
+ canvas.add(new JSeparator());
+
+ JPanel content = new JPanel(new VerticalLayout(12));
+ content.setBorder(new EmptyBorder(20, 100, 0, 0));
+ canvas.add(content);
+
+ ButtonGroup buttonGroup = new ButtonGroup();
+ Collection<OptionUiEntry<T>> optionUiEntryList = Lists.newArrayList();
+ for (T option : options) {
+ JPanel vertical = new JPanel(new VerticalLayout(10));
+ JRadioButton radioButton = new JRadioButton();
+ radioButton.setText(option.getOptionText());
+ vertical.add(radioButton);
+
+ JComponent optionComponent = option.getUiComponent();
+ if (optionComponent != null) {
+ JPanel horizontal = new JPanel(new HorizontalLayout(0));
+ horizontal.setBorder(new EmptyBorder(0, 25, 0, 0));
+ horizontal.add(optionComponent);
+ vertical.add(horizontal);
+
+ option.optionDeselected();
+ radioButton.addItemListener(
+ itemEvent -> {
+ if (radioButton.isSelected()) {
+ option.optionSelected();
+ } else {
+ option.optionDeselected();
+ }
+ });
+ }
+
+ content.add(vertical);
+ buttonGroup.add(radioButton);
+ optionUiEntryList.add(new OptionUiEntry<>(option, radioButton));
+ }
+
+ OptionUiEntry selected = null;
+ String previouslyChosenOption = userSettings.get(getOptionKey(), null);
+ if (previouslyChosenOption != null) {
+ for (OptionUiEntry<T> entry : optionUiEntryList) {
+ if (entry.option.getOptionName().equals(previouslyChosenOption)) {
+ selected = entry;
+ break;
+ }
+ }
+ }
+ if (selected == null) {
+ selected = Iterables.getFirst(optionUiEntryList, null);
+ }
+ if (selected != null) {
+ selected.radioButton.setSelected(true);
+ }
+
+ this.canvas = canvas;
+ this.optionUiEntryList = optionUiEntryList;
+ }
+
+ public BlazeValidationResult validate() {
+ T option = getSelectedOption();
+ if (option == null) {
+ return BlazeValidationResult.failure("No option selected.");
+ }
+ return option.validate();
+ }
+
+ public JComponent getUiComponent() {
+ return canvas;
+ }
+
+ public T getSelectedOption() {
+ for (OptionUiEntry<T> entry : optionUiEntryList) {
+ if (entry.radioButton.isSelected()) {
+ return entry.option;
+ }
+ }
+ return null;
+ }
+
+ public void commit() {
+ T selectedOption = getSelectedOption();
+ if (selectedOption != null) {
+ userSettings.put(getOptionKey(), selectedOption.getOptionName());
+ }
+ }
+
+ /** Call when the title changes. */
+ protected void setTitle(String newTitle) {
+ titleLabel.setText(newTitle);
+ }
+
+ abstract String getTitle();
+
+ abstract String getOptionKey();
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectProjectViewControl.java b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectProjectViewControl.java
new file mode 100644
index 0000000..a2b6467
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectProjectViewControl.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2.ui;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.BlazeSelectProjectViewOption;
+import com.google.idea.blaze.base.wizard2.BlazeWizardOptionProvider;
+import java.util.Collection;
+import javax.swing.JComponent;
+
+/** UI for selecting the project view during the import process. */
+public class BlazeSelectProjectViewControl {
+
+ private BlazeSelectOptionControl<BlazeSelectProjectViewOption> selectOptionControl;
+
+ public BlazeSelectProjectViewControl(BlazeNewProjectBuilder builder) {
+ Collection<BlazeSelectProjectViewOption> options = Lists.newArrayList();
+ for (BlazeWizardOptionProvider optionProvider :
+ BlazeWizardOptionProvider.EP_NAME.getExtensions()) {
+ options.addAll(optionProvider.getSelectProjectViewOptions(builder));
+ }
+
+ this.selectOptionControl =
+ new BlazeSelectOptionControl<BlazeSelectProjectViewOption>(builder, options) {
+ @Override
+ String getTitle() {
+ return BlazeSelectProjectViewControl.getTitle(builder);
+ }
+
+ @Override
+ String getOptionKey() {
+ return "select-project-view.selected-option";
+ }
+ };
+ }
+
+ public JComponent getUiComponent() {
+ return selectOptionControl.getUiComponent();
+ }
+
+ public BlazeValidationResult validate() {
+ return selectOptionControl.validate();
+ }
+
+ public void update(BlazeNewProjectBuilder builder) {
+ selectOptionControl.setTitle(getTitle(builder));
+ }
+
+ public void updateBuilder(BlazeNewProjectBuilder builder) {
+ builder.setProjectViewOption(selectOptionControl.getSelectedOption());
+ }
+
+ public void commit() {
+ selectOptionControl.commit();
+ }
+
+ private static String getTitle(BlazeNewProjectBuilder builder) {
+ String projectViewString =
+ ProjectViewStorageManager.getProjectViewFileName(builder.getBuildSystem());
+ return String.format("Select project view (%s file)", projectViewString);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectWorkspaceControl.java b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectWorkspaceControl.java
new file mode 100644
index 0000000..f0c6b45
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectWorkspaceControl.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2.ui;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.BlazeSelectWorkspaceOption;
+import com.google.idea.blaze.base.wizard2.BlazeWizardOptionProvider;
+import java.util.Collection;
+import javax.swing.JComponent;
+
+/** UI for selecting a client during the import process. */
+public class BlazeSelectWorkspaceControl {
+ BlazeSelectOptionControl<BlazeSelectWorkspaceOption> selectOptionControl;
+
+ public BlazeSelectWorkspaceControl(BlazeNewProjectBuilder builder) {
+ Collection<BlazeSelectWorkspaceOption> options = Lists.newArrayList();
+ for (BlazeWizardOptionProvider optionProvider :
+ BlazeWizardOptionProvider.EP_NAME.getExtensions()) {
+ options.addAll(optionProvider.getSelectWorkspaceOptions(builder));
+ }
+
+ this.selectOptionControl =
+ new BlazeSelectOptionControl<BlazeSelectWorkspaceOption>(builder, options) {
+ @Override
+ String getTitle() {
+ return "Select workspace";
+ }
+
+ @Override
+ String getOptionKey() {
+ return "select-workspace.selected-option";
+ }
+ };
+ }
+
+ public JComponent getUiComponent() {
+ return selectOptionControl.getUiComponent();
+ }
+
+ public BlazeValidationResult validate() {
+ return selectOptionControl.validate();
+ }
+
+ public void updateBuilder(BlazeNewProjectBuilder builder) {
+ builder.setWorkspaceOption(selectOptionControl.getSelectedOption());
+ }
+
+ public void commit() {
+ selectOptionControl.commit();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ui/SelectBazelBinaryControl.java b/base/src/com/google/idea/blaze/base/wizard2/ui/SelectBazelBinaryControl.java
new file mode 100644
index 0000000..e582c8d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/wizard2/ui/SelectBazelBinaryControl.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.wizard2.ui;
+
+import com.google.common.base.Strings;
+import com.google.idea.blaze.base.async.process.ExternalTask;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.settings.ui.BlazeUserSettingsConfigurable;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.ui.FileSelectorWithStoredHistory;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.intellij.ui.components.panels.VerticalLayout;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import javax.annotation.Nullable;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSeparator;
+import javax.swing.border.EmptyBorder;
+
+/** UI for selecting the build system binary during the import process. */
+public class SelectBazelBinaryControl {
+
+ public final BlazeNewProjectBuilder builder;
+
+ private boolean uiInitialized = false;
+ private JPanel component;
+ private FileSelectorWithStoredHistory bazelBinaryPath;
+
+ public SelectBazelBinaryControl(BlazeNewProjectBuilder builder) {
+ this.builder = builder;
+ }
+
+ public JComponent getUiComponent() {
+ if (!uiInitialized) {
+ initUi();
+ uiInitialized = true;
+ }
+ return component;
+ }
+
+ private void initUi() {
+ bazelBinaryPath =
+ FileSelectorWithStoredHistory.create(
+ BlazeUserSettingsConfigurable.BAZEL_BINARY_PATH_KEY, "Specify the bazel binary path");
+ bazelBinaryPath.setText(getInitialBinaryPath());
+
+ component = new JPanel(new VerticalLayout(4));
+ component.add(new JLabel("Select a bazel binary"));
+ component.add(new JSeparator());
+
+ JPanel content = new JPanel(new VerticalLayout(12));
+ content.setBorder(new EmptyBorder(50, 100, 0, 100));
+ component.add(content);
+
+ content.add(new JLabel("Specify a bazel binary to be used for all bazel projects"));
+ content.add(bazelBinaryPath);
+ }
+
+ public BlazeValidationResult validate() {
+ String binaryPath = getBazelPath();
+ if (Strings.isNullOrEmpty(binaryPath)) {
+ return BlazeValidationResult.failure("Select a bazel binary");
+ }
+ if (!FileAttributeProvider.getInstance().isFile(new File(binaryPath))) {
+ return BlazeValidationResult.failure("Invalid bazel binary: file does not exist");
+ }
+ return BlazeValidationResult.success();
+ }
+
+ public void commit() {
+ if (!Strings.isNullOrEmpty(getBazelPath())) {
+ BlazeUserSettings.getInstance().setBazelBinaryPath(getBazelPath());
+ }
+ }
+
+ private String getBazelPath() {
+ String text = bazelBinaryPath.getText();
+ return text != null ? text.trim() : "";
+ }
+
+ private static String getInitialBinaryPath() {
+ String existingPath = BlazeUserSettings.getInstance().getBazelBinaryPath();
+ if (existingPath != null) {
+ return existingPath;
+ }
+ return guessBinaryPath();
+ }
+
+ /** Try to guess an initial binary path */
+ @Nullable
+ private static String guessBinaryPath() {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ int retVal = ExternalTask.builder().args("which", "bazel").stdout(stdout).build().run();
+ if (retVal != 0) {
+ return null;
+ }
+ return stdout.toString().trim();
+ }
+}
diff --git a/base/src/icons/BlazeIcons.java b/base/src/icons/BlazeIcons.java
new file mode 100644
index 0000000..2e3fb4e
--- /dev/null
+++ b/base/src/icons/BlazeIcons.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 icons;
+
+import com.intellij.openapi.util.IconLoader;
+import javax.swing.Icon;
+
+/** Class to manage icons used by the Blaze plugin. */
+public class BlazeIcons {
+
+ private static final String BASE = "/";
+
+ public static final Icon Blaze = load("base/resources/icons/blaze.png"); // 16x16
+ public static final Icon BlazeSlow = load("base/resources/icons/blaze_slow.png"); // 16x16
+ public static final Icon BlazeDirty = load("base/resources/icons/blaze_dirty.png"); // 16x16
+ public static final Icon BlazeClean = load("base/resources/icons/blaze_clean.png"); // 16x16
+ public static final Icon BlazeFailed = load("base/resources/icons/blaze_failed.png"); // 16x16
+ // This is just the Blaze icon scaled down to the size IJ wants for tool windows.
+ public static final Icon BlazeToolWindow =
+ load("base/resources/icons/blazeToolWindow.png"); // 13x13
+
+ public static final Icon BazelLeaf = load("base/resources/icons/bazel_leaf.png"); // 16x16
+
+ // Build file support icons
+ public static final Icon BuildFile = load("base/resources/icons/build_file.png"); // 16x16
+ public static final Icon BuildRule = load("base/resources/icons/build_rule.png"); // 16x16
+
+ private static Icon load(String path) {
+ return IconLoader.getIcon(BASE + path, BlazeIcons.class);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributorTest.java
new file mode 100644
index 0000000..db6e935
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributorTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.testFramework.fixtures.CompletionAutoPopupTester;
+
+/** Tests for code completion of funcall arguments. */
+public class ArgumentCompletionContributorTest extends BuildFileIntegrationTestCase {
+
+ private CompletionAutoPopupTester completionTester;
+
+ public void doSetup() {
+ super.doSetup();
+ completionTester = new CompletionAutoPopupTester(testFixture);
+ }
+
+ @Override
+ protected boolean runInDispatchThread() {
+ return false;
+ }
+
+ @Override
+ protected void invokeTestRunnable(Runnable runnable) throws Exception {
+ completionTester.runWithAutoPopupEnabled(runnable);
+ }
+
+ public void testIncompleteFuncall() {
+ BuildFile file =
+ createBuildFile(
+ "BUILD", "def function(name, deps, srcs):", " # empty function", "function(d");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 2, "function(n".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isNull();
+
+ assertFileContents(
+ file, "def function(name, deps, srcs):", " # empty function", "function(deps");
+ }
+
+ public void testExistingKeywordArg() {
+ BuildFile file =
+ createBuildFile(
+ "BUILD",
+ "def function(name, deps, srcs):",
+ " # empty function",
+ "function(name = \"lib\")");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 2, "function(".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).hasLength(4);
+ assertThat(completionItems).asList().containsAllOf("name", "deps", "srcs", "function");
+ }
+
+ public void testNoArgumentCompletionInComment() {
+ BuildFile file =
+ createBuildFile(
+ "BUILD", "def function(name, deps, srcs):", " # empty function", "function(#");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 2, "function(#".length());
+
+ completionTester.typeWithPauses("n");
+ assertNull(testFixture.getLookup());
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributorTest.java
new file mode 100644
index 0000000..6fe0d21
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributorTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.AttributeDefinition;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Tests for BuiltInFunctionAttributeCompletionContributor. */
+public class BuiltInFunctionAttributeCompletionContributorTest
+ extends BuildFileIntegrationTestCase {
+
+ private MockBuildLanguageSpecProvider specProvider;
+
+ @Override
+ protected void doSetup() {
+ super.doSetup();
+ specProvider = new MockBuildLanguageSpecProvider();
+ registerApplicationService(BuildLanguageSpecProvider.class, specProvider);
+ }
+
+ public void testSimpleCompletion() {
+ setRuleAndAttributes("sh_binary", "name", "deps", "srcs", "data");
+
+ BuildFile file = createBuildFile("BUILD", "sh_binary(");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "sh_binary(".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).asList().containsAllOf("name", "deps", "srcs", "data");
+ }
+
+ public void testSimpleSingleCompletion() {
+ setRuleAndAttributes("sh_binary", "name", "deps", "srcs", "data");
+
+ BuildFile file = createBuildFile("BUILD", "sh_binary(", " n");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 1, " n".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isNull();
+ assertFileContents(file, "sh_binary(", " name");
+ }
+
+ public void testNoCompletionInUnknownRule() {
+ setRuleAndAttributes("sh_binary", "name", "deps", "srcs", "data");
+
+ BuildFile file = createBuildFile("BUILD", "java_binary(");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "java_binary(".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testNoCompletionInComment() {
+ setRuleAndAttributes("sh_binary", "name", "deps", "srcs", "data");
+
+ BuildFile file = createBuildFile("BUILD", "sh_binary(#");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "sh_binary(#".length());
+ assertEmpty(getCompletionItemsAsStrings());
+ }
+
+ public void testCompletionInSkylarkExtension() {
+ setRuleAndAttributes("sh_binary", "name", "deps", "srcs", "data");
+
+ BuildFile file = createBuildFile("skylark.bzl", "native.sh_binary(");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "native.sh_binary(".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).asList().containsAllOf("name", "deps", "srcs", "data");
+ }
+
+ private void setRuleAndAttributes(String ruleName, String... attributes) {
+ ImmutableMap.Builder<String, AttributeDefinition> map = ImmutableMap.builder();
+ for (String attr : attributes) {
+ map.put(
+ attr,
+ new AttributeDefinition(attr, Build.Attribute.Discriminator.UNKNOWN, false, null, null));
+ }
+ RuleDefinition rule = new RuleDefinition(ruleName, map.build(), null);
+ specProvider.setRules(ImmutableMap.of(ruleName, rule));
+ }
+
+ private static class MockBuildLanguageSpecProvider implements BuildLanguageSpecProvider {
+
+ BuildLanguageSpec languageSpec;
+
+ void setRules(ImmutableMap<String, RuleDefinition> rules) {
+ languageSpec = new BuildLanguageSpec(rules);
+ }
+
+ @Nullable
+ @Override
+ public BuildLanguageSpec getLanguageSpec(Project project) {
+ return languageSpec;
+ }
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributorTest.java
new file mode 100644
index 0000000..f448b7a
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributorTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
+import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Tests BuiltInFunctionCompletionContributor */
+public class BuiltInFunctionCompletionContributorTest extends BuildFileIntegrationTestCase {
+
+ private MockBuildLanguageSpecProvider specProvider;
+
+ @Override
+ protected void doSetup() {
+ super.doSetup();
+ specProvider = new MockBuildLanguageSpecProvider();
+ registerApplicationService(BuildLanguageSpecProvider.class, specProvider);
+ }
+
+ public void testSimpleTopLevelCompletion() {
+ setRules("java_library", "android_binary");
+
+ BuildFile file = createBuildFile("BUILD", "");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, 0);
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).hasLength(2);
+ assertThat(completionItems[0].getLookupString()).isEqualTo("android_binary");
+ assertThat(completionItems[1].getLookupString()).isEqualTo("java_library");
+
+ assertFileContents(file, "");
+ }
+
+ public void testUniqueTopLevelCompletion() {
+ setRules("java_library", "android_binary");
+
+ BuildFile file = createBuildFile("BUILD", "ja");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, 2);
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isNull();
+
+ assertFileContents(file, "java_library()");
+ assertCaretPosition(editor, 0, "java_library(".length());
+ }
+
+ public void testSkylarkNativeCompletion() {
+ setRules("java_library", "android_binary");
+
+ BuildFile file = createBuildFile("build_defs.bzl", "def function():", " native.j");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 1, " native.j".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isNull();
+
+ assertFileContents(file, "def function():", " native.java_library()");
+ assertCaretPosition(editor, 1, " native.java_library(".length());
+ }
+
+ public void testNoCompletionInsideRule() {
+ setRules("java_library", "android_binary");
+
+ String[] contents = {"java_library(", " name = \"lib\"", ""};
+
+ BuildFile file = createBuildFile("BUILD", contents);
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 2, 0);
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isEmpty();
+ assertFileContents(file, contents);
+ }
+
+ public void testNoCompletionInComment() {
+ setRules("java_library", "android_binary");
+
+ BuildFile file = createBuildFile("BUILD", "#java");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "#java".length());
+
+ assertEmpty(getCompletionItemsAsStrings());
+ }
+
+ private void setRules(String... ruleNames) {
+ ImmutableMap.Builder<String, RuleDefinition> rules = ImmutableMap.builder();
+ for (String name : ruleNames) {
+ rules.put(name, new RuleDefinition(name, ImmutableMap.of(), null));
+ }
+ specProvider.setRules(rules.build());
+ }
+
+ private static class MockBuildLanguageSpecProvider implements BuildLanguageSpecProvider {
+
+ BuildLanguageSpec languageSpec;
+
+ void setRules(ImmutableMap<String, RuleDefinition> rules) {
+ languageSpec = new BuildLanguageSpec(rules);
+ }
+
+ @Nullable
+ @Override
+ public BuildLanguageSpec getLanguageSpec(Project project) {
+ return languageSpec;
+ }
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/FilePathCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/FilePathCompletionTest.java
new file mode 100644
index 0000000..5838f8f
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/FilePathCompletionTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Tests file path code completion in BUILD file labels. */
+public class FilePathCompletionTest extends BuildFileIntegrationTestCase {
+
+ public void testUniqueDirectoryCompleted() {
+ BuildFile file = createBuildFile("java/BUILD", "'//'");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 0, "'//".length());
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "'//java'");
+ // check caret remains inside closing quote
+ assertCaretPosition(editor, 0, "'//java".length());
+ }
+
+ public void testUniqueMultiSegmentDirectoryCompleted() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "'//'");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 0, "'//".length());
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "'//java/com/google'");
+ }
+
+ // expected to be a typical workflow -- complete a segment,
+ // get the possibilities, then start typing
+ // next segment and complete again
+ public void testMultiStageCompletion() {
+ createDirectory("foo");
+ createDirectory("bar");
+ createDirectory("other");
+ createDirectory("other/foo");
+ createDirectory("other/bar");
+
+ BuildFile file = createBuildFile("BUILD", "'//'");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 0, "'//".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).hasLength(3);
+
+ performTypingAction(editor, 'o');
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "'//other'");
+ assertCaretPosition(editor, 0, "'//other".length());
+
+ performTypingAction(editor, '/');
+ performTypingAction(editor, 'f');
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "'//other/foo'");
+ assertCaretPosition(editor, 0, "'//other/foo".length());
+ }
+
+ public void testCompletionSuggestionString() {
+ createDirectory("foo");
+ createDirectory("bar");
+ createDirectory("other");
+ createDirectory("ostrich/foo");
+ createDirectory("ostrich/fooz");
+
+ VirtualFile file = createAndSetCaret("BUILD", "'//o<caret>'");
+
+ String[] completionItems = getCompletionItemsAsSuggestionStrings();
+ assertThat(completionItems).asList().containsExactly("other", "ostrich");
+
+ performTypingAction(testFixture.getEditor(), 's');
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "'//ostrich'");
+
+ completionItems = getCompletionItemsAsSuggestionStrings();
+ assertThat(completionItems).asList().containsExactly("/foo", "/fooz");
+
+ performTypingAction(testFixture.getEditor(), '/');
+
+ completionItems = getCompletionItemsAsSuggestionStrings();
+ assertThat(completionItems).asList().containsExactly("foo", "fooz");
+
+ performTypingAction(testFixture.getEditor(), 'f');
+
+ completionItems = getCompletionItemsAsSuggestionStrings();
+ assertThat(completionItems).asList().containsExactly("foo", "fooz");
+ }
+
+ private VirtualFile createAndSetCaret(String filePath, String... fileContents) {
+ VirtualFile file = createFile(filePath, fileContents);
+ testFixture.configureFromExistingVirtualFile(file);
+ return file;
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/LocalSymbolCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/LocalSymbolCompletionTest.java
new file mode 100644
index 0000000..aab1659
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/LocalSymbolCompletionTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.psi.PsiFile;
+
+/** Tests code completion works with general symbols in scope. */
+public class LocalSymbolCompletionTest extends BuildFileIntegrationTestCase {
+
+ private PsiFile setInput(String... fileContents) {
+ return testFixture.configureByText("BUILD", Joiner.on("\n").join(fileContents));
+ }
+
+ private void assertResult(String... resultingFileContents) {
+ String s = testFixture.getFile().getText();
+ testFixture.checkResult(Joiner.on("\n").join(resultingFileContents));
+ }
+
+ public void testLocalVariable() {
+ setInput("var = [a, b]", "def function(name, deps, srcs):", " v<caret>");
+
+ completeIfUnique();
+
+ assertResult("var = [a, b]", "def function(name, deps, srcs):", " var<caret>");
+ }
+
+ public void testLocalFunction() {
+ setInput("def fnName():return True", "def function(name, deps, srcs):", " fnN<caret>");
+
+ completeIfUnique();
+
+ assertResult("def fnName():return True", "def function(name, deps, srcs):", " fnName<caret>");
+ }
+
+ public void testNoCompletionAfterDot() {
+ setInput("var = [a, b]", "def function(name, deps, srcs):", " ext.v<caret>");
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testFunctionParam() {
+ setInput("def test(var):", " v<caret>");
+
+ completeIfUnique();
+
+ assertResult("def test(var):", " var<caret>");
+ }
+
+ // b/28912523: when symbol is present in multiple assignment statements, should only be
+ // included once in the code-completion dialog
+ public void testSymbolAssignedMultipleTimes() {
+ setInput("var = 1", "var = 2", "var = 3", "<caret>");
+
+ completeIfUnique();
+
+ assertResult("var = 1", "var = 2", "var = 3", "var<caret>");
+ }
+
+ public void testSymbolDefinedOutsideScope() {
+ setInput("<caret>", "var = 1");
+
+ assertThat(getCompletionItemsAsStrings()).isEmpty();
+ }
+
+ public void testSymbolDefinedOutsideScope2() {
+ setInput("def fn():", " var = 1", "v<caret>");
+
+ assertThat(testFixture.completeBasic()).isEmpty();
+ }
+
+ public void testSymbolDefinedOutsideScope3() {
+ setInput("for var in (1, 2, 3): print var", "v<caret>");
+
+ assertThat(testFixture.completeBasic()).isEmpty();
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributorTest.java
new file mode 100644
index 0000000..afc25d0
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributorTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.editor.Editor;
+
+/** Tests ParameterCompletionContributor. */
+public class ParameterCompletionContributorTest extends BuildFileIntegrationTestCase {
+
+ public void testArgsCompletion() {
+ BuildFile file = createBuildFile("BUILD", "def function(arg1, *");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "def function(arg1, *".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isNull();
+
+ assertFileContents(file, "def function(arg1, *args");
+ }
+
+ public void testKwargsCompletion() {
+ BuildFile file = createBuildFile("BUILD", "def function(arg1, **");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 0, "def function(arg1, **".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isNull();
+
+ assertFileContents(file, "def function(arg1, **kwargs");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/RuleTargetCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/RuleTargetCompletionTest.java
new file mode 100644
index 0000000..6a289f7
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/RuleTargetCompletionTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.openapi.editor.Editor;
+
+/** Tests code completion of rule target labels. */
+public class RuleTargetCompletionTest extends BuildFileIntegrationTestCase {
+
+ public void testLocalTarget() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = 'lib')",
+ "java_library(",
+ " name = 'test',",
+ " deps = [':']");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 3, " deps = [':".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).hasLength(1);
+ assertThat(completionItems[0].toString()).isEqualTo("':lib'");
+ }
+
+ public void testIgnoreContainingTarget() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD", "java_library(", " name = 'lib',", " deps = [':']");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 2, " deps = [':".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testNotCodeCompletionInNameField() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = 'lib')",
+ "java_library(",
+ " name = 'l'",
+ ")");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 2, " name = 'l".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testNonLocalTarget() {
+ BuildFile foo = createBuildFile("java/com/google/foo/BUILD", "java_library(name = 'foo_lib')");
+
+ BuildFile bar =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "java_library(",
+ " name = 'bar_lib',",
+ " deps = '//java/com/google/foo:')");
+
+ Editor editor = openFileInEditor(bar);
+ setCaretPosition(editor, 2, " deps = '//java/com/google/foo:".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).asList().containsExactly("'//java/com/google/foo:foo_lib'");
+ }
+
+ public void testNonLocalRulesNotCompletedWithoutColon() {
+ BuildFile foo = createBuildFile("java/com/google/foo/BUILD", "java_library(name = 'foo_lib')");
+
+ BuildFile bar =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "java_library(",
+ " name = 'bar_lib',",
+ " deps = '//java/com/google/foo')");
+
+ Editor editor = openFileInEditor(bar);
+ setCaretPosition(editor, 2, " deps = '//java/com/google/foo".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testPackageLocalRulesCompletedWithoutColon() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = 'lib')",
+ "java_library(",
+ " name = 'test',",
+ " deps = ['']");
+
+ Editor editor = openFileInEditor(file);
+ setCaretPosition(editor, 3, " deps = ['".length());
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(
+ file,
+ "java_library(name = 'lib')",
+ "java_library(",
+ " name = 'test',",
+ " deps = ['lib']");
+ }
+
+ public void testLocalPathIgnoredForNonLocalLabels() {
+ BuildFile rootPackage = createBuildFile("java/BUILD", "java_library(name = 'root_rule')");
+
+ BuildFile otherPackage =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(",
+ "java_library(name = 'other_rule')",
+ " name = 'lib',",
+ " deps = ['//java:']");
+
+ Editor editor = openFileInEditor(otherPackage);
+ setCaretPosition(editor, 3, " deps = ['//java:".length());
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).asList().contains("'//java:root_rule'");
+ assertThat(completionItems).asList().doesNotContain("'//java/com/google:other_rule'");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionCompletionTest.java
new file mode 100644
index 0000000..9038c9b
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionCompletionTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Tests auto-complete of skylark bzl files in 'load' statements. */
+public class SkylarkExtensionCompletionTest extends BuildFileIntegrationTestCase {
+
+ private VirtualFile createAndSetCaret(String filePath, String... fileContents) {
+ VirtualFile file = createFile(filePath, fileContents);
+ testFixture.configureFromExistingVirtualFile(file);
+ return file;
+ }
+
+ public void testSimpleCase() {
+ createFile("skylark.bzl");
+ VirtualFile file = createAndSetCaret("BUILD", "load(':<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl'");
+ }
+
+ public void testSelfNotInResults() {
+ createFile("BUILD");
+ VirtualFile file = createAndSetCaret("self.bzl", "load(':<caret>'");
+
+ assertThat(testFixture.completeBasic()).isEmpty();
+ }
+
+ public void testSelfNotInResults2() {
+ createFile("skylark.bzl");
+ createFile("BUILD");
+ VirtualFile file = createAndSetCaret("self.bzl", "load(':<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl'");
+ }
+
+ public void testNoRulesInResults() {
+ createFile("java/com/google/foo/skylark.bzl");
+ createFile("java/com/google/foo/BUILD", "java_library(name = 'foo')");
+ VirtualFile file =
+ createAndSetCaret("java/com/google/bar/BUILD", "load('//java/com/google/foo:<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load('//java/com/google/foo:skylark.bzl'");
+
+ // now check that the rule would have been picked up outside of the 'load' context
+ file = createAndSetCaret("java/com/google/baz/BUILD", "'//java/com/google/foo:<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "'//java/com/google/foo:foo'");
+ }
+
+ public void testNonSkylarkFilesNotInResults() {
+ createFile("java/com/google/foo/text.txt");
+
+ VirtualFile file =
+ createAndSetCaret("java/com/google/bar/BUILD", "load('//java/com/google/foo:<caret>'");
+
+ assertThat(testFixture.completeBasic()).isEmpty();
+ }
+
+ public void testLabelStartsWithColon() {
+ createFile("java/com/google/skylark.bzl");
+ VirtualFile file = createAndSetCaret("java/com/google/BUILD", "load(':<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl'");
+ }
+
+ public void testLabelStartsWithSlashes() {
+ createFile("java/com/google/skylark.bzl");
+ VirtualFile file =
+ createAndSetCaret("java/com/google/BUILD", "load('//java/com/google:<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load('//java/com/google:skylark.bzl'");
+ }
+
+ public void testLabelStartsWithSlashesWithoutColon() {
+ createFile("java/com/google/skylark.bzl");
+ VirtualFile file =
+ createAndSetCaret("java/com/google/BUILD", "load('//java/com/google<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load('//java/com/google:skylark.bzl'");
+ }
+
+ public void testDirectoryCompletionInLoadStatement() {
+ createFile("java/com/google/skylark.bzl");
+ VirtualFile file = createAndSetCaret("java/com/google/BUILD", "load('//<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load('//java/com/google'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load('//java/com/google:skylark.bzl'");
+ }
+
+ public void testMultipleFiles() {
+ createFile("java/com/google/skylark.bzl");
+ createFile("java/com/google/other.bzl");
+ VirtualFile file =
+ createAndSetCaret("java/com/google/BUILD", "load('//java/com/google:<caret>'");
+
+ String[] strings = getCompletionItemsAsStrings();
+ assertThat(strings).hasLength(2);
+ assertThat(strings)
+ .asList()
+ .containsExactly("'//java/com/google:other.bzl'", "'//java/com/google:skylark.bzl'");
+ }
+
+ // relative paths in skylark extensions which lie in subdirectories
+ // are relative to the parent blaze package directory
+ public void testRelativePathInSubdirectory() {
+ createFile("java/com/google/BUILD");
+ createFile("java/com/google/nonPackageSubdirectory/skylark.bzl", "def function(): return");
+ VirtualFile file =
+ createAndSetCaret("java/com/google/nonPackageSubdirectory/other.bzl", "load(':n<caret>'");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':nonPackageSubdirectory/skylark.bzl'");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java
new file mode 100644
index 0000000..4c00b51
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.completion;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/** Tests auto-complete of symbols loaded from skylark bzl files. */
+public class SkylarkExtensionSymbolCompletionTest extends BuildFileIntegrationTestCase {
+
+ private VirtualFile createAndSetCaret(String filePath, String... fileContents) {
+ VirtualFile file = createFile(filePath, fileContents);
+ testFixture.configureFromExistingVirtualFile(file);
+ return file;
+ }
+
+ public void testGlobalVariable() {
+ createFile("skylark.bzl", "VAR = []");
+ VirtualFile file = createAndSetCaret("BUILD", "load(':skylark.bzl', '<caret>')");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl', 'VAR')");
+ }
+
+ public void testFunctionStatement() {
+ createFile("skylark.bzl", "def fn(param):stmt");
+ VirtualFile file = createAndSetCaret("BUILD", "load(':skylark.bzl', '<caret>')");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl', 'fn')");
+ }
+
+ public void testMultipleOptions() {
+ createFile("skylark.bzl", "def fn(param):stmt", "VAR = []");
+ VirtualFile file = createAndSetCaret("BUILD", "load(':skylark.bzl', '<caret>')");
+
+ String[] options = getCompletionItemsAsStrings();
+ assertThat(options).asList().containsExactly("'fn'", "'VAR'");
+ }
+
+ public void testRulesNotIncluded() {
+ createFile("skylark.bzl", "java_library(name = 'lib')", "native.java_library(name = 'foo'");
+
+ VirtualFile file = createAndSetCaret("BUILD", "load(':skylark.bzl', '<caret>')");
+
+ assertThat(testFixture.completeBasic()).isEmpty();
+ }
+
+ public void testLoadedSymbols() {
+ createFile("other.bzl", "def function()");
+ createFile("skylark.bzl", "load(':other.bzl', 'function')");
+ VirtualFile file = createAndSetCaret("BUILD", "load(':skylark.bzl', '<caret>')");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl', 'function')");
+ }
+
+ public void testNotLoadedSymbolsAreNotIncluded() {
+ createFile("other.bzl", "def function():stmt", "def other_function():stmt");
+ createFile("skylark.bzl", "load(':other.bzl', 'function')");
+ VirtualFile file = createAndSetCaret("BUILD", "load(':skylark.bzl', '<caret>')");
+
+ assertThat(completeIfUnique()).isTrue();
+ assertFileContents(file, "load(':skylark.bzl', 'function')");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildBraceMatcherTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildBraceMatcherTest.java
new file mode 100644
index 0000000..ac3b331
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildBraceMatcherTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.psi.PsiFile;
+
+/** Test brace matching (auto-inserting closing braces when appropriate) */
+public class BuildBraceMatcherTest extends BuildFileIntegrationTestCase {
+
+ private PsiFile setInput(String... fileContents) {
+ return testFixture.configureByText("BUILD", Joiner.on("\n").join(fileContents));
+ }
+
+ public void testClosingParenInserted() {
+ PsiFile file = setInput("java_library<caret>");
+
+ performTypingAction(testFixture.getEditor(), '(');
+
+ assertFileContents(file, "java_library()");
+ }
+
+ public void testClosingBraceInserted() {
+ PsiFile file = setInput("<caret>");
+
+ performTypingAction(testFixture.getEditor(), '{');
+
+ assertFileContents(file, "{}");
+ }
+
+ public void testClosingBracketInserted() {
+ PsiFile file = setInput("<caret>");
+
+ performTypingAction(testFixture.getEditor(), '[');
+
+ assertFileContents(file, "[]");
+ }
+
+ public void testNoClosingBracketInsertedIfLaterDanglingRBracket() {
+ PsiFile file = setInput("java_library(", " srcs =<caret> 'source.java']", ")");
+
+ performTypingAction(testFixture.getEditor(), '[');
+
+ assertFileContents(file, "java_library(", " srcs =[ 'source.java']", ")");
+ }
+
+ public void testClosingBracketInsertedIfFollowedByWhitespace() {
+ PsiFile file = setInput("java_library(", " srcs =<caret> 'source.java'", ")");
+
+ performTypingAction(testFixture.getEditor(), '[');
+
+ assertFileContents(file, "java_library(", " srcs =[] 'source.java'", ")");
+ }
+
+ public void testNoClosingBraceInsertedWhenFollowedByIdentifier() {
+ PsiFile file = setInput("hello = <caret>test");
+
+ performTypingAction(testFixture.getEditor(), '(');
+
+ assertFileContents(file, "hello = (test");
+
+ file = setInput("hello = <caret>test");
+
+ performTypingAction(testFixture.getEditor(), '[');
+
+ assertFileContents(file, "hello = [test");
+
+ file = setInput("hello = <caret>test");
+
+ performTypingAction(testFixture.getEditor(), '{');
+
+ assertFileContents(file, "hello = {test");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildIndentOnEnterTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildIndentOnEnterTest.java
new file mode 100644
index 0000000..eaccda5
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildIndentOnEnterTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.openapi.actionSystem.IdeActions;
+
+/** Tests that indents are inserted correctly when enter is pressed. */
+public class BuildIndentOnEnterTest extends BuildFileIntegrationTestCase {
+
+ private void setInput(String... fileContents) {
+ testFixture.configureByText("BUILD", Joiner.on("\n").join(fileContents));
+ }
+
+ private void pressEnterAndAssertResult(String... resultingFileContents) {
+ pressButton(IdeActions.ACTION_EDITOR_ENTER);
+ String s = testFixture.getFile().getText();
+ testFixture.checkResult(Joiner.on("\n").join(resultingFileContents));
+ }
+
+ public void testSimpleIndent() {
+ setInput("a=1<caret>");
+ pressEnterAndAssertResult("a=1", "<caret>");
+ }
+
+ public void testAlignInListMiddle() {
+ setInput("target = [a,<caret>", " c]");
+ pressEnterAndAssertResult("target = [a,", " <caret>", " c]");
+ }
+
+ public void testNoAlignAfterList() {
+ setInput("target = [", " arg", "]<caret>");
+ pressEnterAndAssertResult("target = [", " arg", "]", "<caret>");
+ }
+
+ public void testAlignInDict() {
+ setInput("some_call({'aaa': 'v1',<caret>})");
+ pressEnterAndAssertResult("some_call({'aaa': 'v1',", " <caret>})");
+ }
+
+ public void testAlignInDictInParams() { // PY-1947
+ setInput("foobar({<caret>})");
+ pressEnterAndAssertResult("foobar({", " <caret>", "})");
+ }
+
+ public void testAlignInEmptyList() {
+ setInput("target = [<caret>]");
+ pressEnterAndAssertResult("target = [", " <caret>", "]");
+ }
+
+ public void testAlignInEmptyParens() {
+ setInput("foo(<caret>)");
+ pressEnterAndAssertResult("foo(", " <caret>", ")");
+ }
+
+ public void testAlignInEmptyDict() {
+ setInput("{<caret>}");
+ pressEnterAndAssertResult("{", " <caret>", "}");
+ }
+
+ public void testAlignInEmptyTuple() {
+ setInput("(<caret>)");
+ pressEnterAndAssertResult("(", " <caret>", ")");
+ }
+
+ public void testEnterInNonEmptyArgList() {
+ setInput("func(<caret>params=1)");
+ pressEnterAndAssertResult("func(", " <caret>params=1)");
+ }
+
+ public void testNoIndentAfterTuple() {
+ setInput("()<caret>");
+ pressEnterAndAssertResult("()", "<caret>");
+ }
+
+ public void testNoIndentAfterList() {
+ setInput("target = [1, 2]<caret>");
+ pressEnterAndAssertResult("target = [1, 2]", "<caret>");
+ }
+
+ public void testNoIndentAfterDict() {
+ setInput("target = {}<caret>");
+ pressEnterAndAssertResult("target = {}", "<caret>");
+ }
+
+ public void testEmptyFuncallStart() {
+ setInput("func(<caret>", ")");
+ pressEnterAndAssertResult("func(", " <caret>", ")");
+ }
+
+ public void testEmptyFuncallAfterNewlineNoIndent() {
+ setInput("func(", "<caret>)");
+ pressEnterAndAssertResult("func(", "", "<caret>)");
+ }
+
+ public void testEmptyFuncallAfterNewlineWithIndent() {
+ setInput("func(", " <caret>", ")");
+ pressEnterAndAssertResult("func(", " ", " <caret>", ")");
+ }
+
+ public void testFuncallAfterFirstArg() {
+ setInput("func(", " arg1,<caret>", ")");
+ pressEnterAndAssertResult("func(", " arg1,", " <caret>", ")");
+ }
+
+ public void testFuncallFirstArgOnSameLine() {
+ setInput("func(arg1, arg2,<caret>");
+ pressEnterAndAssertResult("func(arg1, arg2,", " <caret>");
+ }
+
+ public void testFuncallFirstArgOnSameLineWithClosingBrace() {
+ setInput("func(arg1, arg2,<caret>)");
+ pressEnterAndAssertResult("func(arg1, arg2,", " <caret>)");
+ }
+
+ public void testNonEmptyDict() {
+ setInput("{key1 : value1,<caret>}");
+ pressEnterAndAssertResult("{key1 : value1,", " <caret>}");
+ }
+
+ public void testNonEmptyDictFirstArgIndented() {
+ setInput("{", " key1 : value1,<caret>" + "}");
+ pressEnterAndAssertResult("{", " key1 : value1,", " <caret>" + "}");
+ }
+
+ public void testEmptyDictAlreadyIndented() {
+ setInput("{", " <caret>" + "}");
+ pressEnterAndAssertResult("{", " ", " <caret>" + "}");
+ }
+
+ public void testEmptyParamIndent() {
+ setInput("def fn(<caret>)");
+ pressEnterAndAssertResult("def fn(", " <caret>", ")");
+ }
+
+ public void testNonEmptyParamIndent() {
+ setInput("def fn(param1,<caret>)");
+ pressEnterAndAssertResult("def fn(param1,", " <caret>)");
+ }
+
+ public void testFunctionDefAfterColon() {
+ setInput("def fn():<caret>");
+ pressEnterAndAssertResult("def fn():", " <caret>");
+ }
+
+ // def fn():stmt* (THIS IS CURRENTLY BROKEN -- shouldn't indent but does)
+ public void testFunctionDefSingleStatement() {
+ setInput("def fn():stmt<caret>");
+ pressEnterAndAssertResult("def fn():stmt", "<caret>");
+ }
+
+ public void testFunctionDefAfterFirstSuiteStatement() {
+ setInput("def fn():", " stmt1<caret>");
+ pressEnterAndAssertResult("def fn():", " stmt1", " <caret>");
+ }
+
+ public void testNoIndentAfterSuiteDedentOnEmptyLine() {
+ setInput("def fn():", " stmt1", " stmt2", "<caret>");
+ pressEnterAndAssertResult("def fn():", " stmt1", " stmt2", "", "<caret>");
+ }
+
+ public void testIndentAfterIf() {
+ setInput("if condition:<caret>");
+ pressEnterAndAssertResult("if condition:", " <caret>");
+ }
+
+ public void testNoIndentAfterIfPlusStatement() {
+ setInput("if condition:stmt<caret>");
+ pressEnterAndAssertResult("if condition:stmt", "<caret>");
+ }
+
+ public void testIndentAfterElseIf() {
+ setInput("if condition:", " stmt", "elif:<caret>");
+ pressEnterAndAssertResult("if condition:", " stmt", "elif:", " <caret>");
+ }
+
+ public void testNoIndentAfterElseIfPlusStatement() {
+ setInput("if condition:", " stmt", "elif:stmt<caret>");
+ pressEnterAndAssertResult("if condition:", " stmt", "elif:stmt", "<caret>");
+ }
+
+ public void testIndentAfterElse() {
+ setInput("if condition:", " stmt", "else:<caret>");
+ pressEnterAndAssertResult("if condition:", " stmt", "else:", " <caret>");
+ }
+
+ public void testNoIndentAfterElsePlusStatement() {
+ setInput("if condition:", " stmt", "else:stmt<caret>");
+ pressEnterAndAssertResult("if condition:", " stmt", "else:stmt", "<caret>");
+ }
+
+ public void testIndentAfterForColon() {
+ setInput("for x in list:<caret>");
+ pressEnterAndAssertResult("for x in list:", " <caret>");
+ }
+
+ public void testNoIndentAfterForPlusStatement() {
+ setInput("for x in list:do_action<caret>");
+ pressEnterAndAssertResult("for x in list:do_action", "<caret>");
+ }
+
+ public void testCommonRuleCase1() {
+ setInput("java_library(", " name = 'lib'", " srcs = [<caret>]");
+ pressEnterAndAssertResult(
+ "java_library(", " name = 'lib'", " srcs = [", " <caret>", " ]");
+ }
+
+ public void testCommonRuleCase2() {
+ setInput(
+ "java_library(", " name = 'lib'", " srcs = [", " 'source',<caret>", " ]");
+ pressEnterAndAssertResult(
+ "java_library(",
+ " name = 'lib'",
+ " srcs = [",
+ " 'source',",
+ " <caret>",
+ " ]");
+ }
+
+ public void testCommonRuleCase3() {
+ setInput("java_library(", " name = 'lib'", " srcs = ['first',<caret>]");
+ pressEnterAndAssertResult(
+ "java_library(", " name = 'lib'", " srcs = ['first',", " <caret>]");
+ }
+
+ public void testDedentAfterReturn() {
+ setInput("def fn():", " return None<caret>");
+ pressEnterAndAssertResult("def fn():", " return None", "<caret>");
+ }
+
+ public void testDedentAfterEmptyReturn() {
+ setInput("def fn():", " return<caret>");
+ pressEnterAndAssertResult("def fn():", " return", "<caret>");
+ }
+
+ public void testDedentAfterReturnWithTrailingWhitespace() {
+ setInput("def fn():", " return<caret> ");
+ pressEnterAndAssertResult("def fn():", " return", "<caret>");
+ }
+
+ public void testDedentAfterComplexReturn() {
+ setInput("def fn():", " return a == b<caret>");
+ pressEnterAndAssertResult("def fn():", " return a == b", "<caret>");
+ }
+
+ public void testDedentAfterPass() {
+ setInput("def fn():", " pass<caret>");
+ pressEnterAndAssertResult("def fn():", " pass", "<caret>");
+ }
+
+ public void testDedentAfterPassInLoop() {
+ setInput("def fn():", " for a in (1,2,3):", " pass<caret>");
+ pressEnterAndAssertResult("def fn():", " for a in (1,2,3):", " pass", " <caret>");
+ }
+
+ // regression test for b/29564041
+ public void testNoExceptionPressingEnterAtStartOfFile() {
+ setInput("#<caret>");
+ pressEnterAndAssertResult("#", "<caret>");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandlerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandlerTest.java
new file mode 100644
index 0000000..459d942
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandlerTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+
+/** Tests for BuildQuoteHandler. */
+public class BuildQuoteHandlerTest extends BuildFileIntegrationTestCase {
+
+ public void testClosingQuoteInserted() {
+ BuildFile file = createBuildFile("BUILD", "");
+
+ performTypingAction(file, '"');
+ assertFileContents(file, "\"\"");
+ }
+
+ public void testClosingSingleQuoteInserted() {
+ BuildFile file = createBuildFile("BUILD", "");
+
+ performTypingAction(file, '\'');
+ assertFileContents(file, "''");
+ }
+
+ public void testClosingTripleQuoteInserted() {
+ BuildFile file = createBuildFile("BUILD", "");
+
+ performTypingAction(file, '"');
+ performTypingAction(file, '"');
+ performTypingAction(file, '"');
+ assertFileContents(file, "\"\"\"\"\"\"");
+ }
+
+ public void testClosingTripleSingleQuoteInserted() {
+ BuildFile file = createBuildFile("BUILD", "");
+
+ performTypingAction(file, '\'');
+ performTypingAction(file, '\'');
+ performTypingAction(file, '\'');
+ assertFileContents(file, "''''''");
+ }
+
+ public void testOnlyCaretMovedWhenCompletingExistingClosingQuotes() {
+ BuildFile file = createBuildFile("BUILD", "'text<caret>'", "laterContents");
+
+ testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
+
+ performTypingAction(file, '\'');
+
+ testFixture.checkResult(Joiner.on("\n").join("'text'<caret>", "laterContents"));
+ }
+
+ public void testOnlyCaretMovedWhenCompletingExistingClosingTripleQuotes() {
+ BuildFile file = createBuildFile("BUILD", "'''text<caret>'''", "laterContents");
+
+ testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
+
+ performTypingAction(file, '\'');
+
+ testFixture.checkResult(Joiner.on("\n").join("'''text'<caret>''", "laterContents"));
+
+ performTypingAction(file, '\'');
+
+ testFixture.checkResult(Joiner.on("\n").join("'''text''<caret>'", "laterContents"));
+
+ performTypingAction(file, '\'');
+
+ testFixture.checkResult(Joiner.on("\n").join("'''text'''<caret>", "laterContents"));
+ }
+
+ public void testAdditionalTripleQuotesNotInsertedWhenClosingQuotes() {
+ BuildFile file = createBuildFile("BUILD", "'''text''<caret>", "laterContents");
+
+ testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
+
+ performTypingAction(file, '\'');
+
+ testFixture.checkResult(Joiner.on("\n").join("'''text'''<caret>", "laterContents"));
+ }
+
+ public void testAdditionalQuoteNotInsertedWhenClosingQuotes() {
+ BuildFile file = createBuildFile("BUILD", "'text<caret>", "laterContents");
+
+ testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
+
+ performTypingAction(file, '\'');
+
+ testFixture.checkResult(Joiner.on("\n").join("'text'<caret>", "laterContents"));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/EnterInLineCommentTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/EnterInLineCommentTest.java
new file mode 100644
index 0000000..554b127
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/EnterInLineCommentTest.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.editor;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.openapi.editor.Editor;
+
+/** Test that comments are continued when creating a newline mid comment. */
+public class EnterInLineCommentTest extends BuildFileIntegrationTestCase {
+
+ public void testInternalNewlineCommented() {
+ BuildFile file = createBuildFile("BUILD", "# first line comment", "# second line comment");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 1, "# second ".length());
+ performTypingAction(editor, '\n');
+ assertFileContents(file, "# first line comment", "# second ", "# line comment");
+ assertCaretPosition(editor, 2, 2);
+ }
+
+ public void testNewlineAtEndOfComment() {
+ BuildFile file = createBuildFile("BUILD", "# first line comment", "# second line comment");
+
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ setCaretPosition(editor, 1, "# second line comment".length());
+ performTypingAction(editor, '\n');
+ assertFileContents(file, "# first line comment", "# second line comment", "");
+ assertCaretPosition(editor, 2, 0);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/BlazePackageFindUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/BlazePackageFindUsagesTest.java
new file mode 100644
index 0000000..c7f9152
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/BlazePackageFindUsagesTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+
+/**
+ * Tests that all references to a blaze package (including in the package components of labels) are
+ * found by the 'Find Usages' action.
+ */
+public class BlazePackageFindUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testDirectReferenceFound() {
+ BuildFile foo = createBuildFile("java/com/google/foo/BUILD");
+
+ BuildFile bar =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "package_group(name = \"grp\", packages = [\"//java/com/google/foo\"])");
+
+ PsiReference[] references = FindUsages.findAllReferences(foo);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(ref.getContainingFile()).isEqualTo(bar);
+ }
+
+ public void testLabelFragmentReferenceFound() {
+ BuildFile foo = createBuildFile("java/com/google/foo/BUILD", "java_library(name = \"lib\")");
+
+ BuildFile bar =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "java_library(name = \"lib2\", exports = [\"//java/com/google/foo:lib\"])");
+
+ PsiReference[] references = FindUsages.findAllReferences(foo);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(ref.getContainingFile()).isEqualTo(bar);
+ }
+
+ /** If these don't resolve, directory rename refactoring won't update all labels correctly */
+ public void testInternalReferencesResolve() {
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = \"lib\")",
+ "java_library(name = \"other\", deps = [\"//java/com/google:lib\"])");
+
+ PsiReference[] references = FindUsages.findAllReferences(buildFile);
+ assertThat(references).hasLength(1);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalFileUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalFileUsagesTest.java
new file mode 100644
index 0000000..a02d996
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalFileUsagesTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+
+/**
+ * Tests that references to external files (e.g. Java classes, text files) are found by the 'Find
+ * Usages' action
+ */
+public class ExternalFileUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testJavaClassUsagesFound() {
+ PsiFile javaFile =
+ createPsiFile(
+ "com/google/foo/JavaClass.java",
+ "package com.google.foo;",
+ "public class JavaClass {}");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "com/google/foo/BUILD", "java_library(name = \"lib\", srcs = [\"JavaClass.java\"])");
+
+ PsiReference[] references = FindUsages.findAllReferences(javaFile);
+ assertThat(references).hasLength(1);
+
+ Argument.Keyword arg =
+ buildFile.findChildByClass(FuncallExpression.class).getKeywordArgument("srcs");
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(PsiUtils.getParentOfType(ref, Argument.Keyword.class)).isEqualTo(arg);
+ }
+
+ public void testTextFileUsagesFound() {
+ PsiFile textFile = createPsiFile("com/google/foo/data.txt");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "com/google/foo/BUILD",
+ "filegroup(name = \"lib\", srcs = [\"data.txt\"])",
+ "filegroup(name = \"lib2\", srcs = [\"//com/google/foo:data.txt\"])");
+
+ PsiReference[] references = FindUsages.findAllReferences(textFile);
+ assertThat(references).hasLength(2);
+ }
+
+ public void testInvalidReferenceDoesntResolve() {
+ BuildFile packageFoo = createBuildFile("com/google/foo/BUILD");
+ PsiFile textFileInFoo = createPsiFile("com/google/foo/data.txt");
+
+ BuildFile packageBar =
+ createBuildFile(
+ "com/google/bar/BUILD", "filegroup(name = \"lib\", srcs = [\":data.txt\"])");
+
+ PsiReference[] references = FindUsages.findAllReferences(textFileInFoo);
+ assertThat(references).isEmpty();
+ }
+
+ public void testSkylarkExtensionUsagesFound() {
+ BuildFile ext = createBuildFile("com/google/foo/ext.bzl", "def fn(): return");
+ createBuildFile(
+ "com/google/foo/BUILD",
+ "load(':ext.bzl', 'fn')",
+ "load('ext.bzl', 'fn')",
+ "load('//com/google/foo:ext.bzl', 'fn')");
+
+ PsiReference[] references = FindUsages.findAllReferences(ext);
+ assertThat(references).hasLength(3);
+ }
+
+ public void testSkylarkExtensionInSubDirectoryUsagesFound() {
+ BuildFile ext = createBuildFile("com/google/foo/subdir/ext.bzl", "def fn(): return");
+ createBuildFile(
+ "com/google/foo/BUILD",
+ "load(':subdir/ext.bzl', 'fn')",
+ "load('subdir/ext.bzl', 'fn')",
+ "load('//com/google/foo:subdir/ext.bzl', 'fn')");
+
+ PsiReference[] references = FindUsages.findAllReferences(ext);
+ assertThat(references).hasLength(3);
+ }
+
+ public void testSkylarkExtensionInSubDirectoryOfDifferentPackage() {
+ BuildFile otherPkg = createBuildFile("com/google/foo/BUILD");
+ BuildFile ext = createBuildFile("com/google/foo/subdir/ext.bzl", "def fn(): return");
+
+ createBuildFile("com/google/bar/BUILD", "load('//com/google/foo:subdir/ext.bzl', 'fn')");
+
+ PsiReference[] references = FindUsages.findAllReferences(ext);
+ assertThat(references).hasLength(1);
+ }
+
+ public void testSkylarkExtensionReferencedFromSubpackage() {
+ BuildFile pkg = createBuildFile("com/google/foo/BUILD");
+ BuildFile ext1 = createBuildFile("com/google/foo/subdir/testing.bzl", "def fn(): return");
+ BuildFile ext2 =
+ createBuildFile("com/google/foo/subdir/other.bzl", "load(':subdir/testing.bzl', 'fn')");
+
+ PsiReference[] references = FindUsages.findAllReferences(ext1);
+ assertThat(references).hasLength(1);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindParameterUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindParameterUsagesTest.java
new file mode 100644
index 0000000..b16e666
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindParameterUsagesTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.psi.PsiReference;
+
+/**
+ * Tests that usages of function parameters (i.e. by named args in funcall expressions) are found
+ */
+public class FindParameterUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testLocalReferences() {
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/build_defs.bzl",
+ "def function(arg1, arg2)",
+ "function(arg1 = 1, arg2 = \"name\")");
+
+ FunctionStatement fn = buildFile.findChildByClass(FunctionStatement.class);
+ ParameterList params = fn.getParameterList();
+
+ PsiReference[] references = FindUsages.findAllReferences(params.findParameterByName("arg1"));
+ assertThat(references).hasLength(1);
+
+ references = FindUsages.findAllReferences(params.findParameterByName("arg2"));
+ assertThat(references).hasLength(1);
+ }
+
+ public void testNonLocalReferences() {
+ BuildFile foo = createBuildFile("java/com/google/build_defs.bzl", "def function(arg1, arg2)");
+
+ BuildFile bar =
+ createBuildFile(
+ "java/com/google/other/BUILD",
+ "load(\"//java/com/google:build_defs.bzl\", \"function\")",
+ "function(arg1 = 1, arg2 = \"name\", extra = x)");
+
+ FunctionStatement fn = foo.findChildByClass(FunctionStatement.class);
+ ParameterList params = fn.getParameterList();
+
+ PsiReference[] references = FindUsages.findAllReferences(params.findParameterByName("arg1"));
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement().getContainingFile()).isEqualTo(bar);
+
+ references = FindUsages.findAllReferences(params.findParameterByName("arg2"));
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement().getContainingFile()).isEqualTo(bar);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindRuleUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindRuleUsagesTest.java
new file mode 100644
index 0000000..4d69567
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindRuleUsagesTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.ListLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+
+/** Tests that usages of build rules are found */
+public class FindRuleUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testLocalReferences() {
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = \"target\")",
+ "top_level_ref = \":target\"",
+ "java_library(name = \"other\", deps = [\":target\"]");
+
+ FuncallExpression target = buildFile.findChildByClass(FuncallExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(2);
+
+ PsiElement firstRef = references[0].getElement();
+ assertThat(firstRef).isInstanceOf(StringLiteral.class);
+ assertThat(firstRef.getParent()).isInstanceOf(AssignmentStatement.class);
+
+ PsiElement secondRef = references[1].getElement();
+ assertThat(secondRef).isInstanceOf(StringLiteral.class);
+ assertThat(secondRef.getParent()).isInstanceOf(ListLiteral.class);
+ }
+
+ // test full package references, made locally
+ public void testLocalFullReference() {
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = \"target\")",
+ "java_library(name = \"other\", deps = [\"//java/com/google:target\"]");
+
+ FuncallExpression target = buildFile.findChildByClass(FuncallExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(ref.getParent()).isInstanceOf(ListLiteral.class);
+ }
+
+ public void testNonLocalReferences() {
+ BuildFile targetFile =
+ createBuildFile("java/com/google/foo/BUILD", "java_library(name = \"target\")");
+
+ BuildFile refFile =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "java_library(name = \"ref\", exports = [\"//java/com/google/foo:target\"])");
+
+ FuncallExpression target = targetFile.findChildByClass(FuncallExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(ref.getContainingFile()).isEqualTo(refFile);
+ }
+
+ public void testFindUsagesWorksFromNameString() {
+ BuildFile targetFile =
+ createBuildFile("java/com/google/foo/BUILD", "java_library(name = \"tar<caret>get\")");
+
+ BuildFile refFile =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "java_library(name = \"ref\", exports = [\"//java/com/google/foo:target\"])");
+
+ testFixture.configureFromExistingVirtualFile(targetFile.getVirtualFile());
+
+ PsiElement targetElement =
+ GotoDeclarationAction.findElementToShowUsagesOf(
+ testFixture.getEditor(), testFixture.getEditor().getCaretModel().getOffset());
+
+ PsiReference[] references = FindUsages.findAllReferences(targetElement);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(ref.getContainingFile()).isEqualTo(refFile);
+ }
+
+ public void testInvalidReferenceDoesntResolve() {
+ // reference ":target" from another build file (missing package path in label)
+ BuildFile targetFile =
+ createBuildFile("java/com/google/foo/BUILD", "java_library(name = \"target\")");
+
+ BuildFile refFile =
+ createBuildFile(
+ "java/com/google/bar/BUILD", "java_library(name = \"ref\", exports = [\":target\"])");
+
+ FuncallExpression target = targetFile.findChildByClass(FuncallExpression.class);
+ assertThat(target).isNotNull();
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(0);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FunctionStatementUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FunctionStatementUsagesTest.java
new file mode 100644
index 0000000..22be9b5
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FunctionStatementUsagesTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+
+/** Tests that usages of function declarations are found */
+public class FunctionStatementUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testLocalReferences() {
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/build_defs.bzl",
+ "def function(name, srcs, deps):",
+ " # function body",
+ "function(name = \"foo\")");
+
+ FunctionStatement funcDef = buildFile.findChildByClass(FunctionStatement.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(funcDef);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(FuncallExpression.class);
+ }
+
+ public void testLoadedFunctionReferences() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google:build_defs.bzl\",",
+ "\"function\"",
+ ")");
+
+ FunctionStatement funcDef = extFile.findChildByClass(FunctionStatement.class);
+ LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(funcDef);
+ assertThat(references).hasLength(1);
+
+ PsiElement ref = references[0].getElement();
+ assertThat(ref).isInstanceOf(StringLiteral.class);
+ assertThat(ref.getParent()).isEqualTo(load);
+ }
+
+ public void testFuncallReference() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/tools/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = []");
+
+ FunctionStatement function = extFile.firstChildOfClass(FunctionStatement.class);
+ FuncallExpression funcall = buildFile.firstChildOfClass(FuncallExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(function);
+ assertThat(references).hasLength(2);
+
+ assertThat(references[1].getElement()).isEqualTo(funcall);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/GlobFindUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/GlobFindUsagesTest.java
new file mode 100644
index 0000000..c1de37e
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/GlobFindUsagesTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.PsiManagerEx;
+import com.intellij.psi.impl.file.impl.FileManager;
+import com.intellij.testFramework.LightVirtualFile;
+
+/** Tests that file references in globs are included in the 'find usages' results. */
+public class GlobFindUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testSimpleGlobReferencingSingleFile() {
+ PsiFile ref = createPsiFile("java/com/google/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+
+ PsiReference[] references = FindUsages.findAllReferences(ref);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isInstanceOf(GlobExpression.class);
+ }
+
+ public void testSimpleGlobReferencingSingleFile2() {
+ PsiFile ref = createPsiFile("java/com/google/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(ref);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+ }
+
+ public void testSimpleGlobReferencingSingleFile3() {
+ PsiFile ref = createPsiFile("java/com/google/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['T*t.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(ref);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+ }
+
+ public void testGlobReferencingMultipleFiles() {
+ PsiFile ref1 = createPsiFile("java/com/google/Test.java");
+ PsiFile ref2 = createPsiFile("java/com/google/Foo.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(ref1);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+
+ references = FindUsages.findAllReferences(ref2);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+ }
+
+ public void testFindsSubDirectories() {
+ PsiFile ref1 = createPsiFile("java/com/google/test/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(ref1);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+ }
+
+ public void testGlobWithExcludes() {
+ PsiFile test = createPsiFile("java/com/google/tests/Test.java");
+ PsiFile foo = createPsiFile("java/com/google/Foo.java");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "glob(" + " ['**/*.java']," + " exclude = ['tests/*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(foo);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+
+ assertThat(FindUsages.findAllReferences(test)).isEmpty();
+ }
+
+ public void testIncludeDirectories() {
+ PsiDirectory dir = createPsiDirectory("java/com/google/tests");
+ PsiFile test = createPsiFile("java/com/google/tests/Test.java");
+ PsiFile foo = createPsiFile("java/com/google/Foo.java");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "glob(" + " ['**/*']," + " exclude = ['BUILD']," + " exclude_directories = 0)");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(dir);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(glob);
+ }
+
+ public void testExcludeDirectories() {
+ PsiDirectory dir = createPsiDirectory("java/com/google/tests");
+ PsiFile test = createPsiFile("java/com/google/tests/Test.java");
+ PsiFile foo = createPsiFile("java/com/google/Foo.java");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD", "glob(" + " ['**/*']," + " exclude = ['BUILD'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(dir);
+ assertThat(references).isEmpty();
+ }
+
+ public void testFilesInSubpackagesExcluded() {
+ BuildFile pkg = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+ BuildFile subPkg = createBuildFile("java/com/google/other/BUILD");
+ createFile("java/com/google/other/Other.java");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(pkg, GlobExpression.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(subPkg);
+ assertThat(references).isEmpty();
+ }
+
+ // regression test for b/29267289
+ public void testInMemoryFileHandledGracefully() {
+ BuildFile pkg = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+
+ LightVirtualFile inMemoryFile =
+ new LightVirtualFile("mockProjectViewFile", ProjectViewLanguage.INSTANCE, "");
+
+ FileManager fileManager =
+ ((PsiManagerEx) PsiManager.getInstance(getProject())).getFileManager();
+ fileManager.setViewProvider(
+ inMemoryFile, fileManager.createFileViewProvider(inMemoryFile, true));
+
+ PsiFile psiFile = fileManager.findFile(inMemoryFile);
+
+ PsiReference[] references = FindUsages.findAllReferences(psiFile);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/LocalVariableUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/LocalVariableUsagesTest.java
new file mode 100644
index 0000000..50fafb4
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/LocalVariableUsagesTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.references.LocalReference;
+import com.google.idea.blaze.base.lang.buildfile.references.TargetReference;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+
+/**
+ * Tests that references to local variables are found by the 'Find Usages' action TODO: Support
+ * comprehension suffix, and add test for it
+ */
+public class LocalVariableUsagesTest extends BuildFileIntegrationTestCase {
+
+ public void testLocalReferences() {
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "localVar = 5",
+ "funcall(localVar)",
+ "def function(name):",
+ " tempVar = localVar");
+
+ TargetExpression target =
+ buildFile.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(2);
+
+ FuncallExpression funcall = buildFile.findChildByClass(FuncallExpression.class);
+ assertThat(funcall).isNotNull();
+
+ PsiElement firstRef = references[0].getElement();
+ assertThat(PsiUtils.getParentOfType(firstRef, FuncallExpression.class)).isEqualTo(funcall);
+
+ FunctionStatement function = buildFile.findChildByClass(FunctionStatement.class);
+ assertThat(function).isNotNull();
+
+ PsiElement secondRef = references[1].getElement();
+ assertThat(secondRef.getParent()).isInstanceOf(AssignmentStatement.class);
+ assertThat(PsiUtils.getParentOfType(secondRef, FunctionStatement.class)).isEqualTo(function);
+ }
+
+ // the case where a symbol is the target of multiple assignment statements
+ public void testMultipleAssignments() {
+ BuildFile buildFile =
+ createBuildFile("java/com/google/BUILD", "var = 5", "var += 1", "var = 0");
+
+ TargetExpression target =
+ buildFile.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(2);
+
+ assertThat(references[0]).isInstanceOf(LocalReference.class);
+ assertThat(references[1]).isInstanceOf(TargetReference.class);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilderTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilderTest.java
new file mode 100644
index 0000000..8581cbc
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilderTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.intellij.lang.folding.FoldingDescriptor;
+import com.intellij.openapi.editor.Editor;
+
+/** Tests for {@link BuildFileFoldingBuilder}. */
+public class BuildFileFoldingBuilderTest extends BuildFileIntegrationTestCase {
+
+ public void testEndOfFileFunctionDelcaration() {
+ // bug 28618935: test no NPE in the case where there's no
+ // statement list following the func-def colon
+ BuildFile file = createBuildFile("java/com/google/BUILD", "def function():");
+
+ getFoldingRegions(file);
+ }
+
+ public void testFuncDefStatementsFolded() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "# multi-line comment, not folded",
+ "# second line of comment",
+ "def function(arg1, arg2):",
+ " stmt1",
+ " stmt2",
+ "",
+ "variable = 1");
+
+ FoldingDescriptor[] foldingRegions = getFoldingRegions(file);
+ assertThat(foldingRegions).hasLength(1);
+ assertThat(foldingRegions[0].getElement().getPsi())
+ .isEqualTo(file.findFunctionInScope("function"));
+ }
+
+ public void testRulesFolded() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(",
+ " name = 'lib',",
+ " srcs = glob(['*.java']),",
+ ")");
+
+ FoldingDescriptor[] foldingRegions = getFoldingRegions(file);
+ assertThat(foldingRegions).hasLength(1);
+ assertThat(foldingRegions[0].getElement().getPsi()).isEqualTo(file.findRule("lib"));
+ }
+
+ public void testLoadStatementFolded() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ " '//java/com/foo/build_defs.bzl',",
+ " 'function1',",
+ " 'function2',",
+ ")");
+
+ FoldingDescriptor[] foldingRegions = getFoldingRegions(file);
+ assertThat(foldingRegions).hasLength(1);
+ assertThat(foldingRegions[0].getElement().getPsi())
+ .isEqualTo(file.findChildByClass(LoadStatement.class));
+ }
+
+ private FoldingDescriptor[] getFoldingRegions(BuildFile file) {
+ Editor editor = openFileInEditor(file.getVirtualFile());
+ return new BuildFileFoldingBuilder().buildFoldRegions(file.getNode(), editor.getDocument());
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeTest.java
new file mode 100644
index 0000000..85b4d65
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.language;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.psi.PsiFile;
+
+/** Tests that BUILD files are recognized as such */
+public class BuildFileTypeTest extends BuildFileIntegrationTestCase {
+
+ public void testSkylarkExtensionRecognized() {
+ PsiFile file = createPsiFile("java/com/google/foo/build_defs.bzl");
+ assertThat(file).isInstanceOf(BuildFile.class);
+ }
+
+ public void testExactNameMatch() {
+ PsiFile file = createPsiFile("java/com/google/foo/BUILD");
+ assertThat(file).isInstanceOf(BuildFile.class);
+ }
+
+ /**
+ * We may want to support these in the future (and in the meantime the user can manually have them
+ * recognized as BUILD files, for syntax highlighting, etc.).<br>
+ * Currently, turned off by default because references won't resolve correctly -- they'll point
+ * back to normal BUILD files.
+ */
+ public void testOtherBuildFilesNotRecognized() {
+ PsiFile file = createPsiFile("java/com/google/foo/BUILD.tools");
+ assertThat(file).isNotInstanceOf(BuildFile.class);
+
+ file = createPsiFile("java/com/google/foo/BUILD.bazel");
+ assertThat(file).isNotInstanceOf(BuildFile.class);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/AbstractLexerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/AbstractLexerTest.java
new file mode 100644
index 0000000..d753970
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/AbstractLexerTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests of tokenization behavior of {@link BuildLexerBase}. */
+@RunWith(JUnit4.class)
+public abstract class AbstractLexerTest {
+
+ private final BuildLexerBase.LexerMode mode;
+ protected String lastError;
+
+ protected AbstractLexerTest(BuildLexerBase.LexerMode mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Create a lexer which takes input from the specified string. Resets the error handler
+ * beforehand.
+ */
+ protected BuildLexerBase createLexer(String input) {
+ lastError = null;
+ return new BuildLexerBase(input, 0, mode) {
+ @Override
+ protected void error(String message, int start, int end) {
+ super.error(message, start, end);
+ lastError = message;
+ }
+ };
+ }
+
+ protected Token[] tokens(String input) {
+ Token[] tokens = createLexer(input).getTokens().toArray(new Token[0]);
+ assertNoCharactersMissing(input.length(), tokens);
+ return tokens;
+ }
+
+ /**
+ * Both the syntax highlighter and the parser require every character be accounted for by a
+ * lexical element.
+ */
+ private static void assertNoCharactersMissing(int totalLength, Token[] tokens) {
+ if (tokens.length != 0 && tokens[tokens.length - 1].right != totalLength) {
+ throw new AssertionError(
+ String.format(
+ "Last tokenized character '%s' doesn't match document length '%s'",
+ tokens[tokens.length - 1].right, totalLength));
+ }
+ int start = 0;
+ for (int i = 0; i < tokens.length; i++) {
+ Token token = tokens[i];
+ if (token.left != start) {
+ throw new AssertionError("Gap/inconsistency at: " + start);
+ }
+ start = token.right;
+ }
+ }
+
+ /**
+ * Returns a string containing the names of the tokens and their associated values.
+ * (String-literals are printed without escaping.)
+ */
+ protected String values(Token[] tokens) {
+ StringBuilder buffer = new StringBuilder();
+ for (Token token : tokens) {
+ if (isIgnored(token.kind)) {
+ continue;
+ }
+ if (buffer.length() > 0) {
+ buffer.append(' ');
+ }
+ buffer.append(token.kind.name());
+ if (token.kind != TokenKind.WHITESPACE && token.value != null) {
+ buffer.append('(').append(token.value).append(')');
+ }
+ }
+ return buffer.toString();
+ }
+
+ /** Returns a string containing just the names of the tokens. */
+ protected String names(Token[] tokens) {
+ StringBuilder buf = new StringBuilder();
+ for (Token token : tokens) {
+ if (isIgnored(token.kind)) {
+ continue;
+ }
+ if (buf.length() > 0) {
+ buf.append(' ');
+ }
+ buf.append(token.kind.name());
+ }
+ return buf.toString();
+ }
+
+ private boolean isIgnored(TokenKind kind) {
+ if (mode == BuildLexerBase.LexerMode.Parsing) {
+ return kind == TokenKind.WHITESPACE || kind == TokenKind.COMMENT;
+ }
+ return false;
+ }
+
+ /**
+ * Returns a string containing just the half-open position intervals of each token. e.g. "[3,4)
+ * [4,9)".
+ */
+ protected String positions(Token[] tokens) {
+ StringBuilder buf = new StringBuilder();
+ for (Token token : tokens) {
+ if (isIgnored(token.kind)) {
+ continue;
+ }
+ if (buf.length() > 0) {
+ buf.append(' ');
+ }
+ buf.append('[').append(token.left).append(',').append(token.right).append(')');
+ }
+ return buf.toString();
+ }
+
+ @Test
+ public void testIntegers() throws Exception {
+ // Detection of MINUS immediately following integer constant proves we
+ // don't consume too many chars.
+
+ // decimal
+ assertEquals("INT(12345) MINUS", values(tokens("12345-")));
+
+ // octal
+ assertEquals("INT(5349) MINUS", values(tokens("012345-")));
+
+ // octal (bad)
+ assertEquals("INT(0) MINUS", values(tokens("012349-")));
+ assertEquals("invalid base-8 integer constant: 012349", lastError);
+
+ // hexadecimal (uppercase)
+ assertEquals("INT(1193055) MINUS", values(tokens("0X12345F-")));
+
+ // hexadecimal (lowercase)
+ assertEquals("INT(1193055) MINUS", values(tokens("0x12345f-")));
+
+ // hexadecimal (lowercase) [note: "g" cause termination of token]
+ assertEquals("INT(74565) IDENTIFIER(g) MINUS", values(tokens("0x12345g-")));
+ }
+
+ @Test
+ public void testStringDelimiters() throws Exception {
+ assertEquals("STRING(foo)", values(tokens("\"foo\"")));
+ assertEquals("STRING(foo)", values(tokens("'foo'")));
+ }
+
+ @Test
+ public void testQuotesInStrings() throws Exception {
+ assertEquals("STRING(foo'bar)", values(tokens("'foo\\'bar'")));
+ assertEquals("STRING(foo'bar)", values(tokens("\"foo'bar\"")));
+ assertEquals("STRING(foo\"bar)", values(tokens("'foo\"bar'")));
+ assertEquals("STRING(foo\"bar)", values(tokens("\"foo\\\"bar\"")));
+ }
+
+ @Test
+ public void testStringEscapes() throws Exception {
+ assertEquals("STRING(a\tb\nc\rd)", values(tokens("'a\\tb\\nc\\rd'"))); // \t \r \n
+ assertEquals("STRING(x\\hx)", values(tokens("'x\\hx'"))); // \h is unknown => "\h"
+ assertEquals("STRING(\\$$)", values(tokens("'\\$$'")));
+ assertEquals("STRING(ab)", values(tokens("'a\\\nb'"))); // escape end of line
+ assertEquals("STRING(abcd)", values(tokens("\"ab\\ucd\"")));
+ assertEquals("escape sequence not implemented: \\u", lastError);
+ }
+
+ @Test
+ public void testRawString() throws Exception {
+ assertEquals("STRING(abcd)", values(tokens("r'abcd'")));
+ assertEquals("STRING(abcd)", values(tokens("r\"abcd\"")));
+ assertEquals("STRING(a\\tb\\nc\\rd)", values(tokens("r'a\\tb\\nc\\rd'"))); // r'a\tb\nc\rd'
+ assertEquals("STRING(a\\\")", values(tokens("r\"a\\\"\""))); // r"a\""
+ assertEquals("STRING(a\\\\b)", values(tokens("r'a\\\\b'"))); // r'a\\b'
+ assertEquals("STRING(ab) IDENTIFIER(r)", values(tokens("r'ab'r")));
+
+ // Unterminated raw string
+ values(tokens("r'\\'")); // r'\'
+ assertEquals("unterminated string literal at eof", lastError);
+ }
+
+ @Test
+ public void testTripleRawString() throws Exception {
+ // r'''a\ncd'''
+ assertEquals("STRING(ab\\ncd)", values(tokens("r'''ab\\ncd'''")));
+ // r"""ab
+ // cd"""
+ assertEquals("STRING(ab\ncd)", values(tokens("\"\"\"ab\ncd\"\"\"")));
+
+ // Unterminated raw string
+ values(tokens("r'''\\'''")); // r'''\'''
+ assertEquals("unterminated string literal at eof", lastError);
+ }
+
+ @Test
+ public void testOctalEscapes() throws Exception {
+ // Regression test for a bug.
+ assertEquals(
+ "STRING(\0 \1 \t \u003f I I1 \u00ff \u00ff \u00fe)",
+ values(tokens("'\\0 \\1 \\11 \\77 \\111 \\1111 \\377 \\777 \\776'")));
+ // Test boundaries (non-octal char, EOF).
+ assertEquals("STRING(\1b \1)", values(tokens("'\\1b \\1'")));
+ }
+
+ @Test
+ public void testTripleQuotedStrings() throws Exception {
+ assertEquals("STRING(a\"b'c \n d\"\"e)", values(tokens("\"\"\"a\"b'c \n d\"\"e\"\"\"")));
+ assertEquals("STRING(a\"b'c \n d\"\"e)", values(tokens("'''a\"b'c \n d\"\"e'''")));
+ }
+
+ @Test
+ public void testBadChar() throws Exception {
+ assertEquals("IDENTIFIER(a) ILLEGAL($) IDENTIFIER(b)", values(tokens("a$b")));
+ assertEquals("invalid character: '$'", lastError);
+ }
+
+ @Test
+ public void testContainsErrors() throws Exception {
+ BuildLexerBase lexerSuccess = createLexer("foo");
+ assertFalse(lexerSuccess.containsErrors());
+
+ BuildLexerBase lexerFail = createLexer("f$o");
+ assertTrue(lexerFail.containsErrors());
+
+ String s = "'unterminated";
+ lexerFail = createLexer(s);
+ assertTrue(lexerFail.containsErrors());
+ assertEquals("STRING(unterminated)", values(tokens(s)));
+ }
+
+ @Test
+ public void testUnterminatedEscapedQuotedString() throws Exception {
+ // regression test --
+ assertEquals(
+ "STRING(escaped \n string) NEWLINE IDENTIFIER(next_line)",
+ values(tokens("\"escaped \\n string\nnext_line")));
+
+ assertEquals("STRING(escaped \n string)", values(tokens("'escaped \\n string")));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/BlazeLexerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/BlazeLexerTest.java
new file mode 100644
index 0000000..dcb3db1
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/BlazeLexerTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests of tokenization behavior of {@link BuildLexerBase} in 'parsing mode' (see {@link
+ * BuildLexerBase.LexerMode})
+ */
+@RunWith(JUnit4.class)
+public class BlazeLexerTest extends AbstractLexerTest {
+
+ public BlazeLexerTest() {
+ super(BuildLexerBase.LexerMode.Parsing);
+ }
+
+ @Test
+ public void testBasics1() throws Exception {
+ assertEquals("IDENTIFIER RPAREN", names(tokens("wiz) ")));
+ assertEquals("IDENTIFIER RPAREN", names(tokens("wiz )")));
+ assertEquals("IDENTIFIER RPAREN", names(tokens(" wiz)")));
+ assertEquals("IDENTIFIER RPAREN", names(tokens(" wiz ) ")));
+ assertEquals("IDENTIFIER RPAREN", names(tokens("wiz\t)")));
+ }
+
+ @Test
+ public void testBasics2() throws Exception {
+ assertEquals("RPAREN", names(tokens(")")));
+ assertEquals("RPAREN", names(tokens(" )")));
+ assertEquals("RPAREN", names(tokens(" ) ")));
+ assertEquals("RPAREN", names(tokens(") ")));
+ }
+
+ @Test
+ public void testBasics3() throws Exception {
+ assertEquals("INT NEWLINE INT", names(tokens("123#456\n789")));
+ assertEquals("INT NEWLINE INT", names(tokens("123 #456\n789")));
+ assertEquals("INT NEWLINE INT", names(tokens("123#456 \n789")));
+ assertEquals("INT NEWLINE INDENT INT", names(tokens("123#456\n 789")));
+ assertEquals("INT NEWLINE INT", names(tokens("123#456\n789 ")));
+ }
+
+ @Test
+ public void testBasics4() throws Exception {
+ assertEquals("", names(tokens("")));
+ assertEquals("", names(tokens("# foo")));
+ assertEquals("INT INT INT INT", names(tokens("1 2 3 4")));
+ assertEquals("INT DOT INT", names(tokens("1.234")));
+ assertEquals(
+ "IDENTIFIER LPAREN IDENTIFIER COMMA IDENTIFIER RPAREN", names(tokens("foo(bar, wiz)")));
+ }
+
+ @Test
+ public void testIntegersAndDot() throws Exception {
+ assertEquals("INT(1) DOT INT(2345)", values(tokens("1.2345")));
+
+ assertEquals("INT(1) DOT INT(2) DOT INT(345)", values(tokens("1.2.345")));
+
+ assertEquals("INT(1) DOT INT(0)", values(tokens("1.23E10")));
+ assertEquals("invalid base-10 integer constant: 23E10", lastError);
+
+ assertEquals("INT(1) DOT INT(0) MINUS INT(10)", values(tokens("1.23E-10")));
+ assertEquals("invalid base-10 integer constant: 23E", lastError);
+
+ assertEquals("DOT INT(123)", values(tokens(". 123")));
+ assertEquals("DOT INT(123)", values(tokens(".123")));
+ assertEquals("DOT IDENTIFIER(abc)", values(tokens(".abc")));
+
+ assertEquals("IDENTIFIER(foo) DOT INT(123)", values(tokens("foo.123")));
+ assertEquals(
+ "IDENTIFIER(foo) DOT IDENTIFIER(bcd)", values(tokens("foo.bcd"))); // 'b' are hex chars
+ assertEquals("IDENTIFIER(foo) DOT IDENTIFIER(xyz)", values(tokens("foo.xyz")));
+ }
+
+ @Test
+ public void testIndentation() throws Exception {
+ assertEquals("INT(1) NEWLINE INT(2) NEWLINE INT(3)", values(tokens("1\n2\n3")));
+ assertEquals(
+ "INT(1) NEWLINE INDENT INT(2) NEWLINE INT(3) NEWLINE DEDENT INT(4)",
+ values(tokens("1\n 2\n 3\n4 ")));
+ assertEquals("INT(1) NEWLINE INDENT INT(2) NEWLINE INT(3)", values(tokens("1\n 2\n 3")));
+ assertEquals(
+ "INT(1) NEWLINE INDENT INT(2) NEWLINE INDENT INT(3)", values(tokens("1\n 2\n 3")));
+ assertEquals(
+ "INT(1) NEWLINE INDENT INT(2) NEWLINE INDENT INT(3) NEWLINE "
+ + "DEDENT INT(4) NEWLINE DEDENT INT(5)",
+ values(tokens("1\n 2\n 3\n 4\n5")));
+
+ assertEquals(
+ "INT(1) NEWLINE INDENT INT(2) NEWLINE INDENT INT(3) NEWLINE "
+ + "DEDENT INT(4) NEWLINE DEDENT INT(5)",
+ values(tokens("1\n 2\n 3\n 4\n5")));
+ assertEquals("indentation error", lastError);
+ }
+
+ @Test
+ public void testIndentationInsideParens() throws Exception {
+ // Indentation is ignored inside parens:
+ assertEquals(
+ "INT(1) LPAREN INT(2) INT(3) INT(4) INT(5)", values(tokens("1 (\n 2\n 3\n 4\n5")));
+ assertEquals(
+ "INT(1) LBRACE INT(2) INT(3) INT(4) INT(5)", values(tokens("1 {\n 2\n 3\n 4\n5")));
+ assertEquals(
+ "INT(1) LBRACKET INT(2) INT(3) INT(4) INT(5)", values(tokens("1 [\n 2\n 3\n 4\n5")));
+ assertEquals(
+ "INT(1) LBRACKET INT(2) RBRACKET NEWLINE INDENT INT(3) "
+ + "NEWLINE INT(4) NEWLINE DEDENT INT(5)",
+ values(tokens("1 [\n 2]\n 3\n 4\n5")));
+ }
+
+ @Test
+ public void testNoIndentationAtEOF() throws Exception {
+ assertEquals("INDENT INT(1)", values(tokens("\n 1")));
+ }
+
+ @Test
+ public void testBlankLineIndentation() throws Exception {
+ // Blank lines and comment lines should not generate any indents
+ // (but note that every input ends with).
+ assertEquals("", names(tokens("\n #\n")));
+ assertEquals("", names(tokens(" #")));
+ assertEquals("NEWLINE", names(tokens(" #\n")));
+ assertEquals("NEWLINE", names(tokens(" #comment\n")));
+ assertEquals(
+ "DEF IDENTIFIER LPAREN IDENTIFIER RPAREN COLON NEWLINE "
+ + "INDENT RETURN IDENTIFIER NEWLINE DEDENT",
+ names(tokens("def f(x):\n" + " # comment\n" + "\n" + " \n" + " return x\n")));
+ }
+
+ @Test
+ public void testMultipleCommentLines() throws Exception {
+ assertEquals(
+ "NEWLINE "
+ + "DEF IDENTIFIER LPAREN IDENTIFIER RPAREN COLON NEWLINE "
+ + "INDENT RETURN IDENTIFIER NEWLINE DEDENT",
+ names(
+ tokens(
+ "# Copyright\n"
+ + "#\n"
+ + "# A comment line\n"
+ + "# An adjoining line\n"
+ + "def f(x):\n"
+ + " return x\n")));
+ }
+
+ @Test
+ public void testBackslash() throws Exception {
+ // backslash followed by newline marked as whitespace (skipped by parser)
+ assertEquals("IDENTIFIER IDENTIFIER", names(tokens("a\\\nb")));
+ assertEquals("IDENTIFIER ILLEGAL IDENTIFIER", names(tokens("a\\ b")));
+ assertEquals("IDENTIFIER LPAREN INT RPAREN", names(tokens("a(\\\n2)")));
+ }
+
+ @Test
+ public void testTokenPositions() throws Exception {
+ // foo ( bar , { 1 :
+ assertEquals(
+ "[0,3) [3,4) [4,7) [7,8) [9,10) [10,11) [11,12)"
+ // 'quux' } )
+ + " [13,19) [19,20) [20,21)",
+ positions(tokens("foo(bar, {1: 'quux'})")));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/HighlightingLexerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/HighlightingLexerTest.java
new file mode 100644
index 0000000..3b87a83
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/HighlightingLexerTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests of tokenization behavior of {@link BuildLexerBase} in 'highlighting mode' (see {@link
+ * BuildLexerBase.LexerMode})
+ */
+@RunWith(JUnit4.class)
+public class HighlightingLexerTest
+ extends com.google.idea.blaze.base.lang.buildfile.lexer.AbstractLexerTest {
+
+ public HighlightingLexerTest() {
+ super(BuildLexerBase.LexerMode.SyntaxHighlighting);
+ }
+
+ @Test
+ public void testBasics1() throws Exception {
+ assertEquals("IDENTIFIER RPAREN WHITESPACE", names(tokens("wiz) ")));
+ assertEquals("IDENTIFIER WHITESPACE RPAREN", names(tokens("wiz )")));
+ assertEquals("WHITESPACE IDENTIFIER RPAREN", names(tokens(" wiz)")));
+ assertEquals("WHITESPACE IDENTIFIER WHITESPACE RPAREN WHITESPACE", names(tokens(" wiz ) ")));
+ assertEquals("IDENTIFIER WHITESPACE RPAREN", names(tokens("wiz\t)")));
+ }
+
+ @Test
+ public void testBasics2() throws Exception {
+ assertEquals("RPAREN", names(tokens(")")));
+ assertEquals("WHITESPACE RPAREN", names(tokens(" )")));
+ assertEquals("WHITESPACE RPAREN WHITESPACE", names(tokens(" ) ")));
+ assertEquals("RPAREN WHITESPACE", names(tokens(") ")));
+ }
+
+ @Test
+ public void testBasics3() throws Exception {
+ assertEquals("INT COMMENT NEWLINE INT", names(tokens("123#456\n789")));
+ assertEquals("INT WHITESPACE COMMENT NEWLINE INT", names(tokens("123 #456\n789")));
+ assertEquals("INT COMMENT NEWLINE INT", names(tokens("123#456 \n789")));
+ assertEquals("INT COMMENT NEWLINE WHITESPACE INT", names(tokens("123#456\n 789")));
+ assertEquals("INT COMMENT NEWLINE INT WHITESPACE", names(tokens("123#456\n789 ")));
+ }
+
+ @Test
+ public void testBasics4() throws Exception {
+ assertEquals("", names(tokens("")));
+ assertEquals("COMMENT", names(tokens("# foo")));
+ assertEquals("INT WHITESPACE INT WHITESPACE INT WHITESPACE INT", names(tokens("1 2 3 4")));
+ assertEquals("INT DOT INT", names(tokens("1.234")));
+ assertEquals(
+ "IDENTIFIER LPAREN IDENTIFIER COMMA WHITESPACE IDENTIFIER RPAREN",
+ names(tokens("foo(bar, wiz)")));
+ }
+
+ @Test
+ public void testIntegersAndDot() throws Exception {
+ assertEquals("INT(1) DOT INT(2345)", values(tokens("1.2345")));
+
+ assertEquals("INT(1) DOT INT(2) DOT INT(345)", values(tokens("1.2.345")));
+
+ assertEquals("INT(1) DOT INT(0)", values(tokens("1.23E10")));
+ assertEquals("invalid base-10 integer constant: 23E10", lastError);
+
+ assertEquals("INT(1) DOT INT(0) MINUS INT(10)", values(tokens("1.23E-10")));
+ assertEquals("invalid base-10 integer constant: 23E", lastError);
+
+ assertEquals("DOT WHITESPACE INT(123)", values(tokens(". 123")));
+ assertEquals("DOT INT(123)", values(tokens(".123")));
+ assertEquals("DOT IDENTIFIER(abc)", values(tokens(".abc")));
+
+ assertEquals("IDENTIFIER(foo) DOT INT(123)", values(tokens("foo.123")));
+ assertEquals(
+ "IDENTIFIER(foo) DOT IDENTIFIER(bcd)", values(tokens("foo.bcd"))); // 'b' are hex chars
+ assertEquals("IDENTIFIER(foo) DOT IDENTIFIER(xyz)", values(tokens("foo.xyz")));
+ }
+
+ @Test
+ public void testNoIndentation() throws Exception {
+ assertEquals("INT(1) NEWLINE INT(2) NEWLINE INT(3)", values(tokens("1\n2\n3")));
+ assertEquals(
+ "INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3) NEWLINE INT(4) WHITESPACE",
+ values(tokens("1\n 2\n 3\n4 ")));
+ assertEquals(
+ "INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3)",
+ values(tokens("1\n 2\n 3")));
+ assertEquals(
+ "INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3)",
+ values(tokens("1\n 2\n 3")));
+ assertEquals(
+ "INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3) "
+ + "NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
+ values(tokens("1\n 2\n 3\n 4\n5")));
+
+ assertEquals(
+ "INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3) "
+ + "NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
+ values(tokens("1\n 2\n 3\n 4\n5")));
+ }
+
+ @Test
+ public void testIndentationInsideParens() throws Exception {
+ // Indentation is ignored inside parens:
+ assertEquals(
+ "INT(1) WHITESPACE LPAREN NEWLINE WHITESPACE INT(2) NEWLINE "
+ + "WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
+ values(tokens("1 (\n 2\n 3\n 4\n5")));
+ assertEquals(
+ "INT(1) WHITESPACE LBRACE NEWLINE WHITESPACE INT(2) NEWLINE "
+ + "WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
+ values(tokens("1 {\n 2\n 3\n 4\n5")));
+ assertEquals(
+ "INT(1) WHITESPACE LBRACKET NEWLINE WHITESPACE INT(2) NEWLINE "
+ + "WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
+ values(tokens("1 [\n 2\n 3\n 4\n5")));
+ assertEquals(
+ "INT(1) WHITESPACE LBRACKET NEWLINE WHITESPACE INT(2) RBRACKET "
+ + "NEWLINE WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
+ values(tokens("1 [\n 2]\n 3\n 4\n5")));
+ }
+
+ @Test
+ public void testNoIndentationAtEOF() throws Exception {
+ assertEquals("NEWLINE WHITESPACE INT(1)", values(tokens("\n 1")));
+ }
+
+ @Test
+ public void testBlankLineIndentation() throws Exception {
+ // Blank lines and comment lines should not generate any newlines indents
+ // (but note that every input ends with).
+ assertEquals("NEWLINE WHITESPACE COMMENT NEWLINE", names(tokens("\n #\n")));
+ assertEquals("WHITESPACE COMMENT", names(tokens(" #")));
+ assertEquals("WHITESPACE COMMENT NEWLINE", names(tokens(" #\n")));
+ assertEquals("WHITESPACE COMMENT NEWLINE", names(tokens(" #comment\n")));
+ assertEquals(
+ "DEF WHITESPACE IDENTIFIER LPAREN IDENTIFIER RPAREN COLON NEWLINE WHITESPACE "
+ + "COMMENT NEWLINE NEWLINE WHITESPACE NEWLINE WHITESPACE "
+ + "RETURN WHITESPACE IDENTIFIER NEWLINE",
+ names(tokens("def f(x):\n" + " # comment\n" + "\n" + " \n" + " return x\n")));
+ }
+
+ @Test
+ public void testMultipleCommentLines() throws Exception {
+ assertEquals(
+ "COMMENT NEWLINE COMMENT NEWLINE COMMENT NEWLINE COMMENT NEWLINE DEF WHITESPACE IDENTIFIER "
+ + "LPAREN IDENTIFIER RPAREN COLON NEWLINE WHITESPACE "
+ + "RETURN WHITESPACE IDENTIFIER NEWLINE",
+ names(
+ tokens(
+ "# Copyright\n"
+ + "#\n"
+ + "# A comment line\n"
+ + "# An adjoining line\n"
+ + "def f(x):\n"
+ + " return x\n")));
+ }
+
+ @Test
+ public void testBackslash() throws Exception {
+ // illegal characters marked as whitespace (skipped by parser)
+ assertEquals("IDENTIFIER WHITESPACE IDENTIFIER", names(tokens("a\\\nb")));
+ assertEquals("IDENTIFIER ILLEGAL WHITESPACE IDENTIFIER", names(tokens("a\\ b")));
+ assertEquals("IDENTIFIER LPAREN WHITESPACE INT RPAREN", names(tokens("a(\\\n2)")));
+ }
+
+ @Test
+ public void testTokenPositions() throws Exception {
+ assertEquals(
+ "[0,3) [3,4) [4,7) [7,8) [8,9) [9,10) [10,11) [11,12) [12,13) [13,19) [19,20) [20,21)",
+ positions(tokens("foo(bar, {1: 'quux'})")));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserTest.java
new file mode 100644
index 0000000..10b7869
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserTest.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.parser;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+import com.intellij.lang.ASTNode;
+import com.intellij.lang.FileASTNode;
+import com.intellij.lang.ParserDefinition;
+import com.intellij.lang.PsiParser;
+import com.intellij.lang.impl.PsiBuilderAdapter;
+import com.intellij.lang.impl.PsiBuilderImpl;
+import com.intellij.lexer.Lexer;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.impl.source.CharTableImpl;
+import com.intellij.psi.impl.source.tree.LeafElement;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Test for the BUILD file parser (converting lexical elements into PSI elements) */
+public class BuildParserTest extends BuildFileIntegrationTestCase {
+
+ private final List<String> errors = Lists.newArrayList();
+
+ @Override
+ protected void doTearDown() {
+ errors.clear();
+ }
+
+ public void testAugmentedAssign() throws Exception {
+ assertThat(parse("x += 1")).isEqualTo("aug_assign(reference, int)");
+ assertThat(parse("x -= 1")).isEqualTo("aug_assign(reference, int)");
+ assertThat(parse("x *= 1")).isEqualTo("aug_assign(reference, int)");
+ assertThat(parse("x /= 1")).isEqualTo("aug_assign(reference, int)");
+ assertThat(parse("x %= 1")).isEqualTo("aug_assign(reference, int)");
+ assertNoErrors();
+ }
+
+ public void testAssign() throws Exception {
+ assertThat(parse("a, b = 5\n")).isEqualTo("assignment(list(reference, target), int)");
+ assertNoErrors();
+ }
+
+ public void testAssign2() throws Exception {
+ assertThat(parse("a = b;c = d\n"))
+ .isEqualTo(
+ Joiner.on("").join("assignment(target, reference), ", "assignment(target, reference)"));
+ assertNoErrors();
+ }
+
+ public void testInvalidAssign() throws Exception {
+ parse("1 + (b = c)");
+ assertContainsErrors();
+ }
+
+ public void testTupleAssign() throws Exception {
+ assertThat(parse("list[0] = 5; dict['key'] = value\n"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "assignment(function_call(reference, positional(int)), int), ",
+ "assignment(function_call(reference, positional(string)), reference)"));
+ assertNoErrors();
+ }
+
+ public void testPrimary() throws Exception {
+ assertThat(parse("f(1 + 2)"))
+ .isEqualTo("function_call(reference, arg_list(positional(binary_op(int, int))))");
+ assertNoErrors();
+ }
+
+ public void testSecondary() throws Exception {
+ assertThat(parse("f(1 % 2)"))
+ .isEqualTo("function_call(reference, arg_list(positional(binary_op(int, int))))");
+ assertNoErrors();
+ }
+
+ public void testDoesNotGetStuck() throws Exception {
+ // Make sure the parser does not get stuck when trying
+ // to parse an expression containing a syntax error.
+ parse("f(1, ], 3)");
+ parse("f(1, ), 3)");
+ parse("[ ) for v in 3)");
+ parse("f(1, [x for foo foo foo foo], 3)");
+ }
+
+ public void testInvalidFunctionStatementDoesNotGetStuck() throws Exception {
+ // Make sure the parser does not get stuck when trying
+ // to parse a function statement containing a syntax error.
+ parse("def is ");
+ parse("def fn(");
+ parse("def empty)");
+ }
+
+ public void testSubstring() throws Exception {
+ assertThat(parse("'FOO.CC'[:].lower()[1:]"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_call(",
+ "function_call(function_call(string), reference, arg_list), ",
+ "positional(int))"));
+ assertNoErrors();
+ }
+
+ public void testFuncallExpr() throws Exception {
+ assertThat(parse("foo(1, 2, bar=wiz)"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_call(reference, arg_list(",
+ "positional(int), ",
+ "positional(int), ",
+ "keyword(reference)))"));
+ assertNoErrors();
+ }
+
+ public void testMethCallExpr() throws Exception {
+ assertThat(parse("foo.foo(1, 2, bar=wiz)"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_call(reference, reference, ",
+ "arg_list(positional(int), positional(int), keyword(reference)))"));
+ assertNoErrors();
+ }
+
+ public void testChainedMethCallExpr() throws Exception {
+ assertThat(parse("foo.replace().split(1)"))
+ .isEqualTo(
+ "function_call(function_call(reference, reference, arg_list), "
+ + "reference, arg_list(positional(int)))");
+ assertNoErrors();
+ }
+
+ public void testPropRefExpr() throws Exception {
+ assertThat(parse("foo.foo")).isEqualTo("dot_expr(reference, reference)");
+ assertNoErrors();
+ }
+
+ public void testStringMethExpr() throws Exception {
+ assertThat(parse("'foo'.foo()")).isEqualTo("function_call(string, reference, arg_list)");
+ assertNoErrors();
+ }
+
+ public void testFuncallLocation() throws Exception {
+ assertThat(parse("a(b);c = d\n"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_call(reference, arg_list(positional(reference))), ",
+ "assignment(target, reference)"));
+ assertNoErrors();
+ }
+
+ public void testList() throws Exception {
+ assertThat(parse("[0,f(1),2]"))
+ .isEqualTo("list(int, function_call(reference, arg_list(positional(int))), int)");
+ assertNoErrors();
+ }
+
+ public void testDict() throws Exception {
+ assertThat(parse("{1:2,2:f(1),3:4}"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "dict(",
+ "dict_entry(int, int), ",
+ "dict_entry(int, function_call(reference, arg_list(positional(int)))), ",
+ "dict_entry(int, int)",
+ ")"));
+ assertNoErrors();
+ }
+
+ public void testArgumentList() throws Exception {
+ assertThat(parse("f(0,g(1,2),2)"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_call(reference, arg_list(",
+ "positional(int), ",
+ "positional("
+ + "function_call(reference, arg_list(positional(int), positional(int)))), ",
+ "positional(int)))"));
+ assertNoErrors();
+ }
+
+ public void testForBreakContinue() throws Exception {
+ String parsed =
+ parse("def foo():", " for i in [1, 2]:", " break", " continue", " break");
+ assertThat(parsed)
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_def(parameter_list, ",
+ "stmt_list(for(target, list(int, int), ",
+ "stmt_list(flow, flow, flow))))"));
+ assertNoErrors();
+ }
+
+ public void testEmptyTuple() throws Exception {
+ assertThat(parse("()")).isEqualTo("list");
+ assertNoErrors();
+ }
+
+ public void testTupleTrailingComma() throws Exception {
+ assertThat(parse("(42,)")).isEqualTo("list(int)");
+ assertNoErrors();
+ }
+
+ public void testSingleton() throws Exception {
+ assertThat(parse("(42)")) // not a tuple!
+ .isEqualTo("list(int)");
+ assertNoErrors();
+ }
+
+ public void testDictionaryLiterals() throws Exception {
+ assertThat(parse("{1:42}")).isEqualTo("dict(dict_entry(int, int))");
+ assertNoErrors();
+ }
+
+ public void testDictionaryLiterals1() throws Exception {
+ assertThat(parse("{}")).isEqualTo("dict");
+ assertNoErrors();
+ }
+
+ public void testDictionaryLiterals2() throws Exception {
+ assertThat(parse("{1:42,}")).isEqualTo("dict(dict_entry(int, int))");
+ assertNoErrors();
+ }
+
+ public void testDictionaryLiterals3() throws Exception {
+ assertThat(parse("{1:42,2:43,3:44}"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "dict(",
+ "dict_entry(int, int), ",
+ "dict_entry(int, int), ",
+ "dict_entry(int, int))"));
+ assertNoErrors();
+ }
+
+ public void testInvalidListComprehensionSyntax() throws Exception {
+ assertThat(parse("[x for x for y in ['a']]")).isEqualTo("list_comp(reference, reference)");
+ assertContainsErrors();
+ }
+
+ public void testListComprehensionEmptyList() throws Exception {
+ // At the moment, we just parse the components of comprehension suffixes.
+ assertThat(parse("['foo/%s.java' % x for x in []]"))
+ .isEqualTo("list_comp(binary_op(string, reference), target, list)");
+ assertNoErrors();
+ }
+
+ public void testListComprehension() throws Exception {
+ assertThat(parse("['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "list_comp(binary_op(string, reference), ",
+ "target, ",
+ "list(string, string, string))"));
+ assertNoErrors();
+ }
+
+ public void testDoesntGetStuck2() throws Exception {
+ parse(
+ "def foo():",
+ " a = 2 for 4", // parse error
+ " b = [3, 4]",
+ "",
+ "d = 4 ada", // parse error
+ "",
+ "def bar():",
+ " a = [3, 4]",
+ " b = 2 + + 5", // parse error
+ "");
+ assertContainsErrors();
+ }
+
+ public void testDoesntGetStuck3() throws Exception {
+ parse("load(*)");
+ parse("load()");
+ parse("load(,)");
+ parse("load)");
+ parse("load(,");
+ parse("load(,\"string\"");
+ assertContainsErrors();
+ }
+
+ public void testExprAsStatement() throws Exception {
+ String parsed =
+ parse("li = []", "li.append('a.c')", "\"\"\" string comment \"\"\"", "foo(bar)");
+ assertThat(parsed)
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "assignment(target, list), ",
+ "function_call(reference, reference, arg_list(positional(string))), ",
+ "string, ",
+ "function_call(reference, arg_list(positional(reference)))"));
+ assertNoErrors();
+ }
+
+ public void testPrecedence1() {
+ assertThat(parse("'%sx' % 'foo' + 'bar'"))
+ .isEqualTo("binary_op(binary_op(string, string), string)");
+ assertNoErrors();
+ }
+
+ public void testPrecedence2() {
+ assertThat(parse("('%sx' + 'foo') * 'bar'"))
+ .isEqualTo("binary_op(list(binary_op(string, string)), string)");
+ assertNoErrors();
+ }
+
+ public void testPrecedence3() {
+ assertThat(parse("'%sx' % ('foo' + 'bar')"))
+ .isEqualTo("binary_op(string, list(binary_op(string, string)))");
+ assertNoErrors();
+ }
+
+ public void testPrecedence4() throws Exception {
+ assertThat(parse("1 + - (2 - 3)"))
+ .isEqualTo("binary_op(int, positional(list(binary_op(int, int))))");
+ assertNoErrors();
+ }
+
+ public void testPrecedence5() throws Exception {
+ assertThat(parse("2 * x | y + 1"))
+ .isEqualTo("binary_op(binary_op(int, reference), binary_op(reference, int))");
+ assertNoErrors();
+ }
+
+ public void testNotIsIgnored() throws Exception {
+ assertThat(parse("not 'b'")).isEqualTo("string");
+ assertNoErrors();
+ }
+
+ public void testNotIn() throws Exception {
+ assertThat(parse("'a' not in 'b'")).isEqualTo("binary_op(string, string)");
+ assertNoErrors();
+ }
+
+ public void testParseBuildFileWithSingeRule() throws Exception {
+ ASTNode tree =
+ createAST(
+ "genrule(name = 'foo',",
+ " srcs = ['input.csv'],",
+ " outs = [ 'result.txt',",
+ " 'result.log'],",
+ " cmd = 'touch result.txt result.log')");
+ List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
+ assertThat(stmts).hasSize(1);
+ assertNoErrors();
+ }
+
+ public void testParseBuildFileWithMultipleRules() throws Exception {
+ ASTNode tree =
+ createAST(
+ "genrule(name = 'foo',",
+ " srcs = ['input.csv'],",
+ " outs = [ 'result.txt',",
+ " 'result.log'],",
+ " srcs = ['input.csv'],",
+ " cmd = 'touch result.txt result.log')",
+ "",
+ "genrule(name = 'bar',",
+ " outs = [ 'graph.svg'],",
+ " cmd = 'touch graph.svg')");
+ List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
+ assertThat(stmts).hasSize(2);
+ assertNoErrors();
+ }
+
+ public void testMissingComma() throws Exception {
+ // missing comma after name='foo'
+ parse("genrule(name = 'foo'", " srcs = ['in'])");
+ assertContainsError("',' expected");
+ }
+
+ public void testDoubleSemicolon() throws Exception {
+ parse("x = 1; ; x = 2;");
+ assertContainsError("expected an expression");
+ }
+
+ public void testMissingBlock() throws Exception {
+ parse("x = 1;", "def foo(x):", "x = 2;\n");
+ assertContainsError("'indent' expected");
+ }
+
+ public void testFunCallBadSyntax() throws Exception {
+ parse("f(1,\n");
+ assertContainsError("')' expected");
+ }
+
+ public void testFunCallBadSyntax2() throws Exception {
+ parse("f(1, 5, ,)\n");
+ assertContainsError("expected an expression");
+ }
+
+ public void testLoad() throws Exception {
+ ASTNode tree = createAST("load('file', 'foo', 'bar',)\n");
+ List<LoadStatement> stmts = getTopLevelNodesOfType(tree, LoadStatement.class);
+ assertThat(stmts).hasSize(1);
+
+ LoadStatement stmt = stmts.get(0);
+ assertThat(stmt.getImportedPath()).isEqualTo("file");
+ assertThat(stmt.getImportedSymbolNames()).isEqualTo(new String[] {"foo", "bar"});
+ assertNoErrors();
+ }
+
+ public void testLoadNoSymbol() throws Exception {
+ parse("load('/foo/bar/file')\n");
+ assertContainsError("'load' statements must include at least one loaded function");
+ }
+
+ public void testFunctionDefinition() throws Exception {
+ ASTNode tree =
+ createAST(
+ "def function(name = 'foo', srcs, outs, *args, **kwargs):",
+ " native.java_library(",
+ " name = name,",
+ " srcs = srcs,",
+ " )",
+ " return");
+ List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
+ assertThat(stmts).hasSize(1);
+ assertNoErrors();
+ }
+
+ public void testFunctionCall() throws Exception {
+ ASTNode tree = createAST("function(name = 'foo', srcs, *args, **kwargs)");
+ List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
+ assertThat(stmts).hasSize(1);
+ assertThat(treeToString(tree))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "function_call(reference, arg_list(",
+ "keyword(string), ",
+ "positional(reference), ",
+ "*(reference), ",
+ "**(reference)))"));
+ assertNoErrors();
+ }
+
+ public void testConditionalStatement() throws Exception {
+ // we don't yet bother specifying which kind of conditionals we hit
+ assertThat(parse("if x : y elif a : b else c"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "if(",
+ "if_part(reference, reference), ",
+ "else_if_part(reference, reference), ",
+ "else_part(reference))"));
+ }
+
+ private ASTNode createAST(String... lines) {
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ builder.append(line).append("\n");
+ }
+ return createAST(builder.toString());
+ }
+
+ private ASTNode createAST(String text) {
+ ParserDefinition definition = new BuildParserDefinition();
+ PsiParser parser = definition.createParser(getProject());
+ Lexer lexer = definition.createLexer(getProject());
+ PsiBuilderImpl psiBuilder =
+ new PsiBuilderImpl(
+ getProject(), null, definition, lexer, new CharTableImpl(), text, null, null);
+ PsiBuilderAdapter adapter =
+ new PsiBuilderAdapter(psiBuilder) {
+ @Override
+ public void error(String messageText) {
+ super.error(messageText);
+ errors.add(messageText);
+ }
+ };
+ return parser.parse(definition.getFileNodeType(), adapter);
+ }
+
+ private String parse(String... lines) {
+ StringBuilder builder = new StringBuilder();
+ for (String line : lines) {
+ builder.append(line).append("\n");
+ }
+ return parse(builder.toString());
+ }
+
+ private String parse(String text) {
+ ASTNode tree = createAST(text);
+ return treeToString(tree);
+ }
+
+ private String treeToString(ASTNode tree) {
+ StringBuilder builder = new StringBuilder();
+ nodeToString(tree, builder);
+ return builder.toString();
+ }
+
+ private void nodeToString(ASTNode node, StringBuilder builder) {
+ if (node instanceof LeafElement || node.getPsi() == null) {
+ return;
+ }
+ PsiElement[] childPsis = getChildBuildPsis(node);
+ if (node instanceof FileASTNode) {
+ appendChildren(childPsis, builder, false);
+ return;
+ }
+ builder.append(node.getElementType());
+ appendChildren(childPsis, builder, true);
+ }
+
+ private void appendChildren(PsiElement[] childPsis, StringBuilder builder, boolean bracket) {
+ if (childPsis.length == 0) {
+ return;
+ }
+ if (bracket) {
+ builder.append("(");
+ }
+ nodeToString(childPsis[0].getNode(), builder);
+ for (int i = 1; i < childPsis.length; i++) {
+ builder.append(", ");
+ nodeToString(childPsis[i].getNode(), builder);
+ }
+ if (bracket) {
+ builder.append(")");
+ }
+ }
+
+ private static <T> List<T> getTopLevelNodesOfType(ASTNode node, Class<T> clazz) {
+ return (List)
+ Arrays.stream(node.getChildren(null))
+ .map(ASTNode::getPsi)
+ .filter(psiElement -> clazz.isInstance(psiElement))
+ .collect(Collectors.toList());
+ }
+
+ private PsiElement[] getChildBuildPsis(ASTNode node) {
+ return Arrays.stream(node.getChildren(null))
+ .map(ASTNode::getPsi)
+ .filter(psiElement -> psiElement instanceof BuildElement)
+ .toArray(PsiElement[]::new);
+ }
+
+ private void assertNoErrors() {
+ assertThat(errors).isEmpty();
+ }
+
+ private void assertContainsErrors() {
+ assertThat(errors).isNotEmpty();
+ }
+
+ private void assertContainsError(String message) {
+ assertThat(errors).contains(message);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/FileCopyTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/FileCopyTest.java
new file mode 100644
index 0000000..a882998
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/FileCopyTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.refactoring.copy.CopyHandler;
+
+/** Tests copying files */
+public class FileCopyTest extends BuildFileIntegrationTestCase {
+
+ public void testCopyingJavaFileReferencedByGlob() {
+ createDirectory("java");
+ PsiFile javaFile = createPsiFile("java/Test.java", "package java;", "public class Test {}");
+
+ PsiFile javaFile2 = createPsiFile("java/Test2.java", "package java;", "public class Test2 {}");
+
+ createBuildFile(
+ "java/BUILD", "java_library(", " name = 'lib',", " srcs = glob(['**/*.java']),", ")");
+
+ PsiDirectory otherDir = createPsiDirectory("java/other");
+
+ WriteCommandAction.runWriteCommandAction(
+ null,
+ () -> {
+ CopyHandler.doCopy(new PsiElement[] {javaFile, javaFile2}, otherDir);
+ });
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/RenameRefactoringTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/RenameRefactoringTest.java
new file mode 100644
index 0000000..ca3a792
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/RenameRefactoringTest.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.psi.PsiFile;
+import com.intellij.refactoring.rename.RenameDialog;
+import com.intellij.refactoring.rename.RenamePsiElementProcessor;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/** Tests that BUILD file references are correctly updated when performing rename refactors. */
+public class RenameRefactoringTest extends BuildFileIntegrationTestCase {
+
+ public void testRenameJavaClass() {
+ PsiFile javaFile =
+ createPsiFile(
+ "com/google/foo/JavaClass.java",
+ "package com.google.foo;",
+ "public class JavaClass {}");
+
+ createBuildFile(
+ "com/google/foo/BUILD",
+ "java_library(name = \"ref1\", srcs = [\"//com/google/foo:JavaClass.java\"])",
+ "java_library(name = \"ref2\", srcs = [\"JavaClass.java\"])",
+ "java_library(name = \"ref3\", srcs = [\":JavaClass.java\"])");
+
+ List<StringLiteral> references =
+ findAllReferencingElementsOfType(javaFile, StringLiteral.class);
+
+ Set<String> oldStrings =
+ references.stream().map(StringLiteral::getStringContents).collect(Collectors.toSet());
+
+ assertThat(references).hasSize(3);
+
+ renamePsiElement(javaFile, "NewName.java");
+
+ Set<String> newStrings =
+ references.stream().map(StringLiteral::getStringContents).collect(Collectors.toSet());
+
+ Set<String> expectedNewStrings =
+ oldStrings
+ .stream()
+ .map((s) -> s.replaceAll("JavaClass", "NewName"))
+ .collect(Collectors.toSet());
+
+ assertThat(expectedNewStrings).containsExactlyElementsIn(newStrings);
+ }
+
+ public void testRenameRule() {
+ BuildFile fooPackage =
+ createBuildFile(
+ "com/google/foo/BUILD",
+ "rule_type(name = \"target\")",
+ "java_library(name = \"local_ref\", srcs = [\":target\"])");
+
+ BuildFile barPackage =
+ createBuildFile(
+ "com/google/test/bar/BUILD",
+ "rule_type(name = \"ref\", arg = \"//com/google/foo:target\")",
+ "top_level_ref = \"//com/google/foo:target\"");
+
+ FuncallExpression targetRule =
+ PsiUtils.findFirstChildOfClassRecursive(fooPackage, FuncallExpression.class);
+ renamePsiElement(targetRule, "newTargetName");
+
+ assertFileContents(
+ fooPackage,
+ "rule_type(name = \"newTargetName\")",
+ "java_library(name = \"local_ref\", srcs = [\":newTargetName\"])");
+
+ assertFileContents(
+ barPackage,
+ "rule_type(name = \"ref\", arg = \"//com/google/foo:newTargetName\")",
+ "top_level_ref = \"//com/google/foo:newTargetName\"");
+ }
+
+ public void testRenameSkylarkExtension() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/tools/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google:tools/build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = []");
+
+ renamePsiElement(extFile, "skylark.bzl");
+
+ assertFileContents(
+ buildFile,
+ "load(",
+ "\"//java/com/google:tools/skylark.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = []");
+ }
+
+ public void testRenameLoadedFunction() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/tools/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = []");
+
+ FunctionStatement fn = extFile.findChildByClass(FunctionStatement.class);
+ renamePsiElement(fn, "action");
+
+ assertFileContents(extFile, "def action(name, deps)");
+
+ assertFileContents(
+ buildFile,
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"action\"",
+ ")",
+ "action(name = \"name\", deps = []");
+ }
+
+ public void testRenameLocalVariable() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "a = 1", "c = a");
+
+ TargetExpression target = PsiUtils.findFirstChildOfClassRecursive(file, TargetExpression.class);
+ assertThat(target.getText()).isEqualTo("a");
+
+ renamePsiElement(target, "b");
+
+ assertFileContents(file, "b = 1", "c = b");
+ }
+
+ // all references, including path fragments in labels, should be renamed.
+ public void testRenameDirectory() {
+ createBuildFile("java/com/baz/BUILD");
+ createBuildFile("java/com/google/tools/BUILD");
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = [\"//java/com/baz:target\"]");
+
+ renameDirectory("java/com", "java/alt");
+
+ assertFileContents(
+ buildFile,
+ "load(",
+ "\"//java/alt/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = [\"//java/alt/baz:target\"]");
+ }
+
+ public void testRenameFunctionParameter() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/tools/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = []");
+
+ FunctionStatement fn = extFile.findChildByClass(FunctionStatement.class);
+ Parameter param = fn.getParameterList().findParameterByName("deps");
+ renamePsiElement(param, "exports");
+
+ assertFileContents(extFile, "def function(name, exports)");
+
+ assertFileContents(
+ buildFile,
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", exports = []");
+ }
+
+ public void testRenameSuggestionForBuildFile() {
+ BuildFile buildFile = createBuildFile("java/com/google/BUILD");
+ RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(buildFile);
+ RenameDialog dialog = processor.createRenameDialog(getProject(), buildFile, buildFile, null);
+ String[] suggestions = dialog.getSuggestedNames();
+ assertThat(suggestions[0]).isEqualTo("BUILD");
+ }
+
+ public void testRenameSuggestionForSkylarkFile() {
+ BuildFile buildFile = createBuildFile("java/com/google/tools/build_defs.bzl");
+ RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(buildFile);
+ RenameDialog dialog = processor.createRenameDialog(getProject(), buildFile, buildFile, null);
+ String[] suggestions = dialog.getSuggestedNames();
+ assertThat(suggestions[0]).isEqualTo("build_defs.bzl");
+ }
+
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/GlobReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/GlobReferenceTest.java
new file mode 100644
index 0000000..0fcd82c
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/GlobReferenceTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.ResolveResult;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/** Tests that glob references are resolved correctly. */
+public class GlobReferenceTest extends BuildFileIntegrationTestCase {
+
+ public void testSimpleGlobReferencingSingleFile() {
+ PsiFile ref = createPsiFile("java/com/google/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(1);
+ assertThat(references).containsExactly(ref);
+ }
+
+ public void testSimpleGlobReferencingSingleFile2() {
+ PsiFile ref = createPsiFile("java/com/google/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(1);
+ assertThat(references).containsExactly(ref);
+ }
+
+ public void testSimpleGlobReferencingSingleFile3() {
+ PsiFile ref = createPsiFile("java/com/google/Test.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['T*t.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(1);
+ assertThat(references).containsExactly(ref);
+ }
+
+ public void testGlobReferencingMultipleFiles() {
+ PsiFile ref1 = createPsiFile("java/com/google/Test.java");
+ PsiFile ref2 = createPsiFile("java/com/google/Foo.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(2);
+ assertThat(references).containsExactly(ref1, ref2);
+ }
+
+ public void testFindsSubDirectories() {
+ PsiFile ref1 = createPsiFile("java/com/google/test/Test.java");
+ PsiFile ref2 = createPsiFile("java/com/google/Foo.java");
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(2);
+ assertThat(references).containsExactly(ref1, ref2);
+ }
+
+ public void testGlobWithExcludes() {
+ PsiFile test = createPsiFile("java/com/google/tests/Test.java");
+ PsiFile foo = createPsiFile("java/com/google/Foo.java");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "glob(" + " ['**/*.java']," + " exclude = ['tests/*.java'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(1);
+ assertThat(references).containsExactly(foo);
+ }
+
+ public void testIncludeDirectories() {
+ createDirectory("java/com/google/tests");
+ PsiFile test = createPsiFile("java/com/google/tests/Test.java");
+ PsiFile foo = createPsiFile("java/com/google/Foo.java");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "glob(" + " ['**/*']," + " exclude = ['BUILD']," + " exclude_directories = 0)");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(3);
+ assertThat(references).containsExactly(foo, test, test.getParent());
+ }
+
+ public void testExcludeDirectories() {
+ createDirectory("java/com/google/tests");
+ PsiFile test = createPsiFile("java/com/google/tests/Test.java");
+ PsiFile foo = createPsiFile("java/com/google/Foo.java");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD", "glob(" + " ['**/*']," + " exclude = ['BUILD'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).hasSize(2);
+ assertThat(references).containsExactly(foo, test);
+ }
+
+ public void testFilesInSubpackagesExcluded() {
+ BuildFile pkg = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+ BuildFile subPkg = createBuildFile("java/com/google/other/BUILD");
+ createFile("java/com/google/other/Other.java");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(pkg, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).isEmpty();
+ }
+
+ private List<PsiElement> multiResolve(GlobExpression glob) {
+ ResolveResult[] result = glob.getReference().multiResolve(false);
+ return Arrays.stream(result)
+ .map(ResolveResult::getElement)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/KeywordReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/KeywordReferenceTest.java
new file mode 100644
index 0000000..310375f
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/KeywordReferenceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.ArgumentList;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
+import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
+
+/** Tests that keyword references are correctly resolved. */
+public class KeywordReferenceTest extends BuildFileIntegrationTestCase {
+
+ public void testPlainKeywordReference() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/build_defs.bzl",
+ "def function(name, deps)",
+ "function(name = \"name\", deps = [])");
+
+ ParameterList params = file.firstChildOfClass(FunctionStatement.class).getParameterList();
+ assertThat(params.getElements()).hasLength(2);
+
+ ArgumentList args = file.firstChildOfClass(FuncallExpression.class).getArgList();
+ assertThat(args.getKeywordArgument("name").getReferencedElement())
+ .isEqualTo(params.findParameterByName("name"));
+
+ assertThat(args.getKeywordArgument("deps").getReferencedElement())
+ .isEqualTo(params.findParameterByName("deps"));
+ }
+
+ public void testKwargsReference() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/build_defs.bzl",
+ "def function(name, **kwargs)",
+ "function(name = \"name\", deps = [])");
+
+ ArgumentList args = file.firstChildOfClass(FuncallExpression.class).getArgList();
+ assertThat(args.getKeywordArgument("deps").getReferencedElement())
+ .isInstanceOf(Parameter.StarStar.class);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LabelReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LabelReferenceTest.java
new file mode 100644
index 0000000..e3f3e7f
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LabelReferenceTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import java.util.List;
+
+/** Tests that string literal references are correctly resolved. */
+public class LabelReferenceTest extends BuildFileIntegrationTestCase {
+
+ public void testExternalFileReference() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "exports_files([\"test.txt\", \"//java/com/google:plugin.xml\"])");
+
+ PsiFile txtFile = createPsiFile("java/com/google/test.txt");
+ PsiFile xmlFile = createPsiFile("java/com/google/plugin.xml");
+
+ List<StringLiteral> strings =
+ PsiUtils.findAllChildrenOfClassRecursive(file, StringLiteral.class);
+ assertThat(strings).hasSize(2);
+ assertThat(strings.get(0).getReferencedElement()).isEqualTo(txtFile);
+ assertThat(strings.get(1).getReferencedElement()).isEqualTo(xmlFile);
+ }
+
+ public void testLocalRuleReference() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "java_library(name = \"lib\")",
+ "java_library(name = \"foo\", deps = [\":lib\"])",
+ "java_library(name = \"bar\", deps = [\"//java/com/google:lib\"])");
+
+ FuncallExpression lib = file.findRule("lib");
+ FuncallExpression foo = file.findRule("foo");
+ FuncallExpression bar = file.findRule("bar");
+
+ assertThat(lib).isNotNull();
+
+ StringLiteral label =
+ PsiUtils.findFirstChildOfClassRecursive(
+ foo.getKeywordArgument("deps"), StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(lib);
+
+ label =
+ PsiUtils.findFirstChildOfClassRecursive(
+ bar.getKeywordArgument("deps"), StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(lib);
+ }
+
+ public void testTargetInAnotherPackageResolves() {
+ BuildFile targetFile = createBuildFile("java/com/google/foo/BUILD", "rule(name = \"target\")");
+
+ BuildFile referencingFile =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "rule(name = \"other\", dep = \"//java/com/google/foo:target\")");
+
+ FuncallExpression target = targetFile.findRule("target");
+ assertThat(target).isNotNull();
+
+ Argument.Keyword depArgument = referencingFile.findRule("other").getKeywordArgument("dep");
+
+ assertThat(depArgument.getValue().getReferencedElement()).isEqualTo(target);
+ }
+
+ public void testRuleNameDoesntCrossPackageBoundaries() {
+ BuildFile targetFile =
+ createBuildFile("java/com/google/pkg/subpkg/BUILD", "rule(name = \"target\")");
+
+ BuildFile referencingFile =
+ createBuildFile(
+ "java/com/google/pkg/BUILD", "rule(name = \"other\", dep = \":subpkg/target\")");
+
+ Argument.Keyword depArgument = referencingFile.findRule("other").getKeywordArgument("dep");
+
+ LabelReference ref = (LabelReference) depArgument.getValue().getReference();
+ assertThat(ref.resolve()).isNull();
+
+ replaceStringContents(ref.getElement(), "//java/com/google/pkg/subpkg:target");
+ assertThat(ref.resolve()).isNotNull();
+ assertThat(ref.resolve()).isEqualTo(targetFile.findRule("target"));
+ }
+
+ public void testLabelWithImplicitRuleName() {
+ BuildFile targetFile = createBuildFile("java/com/google/foo/BUILD", "rule(name = \"foo\")");
+
+ BuildFile referencingFile =
+ createBuildFile(
+ "java/com/google/bar/BUILD", "rule(name = \"other\", dep = \"//java/com/google/foo\")");
+
+ FuncallExpression target = targetFile.findRule("foo");
+ assertThat(target).isNotNull();
+
+ Argument.Keyword depArgument = referencingFile.findRule("other").getKeywordArgument("dep");
+
+ assertThat(depArgument.getValue().getReferencedElement()).isEqualTo(target);
+ }
+
+ public void testAbsoluteLabelInSkylarkExtension() {
+ BuildFile targetFile = createBuildFile("java/com/google/foo/BUILD", "rule(name = \"foo\")");
+
+ BuildFile referencingFile =
+ createBuildFile("java/com/google/foo/skylark.bzl", "LIST = ['//java/com/google/foo:foo']");
+
+ FuncallExpression target = targetFile.findRule("foo");
+ assertThat(target).isNotNull();
+
+ StringLiteral label =
+ PsiUtils.findFirstChildOfClassRecursive(referencingFile, StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(target);
+ }
+
+ public void testRulePreferredOverFile() {
+ BuildFile targetFile = createBuildFile("java/com/foo/BUILD", "java_library(name = 'lib')");
+
+ createDirectory("java/com/foo/lib");
+
+ BuildFile referencingFile =
+ createBuildFile(
+ "java/com/google/bar/BUILD",
+ "java_library(",
+ " name = 'bar',",
+ " src = glob(['**/*.java'])," + " deps = ['//java/com/foo:lib'],",
+ ")");
+
+ FuncallExpression target = targetFile.findRule("lib");
+ assertThat(target).isNotNull();
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(1);
+
+ PsiElement element = references[0].getElement();
+ FuncallExpression rule = PsiUtils.getParentOfType(element, FuncallExpression.class);
+ assertThat(rule.getName()).isEqualTo("bar");
+ assertThat(rule.getContainingFile()).isEqualTo(referencingFile);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LoadedSkylarkExtensionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LoadedSkylarkExtensionTest.java
new file mode 100644
index 0000000..7152ec1
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LoadedSkylarkExtensionTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
+
+/** Tests that funcall references and load statement contents are correctly resolved. */
+public class LoadedSkylarkExtensionTest extends BuildFileIntegrationTestCase {
+
+ public void testStandardLoadReference() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google:build_defs.bzl\",",
+ "\"function\"",
+ ")");
+
+ LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
+ assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
+
+ FunctionStatement function = extFile.firstChildOfClass(FunctionStatement.class);
+ assertThat(function).isNotNull();
+
+ assertThat(load.getImportedSymbolElements()).hasLength(1);
+ assertThat(load.getImportedSymbolElements()[0].getReferencedElement()).isEqualTo(function);
+ }
+
+ // TODO: If we want to support this deprecated format,
+ // we should start by relaxing the ":" requirement in Label
+ //public void testDeprecatedImportLabelFormat() {
+ // BuildFile extFile = createBuildFile(
+ // "java/com/google/build_defs.bzl",
+ // "def function(name, deps)");
+ //
+ // BuildFile buildFile = createBuildFile(
+ // "java/com/google/tools/BUILD",
+ // "load(",
+ // "\"//java/com/google/build_defs.bzl\",",
+ // "\"function\"",
+ // ")");
+ //
+ // LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
+ // assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
+ //}
+
+ public void testPackageLocalImportLabelFormat() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/tools/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/tools/BUILD", "load(", "\":build_defs.bzl\",", "\"function\"", ")");
+
+ LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
+ assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
+ }
+
+ public void testMultipleImportedFunctions() {
+ BuildFile extFile =
+ createBuildFile(
+ "java/com/google/build_defs.bzl", "def fn1(name, deps)", "def fn2(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google:build_defs.bzl\",",
+ "\"fn1\"",
+ "\"fn2\"",
+ ")");
+
+ LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
+ assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
+
+ FunctionStatement[] functions = extFile.childrenOfClass(FunctionStatement.class);
+ assertThat(functions).hasLength(2);
+ assertThat(load.getImportedFunctionReferences()).isEqualTo(functions);
+ }
+
+ public void testFuncallReference() {
+ BuildFile extFile =
+ createBuildFile("java/com/google/tools/build_defs.bzl", "def function(name, deps)");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"function\"",
+ ")",
+ "function(name = \"name\", deps = []");
+
+ FunctionStatement function = extFile.firstChildOfClass(FunctionStatement.class);
+ FuncallExpression funcall = buildFile.firstChildOfClass(FuncallExpression.class);
+
+ assertThat(function).isNotNull();
+ assertThat(funcall.getReferencedElement()).isEqualTo(function);
+ }
+
+ // relative paths in skylark extensions which lie in subdirectories
+ // are relative to the parent blaze package directory
+ public void testRelativePathInSubdirectory() {
+ createFile("java/com/google/BUILD");
+ BuildFile referencedFile =
+ createBuildFile(
+ "java/com/google/nonPackageSubdirectory/skylark.bzl", "def function(): return");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/nonPackageSubdirectory/other.bzl",
+ "load(" + " ':nonPackageSubdirectory/skylark.bzl',",
+ " 'function',",
+ ")",
+ "function()");
+
+ FunctionStatement function = referencedFile.firstChildOfClass(FunctionStatement.class);
+ FuncallExpression funcall = file.firstChildOfClass(FuncallExpression.class);
+
+ assertThat(function).isNotNull();
+ assertThat(funcall.getReferencedElement()).isEqualTo(function);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LocalReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LocalReferenceTest.java
new file mode 100644
index 0000000..7bff52c
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LocalReferenceTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
+import com.intellij.psi.PsiElement;
+
+/**
+ * Tests that local references (to TargetExpressions within a given file) are correctly resolved.
+ */
+public class LocalReferenceTest extends BuildFileIntegrationTestCase {
+
+ public void testCreatesReference() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "a = 1", "c = a");
+
+ AssignmentStatement[] stmts = file.childrenOfClass(AssignmentStatement.class);
+ assertThat(stmts).hasLength(2);
+ assertThat(stmts[1].getAssignedValue()).isInstanceOf(ReferenceExpression.class);
+
+ ReferenceExpression ref = (ReferenceExpression) stmts[1].getAssignedValue();
+ assertThat(ref.getReference()).isInstanceOf(LocalReference.class);
+ }
+
+ public void testReferenceResolves() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "a = 1", "c = a");
+
+ AssignmentStatement[] stmts = file.childrenOfClass(AssignmentStatement.class);
+ ReferenceExpression ref = (ReferenceExpression) stmts[1].getAssignedValue();
+
+ PsiElement referencedElement = ref.getReferencedElement();
+ assertThat(referencedElement).isEqualTo(stmts[0].getLeftHandSideExpression());
+ }
+
+ public void testTargetInOuterScope() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "a = 1", "function(c = a)");
+
+ TargetExpression target =
+ file.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();
+ FuncallExpression funcall = file.findChildByClass(FuncallExpression.class);
+ ReferenceExpression ref =
+ funcall.getKeywordArgument("c").firstChildOfClass(ReferenceExpression.class);
+ assertThat(ref.getReferencedElement()).isEqualTo(target);
+ }
+
+ public void testReferenceInsideFuncallExpression() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "a = 1", "a.function(c)");
+
+ TargetExpression target =
+ file.findChildByClass(AssignmentStatement.class).getLeftHandSideExpression();
+ FuncallExpression funcall = file.findChildByClass(FuncallExpression.class);
+ ReferenceExpression ref = funcall.firstChildOfClass(ReferenceExpression.class);
+ assertThat(ref.getReferencedElement()).isEqualTo(target);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java
new file mode 100644
index 0000000..47d1afc
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.references;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.psi.PsiReference;
+
+/** Tests that package references in string literals are correctly resolved. */
+public class PackageReferenceTest extends BuildFileIntegrationTestCase {
+
+ public void testDirectReferenceResolves() {
+ BuildFile buildFile1 = createBuildFile("java/com/google/tools/BUILD", "# contents");
+
+ BuildFile buildFile2 =
+ createBuildFile(
+ "java/com/google/other/BUILD",
+ "package_group(name = \"grp\", packages = [\"//java/com/google/tools\"])");
+
+ Argument.Keyword packagesArg =
+ buildFile2
+ .firstChildOfClass(FuncallExpression.class)
+ .getArgList()
+ .getKeywordArgument("packages");
+ StringLiteral string =
+ PsiUtils.findFirstChildOfClassRecursive(packagesArg, StringLiteral.class);
+ assertThat(string.getReferencedElement()).isEqualTo(buildFile1);
+ }
+
+ public void testLabelFragmentResolves() {
+ BuildFile buildFile1 =
+ createBuildFile("java/com/google/tools/BUILD", "java_library(name = \"lib\")");
+
+ BuildFile buildFile2 =
+ createBuildFile(
+ "java/com/google/other/BUILD",
+ "java_library(name = \"lib2\", exports = [\"//java/com/google/tools:lib\"])");
+
+ FuncallExpression libTarget = buildFile1.firstChildOfClass(FuncallExpression.class);
+ assertThat(libTarget).isNotNull();
+
+ Argument.Keyword packagesArg =
+ buildFile2
+ .firstChildOfClass(FuncallExpression.class)
+ .getArgList()
+ .getKeywordArgument("exports");
+ StringLiteral string =
+ PsiUtils.findFirstChildOfClassRecursive(packagesArg, StringLiteral.class);
+
+ PsiReference[] references = string.getReferences();
+ assertThat(references).hasLength(2);
+ assertThat(references[0].resolve()).isEqualTo(libTarget);
+ assertThat(references[1].resolve()).isEqualTo(buildFile1);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageTest.java
new file mode 100644
index 0000000..567ad1e
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.psi.PsiFile;
+
+/** Tests for BlazePackage */
+public class BlazePackageTest extends BuildFileIntegrationTestCase {
+
+ public void testFindPackage() {
+ BuildFile packageFile = createBuildFile("java/com/google/BUILD");
+ PsiFile subDirFile = createPsiFile("java/com/google/tools/test.txt");
+ BlazePackage blazePackage = BlazePackage.getContainingPackage(subDirFile);
+ assertThat(blazePackage).isNotNull();
+ assertThat(blazePackage.buildFile).isEqualTo(packageFile);
+ }
+
+ public void testScopeDoesntCrossPackageBoundary() {
+ BuildFile pkg = createBuildFile("java/com/google/BUILD");
+ BuildFile subpkg = createBuildFile("java/com/google/other/BUILD");
+
+ BlazePackage blazePackage = BlazePackage.getContainingPackage(pkg);
+ assertThat(blazePackage.buildFile).isEqualTo(pkg);
+ assertFalse(blazePackage.getSearchScope(false).contains(subpkg.getVirtualFile()));
+ }
+
+ public void testScopeIncludesSubdirectoriesWhichAreNotBlazePackages() {
+ BuildFile pkg = createBuildFile("java/com/google/BUILD");
+ BuildFile subpkg = createBuildFile("java/com/google/foo/bar/BUILD");
+ PsiFile subDirFile = createPsiFile("java/com/google/foo/test.txt");
+
+ BlazePackage blazePackage = BlazePackage.getContainingPackage(subDirFile);
+ assertThat(blazePackage.buildFile).isEqualTo(pkg);
+ assertTrue(blazePackage.getSearchScope(false).contains(subDirFile.getVirtualFile()));
+ }
+
+ public void testScopeLimitedToBlazeFiles() {
+ BuildFile pkg = createBuildFile("java/com/google/BUILD");
+ BuildFile subpkg = createBuildFile("java/com/google/foo/bar/BUILD");
+ PsiFile subDirFile = createPsiFile("java/com/google/foo/test.txt");
+
+ BlazePackage blazePackage = BlazePackage.getContainingPackage(subDirFile);
+ assertThat(blazePackage.buildFile).isEqualTo(pkg);
+ assertFalse(blazePackage.getSearchScope(true).contains(subDirFile.getVirtualFile()));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/GlobalWordIndexTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/GlobalWordIndexTest.java
new file mode 100644
index 0000000..2eb828c
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/GlobalWordIndexTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.search;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.cache.CacheManager;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.UsageSearchContext;
+import java.util.Arrays;
+import org.intellij.lang.annotations.MagicConstant;
+
+/**
+ * Test the WordScanner indexes keywords in the way we expect.<br>
+ * This is vital for navigation, refactoring, highlighting etc.
+ */
+public class GlobalWordIndexTest extends BuildFileIntegrationTestCase {
+
+ public void testWordsInComments() {
+ VirtualFile file = createFile("java/com/google/BUILD", "# words in comments");
+ assertContainsWords(file, UsageSearchContext.IN_COMMENTS, "words", "in", "comments");
+ }
+
+ public void testWordsInStrings() {
+ VirtualFile file =
+ createFile(
+ "java/com/google/BUILD",
+ "name = \"long name with spaces\",",
+ "src = [\"name_without_spaces\"]");
+ assertContainsWords(
+ file,
+ UsageSearchContext.IN_STRINGS,
+ "long",
+ "name",
+ "with",
+ "spaces",
+ "name_without_spaces");
+ }
+
+ public void testWordsInCode() {
+ VirtualFile file =
+ createFile(
+ "java/com/google/BUILD",
+ "java_library(",
+ "name = \"long name with spaces\",",
+ "src = [\"name_without_spaces\"]",
+ ")");
+ assertContainsWords(file, UsageSearchContext.IN_CODE, "java_library", "name", "src");
+ }
+
+ private void assertContainsWords(
+ VirtualFile file,
+ @MagicConstant(flagsFromClass = UsageSearchContext.class) short occurenceMask,
+ String... words) {
+
+ for (String word : words) {
+ VirtualFile[] files =
+ CacheManager.SERVICE
+ .getInstance(getProject())
+ .getVirtualFilesWithWord(
+ word, occurenceMask, GlobalSearchScope.fileScope(getProject(), file), true);
+ if (!Arrays.asList(files).contains(file)) {
+ fail(String.format("Word '%s' not found in file '%s'", word, file));
+ }
+ }
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/GlobValidationTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/GlobValidationTest.java
new file mode 100644
index 0000000..3ba00e5
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/GlobValidationTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.validation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
+import com.intellij.lang.annotation.Annotation;
+import com.intellij.lang.annotation.AnnotationHolder;
+import com.intellij.lang.annotation.AnnotationSession;
+import com.intellij.psi.PsiFile;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Tests glob validation. */
+public class GlobValidationTest extends BuildFileIntegrationTestCase {
+
+ public void testNormalGlob() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'])");
+
+ assertNoErrors(file);
+ }
+
+ public void testNamedIncludeArgument() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(include = ['**/*.java'])");
+
+ assertNoErrors(file);
+ }
+
+ public void testAllArguments() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "glob(['**/*.java'], exclude = ['test/*.java'], exclude_directories = 0)");
+
+ assertNoErrors(file);
+ }
+
+ public void testEmptyExcludeList() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(['**/*.java'], exclude = [])");
+
+ assertNoErrors(file);
+ }
+
+ public void testNoIncludesError() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(exclude = ['BUILD'])");
+
+ assertHasError(file, "Glob expression must contain at least one included string");
+ }
+
+ public void testSingletonExcludeArgumentError() {
+ BuildFile file =
+ createBuildFile("java/com/google/BUILD", "glob(['**/*.java'], exclude = 'BUILD')");
+
+ assertHasError(file, "Glob parameter 'exclude' must be a list of strings");
+ }
+
+ public void testSingletonIncludeArgumentError() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(include = '**/*.java')");
+
+ assertHasError(file, "Glob parameter 'include' must be a list of strings");
+ }
+
+ public void testInvalidExcludeDirectoriesValue() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "glob(['**/*.java'], exclude = ['test/*.java'], exclude_directories = true)");
+
+ assertHasError(file, "exclude_directories parameter to glob must be 0 or 1");
+ }
+
+ public void testUnrecognizedArgumentError() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD", "glob(['**/*.java'], exclude = ['test/*.java'], extra = 1)");
+
+ assertHasError(file, "Unrecognized glob argument");
+ }
+
+ public void testInvalidListArgumentValue() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(include = foo)");
+
+ assertHasError(file, "Glob parameter 'include' must be a list of strings");
+ }
+
+ public void testLocalVariableReference() {
+ BuildFile file =
+ createBuildFile("java/com/google/BUILD", "foo = ['*.java']", "glob(include = foo)");
+
+ assertNoErrors(file);
+ }
+
+ public void testLoadedVariableReference() {
+ BuildFile ext = createBuildFile("java/com/foo/vars.bzl", "LIST_VAR = ['*']");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load('//java/com/foo:vars.bzl', 'LIST_VAR')",
+ "glob(include = LIST_VAR)");
+
+ assertNoErrors(file);
+ }
+
+ public void testInvalidLoadedVariableReference() {
+ BuildFile ext = createBuildFile("java/com/foo/vars.bzl", "LIST_VAR = ['*']", "def function()");
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "load('//java/com/foo:vars.bzl', 'LIST_VAR', 'function')",
+ "glob(include = function)");
+
+ assertHasError(file, "Glob parameter 'include' must be a list of strings");
+ }
+
+ public void testUnresolvedReferenceExpression() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(include = ref)");
+
+ assertHasError(file, "Glob parameter 'include' must be a list of strings");
+ }
+
+ public void testPossibleListExpressionFuncallExpression() {
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(include = fn.list)");
+
+ assertNoErrors(file);
+ }
+
+ public void testPossibleListExpressionParameter() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD", "def function(param1, param2):", " glob(include = param1)");
+
+ assertNoErrors(file);
+ }
+
+ public void testNestedGlobs() {
+ // blaze accepts nested globs
+ BuildFile file = createBuildFile("java/com/google/BUILD", "glob(glob(['*.java']))");
+
+ assertNoErrors(file);
+ }
+
+ public void testKnownInvalidResolvedListExpression() {
+ BuildFile file =
+ createBuildFile("java/com/google/BUILD", "bool_literal = True", "glob(bool_literal)");
+
+ assertHasError(file, "Glob parameter 'include' must be a list of strings");
+ }
+
+ public void testKnownInvalidResolvedString() {
+ BuildFile file =
+ createBuildFile("java/com/google/BUILD", "bool_literal = True", "glob([bool_literal])");
+
+ assertHasError(file, "Glob parameter 'include' must be a list of strings");
+ }
+
+ public void testPossibleStringLiteralIfStatement() {
+ BuildFile file =
+ createBuildFile("java/com/google/BUILD", "glob(include = ['*.java', if test : a else b])");
+
+ // we don't know what the IfStatement evaluates to
+ assertNoErrors(file);
+ }
+
+ public void testPossibleStringLiteralParameter() {
+ BuildFile file =
+ createBuildFile(
+ "java/com/google/BUILD",
+ "def function(param1, param2):",
+ " glob(include = [param1])");
+
+ assertNoErrors(file);
+ }
+
+ private void assertNoErrors(BuildFile file) {
+ assertThat(validateFile(file)).isEmpty();
+ }
+
+ private void assertHasError(BuildFile file, String error) {
+ assertHasError(validateFile(file), error);
+ }
+
+ private void assertHasError(List<Annotation> annotations, String error) {
+ List<String> messages =
+ annotations.stream().map(Annotation::getMessage).collect(Collectors.toList());
+
+ assertThat(messages).contains(error);
+ }
+
+ private List<Annotation> validateFile(BuildFile file) {
+ GlobErrorAnnotator annotator = createAnnotator(file);
+ for (GlobExpression glob :
+ PsiUtils.findAllChildrenOfClassRecursive(file, GlobExpression.class)) {
+ annotator.visitGlobExpression(glob);
+ }
+ return annotationHolder;
+ }
+
+ private GlobErrorAnnotator createAnnotator(PsiFile file) {
+ annotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
+ return new GlobErrorAnnotator() {
+ @Override
+ protected AnnotationHolder getHolder() {
+ return annotationHolder;
+ }
+ };
+ }
+
+ private AnnotationHolderImpl annotationHolder = null;
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewCompletionTest.java
new file mode 100644
index 0000000..4e629f8
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewCompletionTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.projectview.section.sections.Sections;
+import com.intellij.codeInsight.lookup.Lookup;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.psi.PsiFile;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
+/** Tests auto-complete in project view files */
+public class ProjectViewCompletionTest extends ProjectViewIntegrationTestCase {
+
+ private PsiFile setInput(String... fileContents) {
+ return testFixture.configureByText(".blazeproject", Joiner.on("\n").join(fileContents));
+ }
+
+ private void assertResult(String... resultingFileContents) {
+ String s = testFixture.getFile().getText();
+ testFixture.checkResult(Joiner.on("\n").join(resultingFileContents));
+ }
+
+ public void testSectionTypeKeywords() {
+ setInput("<caret>");
+ String[] keywords = getCompletionItemsAsStrings();
+
+ assertThat(keywords)
+ .asList()
+ .containsAllIn(
+ Sections.getUndeprecatedParsers()
+ .stream()
+ .map(SectionParser::getName)
+ .collect(Collectors.toList()));
+ }
+
+ public void testColonAndNewLineAndIndentInsertedAfterListSection() {
+ setInput("direc<caret>");
+ assertThat(completeIfUnique()).isTrue();
+ assertResult("directories:", " <caret>");
+ }
+
+ public void testWhitespaceDividerInsertedAfterScalarSection() {
+ setInput("impo<caret>");
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems[0].getLookupString()).isEqualTo("import");
+
+ testFixture.getLookup().setCurrentItem(completionItems[0]);
+ testFixture.finishLookup(Lookup.NORMAL_SELECT_CHAR);
+
+ assertResult("import <caret>");
+ }
+
+ public void testColonDividerAndSpaceInsertedAfterScalarSection() {
+ setInput("works<caret>");
+ assertThat(completeIfUnique()).isTrue();
+ assertResult("workspace_type: <caret>");
+ }
+
+ public void testNoKeywordCompletionInListItem() {
+ setInput("directories:", " <caret>");
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ if (completionItems == null) {
+ fail("Spurious completion. New file contents: " + testFixture.getFile().getText());
+ }
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testNoKeywordCompletionAfterKeyword() {
+ setInput("import <caret>");
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ if (completionItems == null) {
+ fail("Spurious completion. New file contents: " + testFixture.getFile().getText());
+ }
+ assertThat(completionItems).isEmpty();
+ }
+
+ public void testWorkspaceTypeCompletion() {
+ setInput("workspace_type: <caret>");
+
+ String[] types = getCompletionItemsAsStrings();
+
+ assertThat(types)
+ .asList()
+ .containsAllIn(
+ Arrays.stream(WorkspaceType.values())
+ .map(WorkspaceType::getName)
+ .collect(Collectors.toList()));
+ }
+
+ public void testAdditionalLanguagesCompletion() {
+ setInput("additional_languages:", " <caret>");
+
+ String[] types = getCompletionItemsAsStrings();
+
+ assertThat(types)
+ .asList()
+ .containsAllIn(
+ Arrays.stream(LanguageClass.values())
+ .map(LanguageClass::getName)
+ .collect(Collectors.toList()));
+ }
+
+ public void testUniqueDirectoryCompleted() {
+ setInput("import <caret>");
+
+ createDirectory("java");
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isNull();
+ assertResult("import java<caret>");
+ }
+
+ public void testUniqueMultiSegmentDirectoryCompleted() {
+ setInput("import <caret>");
+
+ createDirectory("java/com/google");
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isNull();
+ assertResult("import java/com/google<caret>");
+ }
+
+ public void testNonDirectoriesIgnored() {
+ setInput("import <caret>");
+
+ createDirectory("java/com/google");
+ createFile("java/IgnoredFile.java");
+
+ String[] completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isNull();
+ assertResult("import java/com/google<caret>");
+ }
+
+ public void testMultipleDirectoryOptions() {
+ createDirectory("foo");
+ createDirectory("bar");
+ createDirectory("other");
+ createDirectory("ostrich/foo");
+ createDirectory("ostrich/fooz");
+
+ setInput("targets:", " //o<caret>");
+
+ String[] completionItems = getCompletionItemsAsSuggestionStrings();
+ assertThat(completionItems).asList().containsExactly("other", "ostrich");
+
+ performTypingAction(testFixture.getEditor(), 's');
+
+ completionItems = getCompletionItemsAsStrings();
+ assertThat(completionItems).isNull();
+ assertResult("targets:", " //ostrich<caret>");
+ }
+
+ public void testRuleCompletion() {
+ createFile("BUILD", "java_library(name = 'lib')");
+
+ setInput("targets:", " //:<caret>");
+
+ String[] completionItems = getCompletionItemsAsSuggestionStrings();
+ assertThat(completionItems).isNull();
+ assertResult("targets:", " //:lib<caret>");
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewIntegrationTestCase.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewIntegrationTestCase.java
new file mode 100644
index 0000000..151d384
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewIntegrationTestCase.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+
+/** Project view file specific integration test base */
+public abstract class ProjectViewIntegrationTestCase extends BlazeIntegrationTestCase {
+
+ @Override
+ protected void doSetup() {
+ mockBlazeProjectDataManager(getMockBlazeProjectData());
+ }
+
+ private BlazeProjectData getMockBlazeProjectData() {
+ BlazeRoots fakeRoots =
+ new BlazeRoots(
+ null,
+ ImmutableList.of(workspaceRoot.directory()),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen"));
+ return new BlazeProjectData(
+ 0,
+ new RuleMap(ImmutableMap.of()),
+ fakeRoots,
+ new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()),
+ new WorkspacePathResolverImpl(workspaceRoot, fakeRoots),
+ null,
+ null,
+ null,
+ null);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewParserIntegrationTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewParserIntegrationTest.java
new file mode 100644
index 0000000..68cf418
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewParserIntegrationTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiElement;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiErrorElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.impl.source.tree.LeafElement;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Tests for the project view file parser */
+public class ProjectViewParserIntegrationTest extends ProjectViewIntegrationTestCase {
+
+ private final List<String> errors = Lists.newArrayList();
+
+ @Override
+ protected void doSetup() {
+ errors.clear();
+ super.doSetup();
+ }
+
+ public void testStandardFile() {
+ assertThat(
+ parse(
+ "directories:",
+ " java/com/google/work",
+ " java/com/google/other",
+ "",
+ "targets:",
+ " //java/com/google/work/...:all",
+ " //java/com/google/other/...:all"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "list_section(list_item, list_item), ", "list_section(list_item, list_item)"));
+ assertNoErrors();
+ }
+
+ public void testIncludeScalarSections() {
+ assertThat(
+ parse(
+ "import java/com/google/work/.blazeproject",
+ "",
+ "workspace_type: intellij_plugin",
+ "",
+ "import_target_output:",
+ " //java/com/google/work:target",
+ "",
+ "test_sources:",
+ " java/com/google/common/*"))
+ .isEqualTo(
+ Joiner.on("")
+ .join(
+ "scalar_section(scalar_item), ",
+ "scalar_section(scalar_item), ",
+ "list_section(list_item), ",
+ "list_section(list_item)"));
+ assertNoErrors();
+ }
+
+ public void testUnrecognizedKeyword() {
+ parse("impart java/com/google/work/.blazeproject", "", "workspace_trype: intellij_plugin");
+
+ assertContainsErrors("Unrecognized keyword: impart", "Unrecognized keyword: workspace_trype");
+ }
+
+ private String parse(String... lines) {
+ PsiFile file = createPsiFile(".blazeproject", lines);
+ collectErrors(file);
+ return treeToString(file);
+ }
+
+ private String treeToString(PsiElement psi) {
+ StringBuilder builder = new StringBuilder();
+ nodeToString(psi, builder);
+ return builder.toString();
+ }
+
+ private void nodeToString(PsiElement psi, StringBuilder builder) {
+ if (psi.getNode() instanceof LeafElement) {
+ return;
+ }
+ PsiElement[] children =
+ Arrays.stream(psi.getChildren())
+ .filter(t -> t instanceof ProjectViewPsiElement)
+ .toArray(PsiElement[]::new);
+ if (psi instanceof ProjectViewPsiElement) {
+ builder.append(psi.getNode().getElementType());
+ appendChildren(children, builder, true);
+ } else {
+ appendChildren(children, builder, false);
+ }
+ }
+
+ private void appendChildren(PsiElement[] childPsis, StringBuilder builder, boolean bracket) {
+ if (childPsis.length == 0) {
+ return;
+ }
+ if (bracket) {
+ builder.append("(");
+ }
+ nodeToString(childPsis[0], builder);
+ for (int i = 1; i < childPsis.length; i++) {
+ builder.append(", ");
+ nodeToString(childPsis[i], builder);
+ }
+ if (bracket) {
+ builder.append(")");
+ }
+ }
+
+ private void assertNoErrors() {
+ assertThat(errors).isEmpty();
+ }
+
+ private void assertContainsErrors(String... errors) {
+ assertThat(this.errors).containsAllIn(Arrays.asList(errors));
+ }
+
+ private void collectErrors(PsiElement psi) {
+ errors.addAll(
+ PsiUtils.findAllChildrenOfClassRecursive(psi, PsiErrorElement.class)
+ .stream()
+ .map(PsiErrorElement::getErrorDescription)
+ .collect(Collectors.toList()));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerTest.java
new file mode 100644
index 0000000..610aef3
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.projectview.lexer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.lang.projectview.ProjectViewIntegrationTestCase;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexerBase.Token;
+
+/** Tests for the project view file lexer */
+public class ProjectViewLexerTest extends ProjectViewIntegrationTestCase {
+
+ public void testStandardCase() {
+ String result =
+ tokenize(
+ "directories:",
+ " java/com/google/work",
+ " java/com/google/other",
+ "",
+ "targets:",
+ " //java/com/google/work/...:all",
+ " //java/com/google/other/...:all");
+
+ assertThat(result)
+ .isEqualTo(
+ Joiner.on(" ")
+ .join(
+ "list_keyword :",
+ "indent identifier",
+ "indent identifier",
+ "list_keyword :",
+ "indent identifier : identifier",
+ "indent identifier : identifier"));
+ }
+
+ public void testIncludeScalarSections() {
+ String result =
+ tokenize(
+ "import java/com/google/work/.blazeproject",
+ "",
+ "workspace_type: intellij_plugin",
+ "",
+ "import_target_output:",
+ " //java/com/google/work:target",
+ "",
+ "test_sources:",
+ " java/com/google/common/*");
+
+ assertThat(result)
+ .isEqualTo(
+ Joiner.on(" ")
+ .join(
+ "scalar_keyword identifier",
+ "scalar_keyword : identifier",
+ "list_keyword :",
+ "indent identifier : identifier",
+ "list_keyword :",
+ "indent identifier"));
+ }
+
+ public void testUnrecognizedKeyword() {
+ String result =
+ tokenize(
+ "impart java/com/google/work/.blazeproject", "", "workspace_trype: intellij_plugin");
+
+ assertThat(result)
+ .isEqualTo(Joiner.on(" ").join("identifier identifier", "identifier : identifier"));
+ }
+
+ private static String tokenize(String... lines) {
+ return names(tokens(Joiner.on("\n").join(lines)));
+ }
+
+ private static Token[] tokens(String input) {
+ Token[] tokens = new ProjectViewLexerBase(input).getTokens().toArray(new Token[0]);
+ assertNoCharactersMissing(input.length(), tokens);
+ return tokens;
+ }
+
+ /**
+ * Both the syntax highlighter and the parser require every character be accounted for by a
+ * lexical element.
+ */
+ private static void assertNoCharactersMissing(int totalLength, Token[] tokens) {
+ if (tokens.length != 0 && tokens[tokens.length - 1].right != totalLength) {
+ throw new AssertionError(
+ String.format(
+ "Last tokenized character '%s' doesn't match document length '%s'",
+ tokens[tokens.length - 1].right, totalLength));
+ }
+ int start = 0;
+ for (int i = 0; i < tokens.length; i++) {
+ Token token = tokens[i];
+ if (token.left != start) {
+ throw new AssertionError("Gap/inconsistency at: " + start);
+ }
+ start = token.right;
+ }
+ }
+
+ /** Returns a string containing the names of the tokens. */
+ private static String names(Token[] tokens) {
+ StringBuilder buf = new StringBuilder();
+ for (Token token : tokens) {
+ if (isIgnored(token.type)) {
+ continue;
+ }
+ if (buf.length() > 0) {
+ buf.append(' ');
+ }
+ buf.append(token.type);
+ }
+ return buf.toString();
+ }
+
+ private static boolean isIgnored(ProjectViewTokenType kind) {
+ return kind == ProjectViewTokenType.WHITESPACE || kind == ProjectViewTokenType.NEWLINE;
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationGenericHandlerIntegrationTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationGenericHandlerIntegrationTest.java
new file mode 100644
index 0000000..1fe63b7
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationGenericHandlerIntegrationTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration.BlazeCommandRunConfigurationSettingsEditor;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeUnknownRunConfigurationHandler;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.util.Disposer;
+import org.jdom.Element;
+
+/**
+ * Integration tests for {@link BlazeCommandRunConfiguration} with {@link
+ * BlazeCommandGenericRunConfigurationHandler} and {@link BlazeUnknownRunConfigurationHandler}.
+ */
+public class BlazeCommandRunConfigurationGenericHandlerIntegrationTest
+ extends BlazeIntegrationTestCase {
+ private static final BlazeCommandName COMMAND = BlazeCommandName.fromString("command");
+
+ private BlazeCommandRunConfigurationType type;
+ private BlazeCommandRunConfiguration configuration;
+
+ @Override
+ protected void doSetup() throws Exception {
+ super.doSetup();
+ // Without BlazeProjectData, the configuration editor is always disabled.
+ mockBlazeProjectDataManager(getMockBlazeProjectData());
+ type = BlazeCommandRunConfigurationType.getInstance();
+ configuration = type.getFactory().createTemplateConfiguration(getProject());
+ }
+
+ private BlazeProjectData getMockBlazeProjectData() {
+ BlazeRoots fakeRoots =
+ new BlazeRoots(
+ null,
+ ImmutableList.of(workspaceRoot.directory()),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen"));
+ return new BlazeProjectData(
+ 0,
+ new RuleMap(ImmutableMap.of()),
+ fakeRoots,
+ new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()),
+ new WorkspacePathResolverImpl(workspaceRoot, fakeRoots),
+ null,
+ null,
+ null,
+ null);
+ }
+
+ public void testNewConfigurationHasUnknownHandler() {
+ assertThat(configuration.getHandler()).isInstanceOf(BlazeUnknownRunConfigurationHandler.class);
+ }
+
+ public void testSetTargetNullMakesGenericHandler() {
+ configuration.setTarget(null);
+ assertThat(configuration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+ }
+
+ public void testTargetExpressionMakesGenericHandler() {
+ configuration.setTarget(TargetExpression.fromString("//..."));
+ assertThat(configuration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+ }
+
+ public void testReadAndWriteMatches() throws Exception {
+ TargetExpression targetExpression = TargetExpression.fromString("//...");
+ configuration.setTarget(targetExpression);
+
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+ handler.setCommand(COMMAND);
+ handler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ handler.setExeFlags(ImmutableList.of("--exeFlag1"));
+ handler.setBlazeBinary("/usr/bin/blaze");
+
+ Element element = new Element("test");
+ configuration.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ readConfiguration.readExternal(element);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(targetExpression);
+ assertThat(readConfiguration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ (BlazeCommandGenericRunConfigurationHandler) readConfiguration.getHandler();
+ assertThat(readHandler.getCommand()).isEqualTo(COMMAND);
+ assertThat(readHandler.getAllBlazeFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readHandler.getAllExeFlags()).containsExactly("--exeFlag1");
+ assertThat(readHandler.getBlazeBinary()).isEqualTo("/usr/bin/blaze");
+ }
+
+ public void testReadAndWriteHandlesNulls() throws Exception {
+ Element element = new Element("test");
+ configuration.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ readConfiguration.readExternal(element);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(configuration.getTarget());
+ assertThat(readConfiguration.getHandler())
+ .isInstanceOf(BlazeUnknownRunConfigurationHandler.class);
+ }
+
+ public void testEditorWithUnknownHandlerDoesNotApplyTo() throws ConfigurationException {
+ assertThat(configuration.getTarget()).isNull();
+ assertThat(configuration.getHandler()).isInstanceOf(BlazeUnknownRunConfigurationHandler.class);
+
+ BlazeCommandRunConfigurationSettingsEditor editor =
+ new BlazeCommandRunConfigurationSettingsEditor(configuration);
+ // Because the configuration's handler is BlazeUnknownRunConfigurationHandler,
+ // resetting the editor to it will leave it in the disabled state.
+ editor.resetFrom(configuration);
+
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ TargetExpression targetExpression = TargetExpression.fromString("//...");
+ readConfiguration.setTarget(targetExpression);
+
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ (BlazeCommandGenericRunConfigurationHandler) readConfiguration.getHandler();
+ readHandler.setCommand(COMMAND);
+ readHandler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ readHandler.setExeFlags(ImmutableList.of("--exeFlag1"));
+ readHandler.setBlazeBinary("/usr/bin/blaze");
+
+ // The editor is disabled, making applyEditorTo a no-op.
+ editor.applyEditorTo(readConfiguration);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(targetExpression);
+ assertThat(readConfiguration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+
+ readHandler = (BlazeCommandGenericRunConfigurationHandler) readConfiguration.getHandler();
+ assertThat(readHandler.getCommand()).isEqualTo(COMMAND);
+ assertThat(readHandler.getAllBlazeFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readHandler.getAllExeFlags()).containsExactly("--exeFlag1");
+ assertThat(readHandler.getBlazeBinary()).isEqualTo("/usr/bin/blaze");
+
+ Disposer.dispose(editor);
+ }
+
+ public void testEditorApplyToAndResetFromMatches() throws ConfigurationException {
+ BlazeCommandRunConfigurationSettingsEditor editor =
+ new BlazeCommandRunConfigurationSettingsEditor(configuration);
+ TargetExpression targetExpression = TargetExpression.fromString("//...");
+ configuration.setTarget(targetExpression);
+
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+ handler.setCommand(COMMAND);
+ handler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ handler.setExeFlags(ImmutableList.of("--exeFlag1"));
+ handler.setBlazeBinary("/usr/bin/blaze");
+
+ editor.resetFrom(configuration);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ editor.applyEditorTo(readConfiguration);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(targetExpression);
+ assertThat(readConfiguration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ (BlazeCommandGenericRunConfigurationHandler) readConfiguration.getHandler();
+ assertThat(readHandler.getCommand()).isEqualTo(handler.getCommand());
+ assertThat(readHandler.getAllBlazeFlags()).isEqualTo(handler.getAllBlazeFlags());
+ assertThat(readHandler.getAllExeFlags()).isEqualTo(handler.getAllExeFlags());
+ assertThat(readHandler.getBlazeBinary()).isEqualTo(handler.getBlazeBinary());
+
+ Disposer.dispose(editor);
+ }
+
+ public void testEditorApplyToAndResetFromHandlesNulls() throws ConfigurationException {
+ BlazeCommandRunConfigurationSettingsEditor editor =
+ new BlazeCommandRunConfigurationSettingsEditor(configuration);
+
+ // Call setTarget to initialize a generic handler, or this won't apply anything.
+ configuration.setTarget(null);
+ assertThat(configuration.getTarget()).isNull();
+ assertThat(configuration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+
+ editor.resetFrom(configuration);
+
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ TargetExpression targetExpression = TargetExpression.fromString("//...");
+ readConfiguration.setTarget(targetExpression);
+
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ (BlazeCommandGenericRunConfigurationHandler) readConfiguration.getHandler();
+ readHandler.setCommand(COMMAND);
+ readHandler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ readHandler.setExeFlags(ImmutableList.of("--exeFlag1"));
+ readHandler.setBlazeBinary("/usr/bin/blaze");
+
+ editor.applyEditorTo(readConfiguration);
+
+ assertThat(readConfiguration.getTarget()).isNull();
+ assertThat(configuration.getHandler())
+ .isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
+
+ readHandler = (BlazeCommandGenericRunConfigurationHandler) readConfiguration.getHandler();
+ assertThat(readHandler.getCommand()).isEqualTo(handler.getCommand());
+ assertThat(readHandler.getAllBlazeFlags()).isEqualTo(handler.getAllBlazeFlags());
+ assertThat(readHandler.getAllExeFlags()).isEqualTo(handler.getAllExeFlags());
+ assertThat(readHandler.getBlazeBinary()).isEqualTo(handler.getBlazeBinary());
+
+ Disposer.dispose(editor);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationSettingsEditorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationSettingsEditorTest.java
new file mode 100644
index 0000000..a0a044d
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationSettingsEditorTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration.BlazeCommandRunConfigurationSettingsEditor;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.util.Disposer;
+
+/** Tests for {@link BlazeCommandRunConfiguration.BlazeCommandRunConfigurationSettingsEditor}. */
+public class BlazeCommandRunConfigurationSettingsEditorTest extends BlazeIntegrationTestCase {
+
+ private BlazeCommandRunConfigurationType type;
+ private BlazeCommandRunConfiguration configuration;
+
+ @Override
+ protected void doSetup() throws Exception {
+ super.doSetup();
+ // Without BlazeProjectData, the configuration editor is always disabled.
+ mockBlazeProjectDataManager(getMockBlazeProjectData());
+ type = BlazeCommandRunConfigurationType.getInstance();
+ configuration = type.getFactory().createTemplateConfiguration(getProject());
+ }
+
+ private BlazeProjectData getMockBlazeProjectData() {
+ BlazeRoots fakeRoots =
+ new BlazeRoots(
+ null,
+ ImmutableList.of(workspaceRoot.directory()),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen"));
+ return new BlazeProjectData(
+ 0,
+ new RuleMap(ImmutableMap.of()),
+ fakeRoots,
+ new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()),
+ new WorkspacePathResolverImpl(workspaceRoot, fakeRoots),
+ null,
+ null,
+ null,
+ null);
+ }
+
+ public void testEditorApplyToAndResetFromMatches() throws ConfigurationException {
+ BlazeCommandRunConfigurationSettingsEditor editor =
+ new BlazeCommandRunConfigurationSettingsEditor(configuration);
+ Label label = new Label("//package:rule");
+ configuration.setTarget(label);
+
+ editor.resetFrom(configuration);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ editor.applyEditorTo(readConfiguration);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(label);
+
+ Disposer.dispose(editor);
+ }
+
+ public void testEditorApplyToAndResetFromHandlesNulls() throws ConfigurationException {
+ BlazeCommandRunConfigurationSettingsEditor editor =
+ new BlazeCommandRunConfigurationSettingsEditor(configuration);
+
+ editor.resetFrom(configuration);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(getProject());
+ editor.applyEditorTo(readConfiguration);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(configuration.getTarget());
+
+ Disposer.dispose(editor);
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/TestRuleHeuristicTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/TestRuleHeuristicTest.java
new file mode 100644
index 0000000..16e7de0
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/TestRuleHeuristicTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.io.File;
+import java.util.Collection;
+
+/** Integration tests for {@link TestRuleHeuristic}. */
+public class TestRuleHeuristicTest extends BlazeIntegrationTestCase {
+
+ public void testTestSizeMatched() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ Collection<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(new Label("//foo:test2"));
+ }
+
+ public void testRuleNameMatched() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ Collection<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder().setLabel("//foo:FirstTest").setKind("java_test").build(),
+ RuleIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, null);
+ assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ }
+
+ public void testNoMatchFallBackToFirstRule() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ ImmutableList<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder()
+ .setLabel("//bar:BarTest")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:OtherTest")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.LARGE);
+ assertThat(match).isEqualTo(new Label("//bar:BarTest"));
+ }
+
+ public void testRuleNameCheckedBeforeTestSize() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ ImmutableList<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder()
+ .setLabel("//bar:BarTest")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:FooTest")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java
new file mode 100644
index 0000000..6a2dadf
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import java.util.stream.Collectors;
+
+/** Tests for ImportRoots */
+public class ImportRootsTest extends BlazeIntegrationTestCase {
+
+ public void testBazelArtifactDirectoriesExcluded() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Bazel)
+ .add(new DirectoryEntry(new WorkspacePath(""), true))
+ .build();
+
+ ImmutableList<String> artifactDirs =
+ BuildSystemProvider.getBuildSystemProvider(BuildSystem.Bazel)
+ .buildArtifactDirectories(workspaceRoot);
+
+ assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath(""));
+ assertThat(
+ importRoots
+ .excludeDirectories()
+ .stream()
+ .map(WorkspacePath::relativePath)
+ .collect(Collectors.toList()))
+ .containsExactlyElementsIn(artifactDirs);
+
+ assertThat(artifactDirs).contains("bazel-" + workspaceRoot.directory().getName());
+ }
+
+ public void testNoAddedExclusionsWithoutWorkspaceRootInclusion() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Bazel)
+ .add(new DirectoryEntry(new WorkspacePath("foo/bar"), true))
+ .build();
+
+ assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath("foo/bar"));
+ assertThat(importRoots.excludeDirectories()).isEmpty();
+ }
+
+ public void testNoAddedExclusionsForBlaze() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(new DirectoryEntry(new WorkspacePath(""), true))
+ .build();
+
+ assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath(""));
+ assertThat(importRoots.excludeDirectories()).isEmpty();
+ }
+
+ // if the workspace root is an included directory, all rules should be imported as sources.
+ public void testAllLabelsIncludedUnderWorkspaceRoot() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(new DirectoryEntry(new WorkspacePath(""), true))
+ .build();
+
+ assertThat(importRoots.importAsSource(new Label("//:target"))).isTrue();
+ assertThat(importRoots.importAsSource(new Label("//foo/bar:target"))).isTrue();
+ }
+
+ public void testNonOverlappingDirectoriesAreNotFilteredOut() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(new DirectoryEntry(new WorkspacePath("root0/subdir0"), true))
+ .add(new DirectoryEntry(new WorkspacePath("root0/subdir1"), true))
+ .add(new DirectoryEntry(new WorkspacePath("root1"), true))
+ .build();
+ assertThat(importRoots.rootDirectories())
+ .containsExactly(
+ new WorkspacePath("root0/subdir0"),
+ new WorkspacePath("root0/subdir1"),
+ new WorkspacePath("root1"));
+ }
+
+ public void testOverlappingDirectoriesAreFilteredOut() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(new DirectoryEntry(new WorkspacePath("root"), true))
+ .add(new DirectoryEntry(new WorkspacePath("root"), true))
+ .add(new DirectoryEntry(new WorkspacePath("root/subdir"), true))
+ .build();
+ assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath("root"));
+ }
+
+ public void testWorkspaceRootIsOnlyDirectoryLeft() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(new DirectoryEntry(new WorkspacePath("."), true))
+ .add(new DirectoryEntry(new WorkspacePath("."), true))
+ .add(new DirectoryEntry(new WorkspacePath("root/subdir"), true))
+ .build();
+ assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath("."));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/BlazeIconsTest.java b/base/tests/unittests/com/google/idea/blaze/base/BlazeIconsTest.java
new file mode 100644
index 0000000..bf0a68b
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/BlazeIconsTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base;
+
+import static org.junit.Assert.assertNotNull;
+
+import icons.BlazeIcons;
+import javax.swing.Icon;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for BlazeIcons */
+@RunWith(JUnit4.class)
+public class BlazeIconsTest {
+
+ @Test
+ public void testIcon() {
+ Icon icon = BlazeIcons.Blaze;
+
+ assertNotNull(icon);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandNameTest.java b/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandNameTest.java
new file mode 100644
index 0000000..6d45278
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandNameTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import java.util.Collection;
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeCommandName}. */
+@RunWith(JUnit4.class)
+public class BlazeCommandNameTest {
+ @Test
+ public void emptyNameShouldThrow() {
+ try {
+ BlazeCommandName.fromString("");
+ fail("Empty commands should not be allowed.");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void hardcodedNamesShouldBeKnown() {
+ assertThat(BlazeCommandName.knownCommands()).contains(BlazeCommandName.MOBILE_INSTALL);
+ }
+
+ @Test
+ public void userCommandNamesShouldBecomeKnown() {
+ Collection<String> knownCommandStrings =
+ Collections2.transform(
+ BlazeCommandName.knownCommands(),
+ new Function<BlazeCommandName, String>() {
+ @Nullable
+ @Override
+ public String apply(BlazeCommandName input) {
+ return input.toString();
+ }
+ });
+ assertThat(knownCommandStrings).doesNotContain("user-command");
+ BlazeCommandName userCommand = BlazeCommandName.fromString("user-command");
+ assertThat(BlazeCommandName.knownCommands()).contains(userCommand);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java b/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java
new file mode 100644
index 0000000..64b6894
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.command;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import java.util.Collections;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeCommand}. */
+@RunWith(JUnit4.class)
+public class BlazeCommandTest extends BlazeTestCase {
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ ExperimentService experimentService = new MockExperimentService();
+ applicationServices.register(ExperimentService.class, experimentService);
+ applicationServices.register(BlazeUserSettings.class, new BlazeUserSettings());
+ }
+
+ @Test
+ public void addedFlagsShouldGoAtStart() {
+ List<String> flagsCommand =
+ BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
+ .addTargets(new Label("//a:b"))
+ .addBlazeFlags("--flag1", "--flag2")
+ .addExeFlags("--exeFlag1", "--exeFlag2")
+ .build()
+ .toList();
+ // First three strings are always 'blaze run --tool_tag=ijwb:IDEA:ultimate'
+ assertThat(flagsCommand.subList(3, 5)).isEqualTo(ImmutableList.of("--flag1", "--flag2"));
+ }
+
+ @Test
+ public void targetsShouldGoAfterBlazeFlagsAndDoubleHyphen() {
+ List<String> command =
+ BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
+ .addTargets(new Label("//a:b"), new Label("//c:d"))
+ .addBlazeFlags("--flag1", "--flag2")
+ .addExeFlags("--exeFlag1", "--exeFlag2")
+ .build()
+ .toList();
+ // First six strings should be 'blaze run --tool_tag=ijwb:IDEA:ultimate --flag1 --flag2 --'
+ assertThat(command.indexOf("--")).isEqualTo(5);
+ assertThat(Collections.indexOfSubList(command, ImmutableList.of("//a:b", "//c:d")))
+ .isEqualTo(6);
+ }
+
+ @Test
+ public void exeFlagsShouldGoLast() {
+ List<String> command =
+ BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
+ .addTargets(new Label("//a:b"), new Label("//c:d"))
+ .addBlazeFlags("--flag1", "--flag2")
+ .addExeFlags("--exeFlag1", "--exeFlag2")
+ .build()
+ .toList();
+ List<String> finalTwoFlags = command.subList(command.size() - 2, command.size());
+ assertThat(finalTwoFlags).containsExactly("--exeFlag1", "--exeFlag2");
+ }
+
+ @Test
+ public void maintainUserOrderingOfTargets() {
+ List<String> command =
+ BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
+ .addTargets(
+ new Label("//a:b"), TargetExpression.fromString("-//e:f"), new Label("//c:d"))
+ .addBlazeFlags("--flag1", "--flag2")
+ .addExeFlags("--exeFlag1", "--exeFlag2")
+ .build()
+ .toList();
+
+ ImmutableList<Object> expected =
+ ImmutableList.builder()
+ .add("/usr/bin/blaze")
+ .add("run")
+ .add(BlazeFlags.getToolTagFlag())
+ .add("--flag1")
+ .add("--flag2")
+ .add("--")
+ .add("//a:b")
+ .add("-//e:f")
+ .add("//c:d")
+ .add("--exeFlag1")
+ .add("--exeFlag2")
+ .build();
+ assertThat(command).isEqualTo(expected);
+ }
+
+ @Test
+ public void binaryAndCommandShouldComeFirst() {
+ List<String> command =
+ BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.BUILD)
+ .addBlazeFlags("--flag")
+ .addExeFlags("--exeFlag")
+ .build()
+ .toList();
+ assertThat(command.subList(0, 2)).isEqualTo(ImmutableList.of("/usr/bin/blaze", "build"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/filecache/FileDifferTest.java b/base/tests/unittests/com/google/idea/blaze/base/filecache/FileDifferTest.java
new file mode 100644
index 0000000..ab28819
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/filecache/FileDifferTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.filecache;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import java.io.File;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link FileDiffer} */
+@RunWith(JUnit4.class)
+public class FileDifferTest extends BlazeTestCase {
+ private MockFileAttributeProvider fileModificationProvider;
+
+ private static class MockFileAttributeProvider extends FileAttributeProvider {
+ List<Long> times = Lists.newArrayList();
+ int index;
+
+ public MockFileAttributeProvider add(long time) {
+ times.add(time);
+ return this;
+ }
+
+ @Override
+ public long getFileModifiedTime(@NotNull File file) {
+ return times.get(index++);
+ }
+ }
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ applicationServices.register(BlazeExecutor.class, new MockBlazeExecutor());
+
+ this.fileModificationProvider = new MockFileAttributeProvider();
+ applicationServices.register(FileAttributeProvider.class, fileModificationProvider);
+ }
+
+ @Test
+ public void testDiffWithDiffMethodTimestamp() throws Exception {
+ ImmutableMap<File, Long> oldState =
+ ImmutableMap.<File, Long>builder()
+ .put(new File("file1"), 13L)
+ .put(new File("file2"), 17L)
+ .put(new File("file3"), 21L)
+ .build();
+ List<File> fileList = ImmutableList.of(new File("file1"), new File("file2"));
+ fileModificationProvider.add(13).add(122);
+
+ List<File> newFiles = Lists.newArrayList();
+ List<File> removedFiles = Lists.newArrayList();
+ FileDiffer.updateFiles(oldState, fileList, newFiles, removedFiles);
+
+ assertThat(newFiles).containsExactly(new File("file2"));
+ assertThat(removedFiles).containsExactly(new File("file3"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/io/MockWorkspaceScanner.java b/base/tests/unittests/com/google/idea/blaze/base/io/MockWorkspaceScanner.java
new file mode 100644
index 0000000..2e3dea8
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/io/MockWorkspaceScanner.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.io;
+
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import java.util.Set;
+import org.jetbrains.annotations.NotNull;
+
+/** Mocks the file system. */
+public final class MockWorkspaceScanner implements WorkspaceScanner {
+
+ Set<WorkspacePath> files = Sets.newHashSet();
+ Set<WorkspacePath> directories = Sets.newHashSet();
+
+ public MockWorkspaceScanner addFile(@NotNull WorkspacePath file) {
+ files.add(file);
+ return this;
+ }
+
+ public MockWorkspaceScanner addDirectory(@NotNull WorkspacePath file) {
+ addFile(file);
+ directories.add(file);
+ return this;
+ }
+
+ public MockWorkspaceScanner addPackage(@NotNull WorkspacePath file) {
+ addFile(new WorkspacePath(file + "/BUILD"));
+ addDirectory(file);
+ return this;
+ }
+
+ public MockWorkspaceScanner addPackages(@NotNull Iterable<WorkspacePath> files) {
+ for (WorkspacePath workspacePath : files) {
+ addPackage(workspacePath);
+ }
+ return this;
+ }
+
+ public MockWorkspaceScanner addImportRoots(@NotNull ImportRoots importRoots) {
+ addPackages(importRoots.rootDirectories());
+ addPackages(importRoots.excludeDirectories());
+ return this;
+ }
+
+ public MockWorkspaceScanner addProjectView(
+ WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze).add(projectViewSet).build();
+ return addImportRoots(importRoots);
+ }
+
+ @Override
+ public boolean exists(WorkspaceRoot workspaceRoot, WorkspacePath file) {
+ return files.contains(file);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java b/base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java
new file mode 100644
index 0000000..322754d
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.issueparser;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeIssueParser}. */
+@RunWith(JUnit4.class)
+public class BlazeIssueParserTest extends BlazeTestCase {
+
+ private ProjectViewManager projectViewManager;
+ private WorkspaceRoot workspaceRoot;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+
+ projectViewManager = mock(ProjectViewManager.class);
+ projectServices.register(ProjectViewManager.class, projectViewManager);
+
+ workspaceRoot = new WorkspaceRoot(new File("/root"));
+ }
+
+ @Test
+ public void testParseTargetError() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: invalid target format "
+ + "'//javatests/com/google/devtools/aswb/testapps/aswbtestlib/...:alls': "
+ + "invalid package name "
+ + "'javatests/com/google/devtools/aswb/testapps/aswbtestlib/...': "
+ + "package name component contains only '.' characters.");
+ assertNotNull(issue);
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testParseCompileError() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "java/com/google/android/samples/helloroot/math/DivideMath.java:17: error: "
+ + "non-static variable this cannot be referenced from a static context");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath())
+ .isEqualTo("/root/java/com/google/android/samples/helloroot/math/DivideMath.java");
+ assertThat(issue.getLine()).isEqualTo(17);
+ assertThat(issue.getMessage())
+ .isEqualTo("non-static variable this cannot be referenced from a static context");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testParseCompileErrorWithColumn() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "java/com/google/devtools/aswb/pluginrepo/googleplex/PluginsEndpoint.java:33:26: "
+ + "error: '|' is not preceded with whitespace.");
+ assertNotNull(issue);
+ assertThat(issue.getLine()).isEqualTo(33);
+ assertThat(issue.getMessage()).isEqualTo("'|' is not preceded with whitespace.");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testParseCompileErrorWithAbsolutePath() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "/root/java/com/google/android/samples/helloroot/math/DivideMath.java:17: error: "
+ + "non-static variable this cannot be referenced from a static context");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath())
+ .isEqualTo("/root/java/com/google/android/samples/helloroot/math/DivideMath.java");
+ }
+
+ @Test
+ public void testParseCompileErrorWithDepotPath() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "//depot/google3/package_path/DivideMath.java:17: error: "
+ + "non-static variable this cannot be referenced from a static context");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo("/root/package_path/DivideMath.java");
+ }
+
+ @Test
+ public void testParseBuildError() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /path/to/root/javatests/package_path/BUILD:42:12: "
+ + "Target '//java/package_path:helloroot_visibility' failed");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo("/path/to/root/javatests/package_path/BUILD");
+ assertThat(issue.getLine()).isEqualTo(42);
+ assertThat(issue.getMessage())
+ .isEqualTo("Target '//java/package_path:helloroot_visibility' failed");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testParseLinelessBuildError() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /path/to/root/java/package_path/BUILD:char offsets 1222--1229: "
+ + "name 'grubber' is not defined");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo("/path/to/root/java/package_path/BUILD");
+ assertThat(issue.getMessage()).isEqualTo("name 'grubber' is not defined");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testLabelProjectViewParser() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ new File(".blazeproject"),
+ ProjectView.builder()
+ .add(
+ ListSection.builder(TargetSection.KEY)
+ .add(TargetExpression.fromString("//package/path:hello4")))
+ .build())
+ .build();
+ when(projectViewManager.getProjectViewSet()).thenReturn(projectViewSet);
+
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "no such target '//package/path:hello4': "
+ + "target 'hello4' not declared in package 'package/path' "
+ + "defined by /path/to/root/package/path/BUILD");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo(".blazeproject");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testPackageProjectViewParser() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ new File(".blazeproject"),
+ ProjectView.builder()
+ .add(
+ ListSection.builder(TargetSection.KEY)
+ .add(TargetExpression.fromString("//package/path:hello4")))
+ .build())
+ .build();
+ when(projectViewManager.getProjectViewSet()).thenReturn(projectViewSet);
+
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "no such package 'package/path': BUILD file not found on package path");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo(".blazeproject");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testDeletedBUILDFileButLeftPackageInLocalTargets() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ new File(".blazeproject"),
+ ProjectView.builder()
+ .add(
+ ListSection.builder(TargetSection.KEY)
+ .add(TargetExpression.fromString("//tests/com/google/a/b/c/d/baz:baz")))
+ .build())
+ .build();
+ when(projectViewManager.getProjectViewSet()).thenReturn(projectViewSet);
+
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "Error:com.google.a.b.Exception exception in Bar: no targets found beneath "
+ + "'tests/com/google/a/b/c/d/baz' Thrown during call: ...");
+ assertNotNull(issue);
+ assertNotNull(issue.getFile());
+ assertThat(issue.getFile().getPath()).isEqualTo(".blazeproject");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ assertThat(issue.getMessage())
+ .isEqualTo("no targets found beneath 'tests/com/google/a/b/c/d/baz'");
+ }
+
+ @Test
+ public void testMultilineTraceback() {
+ String[] lines =
+ new String[] {
+ "ERROR: /home/plumpy/whatever:9:12: Traceback (most recent call last):",
+ "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 8",
+ "\t\tpackage_group(name = BAD_FUNCTION(\"hellogoogle...\"), ...\"])",
+ "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 9, "
+ + "in package_group",
+ "\t\tBAD_FUNCTION",
+ "name 'BAD_FUNCTION' is not defined."
+ };
+
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ for (int i = 0; i < lines.length - 1; ++i) {
+ IssueOutput issue = blazeIssueParser.parseIssue(lines[i]);
+ assertNull(issue);
+ }
+
+ IssueOutput issue = blazeIssueParser.parseIssue(lines[lines.length - 1]);
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo("/home/plumpy/whatever");
+ assertThat(issue.getMessage().split("\n")).hasLength(lines.length);
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testLineAfterTracebackIsAlsoParsed() {
+ String[] lines =
+ new String[] {
+ "ERROR: /home/plumpy/whatever:9:12: Traceback (most recent call last):",
+ "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 8",
+ "\t\tpackage_group(name = BAD_FUNCTION(\"hellogoogle...\"), ...\"])",
+ "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 9, "
+ + "in package_group",
+ "\t\tBAD_FUNCTION",
+ "name 'BAD_FUNCTION' is not defined."
+ };
+
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ for (int i = 0; i < lines.length; ++i) {
+ blazeIssueParser.parseIssue(lines[i]);
+ }
+
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath()).isEqualTo("/home/plumpy/whatever");
+ assertThat(issue.getMessage()).isEqualTo("name 'grubber' is not defined");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
+ public void testMultipleIssues() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined");
+ assertNotNull(issue);
+ issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined");
+ assertNotNull(issue);
+ issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined");
+ assertNotNull(issue);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/lang/buildfile/psi/StripQuotesTest.java b/base/tests/unittests/com/google/idea/blaze/base/lang/buildfile/psi/StripQuotesTest.java
new file mode 100644
index 0000000..f92d5b9
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/lang/buildfile/psi/StripQuotesTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile.psi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test strip quotes method in {@link StringLiteral} */
+@RunWith(JUnit4.class)
+public class StripQuotesTest {
+
+ @Test
+ public void testStandardSingleQuotes() {
+ String s = "'normal string'";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+ }
+
+ @Test
+ public void testStandardDoubleQuotes() {
+ String s = "\"normal string\"";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+ }
+
+ @Test
+ public void testOtherQuoteTypeMixedIn() {
+ String s = "\"normal 'string'\"";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal 'string'");
+ }
+
+ @Test
+ public void testOtherQuoteTypeMixedIn2() {
+ String s = "'normal \"string\"'";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal \"string\"");
+ }
+
+ @Test
+ public void testTrailingQuoteMissing() {
+ String s = "'normal string";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+ }
+
+ @Test
+ public void testStandardTripleSingleQuotes() {
+ String s = "'''normal string'''";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+ }
+
+ @Test
+ public void testStandardTripleDoubleQuotes() {
+ String s = "\"\"\"normal string\"\"\"";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+ }
+
+ @Test
+ public void testTripleQuotesWithMissingTrailingQuotes() {
+ String s = "\"\"\"normal string";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+
+ s = "\"\"\"normal string\"";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+
+ s = "\"\"\"normal string\"\"";
+ assertThat(StringLiteral.stripQuotes(s)).isEqualTo("normal string");
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/metrics/ActionTest.java b/base/tests/unittests/com/google/idea/blaze/base/metrics/ActionTest.java
new file mode 100644
index 0000000..2cbb7ce
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/metrics/ActionTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.metrics;
+
+import com.google.common.collect.Sets;
+import java.util.HashSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for metric actions. */
+@RunWith(JUnit4.class)
+public class ActionTest {
+
+ @Test
+ public void ensureAllActionEnumsHaveUniqueNames() {
+ HashSet<String> names = Sets.newHashSet();
+ for (Action action : Action.values()) {
+ String name = action.getName();
+ Assert.assertTrue(name + " is not unique", names.add(name));
+ }
+ }
+
+ @Test
+ public void ensureAllActionEnumNamesAreAlphanumeric() {
+ Pattern pattern = Pattern.compile("[a-zA-Z0-9]*");
+ for (Action action : Action.values()) {
+ String name = action.getName();
+ Matcher matcher = pattern.matcher(name);
+ Assert.assertTrue(name + " is not valid", matcher.matches());
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/blaze/DeepEqualsTesterTest.java b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/DeepEqualsTesterTest.java
new file mode 100644
index 0000000..c1eea89
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/DeepEqualsTesterTest.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.blaze;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTester;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTester.TestCorrectnessException;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTesterUtil;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples.ExampleNotFoundException;
+import java.io.File;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests to verify that our equals tester is working correctly */
+@RunWith(JUnit4.class)
+public class DeepEqualsTesterTest {
+
+ // The equals method does not work correctly if T is an array
+ private static class Box<T> implements Serializable {
+
+ public T data;
+
+ public Box(T data) {
+ this.data = data;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Box<?> box = (Box<?>) o;
+ return Objects.equal(data, box.data);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(data);
+ }
+ }
+
+ private static class CorrectEqualsAndHash implements Serializable {
+
+ public String name;
+
+ public CorrectEqualsAndHash(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ CorrectEqualsAndHash foo = (CorrectEqualsAndHash) o;
+ return Objects.equal(name, foo.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+ }
+
+ private static class ClassWithCorrectEqualsMember implements Serializable {
+
+ public String myName;
+ public CorrectEqualsAndHash myCorrectEqualsAndHash;
+
+ public ClassWithCorrectEqualsMember(String name, String innerName) {
+ this.myName = name;
+ this.myCorrectEqualsAndHash = new CorrectEqualsAndHash(innerName);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ClassWithCorrectEqualsMember that = (ClassWithCorrectEqualsMember) o;
+ return Objects.equal(myName, that.myName)
+ && Objects.equal(myCorrectEqualsAndHash, that.myCorrectEqualsAndHash);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(myName, myCorrectEqualsAndHash);
+ }
+ }
+
+ private static class IncorrectHash implements Serializable {
+
+ public String name;
+ public int num;
+
+ public IncorrectHash(String name, int num) {
+ this.name = name;
+ this.num = num;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ IncorrectHash foo = (IncorrectHash) o;
+ return Objects.equal(name, foo.name) && Objects.equal(num, foo.num);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+ }
+
+ private static class IncorrectEqualsAndHash implements Serializable {
+
+ public String name;
+ public int num;
+
+ public IncorrectEqualsAndHash(String name, int num) {
+ this.name = name;
+ this.num = num;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ IncorrectEqualsAndHash foo = (IncorrectEqualsAndHash) o;
+ return Objects.equal(name, foo.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+ }
+
+ private static class ClassWithIncorrectEqualsMember implements Serializable {
+
+ public String myName;
+ public IncorrectEqualsAndHash myIncorrectEqualsAndHash;
+
+ public ClassWithIncorrectEqualsMember(String name, String innerName, int innerNum) {
+ this.myName = name;
+ this.myIncorrectEqualsAndHash = new IncorrectEqualsAndHash(innerName, innerNum);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ClassWithIncorrectEqualsMember that = (ClassWithIncorrectEqualsMember) o;
+ return Objects.equal(myName, that.myName)
+ && Objects.equal(myIncorrectEqualsAndHash, that.myIncorrectEqualsAndHash);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(myName, myIncorrectEqualsAndHash);
+ }
+ }
+
+ private static class IncorrectEqualsWithArray implements Serializable {
+
+ public IncorrectEqualsAndHash[] array;
+
+ public IncorrectEqualsWithArray(IncorrectEqualsAndHash[] array) {
+ this.array = array;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ IncorrectEqualsWithArray that = (IncorrectEqualsWithArray) o;
+ return Arrays.equals(array, that.array);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode((Object[]) array);
+ }
+ }
+
+ private static class SubIncorrectEqualsAndHash extends IncorrectEqualsAndHash {
+
+ public Long num;
+
+ public SubIncorrectEqualsAndHash(String name, int iNum, Long num) {
+ super(name, iNum);
+ this.num = num;
+ }
+ }
+
+ private static enum ENUMS {
+ ONE,
+ TWO,
+ THREE
+ }
+
+ private static class DeepClass<T> implements Serializable {
+
+ public ENUMS myEnum;
+ public char myC;
+ public T data;
+ public File f;
+
+ public DeepClass(ENUMS myEnum, char c, T data, File f) {
+ this.myEnum = myEnum;
+ this.myC = c;
+ this.data = data;
+ this.f = f;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DeepClass<?> deepClass = (DeepClass<?>) o;
+ return Objects.equal(myC, deepClass.myC)
+ && Objects.equal(myEnum, deepClass.myEnum)
+ && Objects.equal(data, deepClass.data)
+ && Objects.equal(f, deepClass.f);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(myEnum, myC, data, f);
+ }
+ }
+
+ private static class SimpleClassWithSet implements Serializable {
+
+ public Set<File> files;
+
+ public SimpleClassWithSet(Set<File> files) {
+ this.files = files;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SimpleClassWithSet that = (SimpleClassWithSet) o;
+ return Objects.equal(files, that.files);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(files);
+ }
+ }
+
+ private static class MapWithIncorrectKey implements Serializable {
+
+ public Map<IncorrectEqualsAndHash, File> files;
+
+ public MapWithIncorrectKey(Map<IncorrectEqualsAndHash, File> files) {
+ this.files = files;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MapWithIncorrectKey that = (MapWithIncorrectKey) o;
+ return Objects.equal(files, that.files);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(files);
+ }
+ }
+
+ private static class MapWithIncorrectValue implements Serializable {
+
+ public Map<String, IncorrectEqualsAndHash> map;
+
+ public MapWithIncorrectValue(Map<String, IncorrectEqualsAndHash> map) {
+ this.map = map;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MapWithIncorrectValue that = (MapWithIncorrectValue) o;
+ return Objects.equal(map, that.map);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(map);
+ }
+ }
+
+ private static class MapWithCorrectKeyAndValues implements Serializable {
+
+ public Map<String, String> map;
+
+ public MapWithCorrectKeyAndValues(Map<String, String> map) {
+ this.map = map;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ MapWithCorrectKeyAndValues that = (MapWithCorrectKeyAndValues) o;
+ return Objects.equal(map, that.map);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(map);
+ }
+ }
+
+ private Examples testExamples;
+
+ @Before
+ public void populateExtraExamples() {
+ testExamples = new Examples();
+ testExamples.addExample(
+ CorrectEqualsAndHash.class, new CorrectEqualsAndHash("A"), new CorrectEqualsAndHash("B"));
+ testExamples.addExample(
+ IncorrectEqualsAndHash.class,
+ new IncorrectEqualsAndHash("A", 100),
+ new IncorrectEqualsAndHash("A", 200));
+ testExamples.addExample(
+ IncorrectHash.class, new IncorrectHash("A", 100), new IncorrectHash("A", 200));
+ }
+
+ @Test
+ public void testCorrectEqualsAndHashPassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectEqualsFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectHashFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectHash myFoo = new IncorrectHash("test", 4);
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Test
+ public void testCorrectDeepEqualsAndHashPassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ ClassWithCorrectEqualsMember myFoo = new ClassWithCorrectEqualsMember("test", "inner test");
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testDeepIncorrectEqualsFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ ClassWithIncorrectEqualsMember myFoo =
+ new ClassWithIncorrectEqualsMember("test", "inner test", 4);
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectEqualsInSuperclassFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ SubIncorrectEqualsAndHash myFoo = new SubIncorrectEqualsAndHash("test", 4, new Long(39903));
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Test
+ public void testCorrectEqualsAndHashInArrayPassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
+ CorrectEqualsAndHash[] array = new CorrectEqualsAndHash[1];
+ array[0] = myFoo;
+ DeepEqualsTester.doDeepEqualsAndHashTest(array, testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectEqualsInArrayFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
+ IncorrectEqualsAndHash[] array = new IncorrectEqualsAndHash[1];
+ array[0] = myFoo;
+ IncorrectEqualsWithArray toTest = new IncorrectEqualsWithArray(array);
+ DeepEqualsTester.doDeepEqualsAndHashTest(toTest, testExamples);
+ }
+
+ @Test
+ public void testClassWithSetWithCorrectDeepEqualsAndHashPassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ Set<File> myFiles = Sets.newHashSet();
+ myFiles.add(new File("foo"));
+ myFiles.add(new File("bar"));
+ SimpleClassWithSet myFoo = new SimpleClassWithSet(myFiles);
+ DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
+ }
+
+ @Ignore("causes java reflection return a type variable instead of a concrete type")
+ @Test
+ public void testCorrectEqualsAndHashInSetPassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
+ HashSet<CorrectEqualsAndHash> set = Sets.newHashSet();
+ set.add(myFoo);
+ DeepEqualsTester.doDeepEqualsAndHashTest(
+ new Box<HashSet<CorrectEqualsAndHash>>(set), testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectEqualsInSetFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
+ HashSet<IncorrectEqualsAndHash> set = Sets.newHashSet();
+ set.add(myFoo);
+ DeepEqualsTester.doDeepEqualsAndHashTest(
+ new Box<HashSet<IncorrectEqualsAndHash>>(set), testExamples);
+ }
+
+ @Ignore("causes java reflection return a type variable instead of a concrete type")
+ @Test
+ public void testCorrectDeepEqualsAndHashInSetPassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
+ DeepClass<CorrectEqualsAndHash> data =
+ new DeepClass<CorrectEqualsAndHash>(ENUMS.THREE, 'z', myFoo, new File("home"));
+ HashSet<DeepClass<CorrectEqualsAndHash>> set = Sets.newHashSet();
+ set.add(data);
+ DeepEqualsTester.doDeepEqualsAndHashTest(
+ new Box<HashSet<DeepClass<CorrectEqualsAndHash>>>(set), testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectDeepEqualsInSetFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
+ DeepClass<IncorrectEqualsAndHash> data =
+ new DeepClass<IncorrectEqualsAndHash>(ENUMS.ONE, 'e', myFoo, new File("home"));
+ HashSet<DeepClass<IncorrectEqualsAndHash>> set = Sets.newHashSet();
+ set.add(data);
+ DeepEqualsTester.doDeepEqualsAndHashTest(
+ new Box<HashSet<DeepClass<IncorrectEqualsAndHash>>>(set), testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectEqualsForMapKeyFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
+ Map<IncorrectEqualsAndHash, File> map = Maps.newHashMap();
+ map.put(myFoo, new File("file"));
+ MapWithIncorrectKey data = new MapWithIncorrectKey(map);
+ DeepEqualsTester.doDeepEqualsAndHashTest(data, testExamples);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIncorrectEqualsForMapValueFailsTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
+ Map<String, IncorrectEqualsAndHash> map = Maps.newHashMap();
+ map.put("first", myFoo);
+ MapWithIncorrectValue data = new MapWithIncorrectValue(map);
+ DeepEqualsTester.doDeepEqualsAndHashTest(data, testExamples);
+ }
+
+ @Test
+ public void testCorrectEqualsAndHashForMapKeyValuePassesTester()
+ throws IllegalAccessException, InstantiationException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ Map<String, String> map = Maps.newHashMap();
+ map.put("key", "value");
+ MapWithCorrectKeyAndValues data = new MapWithCorrectKeyAndValues(map);
+ DeepEqualsTester.doDeepEqualsAndHashTest(data, testExamples);
+ }
+
+ @Test
+ public void testEqualsAfterCloneReturnsTrue() {
+ CorrectEqualsAndHash myData = new CorrectEqualsAndHash("my data");
+ CorrectEqualsAndHash clone =
+ (CorrectEqualsAndHash) DeepEqualsTesterUtil.cloneWithSerialization(myData);
+ Assert.assertEquals(myData, clone);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTester.java b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTester.java
new file mode 100644
index 0000000..2e4fd8c
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTester.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples.ExampleNotFoundException;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples.Pair;
+import com.google.idea.blaze.base.model.blaze.deepequalstester.ReachabilityAnalysis.ReachableClasses;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+/** Used to test equals implementations */
+public final class DeepEqualsTester {
+
+ /** Thrown when the test fails */
+ public static class TestCorrectnessException extends Exception {
+
+ public TestCorrectnessException(String s) {
+ super(s);
+ }
+ }
+
+ /**
+ * Ensure that the equals method of {@param rootObject} uses all of its fields in its comparison.
+ * Recurse into every field of {@param rootObject} to ensure that they also use all of their
+ * fields in their equals method. Continue recursion until primitives are hit.
+ *
+ * <p>If multiple failures could occur, there is no guarantee that they will always occur in the
+ * same order. Only the first failure is reported.
+ *
+ * @param rootObject an example instantiation of the class we want to test for deep equals sanity.
+ * The object must be a standard java object (no collections, no arrays, no primitives). If
+ * you would like to pass these types in, you should put them in a box first.
+ * @param examples examples of objects to use for comparison. This should contain a pair of
+ * examples for every type that could be reachable from the root object. This value may be
+ * mutated by this test.
+ */
+ public static <T extends Serializable> void doDeepEqualsAndHashTest(
+ @NotNull T rootObject, Examples examples)
+ throws InstantiationException, IllegalAccessException, NoSuchFieldException,
+ ExampleNotFoundException, TestCorrectnessException {
+ ReachableClasses reachableClasses = new ReachableClasses();
+
+ try {
+ ArrayList<String> initialPath = Lists.newArrayList("root");
+ // Find all of the classes reachable from the root object. This is not sound since it
+ // ignores subtypes (or supertypes) that could be used
+ ReachabilityAnalysis.computeReachableFromObject(
+ rootObject, rootObject.getClass(), initialPath, reachableClasses);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ // Add the root object to our list of reachable classes so we can do all the testing in one
+ // loop
+ reachableClasses.addPath(rootObject.getClass(), Lists.newArrayList("root"));
+ // In our situations, we never need a second example of the root object
+ examples.addExample(rootObject.getClass(), rootObject, rootObject);
+ // For each reachable class, do a shallow equals test where we change each value of the
+ // object one at a time and test for equality
+ for (Class<? extends Serializable> clazz : reachableClasses.getClasses()) {
+ Serializable workitem = (Serializable) examples.getExamples(clazz).getFirst();
+ testShallowEquals(workitem, reachableClasses, examples);
+ }
+ }
+
+ private static String getFailureMessage(String method, Field field, List<String> examplePath) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(field.toString())
+ .append(" is not represented in it's parent's ")
+ .append(method)
+ .append(" method\n");
+ for (String path : examplePath) {
+ sb.append("\t").append(path).append("\n");
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ /**
+ * Mutate each field in the object one at a time and test for equality of the object. Assert a
+ * failure if any mutation doesn't result in the two objects not being equal
+ */
+ private static <T extends Serializable> void testShallowEquals(
+ @NotNull T original, ReachableClasses reachableClasses, Examples examples)
+ throws ExampleNotFoundException, IllegalAccessException, TestCorrectnessException {
+ T clone = (T) DeepEqualsTesterUtil.cloneWithSerialization(original);
+ List<Field> allFields = DeepEqualsTesterUtil.getAllFields(original.getClass());
+ for (Field field : allFields) {
+ if (!Modifier.isStatic(field.getModifiers())) {
+ field.setAccessible(true);
+ Pair<?, ?> examplesPair =
+ examples.getExamples((Class<? extends Serializable>) field.getType());
+ Object newValueForOriginal = examplesPair.getFirst();
+ Object newValueForClone = examplesPair.getSecond();
+ Object oldValueForOriginal = field.get(original);
+ Object oldValueForClone = field.get(clone);
+ // Ensure that the two objects really are equal before we tweak them
+ boolean objectsTheSameBeforeTweak = original.equals(clone);
+ if (!objectsTheSameBeforeTweak) {
+ throw new TestCorrectnessException(
+ "original was not equal to clone before tweaking them");
+ }
+ boolean objectsHashTheSameBeforeTweak = original.hashCode() == clone.hashCode();
+ if (!objectsHashTheSameBeforeTweak) {
+ throw new TestCorrectnessException(
+ "original hash code was not equal to clone hash code before tweaking the objects");
+ }
+ field.set(original, newValueForOriginal);
+ field.set(clone, newValueForClone);
+ boolean equalsWorksAsIntended = !original.equals(clone);
+ boolean hashWorksAsIntended = original.hashCode() != clone.hashCode();
+ // Return to our original state before possibly failing
+ field.set(original, oldValueForOriginal);
+ field.set(clone, oldValueForClone);
+ Assert.assertTrue(
+ getFailureMessage(
+ "equals", field, reachableClasses.getExamplePathTo(original.getClass())),
+ equalsWorksAsIntended);
+ Assert.assertTrue(
+ getFailureMessage(
+ "hash", field, reachableClasses.getExamplePathTo(original.getClass())),
+ hashWorksAsIntended);
+ }
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTesterUtil.java b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTesterUtil.java
new file mode 100644
index 0000000..2ef9472
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTesterUtil.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Utilities for deep equals testing. */
+@VisibleForTesting
+public final class DeepEqualsTesterUtil {
+ public static List<Field> getAllFields(Class<?> clazz) {
+ List<Field> fields = Lists.newArrayList();
+
+ Field[] declaredFields = clazz.getDeclaredFields();
+ for (Field field : declaredFields) {
+ fields.add(field);
+ }
+
+ Class<?> superclass = clazz.getSuperclass();
+ if (superclass != null) {
+ fields.addAll(getAllFields(superclass));
+ }
+ return fields;
+ }
+
+ public static Class getClass(Class declaredClass, Object o) {
+ if (o == null) {
+ return declaredClass;
+ }
+ // The two classes *should* be the same in this case, but the class from o.getClass won't
+ // return true from isPrimitive
+ if (declaredClass.isPrimitive()) {
+ return declaredClass;
+ }
+ return o.getClass();
+ }
+
+ /** Do a deep clone of an object using reflection */
+ public static Object cloneWithSerialization(Object o) {
+ if (o == null) {
+ return null;
+ }
+
+ try {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ObjectOutputStream objOut = new ObjectOutputStream(outputStream);
+ objOut.writeObject(o);
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
+ ObjectInputStream objIn = new ObjectInputStream(inputStream);
+ return objIn.readObject();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static boolean isSubclassOf(
+ @Nullable Class<?> possibleSubClass, @NotNull Class<?> possibleSuperClass) {
+ if (possibleSubClass == null) {
+ return false;
+ }
+
+ if (possibleSubClass.equals(possibleSuperClass)) {
+ return true;
+ }
+
+ if (possibleSubClass.equals(Object.class)) {
+ return false;
+ }
+
+ Class<?>[] interfaces = possibleSubClass.getInterfaces();
+ for (Class<?> interfaze : interfaces) {
+ if (interfaze.equals(possibleSuperClass)) {
+ return true;
+ }
+ }
+
+ return isSubclassOf(possibleSubClass.getSuperclass(), possibleSuperClass);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/Examples.java b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/Examples.java
new file mode 100644
index 0000000..b28ce44
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/Examples.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
+
+import static com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTesterUtil.isSubclassOf;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import java.io.File;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.jetbrains.annotations.NotNull;
+
+/** Examples used in deep equals tests */
+public final class Examples {
+
+ /** pair utility class */
+ public static final class Pair<First, Second> {
+
+ private final First first;
+ private final Second second;
+
+ public static <First, Second> Pair<First, Second> of(First first, Second second) {
+ return new Pair<First, Second>(first, second);
+ }
+
+ public Pair(First first, Second second) {
+ this.first = first;
+ this.second = second;
+ }
+
+ First getFirst() {
+ return first;
+ }
+
+ Second getSecond() {
+ return second;
+ }
+ }
+
+ private static Map<Class<? extends Object>, Pair<? extends Object, ? extends Object>>
+ BASE_EXAMPLES;
+ private static Map<Class<? extends Object>, Pair<? extends Object, ? extends Object>>
+ ARRAY_EXAMPLES;
+
+ private final Map<Class<? extends Object>, Pair<? extends Object, ? extends Object>>
+ customExamples;
+
+ static {
+ BASE_EXAMPLES = Maps.newHashMap();
+ BASE_EXAMPLES.put(String.class, Pair.of("foo", "foobar"));
+ BASE_EXAMPLES.put(File.class, Pair.of(new File("a"), new File("b")));
+ BASE_EXAMPLES.put(Integer.class, Pair.of(1, 2));
+ BASE_EXAMPLES.put(Integer.TYPE, Pair.of(1, 2));
+ BASE_EXAMPLES.put(Long.class, Pair.of(1L, 2L));
+ BASE_EXAMPLES.put(Long.TYPE, Pair.of(1L, 2L));
+ BASE_EXAMPLES.put(Short.class, Pair.of((short) 1, (short) 2));
+ BASE_EXAMPLES.put(Short.TYPE, Pair.of((short) 1, (short) 2));
+ BASE_EXAMPLES.put(Character.class, Pair.of('a', 'b'));
+ BASE_EXAMPLES.put(Character.TYPE, Pair.of('a', 'b'));
+ BASE_EXAMPLES.put(Byte.class, Pair.of((byte) 1, (byte) 2));
+ BASE_EXAMPLES.put(Byte.TYPE, Pair.of((byte) 1, (byte) 2));
+ BASE_EXAMPLES.put(Float.class, Pair.of((float) 1.0, (float) 2.0));
+ BASE_EXAMPLES.put(Float.TYPE, Pair.of((float) 1.0, (float) 2.0));
+ BASE_EXAMPLES.put(Double.class, Pair.of(1.0, 2.0));
+ BASE_EXAMPLES.put(Double.TYPE, Pair.of(1.0, 2.0));
+ BASE_EXAMPLES.put(Boolean.class, Pair.of(true, false));
+ BASE_EXAMPLES.put(Boolean.TYPE, Pair.of(true, false));
+ Map<String, String> mapA = Maps.newHashMap();
+ mapA.put("foo", "bar");
+ Map<String, String> mapB = Maps.newHashMap();
+ mapB.put("tip", "top");
+ BASE_EXAMPLES.put(Map.class, Pair.of(mapA, mapB));
+ Set<String> setA = new ImmutableSet.Builder<String>().add("A").build();
+ Set<String> setB = new ImmutableSet.Builder<String>().add("A").add("B").build();
+ BASE_EXAMPLES.put(Set.class, Pair.of(setA, setB));
+ BASE_EXAMPLES.put(Collection.class, Pair.of(setA, setB));
+ Builder<String> listABuilder = ImmutableList.builder();
+ List<String> listA = listABuilder.add("A").build();
+ Builder<String> listBBuilder = ImmutableList.builder();
+ List<String> listB = listBBuilder.add("A").add("B").build();
+ BASE_EXAMPLES.put(List.class, Pair.of(listA, listB));
+
+ ARRAY_EXAMPLES = Maps.newHashMap();
+ int[] intArrA = {1, 2};
+ int[] intArrB = {3, 4};
+ ARRAY_EXAMPLES.put(Integer.TYPE, Pair.of(intArrA, intArrB));
+ long[] longArrA = {1, 2};
+ long[] longArrB = {3, 4};
+ ARRAY_EXAMPLES.put(Long.TYPE, Pair.of(longArrA, longArrB));
+ short[] shortArrA = {1, 2};
+ short[] shortArrB = {3, 4};
+ ARRAY_EXAMPLES.put(Short.TYPE, Pair.of(shortArrA, shortArrB));
+ char[] charArrA = {'a', 'b'};
+ char[] charArrB = {'c', 'd'};
+ ARRAY_EXAMPLES.put(Character.TYPE, Pair.of(charArrA, charArrB));
+ byte[] byteArrA = {1, 2};
+ byte[] byteArrB = {3, 4};
+ ARRAY_EXAMPLES.put(Byte.TYPE, Pair.of(byteArrA, byteArrB));
+ boolean[] boolArrA = {true, false};
+ boolean[] boolArrB = {false, false};
+ ARRAY_EXAMPLES.put(Boolean.TYPE, Pair.of(boolArrA, boolArrB));
+ float[] floatArrA = {1.0f, 2.0f};
+ float[] floatArrB = {3.0f, 4.0f};
+ ARRAY_EXAMPLES.put(Float.TYPE, Pair.of(floatArrA, floatArrB));
+ double[] doubleArrA = {1.0, 2.0};
+ double[] doubleArrB = {3.0, 4.0};
+ ARRAY_EXAMPLES.put(Double.TYPE, Pair.of(doubleArrA, doubleArrB));
+ }
+
+ /** Thrown when an example could not be found */
+ public static class ExampleNotFoundException extends Exception {
+
+ private final Class<?> clazz;
+
+ public ExampleNotFoundException(Class<?> clazz) {
+ this.clazz = clazz;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Could not find example for: " + clazz.toString();
+ }
+ }
+
+ public Examples() {
+ this.customExamples = Maps.newHashMap();
+ }
+
+ public void addExample(Class<? extends Object> clazz, Object a, Object b) {
+ customExamples.put(clazz, Pair.of(a, b));
+ }
+
+ public <T extends Serializable> Pair<? extends Object, ? extends Object> getExamples(
+ @NotNull Class<T> clazz) throws ExampleNotFoundException {
+ if (customExamples.containsKey(clazz)) {
+ return customExamples.get(clazz);
+ }
+ if (BASE_EXAMPLES.containsKey(clazz)) {
+ return BASE_EXAMPLES.get(clazz);
+ }
+ // Special case subclasses of collections
+ if (isSubclassOf(clazz, Set.class)) {
+ return BASE_EXAMPLES.get(Set.class);
+ }
+ if (isSubclassOf(clazz, List.class)) {
+ return BASE_EXAMPLES.get(List.class);
+ }
+ if (isSubclassOf(clazz, Collection.class)) {
+ return BASE_EXAMPLES.get(Collection.class);
+ }
+
+ // If we have an array of Objects, we have to do a little trickery to create one we can swap
+ // in
+ if (clazz.isArray()) {
+ Class<?> arrayType = clazz.getComponentType();
+ if (!arrayType.isPrimitive()) {
+ Pair<?, ?> examples = getExamples((Class<? extends Serializable>) arrayType);
+ Object arrayA = Array.newInstance(arrayType, 1);
+ Array.set(arrayA, 0, examples.getFirst());
+ Object arrayB = Array.newInstance(arrayType, 1);
+ Array.set(arrayB, 0, examples.getSecond());
+ return Pair.of(arrayA, arrayB);
+ }
+ if (ARRAY_EXAMPLES.containsKey(arrayType)) {
+ return ARRAY_EXAMPLES.get(arrayType);
+ }
+ }
+
+ throw new ExampleNotFoundException(clazz);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/ReachabilityAnalysis.java b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/ReachabilityAnalysis.java
new file mode 100644
index 0000000..3405453
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/ReachabilityAnalysis.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import java.io.File;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.junit.Assert;
+
+final class ReachabilityAnalysis {
+
+ /** Wrapper around a map from class to set of paths that lead to that path from the root object */
+ public static final class ReachableClasses {
+
+ Map<Class<? extends Serializable>, Set<List<String>>> map;
+
+ public ReachableClasses() {
+ map = Maps.newHashMap();
+ }
+
+ boolean alreadyFound(Class<? extends Serializable> clazz) {
+ return map.containsKey(clazz);
+ }
+
+ void addPath(Class<? extends Serializable> clazz, List<String> path) {
+ Set<List<String>> paths;
+ if (map.containsKey(clazz)) {
+ paths = map.get(clazz);
+ } else {
+ paths = Sets.newHashSet();
+ map.put(clazz, paths);
+ }
+ paths.add(path);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ Set<? extends Entry<Class<? extends Serializable>, ? extends Set<? extends List<String>>>>
+ entries = map.entrySet();
+ for (Entry<Class<? extends Serializable>, ? extends Set<? extends List<String>>> entry :
+ entries) {
+ sb.append(entry.getKey().toString());
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ public Set<Class<? extends Serializable>> getClasses() {
+ return map.keySet();
+ }
+
+ public List<String> getExamplePathTo(Class<? extends Serializable> aClass) {
+ if (map.containsKey(aClass)) {
+ return map.get(aClass).iterator().next();
+ }
+ return Lists.newArrayList();
+ }
+ }
+
+ /**
+ * Find all of the classes reachable from a root object
+ *
+ * @param root object to start reachability calculation from
+ * @param declaredRootClass declared class of the root object
+ * @param currentPath field access path to get to root
+ * @param reachableClasses output: add classes reachable from root to this object
+ * @throws IllegalAccessException
+ * @throws ClassNotFoundException
+ */
+ public static void computeReachableFromObject(
+ Object root,
+ Class<?> declaredRootClass,
+ List<String> currentPath,
+ ReachableClasses reachableClasses)
+ throws IllegalAccessException, ClassNotFoundException {
+ final Class<?> concreteRootClass = DeepEqualsTesterUtil.getClass(declaredRootClass, root);
+ List<Field> allFields = DeepEqualsTesterUtil.getAllFields(concreteRootClass);
+ for (Field field : allFields) {
+ if (!Modifier.isStatic(field.getModifiers())) {
+ field.setAccessible(true);
+ final Object fieldObject;
+ if (root == null) {
+ fieldObject = null;
+ } else {
+ fieldObject = field.get(root);
+ }
+ List<String> childPath = Lists.newArrayList();
+ childPath.addAll(currentPath);
+ childPath.add(field.toString());
+ addToReachableAndRecurse(
+ fieldObject, field.getType(), field.getGenericType(), childPath, reachableClasses);
+ }
+ }
+ }
+
+ /**
+ * Determine the action we should take based on the type of Object and then take it. In the normal
+ * object case, this results in a recursive call to {@link #computeReachableFromObject(Object,
+ * Class, List, ReachableClasses)}. In the case of Collections, we skip the Collection type and
+ * continue on with the type contained in the collection.
+ */
+ private static void addToReachableAndRecurse(
+ Object object,
+ Class<?> declaredObjectClass,
+ Type genericType,
+ List<String> currentPath,
+ ReachableClasses reachableClasses)
+ throws ClassNotFoundException, IllegalAccessException {
+ Class<? extends Serializable> objectType =
+ DeepEqualsTesterUtil.getClass(declaredObjectClass, object);
+ // TODO(salguarnieri) modify if so all ignored classes are taken care of together
+ if (objectType.isPrimitive()) {
+ // ignore
+ } else if (objectType.isEnum()) {
+ // assume enums do the right thing, ignore
+ } else if (DeepEqualsTesterUtil.isSubclassOf(objectType, String.class)) {
+ // ignore
+ } else if (DeepEqualsTesterUtil.isSubclassOf(objectType, File.class)) {
+ // ignore
+ } else if (DeepEqualsTesterUtil.isSubclassOf(objectType, Collection.class)
+ || DeepEqualsTesterUtil.isSubclassOf(objectType, Map.class)) {
+ if (genericType instanceof ParameterizedType) {
+ ParameterizedType parameterType = (ParameterizedType) genericType;
+ Type[] actualTypeArguments = parameterType.getActualTypeArguments();
+ for (Type typeArgument : actualTypeArguments) {
+ if (typeArgument instanceof Class) {
+ List<String> childPath = Lists.newArrayList();
+ childPath.addAll(currentPath);
+ childPath.add("[[IN COLLECTION]]");
+ // this does not properly handle subtyping
+ addToReachableAndRecurse(null, (Class) typeArgument, null, childPath, reachableClasses);
+ } else {
+ Assert.fail("This case is not handled yet");
+ }
+ }
+ } else {
+ Assert.fail("This case is not handled yet");
+ }
+ } else if (objectType.isArray()) {
+ Class<?> typeInArray = objectType.getComponentType();
+ // This does not properly handle subtyping
+ List<String> childPath = Lists.newArrayList();
+ childPath.addAll(currentPath);
+ childPath.add("[[IN ARRAY]]");
+ addToReachableAndRecurse(null, typeInArray, null, childPath, reachableClasses);
+ } else {
+ boolean doRecursion = !reachableClasses.alreadyFound(objectType);
+ reachableClasses.addPath(objectType, currentPath);
+ if (doRecursion) {
+ computeReachableFromObject(object, declaredObjectClass, currentPath, reachableClasses);
+ }
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/primitives/ExecutionRootPathTest.java b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/ExecutionRootPathTest.java
new file mode 100644
index 0000000..d85de4b
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/ExecutionRootPathTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import java.io.File;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+
+/** Tests execution root path. */
+@RunWith(JUnit4.class)
+public class ExecutionRootPathTest extends BlazeTestCase {
+ @Test
+ public void testSingleLevelPathEndInSlash() {
+ ExecutionRootPath executionRootPath = new ExecutionRootPath("foo");
+ assertThat(executionRootPath.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/"));
+
+ ExecutionRootPath executionRootPath2 = new ExecutionRootPath("foo/");
+ assertThat(executionRootPath2.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/"));
+ }
+
+ @Test
+ public void testMultiLevelPathEndInSlash() {
+ ExecutionRootPath executionRootPath = new ExecutionRootPath("foo/bar");
+ assertThat(executionRootPath.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/bar/"));
+
+ ExecutionRootPath executionRootPath2 = new ExecutionRootPath("foo/bar/");
+ assertThat(executionRootPath2.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/bar/"));
+ }
+
+ @Test
+ public void testAbsoluteFileDoesNotGetRerooted() {
+ ExecutionRootPath executionRootPath = new ExecutionRootPath("/root/foo/bar");
+ File rootedFile = executionRootPath.getFileRootedAt(new File("/core/dev"));
+ assertThat(rootedFile).isEqualTo(new File("/root/foo/bar"));
+ }
+
+ @Test
+ public void testRelativeFileGetsRerooted() {
+ ExecutionRootPath executionRootPath = new ExecutionRootPath("foo/bar");
+ File rootedFile = executionRootPath.getFileRootedAt(new File("/root"));
+ assertThat(rootedFile).isEqualTo(new File("/root/foo/bar"));
+ }
+
+ @Test
+ public void testCreateRelativePathWithTwoRelativePaths() {
+ ExecutionRootPath relativePathFragment =
+ ExecutionRootPath.createAncestorRelativePath(
+ createMockDirectory("code/lib/fastmath"),
+ createMockDirectory("code/lib/fastmath/lib1"));
+ assertThat(relativePathFragment).isNotNull();
+ assertThat(relativePathFragment.getAbsoluteOrRelativeFile()).isEqualTo(new File("lib1"));
+ }
+
+ @Test
+ public void testCreateRelativePathWithTwoRelativePathsWithNoRelativePath() {
+ ExecutionRootPath relativePathFragment =
+ ExecutionRootPath.createAncestorRelativePath(
+ createMockDirectory("obj/lib/fastmath"), createMockDirectory("code/lib/slowmath"));
+ assertThat(relativePathFragment).isNull();
+ }
+
+ @Test
+ public void testCreateRelativePathWithTwoAbsolutePaths() {
+ ExecutionRootPath relativePathFragment =
+ ExecutionRootPath.createAncestorRelativePath(
+ createMockDirectory("/code/lib/fastmath"),
+ createMockDirectory("/code/lib/fastmath/lib1"));
+ assertThat(relativePathFragment).isNotNull();
+ assertThat(relativePathFragment.getAbsoluteOrRelativeFile()).isEqualTo(new File("lib1"));
+ }
+
+ @Test
+ public void testCreateRelativePathWithTwoAbsolutePathsWithNoRelativePath() {
+ ExecutionRootPath relativePathFragment =
+ ExecutionRootPath.createAncestorRelativePath(
+ createMockDirectory("/obj/lib/fastmath"), createMockDirectory("/code/lib/slowmath"));
+ assertThat(relativePathFragment).isNull();
+ }
+
+ @Test
+ public void testCreateRelativePathWithOneAbsolutePathAndOneRelativePathReturnsNull1() {
+ ExecutionRootPath relativePathFragment =
+ ExecutionRootPath.createAncestorRelativePath(
+ createMockDirectory("/code/lib/fastmath"),
+ createMockDirectory("code/lib/fastmath/lib1"));
+ assertThat(relativePathFragment).isNull();
+ }
+
+ @Test
+ public void testCreateRelativePathWithOneAbsolutePathAndOneRelativePathReturnsNull2() {
+ ExecutionRootPath relativePathFragment =
+ ExecutionRootPath.createAncestorRelativePath(
+ createMockDirectory("code/lib/fastmath"), createMockDirectory("/code/lib/slowmath"));
+ assertThat(relativePathFragment).isNull();
+ }
+
+ private static File createMockDirectory(String path) {
+ File org = new File(path);
+ File spy = Mockito.spy(org);
+ Mockito.when(spy.isDirectory()).then((Answer<Boolean>) invocationOnMock -> true);
+ return spy;
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/primitives/LabelTest.java b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/LabelTest.java
new file mode 100644
index 0000000..4ceb066
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/LabelTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests label validation */
+@RunWith(JUnit4.class)
+public class LabelTest extends BlazeTestCase {
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ }
+
+ @Test
+ public void testValidatePackage() {
+ // Legal names
+ assertThat(Label.validatePackagePath("foo")).isTrue();
+ assertThat(Label.validatePackagePath("f")).isTrue();
+ assertThat(Label.validatePackagePath("fooBAR")).isTrue();
+ assertThat(Label.validatePackagePath("foo/bar")).isTrue();
+ assertThat(Label.validatePackagePath("f9oo")).isTrue();
+ assertThat(Label.validatePackagePath("f_9oo")).isTrue();
+ assertThat(Label.validatePackagePath("Foo")).isTrue();
+ assertThat(Label.validatePackagePath("9.oo")).isTrue();
+ // This is not advised but is technically legal
+ assertThat(Label.validatePackagePath("")).isTrue();
+
+ // Illegal names
+ assertThat(Label.validatePackagePath("/foo")).isFalse();
+ assertThat(Label.validatePackagePath("foo/")).isFalse();
+ assertThat(Label.validatePackagePath("foo//bar")).isFalse();
+ }
+
+ @Test
+ public void testValidateLabel() {
+ // Valid labels
+ assertThat(Label.validate("//foo:bar")).isTrue();
+ assertThat(Label.validate("//foo/baz:bar")).isTrue();
+ assertThat(Label.validate("//:bar")).isTrue();
+
+ // Invalid labels
+ assertThat(Label.validate("//foo")).isFalse();
+ assertThat(Label.validate("foo")).isFalse();
+ assertThat(Label.validate("foo:bar")).isFalse();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/primitives/RuleNameTest.java b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/RuleNameTest.java
new file mode 100644
index 0000000..1fbb704
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/RuleNameTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for rule name validation */
+@RunWith(JUnit4.class)
+public class RuleNameTest extends BlazeTestCase {
+
+ @Test
+ public void testValidateRuleName() {
+ // Legal names
+ assertThat(RuleName.validate("foo")).isTrue();
+ assertThat(RuleName.validate(".")).isTrue();
+ assertThat(RuleName.validate(".foo")).isTrue();
+ assertThat(RuleName.validate("foo+")).isTrue();
+ assertThat(RuleName.validate("_foo")).isTrue();
+ assertThat(RuleName.validate("-foo")).isTrue();
+ assertThat(RuleName.validate("foo-bar")).isTrue();
+ assertThat(RuleName.validate("foo..")).isTrue();
+ assertThat(RuleName.validate("..foo")).isTrue();
+
+ // Illegal names
+ assertThat(RuleName.validate("")).isFalse();
+ assertThat(RuleName.validate("/foo")).isFalse();
+ assertThat(RuleName.validate("../foo")).isFalse();
+ assertThat(RuleName.validate("./foo")).isFalse();
+ assertThat(RuleName.validate("..")).isFalse();
+ assertThat(RuleName.validate("foo/../bar")).isFalse();
+ assertThat(RuleName.validate("foo/./bar")).isFalse();
+ assertThat(RuleName.validate("foo//bar")).isFalse();
+ assertThat(RuleName.validate("foo/..")).isFalse();
+ assertThat(RuleName.validate("/..")).isFalse();
+ assertThat(RuleName.validate("foo/")).isFalse();
+ assertThat(RuleName.validate("/")).isFalse();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/primitives/TargetExpressionTest.java b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/TargetExpressionTest.java
new file mode 100644
index 0000000..880c779
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/TargetExpressionTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link com.google.idea.blaze.base.model.primitives.TargetExpressionFactory}. */
+@RunWith(JUnit4.class)
+public class TargetExpressionTest extends BlazeTestCase {
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ }
+
+ @Test
+ public void validLabelShouldYieldLabel() {
+ TargetExpression target = TargetExpression.fromString("//package:rule");
+ assertThat(target).isInstanceOf(Label.class);
+ }
+
+ @Test
+ public void globExpressionShouldYieldGeneralTargetExpression() {
+ TargetExpression target = TargetExpression.fromString("//package/...");
+ assertThat(target.getClass()).isSameAs(TargetExpression.class);
+ }
+
+ @Test
+ public void emptyExpressionShouldThrow() {
+ try {
+ TargetExpression.fromString("");
+ fail("Empty expressions should not be allowed.");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/model/primitives/WorkspacePathTest.java b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/WorkspacePathTest.java
new file mode 100644
index 0000000..67e74e7
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/model/primitives/WorkspacePathTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.model.primitives;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ui.BlazeValidationError;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for workspace path validation */
+@RunWith(JUnit4.class)
+public class WorkspacePathTest extends BlazeTestCase {
+
+ @Test
+ public void testValidation() {
+ // Valid workspace paths
+ assertThat(WorkspacePath.validate("")).isTrue();
+ assertThat(WorkspacePath.validate("foo")).isTrue();
+ assertThat(WorkspacePath.validate("foo")).isTrue();
+ assertThat(WorkspacePath.validate("foo/bar")).isTrue();
+ assertThat(WorkspacePath.validate("foo/bar/baz")).isTrue();
+
+ // Invalid workspace paths
+ assertThat(WorkspacePath.validate("/foo")).isFalse();
+ assertThat(WorkspacePath.validate("//foo")).isFalse();
+ assertThat(WorkspacePath.validate("/")).isFalse();
+ assertThat(WorkspacePath.validate("foo/")).isFalse();
+ assertThat(WorkspacePath.validate("foo:")).isFalse();
+ assertThat(WorkspacePath.validate(":")).isFalse();
+ assertThat(WorkspacePath.validate("foo:bar")).isFalse();
+
+ List<BlazeValidationError> errors = Lists.newArrayList();
+
+ WorkspacePath.validate("/foo", errors);
+ assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not start with '/': /foo");
+ errors.clear();
+
+ WorkspacePath.validate("/", errors);
+ assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not start with '/': /");
+ errors.clear();
+
+ WorkspacePath.validate("foo/", errors);
+ assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not end with '/': foo/");
+ errors.clear();
+
+ WorkspacePath.validate("foo:bar", errors);
+ assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not contain ':': foo:bar");
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java b/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java
new file mode 100644
index 0000000..40ea19f
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.TestUtils;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.Section;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection;
+import com.google.idea.blaze.base.projectview.section.sections.BuildFlagsSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.projectview.section.sections.ExcludeTargetSection;
+import com.google.idea.blaze.base.projectview.section.sections.ExcludedSourceSection;
+import com.google.idea.blaze.base.projectview.section.sections.ImportSection;
+import com.google.idea.blaze.base.projectview.section.sections.ImportTargetOutputSection;
+import com.google.idea.blaze.base.projectview.section.sections.MetricsProjectSection;
+import com.google.idea.blaze.base.projectview.section.sections.Sections;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.projectview.section.sections.TestSourceSection;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlock;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection;
+import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for project view sets */
+@RunWith(JUnit4.class)
+public class ProjectViewSetTest extends BlazeTestCase {
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+ }
+
+ @Test
+ public void testProjectViewSetSerializable() throws Exception {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("test"))))
+ .add(
+ ListSection.builder(TargetSection.KEY)
+ .add(TargetExpression.fromString("//test:all")))
+ .add(ScalarSection.builder(ImportSection.KEY).set(new WorkspacePath("test")))
+ .add(ListSection.builder(TestSourceSection.KEY).add(new Glob("javatests/*")))
+ .add(ListSection.builder(ExcludedSourceSection.KEY).add(new Glob("*.java")))
+ .add(ListSection.builder(BuildFlagsSection.KEY).add("--android_sdk=abcd"))
+ .add(
+ ListSection.builder(ImportTargetOutputSection.KEY)
+ .add(new Label("//test:test")))
+ .add(
+ ListSection.builder(ExcludeTargetSection.KEY).add(new Label("//test:test")))
+ .add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.JAVA))
+ .add(
+ ListSection.builder(AdditionalLanguagesSection.KEY).add(LanguageClass.JAVA))
+ .add(ScalarSection.builder(MetricsProjectSection.KEY).set("my project"))
+ .add(TextBlockSection.of(TextBlock.newLine()))
+ .build())
+ .build();
+
+ // Assert we have all sections
+ assert projectViewSet.getTopLevelProjectViewFile() != null;
+ ProjectView projectView = projectViewSet.getTopLevelProjectViewFile().projectView;
+ for (SectionParser parser : Sections.getParsers()) {
+ ImmutableList<Section<?>> sections = projectView.getSections();
+ assertThat(
+ sections.stream().anyMatch(section -> section.isSectionType(parser.getSectionKey())))
+ .isTrue();
+ }
+
+ TestUtils.assertIsSerializable(projectViewSet);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java b/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java
new file mode 100644
index 0000000..78506ef
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.io.MockWorkspaceScanner;
+import com.google.idea.blaze.base.io.WorkspaceScanner;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ErrorCollector;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for ProjectViewVerifier */
+@RunWith(JUnit4.class)
+public class ProjectViewVerifierTest extends BlazeTestCase {
+
+ private static final String FAKE_ROOT = "/root";
+ private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File(FAKE_ROOT));
+ private MockWorkspaceScanner workspaceScanner;
+ private ErrorCollector errorCollector = new ErrorCollector();
+ private BlazeContext context;
+ private WorkspaceLanguageSettings workspaceLanguageSettings =
+ new WorkspaceLanguageSettings(WorkspaceType.JAVA, ImmutableSet.of(LanguageClass.JAVA));
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+
+ workspaceScanner = new MockWorkspaceScanner();
+ applicationServices.register(WorkspaceScanner.class, workspaceScanner);
+ context = new BlazeContext();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+ }
+
+ @Test
+ public void testNoIssues() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(
+ DirectoryEntry.include(
+ new WorkspacePath("java/com/google/android/apps/example")))
+ .add(
+ DirectoryEntry.include(
+ new WorkspacePath("java/com/google/android/apps/example2"))))
+ .build())
+ .build();
+ workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
+ ProjectViewVerifier.verifyProjectView(
+ context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
+ errorCollector.assertNoIssues();
+ }
+
+ @Test
+ public void testExcludingExactRootResultsInIssue() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(
+ DirectoryEntry.include(
+ new WorkspacePath("java/com/google/android/apps/example")))
+ .add(
+ DirectoryEntry.exclude(
+ new WorkspacePath("java/com/google/android/apps/example"))))
+ .build())
+ .build();
+ workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
+ ProjectViewVerifier.verifyProjectView(
+ context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
+ errorCollector.assertIssues(
+ "java/com/google/android/apps/example is included, "
+ + "but that contradicts java/com/google/android/apps/example which was excluded");
+ }
+
+ @Test
+ public void testExcludingRootViaParentResultsInIssue() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(
+ DirectoryEntry.include(
+ new WorkspacePath("java/com/google/android/apps/example")))
+ .add(
+ DirectoryEntry.exclude(
+ new WorkspacePath("java/com/google/android/apps"))))
+ .build())
+ .build();
+ workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
+ ProjectViewVerifier.verifyProjectView(
+ context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
+ errorCollector.assertIssues(
+ "java/com/google/android/apps/example is included, "
+ + "but that contradicts java/com/google/android/apps which was excluded");
+ }
+
+ @Test
+ public void testExcludingSubdirectoryOfRootResultsInNoIssues() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(
+ DirectoryEntry.include(
+ new WorkspacePath("java/com/google/android/apps/example")))
+ .add(
+ DirectoryEntry.exclude(
+ new WorkspacePath(
+ "java/com/google/android/apps/example/subdir"))))
+ .build())
+ .build();
+ workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
+ ProjectViewVerifier.verifyProjectView(
+ context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
+ errorCollector.assertNoIssues();
+ }
+
+ @Test
+ public void testImportRootMissingResultsInIssue() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(
+ DirectoryEntry.include(
+ new WorkspacePath("java/com/google/android/apps/example"))))
+ .build())
+ .build();
+ ProjectViewVerifier.verifyProjectView(
+ context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
+ errorCollector.assertIssues(
+ String.format(
+ "Directory '%s' specified in import roots not found under workspace root '%s'",
+ "java/com/google/android/apps/example", "/root"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/projectview/parser/ProjectViewParserTest.java b/base/tests/unittests/com/google/idea/blaze/base/projectview/parser/ProjectViewParserTest.java
new file mode 100644
index 0000000..08fea57
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/projectview/parser/ProjectViewParserTest.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.projectview.parser;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.projectview.section.sections.ImportSection;
+import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlock;
+import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection;
+import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ErrorCollector;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for the project view parser */
+@RunWith(JUnit4.class)
+public class ProjectViewParserTest extends BlazeTestCase {
+ private ProjectViewParser projectViewParser;
+ private BlazeContext context;
+ private ErrorCollector errorCollector;
+ private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/"));
+ private MockProjectViewStorageManager projectViewStorageManager;
+
+ static class MockProjectViewStorageManager extends ProjectViewStorageManager {
+ Map<String, String> projectViewFiles = Maps.newHashMap();
+
+ @Nullable
+ @Override
+ public String loadProjectView(@NotNull File projectViewFile) throws IOException {
+ return projectViewFiles.get(projectViewFile.getPath());
+ }
+
+ @Override
+ public void writeProjectView(@NotNull String projectViewText, @NotNull File projectViewFile)
+ throws IOException {
+ // no-op
+ }
+
+ void add(String name, String... text) {
+ projectViewFiles.put(name, Joiner.on('\n').join(text));
+ }
+ }
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ context = new BlazeContext();
+ errorCollector = new ErrorCollector();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+ projectViewParser =
+ new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot));
+ projectViewStorageManager = new MockProjectViewStorageManager();
+ applicationServices.register(ProjectViewStorageManager.class, projectViewStorageManager);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+ }
+
+ @Test
+ public void testDirectoriesAndTargets() throws Exception {
+ projectViewStorageManager.add(
+ ".blazeproject",
+ "directories:",
+ " java/com/google",
+ " java/com/google/android",
+ " -java/com/google/android/notme",
+ "",
+ "targets:",
+ " //java/com/google:all",
+ " //java/com/google/...:all",
+ " -//java/com/google:thistarget");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
+ assertThat(projectViewFile).isNotNull();
+ assertThat(projectViewFile.projectViewFile).isEqualTo(new File(".blazeproject"));
+ assertThat(projectViewSet.getProjectViewFiles()).containsExactly(projectViewFile);
+
+ ProjectView projectView = projectViewFile.projectView;
+ assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items())
+ .containsExactly(
+ new DirectoryEntry(new WorkspacePath("java/com/google"), true),
+ new DirectoryEntry(new WorkspacePath("java/com/google/android"), true),
+ new DirectoryEntry(new WorkspacePath("java/com/google/android/notme"), false));
+ assertThat(projectView.getSectionsOfType(TargetSection.KEY).get(0).items())
+ .containsExactly(
+ TargetExpression.fromString("//java/com/google:all"),
+ TargetExpression.fromString("//java/com/google/...:all"),
+ TargetExpression.fromString("-//java/com/google:thistarget"));
+ }
+
+ @Test
+ public void testRootDirectory() throws Exception {
+ projectViewStorageManager.add(
+ ".blazeproject",
+ "directories:",
+ " .",
+ " -java/com/google/android/notme",
+ "",
+ "targets:",
+ " //java/com/google:all");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
+ assertThat(projectViewFile).isNotNull();
+ assertThat(projectViewFile.projectViewFile).isEqualTo(new File(".blazeproject"));
+ assertThat(projectViewSet.getProjectViewFiles()).containsExactly(projectViewFile);
+
+ ProjectView projectView = projectViewFile.projectView;
+ assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items())
+ .containsExactly(
+ new DirectoryEntry(new WorkspacePath(""), true),
+ new DirectoryEntry(new WorkspacePath("java/com/google/android/notme"), false));
+ assertThat(projectView.getSectionsOfType(TargetSection.KEY).get(0).items())
+ .containsExactly(TargetExpression.fromString("//java/com/google:all"));
+
+ String text = ProjectViewParser.projectViewToString(projectView);
+ assertThat(text)
+ .isEqualTo(
+ Joiner.on('\n')
+ .join(
+ "directories:",
+ " .",
+ " -java/com/google/android/notme",
+ "",
+ "targets:",
+ " //java/com/google:all"));
+ }
+
+ @Test
+ public void testPrint() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/com/google/one")))
+ .add(DirectoryEntry.exclude(new WorkspacePath("java/com/google/two"))))
+ .add(
+ ListSection.builder(TargetSection.KEY)
+ .add(TargetExpression.fromString("//java/com/google:one"))
+ .add(TargetExpression.fromString("//java/com/google:two")))
+ .add(
+ ScalarSection.builder(ImportSection.KEY)
+ .set(new WorkspacePath("some/file.blazeproject")))
+ .build();
+ String text = ProjectViewParser.projectViewToString(projectView);
+ assertThat(text)
+ .isEqualTo(
+ Joiner.on('\n')
+ .join(
+ "directories:",
+ " java/com/google/one",
+ " -java/com/google/two",
+ "targets:",
+ " //java/com/google:one",
+ " //java/com/google:two",
+ "import some/file.blazeproject"));
+ }
+
+ @Test
+ public void testImport() {
+ projectViewStorageManager.add("/parent.blazeproject", "directories:", " parent", "");
+ projectViewStorageManager.add(
+ ".blazeproject", "import parent.blazeproject", "directories:", " child", "");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ assertThat(projectViewSet.getProjectViewFiles()).hasSize(2);
+ Collection<DirectoryEntry> entries = projectViewSet.listItems(DirectorySection.KEY);
+ assertThat(entries)
+ .containsExactly(
+ new DirectoryEntry(new WorkspacePath("parent"), true),
+ new DirectoryEntry(new WorkspacePath("child"), true));
+ }
+
+ @Test
+ public void testMultipleImports() {
+ projectViewStorageManager.add("/grandparent.blazeproject", "directories:", " grandparent");
+ projectViewStorageManager.add(
+ "/mother.blazeproject", "import grandparent.blazeproject", "directories:", " mother");
+ projectViewStorageManager.add(
+ "/father.blazeproject", "import grandparent.blazeproject", "directories:", " father");
+ projectViewStorageManager.add(
+ "/child.blazeproject",
+ "import mother.blazeproject",
+ "directories:",
+ " child1",
+ "import father.blazeproject",
+ "directories:",
+ " child2");
+ projectViewParser.parseProjectView(new File("/child.blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+
+ // Ensures we don't parse grandfather twice
+ assertThat(projectViewSet.getProjectViewFiles()).hasSize(4);
+ Collection<DirectoryEntry> entries = projectViewSet.listItems(DirectorySection.KEY);
+
+ // All imports' contributions appear before the children, no matter where they appear
+ assertThat(entries)
+ .containsExactly(
+ new DirectoryEntry(new WorkspacePath("grandparent"), true),
+ new DirectoryEntry(new WorkspacePath("mother"), true),
+ new DirectoryEntry(new WorkspacePath("father"), true),
+ new DirectoryEntry(new WorkspacePath("child1"), true),
+ new DirectoryEntry(new WorkspacePath("child2"), true))
+ .inOrder();
+ }
+
+ @Test
+ public void testMinimumIndentRequired() {
+ projectViewStorageManager.add(
+ ".blazeproject", "directories:", " java/com/google", "java/com/google2", "");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertIssues("Could not parse: 'java/com/google2'");
+ }
+
+ @Test
+ public void testIncorrectIndentationResultsInIssue() {
+ projectViewStorageManager.add(
+ ".blazeproject", "directories:", " java/com/google", " java/com/google2", "");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertIssues("Invalid indentation on line: 'java/com/google2'");
+ }
+
+ @Test
+ public void testCanParseWithMissingCarriageReturnAtEndOfSection() {
+ projectViewStorageManager.add(".blazeproject", "directories:", " java/com/google");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ ProjectView projectView =
+ projectViewParser.getResult().getTopLevelProjectViewFile().projectView;
+ assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items())
+ .containsExactly(new DirectoryEntry(new WorkspacePath("java/com/google"), true));
+ }
+
+ @Test
+ public void testImportMissingFileResultsInIssue() {
+ projectViewStorageManager.add(".blazeproject", "import parent.blazeproject");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertIssues("Could not load project view file: '/parent.blazeproject'");
+ }
+
+ @Test
+ public void testMissingSectionResultsInIssue() {
+ projectViewStorageManager.add(".blazeproject", "nosuchsection:", " java/com/google");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertIssues("Could not parse: 'nosuchsection:'");
+ }
+
+ @Test
+ public void testMissingColonResultInIssue() {
+ projectViewStorageManager.add(".blazeproject", "directories", " java/com/google");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertIssues("Could not parse: 'directories'");
+ }
+
+ @Test
+ public void testEmptySectionYieldsError() {
+ projectViewStorageManager.add(".blazeproject", "directories:", "");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertIssues("Empty section: 'directories'");
+ }
+
+ @Test
+ public void testCommentsAreParsed() throws Exception {
+ projectViewStorageManager.add(
+ ".blazeproject",
+ "# comment",
+ "directories:",
+ " # another comment",
+ " java/com/google",
+ " # comment",
+ " java/com/google/android",
+ "");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
+ ProjectView projectView = projectViewFile.projectView;
+ assertThat(projectView.getSectionsOfType(TextBlockSection.KEY).get(0).getTextBlock())
+ .isEqualTo(new TextBlock(ImmutableList.of("# comment")));
+ assertThat(projectView.getSectionsOfType(DirectorySection.KEY).get(0).items())
+ .containsExactly(
+ new DirectoryEntry(new WorkspacePath("java/com/google"), true),
+ new DirectoryEntry(new WorkspacePath("java/com/google/android"), true));
+ }
+
+ @Test
+ public void testMultipleSections() throws Exception {
+ projectViewStorageManager.add(
+ ".blazeproject",
+ "directories:",
+ " java/com/google",
+ "directories:",
+ " java/com/google2",
+ "",
+ "workspace_type: java",
+ "workspace_type: android");
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ assertThat(projectViewSet.listItems(DirectorySection.KEY))
+ .containsExactly(
+ new DirectoryEntry(new WorkspacePath("java/com/google"), true),
+ new DirectoryEntry(new WorkspacePath("java/com/google2"), true));
+ assertThat(projectViewSet.listScalarItems(WorkspaceTypeSection.KEY))
+ .containsExactly(WorkspaceType.JAVA, WorkspaceType.ANDROID);
+ }
+
+ @Test
+ public void testListParserAcceptsWhitespace() throws Exception {
+ String text =
+ Joiner.on('\n')
+ .join(
+ "directories:",
+ " dir0",
+ " ",
+ "",
+ " dir1",
+ " ",
+ " ",
+ "# comment",
+ " dir2",
+ "",
+ " # commented out dir",
+ " ",
+ "# comment",
+ "# comment");
+ projectViewStorageManager.add(".blazeproject", text);
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
+ assert projectViewFile != null;
+ ProjectView projectView = projectViewFile.projectView;
+
+ assertThat(projectView)
+ .isEqualTo(
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("dir0")))
+ .add(TextBlock.of(" "))
+ .add(TextBlock.of(""))
+ .add(DirectoryEntry.include(new WorkspacePath("dir1")))
+ .add(TextBlock.of(" ", " "))
+ .add(TextBlock.of("# comment"))
+ .add(DirectoryEntry.include(new WorkspacePath("dir2")))
+ .add(TextBlock.of(""))
+ .add(TextBlock.of(" # commented out dir"))
+ .add(TextBlock.of(" ")))
+ .add(TextBlockSection.of(TextBlock.of("# comment", "# comment")))
+ .build());
+
+ String outputString = ProjectViewParser.projectViewToString(projectView);
+ assertThat(outputString).isEqualTo(text);
+ }
+
+ @Test
+ public void testCommentsAndWhitespacePreserved() throws Exception {
+ String text =
+ Joiner.on('\n')
+ .join(
+ "",
+ "# comment",
+ " ",
+ " ",
+ "directories:",
+ " # another comment",
+ " java/com/google",
+ " # comment",
+ "#unindented comment",
+ " java/com/google/android",
+ "",
+ " # needlessly indented comment",
+ "",
+ "directories:",
+ " java/com/google",
+ " # trailing comment",
+ "directories:",
+ " java/com/google");
+ projectViewStorageManager.add(".blazeproject", text);
+ projectViewParser.parseProjectView(new File(".blazeproject"));
+ errorCollector.assertNoIssues();
+
+ ProjectViewSet projectViewSet = projectViewParser.getResult();
+ ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
+ ProjectView projectView = projectViewFile.projectView;
+ String outputString = ProjectViewParser.projectViewToString(projectView);
+ assertThat(outputString).isEqualTo(text);
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/rulemaps/ReverseDependencyMapTest.java b/base/tests/unittests/com/google/idea/blaze/base/rulemaps/ReverseDependencyMapTest.java
new file mode 100644
index 0000000..310b7c3
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/rulemaps/ReverseDependencyMapTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.rulemaps;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Label;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for the reverse dependency map */
+@RunWith(JUnit4.class)
+public class ReverseDependencyMapTest extends BlazeTestCase {
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ }
+
+ @Test
+ public void testSingleDep() {
+ RuleMapBuilder builder = RuleMapBuilder.builder();
+ RuleMap ruleMap =
+ builder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l1")
+ .setKind("java_library")
+ .addDependency("//l:l2"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l2")
+ .setKind("java_library"))
+ .build();
+
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l2"), new Label("//l:l1"));
+ }
+
+ @Test
+ public void testLabelDepsOnTwoLabels() {
+ RuleMapBuilder builder = RuleMapBuilder.builder();
+ RuleMap ruleMap =
+ builder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l1")
+ .setKind("java_library")
+ .addDependency("//l:l2")
+ .addDependency("//l:l3"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l2")
+ .setKind("java_library"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l3")
+ .setKind("java_library"))
+ .build();
+
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l2"), new Label("//l:l1"));
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l1"));
+ }
+
+ @Test
+ public void testTwoLabelsDepOnSameLabel() {
+ RuleMapBuilder builder = RuleMapBuilder.builder();
+ RuleMap ruleMap =
+ builder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l1")
+ .setKind("java_library")
+ .addDependency("//l:l3"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l2")
+ .addDependency("//l:l3")
+ .setKind("java_library"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l3")
+ .setKind("java_library"))
+ .build();
+
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l1"));
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l2"));
+ }
+
+ @Test
+ public void testThreeLevelGraph() {
+ RuleMapBuilder builder = RuleMapBuilder.builder();
+ RuleMap ruleMap =
+ builder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l1")
+ .setKind("java_library")
+ .addDependency("//l:l3"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l2")
+ .addDependency("//l:l3")
+ .setKind("java_library"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l3")
+ .setKind("java_library"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l4")
+ .addDependency("//l:l3")
+ .setKind("java_library"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//l:l5")
+ .addDependency("//l:l4")
+ .setKind("java_library"))
+ .build();
+
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l1"));
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l2"));
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l4"));
+ assertThat(reverseDependencies).containsEntry(new Label("//l:l4"), new Label("//l:l5"));
+ }
+
+ private static ArtifactLocation sourceRoot(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootPath("/")
+ .setRelativePath(relativePath)
+ .setIsSource(true)
+ .build();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationTest.java
new file mode 100644
index 0000000..334557e
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import com.intellij.ide.ui.UISettings;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import com.intellij.openapi.project.Project;
+import java.util.List;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeCommandRunConfiguration}. */
+@RunWith(JUnit4.class)
+public class BlazeCommandRunConfigurationTest extends BlazeTestCase {
+ private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
+ new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze);
+
+ private final BlazeCommandRunConfigurationType type = new BlazeCommandRunConfigurationType();
+ private BlazeCommandRunConfiguration configuration;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ applicationServices.register(UISettings.class, new UISettings());
+ projectServices.register(
+ BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
+
+ this.configuration = this.type.getFactory().createTemplateConfiguration(project);
+
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ applicationServices.register(RuleFinder.class, new MockRuleFinder());
+ ExtensionPointImpl<BlazeCommandRunConfigurationHandlerProvider> handlerProviderEp =
+ registerExtensionPoint(
+ BlazeCommandRunConfigurationHandlerProvider.EP_NAME,
+ BlazeCommandRunConfigurationHandlerProvider.class);
+ handlerProviderEp.registerExtension(new MockBlazeCommandRunConfigurationHandlerProvider());
+ }
+
+ @Test
+ public void readAndWriteShouldMatch() throws Exception {
+ Label label = new Label("//package:rule");
+ configuration.setTarget(label);
+
+ Element element = new Element("test");
+ configuration.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ readConfiguration.readExternal(element);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(label);
+ }
+
+ @Test
+ public void readAndWriteShouldHandleNulls() throws Exception {
+ Element element = new Element("test");
+ configuration.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ readConfiguration.readExternal(element);
+
+ assertThat(readConfiguration.getTarget()).isEqualTo(configuration.getTarget());
+ }
+
+ private static class MockRuleFinder extends RuleFinder {
+ @Override
+ public List<RuleIdeInfo> findRules(Project project, Predicate<RuleIdeInfo> predicate) {
+ return ImmutableList.of();
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/RuleNameHeuristicTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/RuleNameHeuristicTest.java
new file mode 100644
index 0000000..1cb0276
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/RuleNameHeuristicTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import java.io.File;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link RuleNameHeuristic}. */
+@RunWith(JUnit4.class)
+public class RuleNameHeuristicTest extends BlazeTestCase {
+
+ @Override
+ protected void initTest(Container applicationServices, Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ ExtensionPointImpl<TestRuleHeuristic> ep =
+ registerExtensionPoint(TestRuleHeuristic.EP_NAME, TestRuleHeuristic.class);
+ ep.registerExtension(new RuleNameHeuristic());
+ }
+
+ @Test
+ public void testPredicateMatchingName() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ RuleIdeInfo rule = RuleIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build();
+ assertThat(new RuleNameHeuristic().matchesSource(rule, source, null)).isTrue();
+ }
+
+ @Test
+ public void testPredicateDifferentName() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ RuleIdeInfo rule = RuleIdeInfo.builder().setLabel("//foo:ForTest").setKind("java_test").build();
+ assertThat(new RuleNameHeuristic().matchesSource(rule, source, null)).isFalse();
+ }
+
+ @Test
+ public void testFilterNoMatchesFallBackToFirstRule() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ Collection<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder().setLabel("//foo:FirstTest").setKind("java_test").build(),
+ RuleIdeInfo.builder().setLabel("//bar:OtherTest").setKind("java_test").build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, null);
+ assertThat(match).isEqualTo(new Label("//foo:FirstTest"));
+ }
+
+ @Test
+ public void testFilterOneMatch() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ Collection<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder().setLabel("//bar:FirstTest").setKind("java_test").build(),
+ RuleIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, null);
+ assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ }
+
+ @Test
+ public void testFilterChoosesFirstMatch() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ Collection<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder().setLabel("//bar:OtherTest").setKind("java_test").build(),
+ RuleIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build(),
+ RuleIdeInfo.builder().setLabel("//bar/foo:FooTest").setKind("java_test").build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, null);
+ assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/TestSizeHeuristicTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/TestSizeHeuristicTest.java
new file mode 100644
index 0000000..f75be8a
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/TestSizeHeuristicTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import java.io.File;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link TestSizeHeuristic}. */
+@RunWith(JUnit4.class)
+public class TestSizeHeuristicTest extends BlazeTestCase {
+
+ @Override
+ protected void initTest(Container applicationServices, Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ ExtensionPointImpl<TestRuleHeuristic> ep =
+ registerExtensionPoint(TestRuleHeuristic.EP_NAME, TestRuleHeuristic.class);
+ ep.registerExtension(new TestSizeHeuristic());
+ }
+
+ @Test
+ public void testPredicateMatchingSize() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ RuleIdeInfo rule =
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build();
+ assertThat(new TestSizeHeuristic().matchesSource(rule, source, TestSize.MEDIUM)).isTrue();
+ }
+
+ @Test
+ public void testPredicateDifferentSize() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ RuleIdeInfo rule =
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build();
+ assertThat(new TestSizeHeuristic().matchesSource(rule, source, TestSize.SMALL)).isFalse();
+ }
+
+ @Test
+ public void testPredicateDefaultToSmallSize() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ RuleIdeInfo rule =
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build();
+ assertThat(new TestSizeHeuristic().matchesSource(rule, source, null)).isTrue();
+
+ rule =
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build();
+ assertThat(new TestSizeHeuristic().matchesSource(rule, source, null)).isFalse();
+ }
+
+ @Test
+ public void testFilterNoMatchesFallBackToFirstRule() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ ImmutableList<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.LARGE))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test3")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.ENORMOUS))
+ .build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(new Label("//foo:test1"));
+ }
+
+ @Test
+ public void testFilterOneMatch() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ ImmutableList<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(new Label("//foo:test2"));
+ }
+
+ @Test
+ public void testFilterChoosesFirstMatch() throws Exception {
+ File source = new File("java/com/foo/FooTest.java");
+ ImmutableList<RuleIdeInfo> rules =
+ ImmutableList.of(
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build(),
+ RuleIdeInfo.builder()
+ .setLabel("//foo:test3")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .build());
+ Label match = TestRuleHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(new Label("//foo:test2"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandlerTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandlerTest.java
new file mode 100644
index 0000000..64d3900
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandlerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler.BlazeCommandGenericRunConfigurationHandlerEditor;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.ide.ui.UISettings;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.util.InvalidDataException;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeCommandGenericRunConfigurationHandler}. */
+@RunWith(JUnit4.class)
+public class BlazeCommandGenericRunConfigurationHandlerTest extends BlazeTestCase {
+ private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
+ new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze);
+ private static final BlazeCommandName COMMAND = BlazeCommandName.fromString("command");
+
+ private final BlazeCommandRunConfigurationType type = new BlazeCommandRunConfigurationType();
+ private BlazeCommandRunConfiguration configuration;
+ private BlazeCommandGenericRunConfigurationHandler handler;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ applicationServices.register(UISettings.class, new UISettings());
+ projectServices.register(
+ BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
+
+ configuration = type.getFactory().createTemplateConfiguration(project);
+ handler = new BlazeCommandGenericRunConfigurationHandler(configuration);
+ }
+
+ @Test
+ public void readAndWriteShouldMatch() throws InvalidDataException {
+ handler.setCommand(COMMAND);
+ handler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ handler.setExeFlags(ImmutableList.of("--exeFlag1"));
+ handler.setBlazeBinary("/usr/bin/blaze");
+
+ Element element = new Element("test");
+ handler.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ new BlazeCommandGenericRunConfigurationHandler(readConfiguration);
+ readHandler.readExternal(element);
+
+ assertThat(readHandler.getCommand()).isEqualTo(COMMAND);
+ assertThat(readHandler.getAllBlazeFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readHandler.getAllExeFlags()).containsExactly("--exeFlag1");
+ assertThat(readHandler.getBlazeBinary()).isEqualTo("/usr/bin/blaze");
+ }
+
+ @Test
+ public void readAndWriteShouldHandleNulls() throws InvalidDataException {
+ Element element = new Element("test");
+ handler.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ new BlazeCommandGenericRunConfigurationHandler(readConfiguration);
+ readHandler.readExternal(element);
+
+ assertThat(readHandler.getCommand()).isEqualTo(handler.getCommand());
+ assertThat(readHandler.getAllBlazeFlags()).isEqualTo(handler.getAllBlazeFlags());
+ assertThat(readHandler.getAllExeFlags()).isEqualTo(handler.getAllExeFlags());
+ assertThat(readHandler.getBlazeBinary()).isEqualTo(handler.getBlazeBinary());
+ }
+
+ @Test
+ public void readShouldOmitEmptyFlags() throws InvalidDataException {
+ handler.setBlazeFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
+ handler.setExeFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
+
+ Element element = new Element("test");
+ handler.writeExternal(element);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ new BlazeCommandGenericRunConfigurationHandler(readConfiguration);
+ readHandler.readExternal(element);
+
+ assertThat(readHandler.getAllBlazeFlags()).containsExactly("hi", "I'm", "Josh").inOrder();
+ assertThat(readHandler.getAllExeFlags()).containsExactly("hi", "I'm", "Josh").inOrder();
+ }
+
+ @Test
+ public void editorApplyToAndResetFromShouldMatch() throws ConfigurationException {
+ BlazeCommandGenericRunConfigurationHandlerEditor editor =
+ new BlazeCommandGenericRunConfigurationHandlerEditor(handler);
+
+ handler.setCommand(COMMAND);
+ handler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ handler.setExeFlags(ImmutableList.of("--exeFlag1", "--exeFlag2"));
+ handler.setBlazeBinary("/usr/bin/blaze");
+
+ editor.resetEditorFrom(handler);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ new BlazeCommandGenericRunConfigurationHandler(readConfiguration);
+ editor.applyEditorTo(readHandler);
+
+ assertThat(readHandler.getCommand()).isEqualTo(handler.getCommand());
+ assertThat(readHandler.getAllBlazeFlags()).isEqualTo(handler.getAllBlazeFlags());
+ assertThat(readHandler.getAllExeFlags()).isEqualTo(handler.getAllExeFlags());
+ assertThat(readHandler.getBlazeBinary()).isEqualTo(handler.getBlazeBinary());
+ }
+
+ @Test
+ public void editorApplyToAndResetFromShouldHandleNulls() throws ConfigurationException {
+ BlazeCommandGenericRunConfigurationHandlerEditor editor =
+ new BlazeCommandGenericRunConfigurationHandlerEditor(handler);
+
+ editor.resetEditorFrom(handler);
+ BlazeCommandRunConfiguration readConfiguration =
+ type.getFactory().createTemplateConfiguration(project);
+ BlazeCommandGenericRunConfigurationHandler readHandler =
+ new BlazeCommandGenericRunConfigurationHandler(readConfiguration);
+ editor.applyEditorTo(readHandler);
+
+ assertThat(readHandler.getCommand()).isEqualTo(handler.getCommand());
+ assertThat(readHandler.getAllBlazeFlags()).isEqualTo(handler.getAllBlazeFlags());
+ assertThat(readHandler.getAllExeFlags()).isEqualTo(handler.getAllExeFlags());
+ assertThat(readHandler.getBlazeBinary()).isEqualTo(handler.getBlazeBinary());
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/confighandler/BlazeUnknownRunConfigurationHandlerTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/confighandler/BlazeUnknownRunConfigurationHandlerTest.java
new file mode 100644
index 0000000..7752f26
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/confighandler/BlazeUnknownRunConfigurationHandlerTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.confighandler;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.ide.ui.UISettings;
+import com.intellij.openapi.util.InvalidDataException;
+import java.io.StringReader;
+import org.jdom.Element;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeUnknownRunConfigurationHandler}. */
+@RunWith(JUnit4.class)
+public class BlazeUnknownRunConfigurationHandlerTest extends BlazeTestCase {
+ private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
+ new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze);
+
+ private final BlazeCommandRunConfigurationType type = new BlazeCommandRunConfigurationType();
+ private BlazeCommandRunConfiguration configuration;
+ private BlazeUnknownRunConfigurationHandler handler;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ applicationServices.register(UISettings.class, new UISettings());
+ projectServices.register(
+ BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
+
+ configuration = type.getFactory().createTemplateConfiguration(project);
+ handler = new BlazeUnknownRunConfigurationHandler(configuration);
+ }
+
+ @Test
+ public void readAndWriteShouldPreserveOldContent() throws Exception {
+ SAXBuilder saxBuilder = new SAXBuilder();
+ XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
+
+ String inputXml =
+ "<?xml version=\"1.0\"?>"
+ + "<test foo=\"bar\" bar=\"baz\">"
+ + " <child abc=\"def\">"
+ + " <grandchild />"
+ + " </child>"
+ + " <child foo=\"baz\" />"
+ + "</test>";
+ Element element = saxBuilder.build(new StringReader(inputXml)).getRootElement();
+ handler.readExternal(element);
+
+ Element writeElement = new Element("test");
+ handler.writeExternal(writeElement);
+
+ assertThat(xmlOutputter.outputString(writeElement))
+ .isEqualTo(xmlOutputter.outputString(element));
+ }
+
+ @Test
+ public void readAndWriteShouldHandleEmptyElements() throws InvalidDataException {
+ //<test />
+ Element element = new Element("test");
+ handler.readExternal(element);
+
+ Element writeElement = new Element("test");
+ handler.writeExternal(writeElement);
+
+ assertThat(writeElement.getAttributes()).isEmpty();
+ assertThat(writeElement.getChildren()).isEmpty();
+ }
+
+ @Test
+ public void writeShouldPreserveNewContent() throws Exception {
+ SAXBuilder saxBuilder = new SAXBuilder();
+ XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
+
+ //<test />
+ Element element = new Element("test");
+ handler.readExternal(element);
+
+ String newXml =
+ "<?xml version=\"1.0\"?>"
+ + "<test foo=\"bar\">"
+ + " <child abc=\"def\" />"
+ + " <child />"
+ + "</test>";
+ Element writeElement = saxBuilder.build(new StringReader(newXml)).getRootElement();
+ handler.writeExternal(writeElement);
+
+ Element newElement = saxBuilder.build(new StringReader(newXml)).getRootElement();
+ assertThat(xmlOutputter.outputString(writeElement))
+ .isEqualTo(xmlOutputter.outputString(newElement));
+ }
+
+ @Test
+ public void writeShouldMergeAndOverwriteOldContent() throws Exception {
+ SAXBuilder saxBuilder = new SAXBuilder();
+ XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
+
+ String oldXml =
+ "<?xml version=\"1.0\"?>"
+ + "<test foo=\"old\" bar=\"old\">"
+ + " <child abc=\"old\">"
+ + " <grandchild />"
+ + " </child>"
+ + " <backup foo=\"baz\" />"
+ + " <backup />"
+ + "</test>";
+ Element element = saxBuilder.build(new StringReader(oldXml)).getRootElement();
+ handler.readExternal(element);
+
+ String newXml =
+ "<?xml version=\"1.0\"?>"
+ + "<test foo=\"bar\">"
+ + " <child abc=\"def\" />"
+ + " <child />"
+ + "</test>";
+ Element writeElement = saxBuilder.build(new StringReader(newXml)).getRootElement();
+ handler.writeExternal(writeElement);
+
+ String mergedXml =
+ "<?xml version=\"1.0\"?>"
+ + "<test foo=\"bar\" bar=\"old\">"
+ + " <child abc=\"def\" />"
+ + " <child />"
+ + " <backup foo=\"baz\" />"
+ + " <backup />"
+ + "</test>";
+ Element mergedElement = saxBuilder.build(new StringReader(mergedXml)).getRootElement();
+ assertThat(xmlOutputter.outputString(writeElement))
+ .isEqualTo(xmlOutputter.outputString(mergedElement));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/testmap/TestMapTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/testmap/TestMapTest.java
new file mode 100644
index 0000000..acb1a01
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/testmap/TestMapTest.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run.testmap;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.rulemaps.ReverseDependencyMap;
+import com.google.idea.blaze.base.run.testmap.TestRuleFinderImpl.TestMap;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for the test map */
+@RunWith(JUnit4.class)
+public class TestMapTest extends BlazeTestCase {
+ private RuleMapBuilder ruleMapBuilder;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ ruleMapBuilder = RuleMapBuilder.builder();
+ }
+
+ @Test
+ public void testTrivialTestMap() throws Exception {
+ RuleMap ruleMap =
+ ruleMapBuilder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test")
+ .setKind("java_test")
+ .addSource(sourceRoot("test/Test.java")))
+ .build();
+
+ TestMap testMap = new TestMap(project, ruleMap);
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
+ .containsExactly(new Label("//test:test"));
+ }
+
+ @Test
+ public void testOneStepRemovedTestMap() throws Exception {
+ RuleMap ruleMap =
+ ruleMapBuilder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test")
+ .setKind("java_test")
+ .addDependency("//test:lib"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .build();
+
+ TestMap testMap = new TestMap(project, ruleMap);
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
+ .containsExactly(new Label("//test:test"));
+ }
+
+ @Test
+ public void testTwoCandidatesTestMap() throws Exception {
+ RuleMap ruleMap =
+ ruleMapBuilder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test")
+ .setKind("java_test")
+ .addDependency("//test:lib"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test2")
+ .setKind("java_test")
+ .addDependency("//test:lib"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .build();
+
+ TestMap testMap = new TestMap(project, ruleMap);
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
+ .containsExactly(new Label("//test:test"), new Label("//test:test2"));
+ }
+
+ @Test
+ public void testBfsPreferred() throws Exception {
+ RuleMap ruleMap =
+ ruleMapBuilder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib2")
+ .setKind("java_library")
+ .addDependency("//test:lib"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test2")
+ .setKind("java_test")
+ .addDependency("//test:lib2"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test")
+ .setKind("java_test")
+ .addDependency("//test:lib"))
+ .build();
+
+ TestMap testMap = new TestMap(project, ruleMap);
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
+ .containsExactly(new Label("//test:test"), new Label("//test:test2"))
+ .inOrder();
+ }
+
+ @Test
+ public void testSourceIncludedMultipleTimesFindsAll() throws Exception {
+ RuleMap ruleMap =
+ ruleMapBuilder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test")
+ .setKind("java_test")
+ .addDependency("//test:lib"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test2")
+ .setKind("java_test")
+ .addDependency("//test:lib2"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib2")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .build();
+
+ TestMap testMap = new TestMap(project, ruleMap);
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
+ .containsExactly(new Label("//test:test"), new Label("//test:test2"));
+ }
+
+ @Test
+ public void testSourceIncludedMultipleTimesShouldOnlyGiveOneInstanceOfTest() throws Exception {
+ RuleMap ruleMap =
+ ruleMapBuilder
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:test")
+ .setKind("java_test")
+ .addDependency("//test:lib")
+ .addDependency("//test:lib2"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("test/BUILD"))
+ .setLabel("//test:lib2")
+ .setKind("java_library")
+ .addSource(sourceRoot("test/Test.java")))
+ .build();
+
+ TestMap testMap = new TestMap(project, ruleMap);
+ ImmutableMultimap<Label, Label> reverseDependencies =
+ ReverseDependencyMap.createRdepsMap(ruleMap);
+ assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
+ .containsExactly(new Label("//test:test"));
+ }
+
+ private ArtifactLocation sourceRoot(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootPath("/")
+ .setRelativePath(relativePath)
+ .setIsSource(true)
+ .build();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/scope/BlazeContextTest.java b/base/tests/unittests/com/google/idea/blaze/base/scope/BlazeContextTest.java
new file mode 100644
index 0000000..eab311c
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/scope/BlazeContextTest.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.BlazeTestCase;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeContext}. */
+@RunWith(JUnit4.class)
+public class BlazeContextTest extends BlazeTestCase {
+
+ @Test
+ public void testScopeBeginsWhenPushedToContext() {
+ BlazeContext context = new BlazeContext();
+ final BlazeScope scope = mock(BlazeScope.class);
+ context.push(scope);
+ verify(scope).onScopeBegin(context);
+ }
+
+ @Test
+ public void testScopeEndsWhenContextEnds() {
+ BlazeContext context = new BlazeContext();
+ final BlazeScope scope = mock(BlazeScope.class);
+ context.push(scope);
+ context.endScope();
+ verify(scope).onScopeEnd(context);
+ }
+
+ @Test
+ public void testEndingTwiceHasNoEffect() {
+ BlazeContext context = new BlazeContext();
+ final BlazeScope scope = mock(BlazeScope.class);
+ context.push(scope);
+ context.endScope();
+ context.endScope();
+ verify(scope).onScopeEnd(context);
+ }
+
+ @Test
+ public void testEndingScopeNormallyDoesntEndParent() {
+ BlazeContext parentContext = new BlazeContext();
+ BlazeContext childContext = new BlazeContext(parentContext);
+ childContext.endScope();
+ assertTrue(childContext.isEnding());
+ assertFalse(parentContext.isEnding());
+ }
+
+ @Test
+ public void testCancellingScopeCancelsParent() {
+ BlazeContext parentContext = new BlazeContext();
+ BlazeContext childContext = new BlazeContext(parentContext);
+ childContext.setCancelled();
+ assertTrue(childContext.isCancelled());
+ assertTrue(parentContext.isCancelled());
+ }
+
+ /** A simple scope that records its start and end by ID. */
+ static class RecordScope implements BlazeScope {
+ private final int id;
+ private final List<String> record;
+
+ public RecordScope(int id, List<String> record) {
+ this.id = id;
+ this.record = record;
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {
+ record.add("begin" + id);
+ }
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ record.add("end" + id);
+ }
+ }
+
+ @Test
+ public void testScopesBeginAndEndInStackOrder() {
+ List<String> record = Lists.newArrayList();
+ BlazeContext context = new BlazeContext();
+ context
+ .push(new RecordScope(1, record))
+ .push(new RecordScope(2, record))
+ .push(new RecordScope(3, record));
+ context.endScope();
+ assertThat(record)
+ .isEqualTo(ImmutableList.of("begin1", "begin2", "begin3", "end3", "end2", "end1"));
+ }
+
+ @Test
+ public void testParentFoundInStackOrder() {
+ BlazeContext context = new BlazeContext();
+ BlazeScope scope1 = mock(BlazeScope.class);
+ BlazeScope scope2 = mock(BlazeScope.class);
+ BlazeScope scope3 = mock(BlazeScope.class);
+ context.push(scope1).push(scope2).push(scope3);
+ assertThat(context.getParentScope(scope3)).isEqualTo(scope2);
+ assertThat(context.getParentScope(scope2)).isEqualTo(scope1);
+ assertThat(context.getParentScope(scope1)).isNull();
+ }
+
+ @Test
+ public void testParentFoundInStackOrderAcrossContexts() {
+ BlazeContext parentContext = new BlazeContext();
+ BlazeContext childContext = new BlazeContext(parentContext);
+ BlazeScope scope1 = mock(BlazeScope.class);
+ BlazeScope scope2 = mock(BlazeScope.class);
+ BlazeScope scope3 = mock(BlazeScope.class);
+ parentContext.push(scope1).push(scope2);
+ childContext.push(scope3);
+ assertThat(childContext.getParentScope(scope3)).isEqualTo(scope2);
+ }
+
+ static class TestOutput1 implements Output {}
+
+ static class TestOutput2 implements Output {}
+
+ static class TestOutputSink<T extends Output> implements OutputSink<T> {
+ public boolean gotOutput;
+
+ @Override
+ public Propagation onOutput(@NotNull T output) {
+ gotOutput = true;
+ return Propagation.Continue;
+ }
+ }
+
+ static class TestOutputSink1 extends TestOutputSink<TestOutput1> {}
+
+ static class TestOutputSink2 extends TestOutputSink<TestOutput2> {}
+
+ @Test
+ public void testOutputGoesToRegisteredSink() {
+ BlazeContext context = new BlazeContext();
+ TestOutputSink1 sink = new TestOutputSink1();
+ context.addOutputSink(TestOutput1.class, sink);
+
+ assertFalse(sink.gotOutput);
+ context.output(new TestOutput1());
+ assertTrue(sink.gotOutput);
+ }
+
+ @Test
+ public void testOutputDoesntGoToWrongSink() {
+ BlazeContext context = new BlazeContext();
+ TestOutputSink2 sink = new TestOutputSink2();
+ context.addOutputSink(TestOutput2.class, sink);
+
+ assertFalse(sink.gotOutput);
+ context.output(new TestOutput1());
+ assertFalse(sink.gotOutput);
+ }
+
+ @Test
+ public void testOutputGoesToParentContexts() {
+ BlazeContext parentContext = new BlazeContext();
+ BlazeContext childContext = new BlazeContext(parentContext);
+ TestOutputSink1 sink = new TestOutputSink1();
+ parentContext.addOutputSink(TestOutput1.class, sink);
+
+ assertFalse(sink.gotOutput);
+ childContext.output(new TestOutput1());
+ assertTrue(sink.gotOutput);
+ }
+
+ @Test
+ public void testHoldingPreventsEndingContext() {
+ BlazeContext context = new BlazeContext();
+ context.hold();
+ context.endScope();
+ assertFalse(context.isEnding());
+ context.release();
+ assertTrue(context.isEnding());
+ }
+
+ private static class StringScope implements BlazeScope {
+
+ public final String str;
+
+ public StringScope(String s) {
+ this.str = s;
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {}
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {}
+ }
+
+ private static class CollectorScope implements BlazeScope {
+
+ public final List<String> output;
+
+ public CollectorScope(List<String> output) {
+ this.output = output;
+ }
+
+ @Override
+ public void onScopeBegin(@NotNull BlazeContext context) {}
+
+ @Override
+ public void onScopeEnd(@NotNull BlazeContext context) {
+ List<StringScope> scopes = context.getScopes(StringScope.class, this);
+ for (StringScope scope : scopes) {
+ output.add(scope.str);
+ }
+ }
+ }
+
+ @Test
+ public void testGetScopesOnlyReturnsScopesLowerOnTheStack() {
+ List<String> output1 = Lists.newArrayList();
+ List<String> output2 = Lists.newArrayList();
+ List<String> output3 = Lists.newArrayList();
+
+ BlazeContext context = new BlazeContext();
+ context.push(new StringScope("a"));
+ context.push(new StringScope("b"));
+ CollectorScope scope = new CollectorScope(output1);
+ context.push(scope);
+ context.push(new StringScope("c"));
+ context.push(new CollectorScope(output2));
+ context.push(new StringScope("d"));
+ context.push(new StringScope("e"));
+ context.push(new CollectorScope(output3));
+ context.endScope();
+
+ assertThat(output1).isEqualTo(ImmutableList.of("b", "a"));
+ assertThat(output2).isEqualTo(ImmutableList.of("c", "b", "a"));
+ assertThat(output3).isEqualTo(ImmutableList.of("e", "d", "c", "b", "a"));
+ }
+
+ @Test
+ public void testGetScopesOnlyReturnsScopesLowerOnTheStackForMultipleContexts() {
+ List<String> output1 = Lists.newArrayList();
+ List<String> output2 = Lists.newArrayList();
+ List<String> output3 = Lists.newArrayList();
+
+ BlazeContext context1 = new BlazeContext();
+ context1.push(new StringScope("a"));
+ context1.push(new StringScope("b"));
+ CollectorScope scope = new CollectorScope(output1);
+ context1.push(scope);
+
+ BlazeContext context2 = new BlazeContext(context1);
+ context2.push(new StringScope("c"));
+ context2.push(new CollectorScope(output2));
+ context2.push(new StringScope("d"));
+ context2.push(new StringScope("e"));
+
+ BlazeContext context3 = new BlazeContext(context2);
+ context3.push(new CollectorScope(output3));
+ context3.endScope();
+ context2.endScope();
+ context1.endScope();
+
+ assertThat(output1).isEqualTo(ImmutableList.of("b", "a"));
+ assertThat(output2).isEqualTo(ImmutableList.of("c", "b", "a"));
+ assertThat(output3).isEqualTo(ImmutableList.of("e", "d", "c", "b", "a"));
+ }
+
+ @Test
+ public void testGetScopesOnlyReturnsScopesIfStartingScopeInContext() {
+ List<String> output1 = Lists.newArrayList();
+
+ BlazeContext context1 = new BlazeContext();
+ context1.push(new StringScope("a"));
+ context1.push(new StringScope("b"));
+ CollectorScope scope = new CollectorScope(output1);
+ context1.push(scope);
+
+ BlazeContext context2 = new BlazeContext(context1);
+ context2.push(new StringScope("c"));
+
+ List<StringScope> scopes = context2.getScopes(StringScope.class, scope);
+ assertThat(scopes).isEqualTo(ImmutableList.of());
+ }
+
+ @Test
+ public void testGetScopesIncludesStartingScope() {
+ BlazeContext context1 = new BlazeContext();
+ StringScope a = new StringScope("a");
+ context1.push(a);
+ StringScope b = new StringScope("b");
+ context1.push(b);
+
+ List<StringScope> scopes = context1.getScopes(StringScope.class, b);
+ assertThat(scopes).isEqualTo(ImmutableList.of(b, a));
+ }
+
+ @Test
+ public void testGetScopesIndexIsNoninclusive() {
+ BlazeContext context1 = new BlazeContext();
+ StringScope scopeA = new StringScope("a");
+ context1.push(scopeA);
+ StringScope scopeB = new StringScope("b");
+ context1.push(scopeB);
+
+ List<StringScope> scopes = Lists.newArrayList();
+ context1.getScopes(scopes, StringScope.class, 1);
+ assertThat(scopes).isEqualTo(ImmutableList.of(scopeA));
+ }
+
+ @Test
+ public void testGetScopesWithoutStartScopeGetsAll() {
+ BlazeContext context1 = new BlazeContext();
+ StringScope a = new StringScope("a");
+ context1.push(a);
+ StringScope b = new StringScope("b");
+ context1.push(b);
+
+ List<StringScope> scopes = context1.getScopes(StringScope.class);
+ assertThat(scopes).isEqualTo(ImmutableList.of(b, a));
+ }
+
+ static class NonPropagatingOutputSink implements OutputSink<TestOutput1> {
+ boolean gotOutput;
+
+ @Override
+ public Propagation onOutput(@NotNull TestOutput1 output) {
+ this.gotOutput = true;
+ return Propagation.Stop;
+ }
+ }
+
+ @Test
+ public void testOutputIsTerminatedByFirstSink() {
+ NonPropagatingOutputSink sink1 = new NonPropagatingOutputSink();
+ NonPropagatingOutputSink sink2 = new NonPropagatingOutputSink();
+ NonPropagatingOutputSink sink3 = new NonPropagatingOutputSink();
+
+ BlazeContext context1 = new BlazeContext();
+ context1.addOutputSink(TestOutput1.class, sink1);
+
+ BlazeContext context2 = new BlazeContext(context1);
+ context2.addOutputSink(TestOutput1.class, sink2);
+ context2.addOutputSink(TestOutput1.class, sink3);
+
+ context2.output(new TestOutput1());
+
+ assertThat(sink1.gotOutput).isFalse();
+ assertThat(sink2.gotOutput).isFalse();
+ assertThat(sink3.gotOutput).isTrue();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/scope/ScopeTest.java b/base/tests/unittests/com/google/idea/blaze/base/scope/ScopeTest.java
new file mode 100644
index 0000000..7039030
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/scope/ScopeTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.google.idea.blaze.base.BlazeTestCase;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link Scope}. */
+@RunWith(JUnit4.class)
+public class ScopeTest extends BlazeTestCase {
+
+ @Test
+ public void testScopedOperationRuns() {
+ final boolean[] ran = new boolean[1];
+ Scope.root(
+ new ScopedOperation() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ ran[0] = true;
+ }
+ });
+ assertTrue(ran[0]);
+ }
+
+ @Test
+ public void testScopedFunctionReturnsValue() {
+ String result =
+ Scope.root(
+ new ScopedFunction<String>() {
+ @Override
+ public String execute(@NotNull BlazeContext context) {
+ return "test";
+ }
+ });
+ assertThat(result).isEqualTo("test");
+ }
+
+ @Test
+ public void testScopedOperationEndsContext() {
+ final BlazeScope scope = mock(BlazeScope.class);
+ Scope.root(
+ new ScopedOperation() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ context.push(scope);
+ }
+ });
+ verify(scope).onScopeEnd(any(BlazeContext.class));
+ }
+
+ @Test
+ public void testScopedFunctionEndsContext() {
+ final BlazeScope scope = mock(BlazeScope.class);
+ Scope.root(
+ new ScopedFunction<String>() {
+ @Override
+ public String execute(@NotNull BlazeContext context) {
+ context.push(scope);
+ return "";
+ }
+ });
+ verify(scope).onScopeEnd(any(BlazeContext.class));
+ }
+
+ /*
+ @Test
+ public void testThrowingExceptionEndsScopedOperationWithFailure() {
+ final RuntimeException e = new RuntimeException();
+ final BlazeScope scope = mock(BlazeScope.class);
+ Throwable throwable = Scope.root(project, new ScopedOperation() {
+ @Override
+ public void execute(@NotNull BlazeContext context) {
+ context.push(scope);
+ throw e;
+ }
+ }).throwable;
+ verify(scope).onScopeEnd(any(BlazeContext.class));
+ assertThat(e).isEqualTo(throwable);
+ }
+
+ @Test
+ public void testThrowingExceptionEndsScopeFunctionWithFailure() {
+ final RuntimeException e = new RuntimeException();
+ final BlazeScope scope = mock(BlazeScope.class);
+ Throwable throwable = Scope.root(project, new ScopedFunction<String>() {
+ @Override
+ public String execute(@NotNull BlazeContext context) {
+ context.push(scope);
+ throw e;
+ }
+ }).throwable;
+ verify(scope).onScopeEnd(any(BlazeContext.class));
+ assertThat(e).isEqualTo(throwable);
+ }
+ */
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java
new file mode 100644
index 0000000..33f2ef4
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ErrorCollector;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import java.util.Set;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test cases for {@link LanguageSupport} */
+@RunWith(JUnit4.class)
+public class LanguageSupportTest extends BlazeTestCase {
+ private ErrorCollector errorCollector = new ErrorCollector();
+ private BlazeContext context;
+ private ExtensionPointImpl<BlazeSyncPlugin> syncPlugins;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ syncPlugins = registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+
+ context = new BlazeContext();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+ }
+
+ @Test
+ public void testSimpleCase() {
+ syncPlugins.registerExtension(
+ new BlazeSyncPlugin.Adapter() {
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ return ImmutableSet.of(LanguageClass.C);
+ }
+ });
+
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.C))
+ .build())
+ .build();
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ errorCollector.assertNoIssues();
+ assertThat(workspaceLanguageSettings)
+ .isEqualTo(
+ new WorkspaceLanguageSettings(WorkspaceType.C, ImmutableSet.of(LanguageClass.C)));
+ }
+
+ @Test
+ public void testFailWithUnsupportedLanguage() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.C))
+ .build())
+ .build();
+ LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ errorCollector.assertIssues(
+ "Language 'c' is not supported for this plugin with workspace type: 'c'");
+ }
+
+ /** Tests that we ask for java and android when the workspace type is android. */
+ @Test
+ public void testWorkspaceTypeImpliesLanguages() {
+ syncPlugins.registerExtension(
+ new BlazeSyncPlugin.Adapter() {
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ return ImmutableSet.of(LanguageClass.ANDROID, LanguageClass.JAVA, LanguageClass.C);
+ }
+ });
+
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.ANDROID))
+ .build())
+ .build();
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ assertThat(workspaceLanguageSettings)
+ .isEqualTo(
+ new WorkspaceLanguageSettings(
+ WorkspaceType.ANDROID, ImmutableSet.of(LanguageClass.JAVA, LanguageClass.ANDROID)));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImplTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImplTest.java
new file mode 100644
index 0000000..24a6200
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImplTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.TestUtils;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeIdeInterfaceAspectsImpl}. */
+@RunWith(JUnit4.class)
+public class BlazeIdeInterfaceAspectsImplTest extends BlazeTestCase {
+
+ private static final File DUMMY_ROOT = new File("/");
+ private static final WorkspaceRoot WORKSPACE_ROOT = new WorkspaceRoot(DUMMY_ROOT);
+ private static final BlazeRoots BLAZE_ROOTS =
+ new BlazeRoots(
+ DUMMY_ROOT,
+ ImmutableList.of(DUMMY_ROOT),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen"));
+ private static final ArtifactLocationDecoder DUMMY_DECODER =
+ new ArtifactLocationDecoder(
+ BLAZE_ROOTS, new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_ROOTS));
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ applicationServices.register(ExperimentService.class, new MockExperimentService());
+ applicationServices.register(FileAttributeProvider.class, new FileAttributeProvider());
+ }
+
+ @Test
+ public void testRuleIdeInfoIsSerializable() {
+ AndroidStudioIdeInfo.RuleIdeInfo ideProto =
+ AndroidStudioIdeInfo.RuleIdeInfo.newBuilder()
+ .setLabel("//test:test")
+ .setKindString("android_binary")
+ .addDependencies("//test:dep")
+ .addTags("tag")
+ .setJavaRuleIdeInfo(
+ AndroidStudioIdeInfo.JavaRuleIdeInfo.newBuilder()
+ .addJars(
+ AndroidStudioIdeInfo.LibraryArtifact.newBuilder()
+ .setJar(artifactLocation("jar.jar"))
+ .build())
+ .addGeneratedJars(
+ AndroidStudioIdeInfo.LibraryArtifact.newBuilder()
+ .setJar(artifactLocation("jar.jar"))
+ .build())
+ .addSources(artifactLocation("source.java")))
+ .setAndroidRuleIdeInfo(
+ AndroidStudioIdeInfo.AndroidRuleIdeInfo.newBuilder()
+ .addResources(artifactLocation("res"))
+ .setApk(artifactLocation("apk"))
+ .addDependencyApk(artifactLocation("apk"))
+ .setJavaPackage("package"))
+ .build();
+
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ new WorkspaceLanguageSettings(
+ WorkspaceType.ANDROID, ImmutableSet.of(LanguageClass.ANDROID));
+ RuleIdeInfo ruleIdeInfo =
+ IdeInfoFromProtobuf.makeRuleIdeInfo(workspaceLanguageSettings, DUMMY_DECODER, ideProto);
+ TestUtils.assertIsSerializable(ruleIdeInfo);
+ }
+
+ @Test
+ public void testBlazeStateIsSerializable() {
+ BlazeIdeInterfaceAspectsImpl.State state = new BlazeIdeInterfaceAspectsImpl.State();
+ state.fileToLabel = ImmutableMap.of(new File("fileName"), new Label("//java/com/test:test"));
+ state.fileState = ImmutableMap.of();
+ state.ruleMap =
+ new RuleMap(ImmutableMap.of()); // Tested separately in testRuleIdeInfoIsSerializable
+
+ TestUtils.assertIsSerializable(state);
+ }
+
+ static AndroidStudioIdeInfo.ArtifactLocation artifactLocation(String relativePath) {
+ return artifactLocation(DUMMY_ROOT.toString(), relativePath);
+ }
+
+ static AndroidStudioIdeInfo.ArtifactLocation artifactLocation(
+ String rootPath, String relativePath) {
+ return AndroidStudioIdeInfo.ArtifactLocation.newBuilder()
+ .setRelativePath(relativePath)
+ .build();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptionsTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptionsTest.java
new file mode 100644
index 0000000..fb09872
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptionsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.aspects;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.BlazeTestCase;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for any unfiltered compiler options */
+@RunWith(JUnit4.class)
+public class UnfilteredCompilerOptionsTest extends BlazeTestCase {
+ @Test
+ public void testUnfilteredOptionsParsingForISystemOptions() {
+ ImmutableList<String> unfilteredOptions =
+ ImmutableList.of(
+ "-isystem",
+ "sys/inc1",
+ "-VER2",
+ "-isystem",
+ "sys2/inc1",
+ "-isystem",
+ "sys3/inc1",
+ "-isystm",
+ "sys4/inc1");
+ List<String> sysIncludes = Lists.newArrayList();
+ List<String> flags = Lists.newArrayList();
+ UnfilteredCompilerOptions.splitUnfilteredCompilerOptions(unfilteredOptions, sysIncludes, flags);
+
+ assertThat(sysIncludes).containsExactly("sys/inc1", "sys2/inc1", "sys3/inc1");
+
+ assertThat(flags).containsExactly("-VER2", "-isystm", "sys4/inc1");
+ }
+
+ @Test
+ public void testUnfilteredOptionsParsingForISystemOptionsNoSpaceAfterIsystem() {
+ ImmutableList<String> unfilteredOptions =
+ ImmutableList.of(
+ "-isystem", "sys/inc1", "-VER2", "-isystemsys2/inc1", "-isystem", "sys3/inc1");
+ List<String> sysIncludes = Lists.newArrayList();
+ List<String> flags = Lists.newArrayList();
+ UnfilteredCompilerOptions.splitUnfilteredCompilerOptions(unfilteredOptions, sysIncludes, flags);
+
+ assertThat(sysIncludes).containsExactly("sys/inc1", "sys2/inc1", "sys3/inc1");
+
+ assertThat(flags).containsExactly("-VER2");
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderTest.java
new file mode 100644
index 0000000..c6ea540
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass;
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test cases for {@link ArtifactLocationDecoder}. */
+@RunWith(JUnit4.class)
+public class ArtifactLocationDecoderTest extends BlazeTestCase {
+
+ private static final WorkspaceRoot WORKSPACE_ROOT = new WorkspaceRoot(new File("/path/to/root"));
+ private static final String EXECUTION_ROOT = "/path/to/_blaze_user/1234bf129e/root";
+
+ private static final BlazeRoots BLAZE_GIT5_ROOTS =
+ new BlazeRoots(
+ new File(EXECUTION_ROOT),
+ ImmutableList.of(
+ WORKSPACE_ROOT.directory(),
+ new File(WORKSPACE_ROOT.directory().getParentFile(), "READONLY/root")),
+ new ExecutionRootPath("root/blaze-out/crosstool/bin"),
+ new ExecutionRootPath("root/blaze-out/crosstool/genfiles"));
+
+ private static final BlazeRoots BLAZE_CITC_ROOTS =
+ new BlazeRoots(
+ new File(EXECUTION_ROOT),
+ ImmutableList.of(WORKSPACE_ROOT.directory()),
+ new ExecutionRootPath("root/blaze-out/crosstool/bin"),
+ new ExecutionRootPath("root/blaze-out/crosstool/genfiles"));
+
+ static class MockFileAttributeProvider extends FileAttributeProvider {
+ final Set<File> files = Sets.newHashSet();
+
+ void addFiles(@NotNull File... files) {
+ this.files.addAll(Lists.newArrayList(files));
+ }
+
+ @Override
+ public boolean exists(@NotNull File file) {
+ return files.contains(file);
+ }
+ }
+
+ private MockFileAttributeProvider fileChecker;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ fileChecker = new MockFileAttributeProvider();
+ applicationServices.register(FileAttributeProvider.class, fileChecker);
+ }
+
+ @Test
+ public void testManualPackagePaths() throws Exception {
+ List<File> packagePaths =
+ ImmutableList.of(
+ WORKSPACE_ROOT.directory(),
+ new File(WORKSPACE_ROOT.directory().getParentFile(), "READONLY/root"),
+ new File(WORKSPACE_ROOT.directory().getParentFile(), "CUSTOM/root"));
+
+ BlazeRoots blazeRoots =
+ new BlazeRoots(
+ new File(EXECUTION_ROOT),
+ packagePaths,
+ new ExecutionRootPath("root/blaze-out/crosstool/bin"),
+ new ExecutionRootPath("root/blaze-out/crosstool/genfiles"));
+
+ fileChecker.addFiles(
+ new File(packagePaths.get(0), "com/google/Bla.java"),
+ new File(packagePaths.get(1), "com/google/Foo.java"),
+ new File(packagePaths.get(2), "com/other/Test.java"));
+
+ ArtifactLocationDecoder decoder =
+ new ArtifactLocationDecoder(
+ blazeRoots, new WorkspacePathResolverImpl(WORKSPACE_ROOT, blazeRoots));
+
+ ArtifactLocationBuilder builder =
+ new ArtifactLocationBuilder().setRelativePath("com/google/Bla.java").setIsSource(true);
+
+ assertThat(decoder.decode(builder.buildIdeInfoArtifact()).getRootPath())
+ .isEqualTo(packagePaths.get(0).toString());
+
+ builder.setRelativePath("com/google/Foo.java");
+
+ assertThat(decoder.decode(builder.buildIdeInfoArtifact()).getRootPath())
+ .isEqualTo(packagePaths.get(1).toString());
+
+ builder.setRelativePath("com/other/Test.java");
+
+ assertThat(decoder.decode(builder.buildIdeInfoArtifact()).getRootPath())
+ .isEqualTo(packagePaths.get(2).toString());
+
+ builder.setRelativePath("third_party/other/Temp.java");
+
+ assertThat(decoder.decode(builder.buildIdeInfoArtifact())).isNull();
+ }
+
+ @Test
+ public void testDerivedArtifact() throws Exception {
+ ArtifactLocationBuilder builder =
+ new ArtifactLocationBuilder()
+ .setRootExecutionPathFragment("/blaze-out/bin")
+ .setRelativePath("com/google/Bla.java")
+ .setIsSource(false);
+
+ ArtifactLocationDecoder decoder = new ArtifactLocationDecoder(BLAZE_CITC_ROOTS, null);
+
+ ArtifactLocation parsed = decoder.decode(builder.buildIdeInfoArtifact());
+
+ assertThat(parsed).isEqualTo(decoder.decode(builder.buildManifestArtifact()));
+
+ assertThat(parsed)
+ .isEqualTo(
+ ArtifactLocation.builder()
+ .setRootPath(EXECUTION_ROOT + "/blaze-out/bin")
+ .setRootExecutionPathFragment("/blaze-out/bin")
+ .setRelativePath("com/google/Bla.java")
+ .setIsSource(false)
+ .build());
+ }
+
+ @Test
+ public void testSourceArtifactAllVersions() throws Exception {
+ ArtifactLocationBuilder builder =
+ new ArtifactLocationBuilder().setRelativePath("com/google/Bla.java").setIsSource(true);
+
+ ArtifactLocationDecoder decoder =
+ new ArtifactLocationDecoder(
+ BLAZE_CITC_ROOTS, new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS));
+
+ ArtifactLocation parsed = decoder.decode(builder.buildIdeInfoArtifact());
+
+ assertThat(parsed).isEqualTo(decoder.decode(builder.buildManifestArtifact()));
+
+ assertThat(parsed)
+ .isEqualTo(
+ ArtifactLocation.builder()
+ .setRootPath(WORKSPACE_ROOT.toString())
+ .setRelativePath("com/google/Bla.java")
+ .setIsSource(true)
+ .build());
+ }
+
+ static class ArtifactLocationBuilder {
+ String rootExecutionPathFragment = "";
+ String relativePath;
+ boolean isSource;
+
+ ArtifactLocationBuilder setRootExecutionPathFragment(String rootExecutionPathFragment) {
+ this.rootExecutionPathFragment = rootExecutionPathFragment;
+ return this;
+ }
+
+ ArtifactLocationBuilder setRelativePath(String relativePath) {
+ this.relativePath = relativePath;
+ return this;
+ }
+
+ ArtifactLocationBuilder setIsSource(boolean isSource) {
+ this.isSource = isSource;
+ return this;
+ }
+
+ AndroidStudioIdeInfo.ArtifactLocation buildIdeInfoArtifact() {
+ AndroidStudioIdeInfo.ArtifactLocation.Builder builder =
+ AndroidStudioIdeInfo.ArtifactLocation.newBuilder()
+ .setIsSource(isSource)
+ .setRelativePath(relativePath);
+ builder.setRootExecutionPathFragment(rootExecutionPathFragment);
+ return builder.build();
+ }
+
+ PackageManifestOuterClass.ArtifactLocation buildManifestArtifact() {
+ PackageManifestOuterClass.ArtifactLocation.Builder builder =
+ PackageManifestOuterClass.ArtifactLocation.newBuilder()
+ .setIsSource(isSource)
+ .setRelativePath(relativePath);
+ builder.setRootExecutionPathFragment(rootExecutionPathFragment);
+ return builder.build();
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImplTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImplTest.java
new file mode 100644
index 0000000..13b71f5
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImplTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync.workspace;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import java.io.File;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for workspace path resolver */
+@RunWith(JUnit4.class)
+public class WorkspacePathResolverImplTest extends BlazeTestCase {
+ private static final WorkspaceRoot WORKSPACE_ROOT = new WorkspaceRoot(new File("/path/to/root"));
+ private static final String EXECUTION_ROOT = "/path/to/_blaze_user/1234bf129e/root";
+
+ private static final BlazeRoots BLAZE_CITC_ROOTS =
+ new BlazeRoots(
+ new File(EXECUTION_ROOT),
+ ImmutableList.of(WORKSPACE_ROOT.directory()),
+ new ExecutionRootPath("blaze-out/crosstool/bin"),
+ new ExecutionRootPath("blaze-out/crosstool/genfiles"));
+
+ @Test
+ public void testResolveToIncludeDirectories() {
+ WorkspacePathResolver workspacePathResolver =
+ new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS);
+ ImmutableList<File> files =
+ workspacePathResolver.resolveToIncludeDirectories(new ExecutionRootPath("tools/fast"));
+ assertThat(files).containsExactly(new File("/path/to/root/tools/fast"));
+ }
+
+ @Test
+ public void testResolveToIncludeDirectoriesForExecRootPath() {
+ WorkspacePathResolver workspacePathResolver =
+ new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS);
+ ImmutableList<File> files =
+ workspacePathResolver.resolveToIncludeDirectories(
+ new ExecutionRootPath("blaze-out/crosstool/bin/tools/fast"));
+ assertThat(files).containsExactly(new File("/path/to/root/blaze-out/crosstool/bin/tools/fast"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessorTest.java b/base/tests/unittests/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessorTest.java
new file mode 100644
index 0000000..06cbe96
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessorTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.vcs.git;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import java.io.File;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link GitStatusLineProcessor} */
+@RunWith(JUnit4.class)
+public class GitStatusLineProcessorTest {
+
+ @Test
+ public void testGitStatusParser() {
+ GitStatusLineProcessor lineProcessor =
+ new GitStatusLineProcessor(new WorkspaceRoot(new File("/usr/blah")), "/usr/blah");
+ for (String line :
+ ImmutableList.of(
+ "D root/README",
+ "M root/blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java",
+ "A root/blah",
+ "A java/com/google/Test.java",
+ "M java/com/other/")) {
+ lineProcessor.processLine(line);
+ }
+ assertThat(lineProcessor.addedFiles)
+ .containsExactly(
+ new WorkspacePath("root/blah"), new WorkspacePath("java/com/google/Test.java"));
+ assertThat(lineProcessor.modifiedFiles)
+ .containsExactly(
+ new WorkspacePath(
+ "root/blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java"),
+ new WorkspacePath("java/com/other"));
+ assertThat(lineProcessor.deletedFiles).containsExactly(new WorkspacePath("root/README"));
+ }
+
+ @Test
+ public void testGitStatusParserDifferentRoots() {
+ GitStatusLineProcessor lineProcessor =
+ new GitStatusLineProcessor(new WorkspaceRoot(new File("/usr/blah/root")), "/usr/blah");
+ for (String line :
+ ImmutableList.of(
+ "D root/README",
+ "M root/blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java",
+ "A root/blah",
+ "A java/com/google/Test.java",
+ "M java/com/other/")) {
+ lineProcessor.processLine(line);
+ }
+ assertThat(lineProcessor.addedFiles).containsExactly(new WorkspacePath("blah"));
+ assertThat(lineProcessor.modifiedFiles)
+ .containsExactly(
+ new WorkspacePath("blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java"));
+ assertThat(lineProcessor.deletedFiles).containsExactly(new WorkspacePath("README"));
+ }
+}
diff --git a/base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java b/base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java
new file mode 100644
index 0000000..06596be
--- /dev/null
+++ b/base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.io.InputStreamProvider;
+import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
+import com.intellij.codeInsight.lookup.Lookup;
+import com.intellij.codeInsight.lookup.LookupElement;
+import com.intellij.codeInsight.lookup.LookupElementPresentation;
+import com.intellij.ide.plugins.PluginManagerCore;
+import com.intellij.openapi.actionSystem.IdeActions;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.application.ReadAction;
+import com.intellij.openapi.application.Result;
+import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.LogicalPosition;
+import com.intellij.openapi.extensions.ExtensionPoint;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.PsiNamedElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.impl.source.PostprocessReformattingAspect;
+import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesProcessor;
+import com.intellij.testFramework.EditorTestUtil;
+import com.intellij.testFramework.EditorTestUtil.CaretAndSelectionState;
+import com.intellij.testFramework.EditorTestUtil.CaretInfo;
+import com.intellij.testFramework.EdtTestUtil;
+import com.intellij.testFramework.IdeaTestUtil;
+import com.intellij.testFramework.LightPlatformTestCase;
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.UsefulTestCase;
+import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
+import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
+import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
+import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import com.intellij.testFramework.fixtures.TestFixtureBuilder;
+import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.picocontainer.MutablePicoContainer;
+
+/** Base test class for blaze integration tests. */
+public abstract class BlazeIntegrationTestCase extends UsefulTestCase {
+
+ private static final LightProjectDescriptor projectDescriptor =
+ LightCodeInsightFixtureTestCase.JAVA_8;
+
+ private static boolean isRunThroughBlaze() {
+ return System.getenv("JAVA_RUNFILES") != null;
+ }
+
+ protected CodeInsightTestFixture testFixture;
+ protected WorkspaceRoot workspaceRoot;
+ private String oldPluginPathProperty;
+
+ @Override
+ protected final void setUp() throws Exception {
+ if (!isRunThroughBlaze()) {
+ // If running directly through the IDE, don't try to load plugins from the sandbox environment
+ // Instead we'll rely on the slightly more hermetic module classpath
+ oldPluginPathProperty = System.getProperty(PathManager.PROPERTY_PLUGINS_PATH);
+ System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, "/dev/null");
+ }
+
+ // Some plugins have a since-build and until-build restriction, so we need
+ // to update the build number here
+ PluginManagerCore.BUILD_NUMBER = "162.1447.26";
+
+ super.setUp();
+
+ IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory();
+ TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder =
+ factory.createLightFixtureBuilder(projectDescriptor);
+ final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture();
+ testFixture = factory.createCodeInsightFixture(fixture, createTempDirFixture());
+ testFixture.setUp();
+
+ Runnable writeAction =
+ () ->
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> ProjectJdkTable.getInstance().addJdk(IdeaTestUtil.getMockJdk18()));
+ EdtTestUtil.runInEdtAndWait(writeAction);
+
+ workspaceRoot = new WorkspaceRoot(new File(LightPlatformTestCase.getSourceRoot().getPath()));
+ setBlazeImportSettings(
+ new BlazeImportSettings(
+ workspaceRoot.toString(),
+ "test-project",
+ workspaceRoot + "/project-data-dir",
+ "location-hash",
+ workspaceRoot + "/project-view-file",
+ buildSystem()));
+
+ registerApplicationService(FileAttributeProvider.class, new TempFileAttributeProvider());
+ registerApplicationService(
+ InputStreamProvider.class,
+ file -> {
+ VirtualFile vf = findFile(file.getPath());
+ if (vf == null) {
+ throw new FileNotFoundException();
+ }
+ return vf.getInputStream();
+ });
+
+ doSetup();
+ }
+
+ /** Override to run tests with bazel specified as the project's build system. */
+ protected BuildSystem buildSystem() {
+ return BuildSystem.Blaze;
+ }
+
+ protected void doSetup() throws Exception {}
+
+ @Override
+ protected final void tearDown() throws Exception {
+ if (oldPluginPathProperty != null) {
+ System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, oldPluginPathProperty);
+ } else {
+ System.clearProperty(PathManager.PROPERTY_PLUGINS_PATH);
+ }
+ testFixture.tearDown();
+ testFixture = null;
+ super.tearDown();
+ clearFields(this);
+ doTearDown();
+ }
+
+ protected void doTearDown() throws Exception {}
+
+ protected void setBlazeImportSettings(BlazeImportSettings importSettings) {
+ BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(importSettings);
+ }
+
+ /** @return fixture to be used as temporary dir. */
+ protected TempDirTestFixture createTempDirFixture() {
+ return new LightTempDirTestFixtureImpl(true); // "tmp://src/" dir by default
+ }
+
+ /**
+ * Absolute file paths are prohibited -- the TempDirTestFixture used in these tests will prepend
+ * it's own root to the path.
+ */
+ protected void assertPathIsNotAbsolute(String filePath) {
+ assertThat(FileUtil.isAbsolute(filePath)).isFalse();
+ }
+
+ /** Creates a file with the specified contents and file path in the test project */
+ protected VirtualFile createFile(String filePath) {
+ return testFixture.getTempDirFixture().createFile(filePath);
+ }
+
+ /** Creates a file with the specified contents and file path in the test project */
+ protected VirtualFile createFile(String filePath, String... contentLines) {
+ return createFile(filePath, Joiner.on("\n").join(contentLines));
+ }
+
+ /** Creates a file with the specified contents and file path in the test project */
+ protected VirtualFile createFile(String filePath, String contents) {
+ assertPathIsNotAbsolute(filePath);
+ try {
+ return testFixture.getTempDirFixture().createFile(filePath, contents);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected PsiDirectory createPsiDirectory(String path) {
+ return getPsiDirectory(createDirectory(path));
+ }
+
+ protected VirtualFile createDirectory(String path) {
+ assertPathIsNotAbsolute(path);
+ try {
+ return testFixture.getTempDirFixture().findOrCreateDir(path);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected Editor openFileInEditor(PsiFile file) {
+ return openFileInEditor(file.getVirtualFile());
+ }
+
+ protected Editor openFileInEditor(VirtualFile file) {
+ EdtTestUtil.runInEdtAndWait((Runnable) () -> testFixture.openFileInEditor(file));
+ return testFixture.getEditor();
+ }
+
+ /** @return null if the only item was auto-completed */
+ @Nullable
+ protected String[] getCompletionItemsAsStrings() {
+ LookupElement[] completionItems = testFixture.completeBasic();
+ if (completionItems == null) {
+ return null;
+ }
+ return Arrays.stream(completionItems)
+ .map(LookupElement::getLookupString)
+ .toArray(String[]::new);
+ }
+
+ /** @return null if the only item was auto-completed */
+ @Nullable
+ protected String[] getCompletionItemsAsSuggestionStrings() {
+ LookupElement[] completionItems = testFixture.completeBasic();
+ if (completionItems == null) {
+ return null;
+ }
+ LookupElementPresentation presentation = new LookupElementPresentation();
+ String[] strings = new String[completionItems.length];
+ for (int i = 0; i < strings.length; i++) {
+ completionItems[i].renderElement(presentation);
+ strings[i] = presentation.getItemText();
+ }
+ return strings;
+ }
+
+ /** @return true if a LookupItem was inserted. */
+ protected boolean completeIfUnique() {
+ LookupElement[] completionItems = testFixture.completeBasic();
+ if (completionItems == null) {
+ return true;
+ }
+ if (completionItems.length != 1) {
+ return false;
+ }
+ testFixture.getLookup().setCurrentItem(completionItems[0]);
+ testFixture.finishLookup(Lookup.NORMAL_SELECT_CHAR);
+ return true;
+ }
+
+ /** Simulates a user typing action, at current caret position of file. */
+ protected void performTypingAction(PsiFile file, char typedChar) {
+ performTypingAction(openFileInEditor(file.getVirtualFile()), typedChar);
+ }
+
+ /** Simulates a user typing action, at current caret position of document. */
+ protected void performTypingAction(Editor editor, char typedChar) {
+ EditorTestUtil.performTypingAction(editor, typedChar);
+ getProject().getComponent(PostprocessReformattingAspect.class).doPostponedFormatting();
+ PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+ }
+
+ /**
+ * Clicks the specified button in current document at the current caret position
+ *
+ * @param action which button to click (see {@link IdeActions})
+ */
+ protected final void pressButton(final String action) {
+ CommandProcessor.getInstance()
+ .executeCommand(getProject(), () -> testFixture.performEditorAction(action), "", null);
+ }
+
+ protected void setCaretPosition(Editor editor, int lineNumber, int columnNumber) {
+ final CaretInfo info = new CaretInfo(new LogicalPosition(lineNumber, columnNumber), null);
+ EdtTestUtil.runInEdtAndWait(
+ (Runnable)
+ () ->
+ EditorTestUtil.setCaretsAndSelection(
+ editor, new CaretAndSelectionState(ImmutableList.of(info), null)));
+ }
+
+ protected void assertCaretPosition(Editor editor, int lineNumber, int columnNumber) {
+ CaretInfo info = new CaretInfo(new LogicalPosition(lineNumber, columnNumber), null);
+ EditorTestUtil.verifyCaretAndSelectionState(
+ editor, new CaretAndSelectionState(ImmutableList.of(info), null));
+ }
+
+ protected Project getProject() {
+ return testFixture.getProject();
+ }
+
+ protected VirtualFile findFile(String filePath) {
+ VirtualFile vf = TempFileSystem.getInstance().findFileByPath(filePath);
+ if (vf == null) {
+ // this might be a relative path
+ vf = testFixture.getTempDirFixture().getFile(filePath);
+ }
+ return vf;
+ }
+
+ protected void assertFileContents(String filePath, String... contentLines) {
+ assertFileContents(findFile(filePath), contentLines);
+ }
+
+ protected void assertFileContents(VirtualFile file, String... contentLines) {
+ assertFileContents(getPsiFile(file), contentLines);
+ }
+
+ protected void assertFileContents(PsiFile file, String... contentLines) {
+ String contents = Joiner.on("\n").join(contentLines);
+ assertThat(file.getText()).isEqualTo(contents);
+ }
+
+ /** Creates a file with the specified contents and file path in the test project */
+ protected PsiFile createPsiFile(String filePath) {
+ return getPsiFile(testFixture.getTempDirFixture().createFile(filePath));
+ }
+
+ /** Creates a file with the specified contents and file path in the test project */
+ protected PsiFile createPsiFile(String filePath, String... contentLines) {
+ return getPsiFile(createFile(filePath, contentLines));
+ }
+
+ /** Finds PsiFile, and asserts that it's not null. */
+ protected PsiFile getPsiFile(VirtualFile file) {
+ return new ReadAction<PsiFile>() {
+ @Override
+ protected void run(Result<PsiFile> result) throws Throwable {
+ PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
+ assertThat(psiFile).isNotNull();
+ result.setResult(psiFile);
+ }
+ }.execute().getResultObject();
+ }
+
+ /** Finds PsiDirectory, and asserts that it's not null. */
+ protected PsiDirectory getPsiDirectory(VirtualFile file) {
+ return new ReadAction<PsiDirectory>() {
+ @Override
+ protected void run(Result<PsiDirectory> result) throws Throwable {
+ PsiDirectory psiFile = PsiManager.getInstance(getProject()).findDirectory(file);
+ assertThat(psiFile).isNotNull();
+ result.setResult(psiFile);
+ }
+ }.execute().getResultObject();
+ }
+
+ protected PsiDirectory renameDirectory(String oldPath, String newPath) {
+ try {
+ VirtualFile original = findFile(oldPath);
+ PsiDirectory originalPsi = PsiManager.getInstance(getProject()).findDirectory(original);
+ assertThat(originalPsi).isNotNull();
+
+ VirtualFile destination = testFixture.getTempDirFixture().findOrCreateDir(newPath);
+ PsiDirectory destPsi = PsiManager.getInstance(getProject()).findDirectory(destination);
+ assertThat(destPsi).isNotNull();
+
+ new MoveDirectoryWithClassesProcessor(
+ getProject(), new PsiDirectory[] {originalPsi}, destPsi, true, true, false, null)
+ .run();
+ return destPsi;
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void renamePsiElement(PsiNamedElement element, String newName) {
+ testFixture.renameElement(element, newName);
+ }
+
+ protected void handleRename(PsiReference reference, String newName) {
+ doRenameOperation(() -> reference.handleElementRename(newName));
+ }
+
+ protected void doRenameOperation(Runnable renameOp) {
+ ApplicationManager.getApplication()
+ .runWriteAction(() -> CommandProcessor.getInstance().runUndoTransparentAction(renameOp));
+ }
+
+ protected static <T> List<T> findAllReferencingElementsOfType(
+ PsiElement target, Class<T> referenceType) {
+ return Arrays.stream(FindUsages.findAllReferences(target))
+ .map(PsiReference::getElement)
+ .filter(referenceType::isInstance)
+ .map(e -> (T) e)
+ .collect(Collectors.toList());
+ }
+
+ protected void mockBlazeProjectDataManager(BlazeProjectData data) {
+ BlazeProjectDataManager mockProjectDataManager =
+ new BlazeProjectDataManager() {
+ @Nullable
+ @Override
+ public BlazeProjectData getBlazeProjectData() {
+ return data;
+ }
+
+ @Override
+ public BlazeSyncPlugin.ModuleEditor editModules() {
+ return ModuleEditorProvider.getInstance()
+ .getModuleEditor(
+ getProject(),
+ BlazeImportSettingsManager.getInstance(getProject()).getImportSettings());
+ }
+ };
+ registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
+ }
+
+ protected <T> void registerApplicationService(Class<T> key, T implementation) {
+ registerComponentInstance(
+ (MutablePicoContainer) ApplicationManager.getApplication().getPicoContainer(),
+ key,
+ implementation);
+ }
+
+ protected <T> void registerProjectService(Class<T> key, T implementation) {
+ registerComponentInstance(
+ (MutablePicoContainer) getProject().getPicoContainer(), key, implementation);
+ }
+
+ protected <T> void registerComponentInstance(
+ MutablePicoContainer container, Class<T> key, T implementation) {
+ Object old = container.getComponentInstance(key);
+ container.unregisterComponent(key.getName());
+ container.registerComponentInstance(key.getName(), implementation);
+ Disposer.register(
+ getTestRootDisposable(),
+ () -> {
+ container.unregisterComponent(key.getName());
+ if (old != null) {
+ container.registerComponentInstance(key.getName(), old);
+ }
+ });
+ }
+
+ protected <T> void registerExtension(ExtensionPointName<T> name, T instance) {
+ ExtensionPoint<T> ep = Extensions.getRootArea().getExtensionPoint(name);
+ ep.registerExtension(instance);
+ Disposer.register(getTestRootDisposable(), () -> ep.unregisterExtension(instance));
+ }
+
+ /** Redirects file system checks via the TempFileSystem used for these tests. */
+ private static class TempFileAttributeProvider extends FileAttributeProvider {
+
+ final TempFileSystem fileSystem = TempFileSystem.getInstance();
+
+ @Override
+ public boolean exists(File file) {
+ VirtualFile vf = getVirtualFile(file);
+ return vf != null && vf.exists();
+ }
+
+ @Override
+ public boolean isDirectory(File file) {
+ VirtualFile vf = getVirtualFile(file);
+ return vf != null && vf.isDirectory();
+ }
+
+ @Override
+ public boolean isFile(File file) {
+ VirtualFile vf = getVirtualFile(file);
+ return vf != null && vf.exists() && !vf.isDirectory();
+ }
+
+ private VirtualFile getVirtualFile(File file) {
+ return fileSystem.findFileByPath(file.getPath());
+ }
+ }
+}
diff --git a/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java b/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java
new file mode 100644
index 0000000..fa91385
--- /dev/null
+++ b/base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.lang.buildfile;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiFile;
+
+/** BUILD file specific integration test base */
+public abstract class BuildFileIntegrationTestCase extends BlazeIntegrationTestCase {
+
+ @Override
+ protected void doSetup() {
+ mockBlazeProjectDataManager(getMockBlazeProjectData());
+ }
+
+ /**
+ * Creates a file with the specified contents and file path in the test project, and asserts that
+ * it's parsed as a BuildFile
+ */
+ protected BuildFile createBuildFile(String filePath, String... contentLines) {
+ PsiFile file = createPsiFile(filePath, contentLines);
+ assertThat(file).isInstanceOf(BuildFile.class);
+ return (BuildFile) file;
+ }
+
+ protected void replaceStringContents(StringLiteral string, String newStringContents) {
+ doRenameOperation(
+ () -> {
+ ASTNode node = string.getNode();
+ node.replaceChild(
+ node.getFirstChildNode(),
+ PsiUtils.createNewLabel(string.getProject(), newStringContents));
+ });
+ }
+
+ private BlazeProjectData getMockBlazeProjectData() {
+ BlazeRoots fakeRoots =
+ new BlazeRoots(
+ null,
+ ImmutableList.of(workspaceRoot.directory()),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen"));
+ return new BlazeProjectData(
+ 0,
+ new RuleMap(ImmutableMap.of()),
+ fakeRoots,
+ new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()),
+ new WorkspacePathResolverImpl(workspaceRoot, fakeRoots),
+ null,
+ null,
+ null,
+ null);
+ }
+}
diff --git a/base/tests/utils/integration/com/google/idea/blaze/base/sync/BlazeSyncIntegrationTestCase.java b/base/tests/utils/integration/com/google/idea/blaze/base/sync/BlazeSyncIntegrationTestCase.java
new file mode 100644
index 0000000..180e1cc
--- /dev/null
+++ b/base/tests/utils/integration/com/google/idea/blaze/base/sync/BlazeSyncIntegrationTestCase.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.sync;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.io.WorkspaceScanner;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ErrorCollector;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorImpl;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+/** Sets up mocks required for integration tests of the blaze sync process. */
+public abstract class BlazeSyncIntegrationTestCase extends BlazeIntegrationTestCase {
+
+ // root directory for all files outside the project directory.
+ protected TempDirTestFixture tempDirectoryHandler;
+ protected VirtualFile tempDirectory;
+
+ // blaze-info data
+ private static final String EXECUTION_ROOT = "/execroot/root";
+ private static final String BLAZE_BIN =
+ EXECUTION_ROOT + "/blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin";
+ private static final String BLAZE_GENFILES =
+ EXECUTION_ROOT + "/blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/genfiles";
+
+ private static final String PROJECT_DATA_DIR = "project-data-dir";
+
+ private MockProjectViewManager projectViewManager;
+ private MockBlazeVcsHandler vcsHandler;
+ private MockBlazeInfo blazeInfoData;
+ private MockBlazeIdeInterface blazeIdeInterface;
+
+ protected ErrorCollector errorCollector;
+ protected BlazeContext context;
+
+ @Override
+ protected void doSetup() throws IOException {
+ // Set up a workspace root outside of the tracked temp file system.
+ tempDirectoryHandler = new LightTempDirTestFixtureImpl();
+ tempDirectory = tempDirectoryHandler.getFile("");
+ workspaceRoot = new WorkspaceRoot(new File(tempDirectory.getPath()));
+ setBlazeImportSettings(
+ new BlazeImportSettings(
+ workspaceRoot.toString(),
+ "test-project",
+ workspaceRoot + "/" + PROJECT_DATA_DIR,
+ "location-hash",
+ workspaceRoot + "/project-view-file",
+ BuildSystem.Blaze));
+
+ projectViewManager = new MockProjectViewManager();
+ vcsHandler = new MockBlazeVcsHandler();
+ blazeInfoData = new MockBlazeInfo();
+ blazeIdeInterface = new MockBlazeIdeInterface();
+ registerProjectService(ProjectViewManager.class, projectViewManager);
+ registerExtension(BlazeVcsHandler.EP_NAME, vcsHandler);
+ registerApplicationService(WorkspaceScanner.class, (workspaceRoot, workspacePath) -> true);
+ registerApplicationService(BlazeInfo.class, blazeInfoData);
+ registerApplicationService(BlazeIdeInterface.class, blazeIdeInterface);
+ registerApplicationService(
+ ModuleEditorProvider.class,
+ new ModuleEditorProvider() {
+ @Override
+ public ModuleEditorImpl getModuleEditor(
+ Project project, BlazeImportSettings importSettings) {
+ return new ModuleEditorImpl(project, importSettings) {
+ @Override
+ public void commit() {
+ // don't commit module changes,
+ // but make sure they're properly disposed when the test is finished
+ for (ModifiableRootModel model : modifiableModels) {
+ Disposer.register(myTestRootDisposable, model::dispose);
+ }
+ }
+ };
+ }
+ });
+
+ errorCollector = new ErrorCollector();
+ context = new BlazeContext();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+
+ tempDirectoryHandler.findOrCreateDir(PROJECT_DATA_DIR + "/.blaze/modules");
+
+ setBlazeInfoResults(
+ ImmutableMap.of(
+ BlazeInfo.blazeBinKey(Blaze.getBuildSystem(getProject())),
+ BLAZE_BIN,
+ BlazeInfo.blazeGenfilesKey(Blaze.getBuildSystem(getProject())),
+ BLAZE_GENFILES,
+ BlazeInfo.EXECUTION_ROOT_KEY,
+ EXECUTION_ROOT,
+ BlazeInfo.PACKAGE_PATH_KEY,
+ workspaceRoot.toString()));
+ }
+
+ @Override
+ protected void doTearDown() throws Exception {
+ if (tempDirectoryHandler != null) {
+ tempDirectoryHandler.tearDown();
+ }
+ super.doTearDown();
+ }
+
+ protected VirtualFile createWorkspaceFile(String relativePath, @Nullable String... contents) {
+ try {
+ String content = contents != null ? Joiner.on("\n").join(contents) : "";
+ return tempDirectoryHandler.createFile(relativePath, content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void assertNoErrors() {
+ errorCollector.assertNoIssues();
+ }
+
+ protected ArtifactLocation sourceRoot(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootPath(workspaceRoot.toString())
+ .setRelativePath(relativePath)
+ .setIsSource(true)
+ .build();
+ }
+
+ protected void setProjectView(String... contents) {
+ ProjectViewParser projectViewParser =
+ new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot));
+ projectViewParser.parseProjectView(Joiner.on("\n").join(contents));
+
+ ProjectViewSet result = projectViewParser.getResult();
+ assertThat(result.getProjectViewFiles()).isNotEmpty();
+ assertNoErrors();
+ setProjectViewSet(result);
+ }
+
+ protected void setProjectViewSet(ProjectViewSet projectViewSet) {
+ projectViewManager.projectViewSet = projectViewSet;
+ }
+
+ protected void setRuleMap(RuleMap ruleMap) {
+ blazeIdeInterface.ruleMap = ruleMap;
+ }
+
+ protected void setBlazeInfoResults(Map<String, String> blazeInfoResults) {
+ blazeInfoData.setResults(blazeInfoResults);
+ }
+
+ protected void runBlazeSync(BlazeSyncParams syncParams) {
+ Project project = getProject();
+ final BlazeSyncTask syncTask =
+ new BlazeSyncTask(
+ project,
+ BlazeImportSettingsManager.getInstance(project).getImportSettings(),
+ syncParams);
+ syncTask.syncProject(context);
+ }
+
+ private static class MockProjectViewManager extends ProjectViewManager {
+
+ private ProjectViewSet projectViewSet;
+
+ @Nullable
+ @Override
+ public ProjectViewSet getProjectViewSet() {
+ return projectViewSet;
+ }
+
+ @Nullable
+ @Override
+ public ProjectViewSet reloadProjectView(
+ BlazeContext context, WorkspacePathResolver workspacePathResolver) {
+ return getProjectViewSet();
+ }
+ }
+
+ private static class MockBlazeVcsHandler implements BlazeVcsHandler {
+
+ private List<WorkspacePath> addedFiles = Lists.newArrayList();
+
+ @Override
+ public String getVcsName() {
+ return "Mock";
+ }
+
+ @Override
+ public boolean handlesProject(BuildSystem buildSystem, WorkspaceRoot workspaceRoot) {
+ return true;
+ }
+
+ @Override
+ public ListenableFuture<WorkingSet> getWorkingSet(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ListeningExecutorService executor) {
+ WorkingSet workingSet =
+ new WorkingSet(ImmutableList.copyOf(addedFiles), ImmutableList.of(), ImmutableList.of());
+ return Futures.immediateFuture(workingSet);
+ }
+
+ @Nullable
+ @Override
+ public BlazeVcsSyncHandler createSyncHandler(Project project, WorkspaceRoot workspaceRoot) {
+ return null;
+ }
+ }
+
+ private static class MockBlazeInfo extends BlazeInfo {
+ private final Map<String, String> results = Maps.newHashMap();
+
+ @Override
+ public ListenableFuture<String> runBlazeInfo(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags,
+ String key) {
+ return Futures.immediateFuture(results.get(key));
+ }
+
+ @Override
+ public ListenableFuture<byte[]> runBlazeInfoGetBytes(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags,
+ String key) {
+ return Futures.immediateFuture(null);
+ }
+
+ @Override
+ public ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(
+ @Nullable BlazeContext context,
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags) {
+ return Futures.immediateFuture(ImmutableMap.copyOf(results));
+ }
+
+ public void setResults(Map<String, String> results) {
+ this.results.clear();
+ this.results.putAll(results);
+ }
+ }
+
+ private static class MockBlazeIdeInterface implements BlazeIdeInterface {
+ private RuleMap ruleMap = new RuleMap(ImmutableMap.of());
+
+ @Override
+ public IdeResult updateRuleMap(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState,
+ boolean mergeWithOldState) {
+ return new IdeResult(ruleMap, BuildResult.SUCCESS);
+ }
+
+ @Override
+ public BuildResult resolveIdeArtifacts(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets) {
+ return BuildResult.SUCCESS;
+ }
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java b/base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java
new file mode 100644
index 0000000..428b180
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base;
+
+import com.intellij.mock.MockProject;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.extensions.DefaultPluginDescriptor;
+import com.intellij.openapi.extensions.ExtensionPoint;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.picocontainer.MutablePicoContainer;
+
+/**
+ * Test base class.
+ *
+ * <p>
+ *
+ * <p>Provides a mock application and a mock project.
+ */
+public class BlazeTestCase {
+
+ protected Project project;
+ private ExtensionsAreaImpl extensionsArea;
+ private Disposable testDisposable;
+
+ private static class RootDisposable implements Disposable {
+ @Override
+ public void dispose() {}
+ }
+
+ /** A wrapper around the pico container used by IntelliJ's DI system */
+ public static class Container {
+ private final MutablePicoContainer container;
+
+ Container(@NotNull MutablePicoContainer container) {
+ this.container = container;
+ }
+
+ public <T> Container register(Class<T> klass, T instance) {
+ this.container.registerComponentInstance(klass.getName(), instance);
+ return this;
+ }
+ }
+
+ @Before
+ public final void setup() {
+ testDisposable = new RootDisposable();
+ TestUtils.createMockApplication(testDisposable);
+ MutablePicoContainer applicationContainer =
+ (MutablePicoContainer) ApplicationManager.getApplication().getPicoContainer();
+ MockProject mockProject = TestUtils.mockProject(applicationContainer, testDisposable);
+
+ Extensions.cleanRootArea(testDisposable);
+ extensionsArea = (ExtensionsAreaImpl) Extensions.getRootArea();
+
+ this.project = mockProject;
+
+ initTest(new Container(applicationContainer), new Container(mockProject.getPicoContainer()));
+ }
+
+ @After
+ public final void tearDown() {
+ Disposer.dispose(testDisposable);
+ }
+
+ public final Project getProject() {
+ return project;
+ }
+
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {}
+
+ protected <T> ExtensionPointImpl<T> registerExtensionPoint(
+ @NotNull ExtensionPointName<T> name, @NotNull Class<T> type) {
+ ExtensionPointImpl<T> extensionPoint =
+ new ExtensionPointImpl<T>(
+ name.getName(),
+ type.getName(),
+ ExtensionPoint.Kind.INTERFACE,
+ extensionsArea,
+ null,
+ new Extensions.SimpleLogProvider(),
+ new DefaultPluginDescriptor(PluginId.getId(type.getName()), type.getClassLoader()));
+ extensionsArea.registerExtensionPoint(extensionPoint);
+ return extensionPoint;
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java b/base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java
new file mode 100644
index 0000000..f040cf2
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base;
+
+import static org.junit.Assert.fail;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.intellij.mock.MockApplicationEx;
+import com.intellij.mock.MockProject;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vfs.encoding.EncodingManager;
+import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
+import com.intellij.util.pico.DefaultPicoContainer;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.picocontainer.PicoContainer;
+
+/** Test utilities. */
+public class TestUtils {
+
+ static class BlazeMockApplication extends MockApplicationEx {
+ private final ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+
+ public BlazeMockApplication(@NotNull Disposable parentDisposable) {
+ super(parentDisposable);
+ }
+
+ @NotNull
+ @Override
+ public Future<?> executeOnPooledThread(@NotNull Runnable action) {
+ return executor.submit(action);
+ }
+
+ @NotNull
+ @Override
+ public <T> Future<T> executeOnPooledThread(@NotNull Callable<T> action) {
+ return executor.submit(action);
+ }
+ }
+
+ public static void createMockApplication(Disposable parentDisposable) {
+ final BlazeMockApplication instance = new BlazeMockApplication(parentDisposable);
+
+ // If there was no previous application,
+ // ApplicationManager leaves the MockApplication in place, which can break future tests.
+ Application oldApplication = ApplicationManager.getApplication();
+ if (oldApplication == null) {
+ Disposer.register(
+ parentDisposable,
+ () -> {
+ new ApplicationManager() {
+ {
+ ourApplication = null;
+ }
+ };
+ });
+ }
+
+ ApplicationManager.setApplication(instance, FileTypeManager::getInstance, parentDisposable);
+ instance.registerService(EncodingManager.class, EncodingManagerImpl.class);
+ }
+
+ @NotNull
+ public static MockProject mockProject(
+ @Nullable PicoContainer container, Disposable parentDisposable) {
+ Extensions.registerAreaClass("IDEA_PROJECT", null);
+ container = container != null ? container : new DefaultPicoContainer();
+ return new MockProject(container, parentDisposable);
+ }
+
+ public static void assertIsSerializable(@NotNull Serializable object) {
+ ObjectOutputStream out = null;
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ try {
+ out = new ObjectOutputStream(byteArrayOutputStream);
+ out.writeObject(object);
+ } catch (NotSerializableException e) {
+ fail("An object is not serializable: " + e.getMessage());
+ } catch (IOException e) {
+ fail("Could not serialize object: " + e.getMessage());
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ try {
+ byteArrayOutputStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/async/executor/MockBlazeExecutor.java b/base/tests/utils/unit/com/google/idea/blaze/base/async/executor/MockBlazeExecutor.java
new file mode 100644
index 0000000..3e970b4
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/async/executor/MockBlazeExecutor.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.async.executor;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.concurrent.Callable;
+
+/** Used in tests. */
+public class MockBlazeExecutor extends BlazeExecutor {
+
+ private final ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+
+ @Override
+ public <T> ListenableFuture<T> submit(final Callable<T> callable) {
+ return executor.submit(callable);
+ }
+
+ @Override
+ public ListeningExecutorService getExecutor() {
+ return executor;
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/ideinfo/RuleMapBuilder.java b/base/tests/utils/unit/com/google/idea/blaze/base/ideinfo/RuleMapBuilder.java
new file mode 100644
index 0000000..2586377
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/ideinfo/RuleMapBuilder.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.ideinfo;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** Builds a rule map. */
+public class RuleMapBuilder {
+ private List<RuleIdeInfo> rules = Lists.newArrayList();
+
+ public static RuleMapBuilder builder() {
+ return new RuleMapBuilder();
+ }
+
+ @NotNull
+ public RuleMapBuilder addRule(@NotNull RuleIdeInfo ruleOrLibrary) {
+ rules.add(ruleOrLibrary);
+ return this;
+ }
+
+ @NotNull
+ public RuleMapBuilder addRule(@NotNull RuleIdeInfo.Builder ruleOrLibrary) {
+ return addRule(ruleOrLibrary.build());
+ }
+
+ @NotNull
+ public RuleMap build() {
+ ImmutableMap.Builder<Label, RuleIdeInfo> ruleMap = ImmutableMap.builder();
+ for (RuleIdeInfo rule : rules) {
+ ruleMap.put(rule.label, rule);
+ }
+ return new RuleMap(ruleMap.build());
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/prefetch/MockPrefetchService.java b/base/tests/utils/unit/com/google/idea/blaze/base/prefetch/MockPrefetchService.java
new file mode 100644
index 0000000..8dbac18
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/prefetch/MockPrefetchService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.prefetch;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+
+/** Mocks the prefetch service. */
+public class MockPrefetchService implements PrefetchService {
+
+ @Override
+ public ListenableFuture<?> prefetchFiles(Project project, Collection<File> files) {
+ return Futures.immediateFuture(null);
+ }
+
+ @Override
+ public ListenableFuture<?> prefetchProjectFiles(
+ Project project, BlazeProjectData blazeProjectData) {
+ return Futures.immediateFuture(null);
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/run/MockBlazeCommandRunConfigurationHandlerProvider.java b/base/tests/utils/unit/com/google/idea/blaze/base/run/MockBlazeCommandRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..92ab14e
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/run/MockBlazeCommandRunConfigurationHandlerProvider.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.run;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerEditor;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.util.InvalidDataException;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import org.jdom.Element;
+
+/** A mock {@link BlazeCommandRunConfigurationHandlerProvider}. */
+public class MockBlazeCommandRunConfigurationHandlerProvider
+ implements BlazeCommandRunConfigurationHandlerProvider {
+ @Override
+ public boolean canHandleKind(Kind kind) {
+ return true;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config) {
+ return new MockBlazeCommandRunConfigurationHandler(config);
+ }
+
+ @Override
+ public String getId() {
+ return "MockBlazeCommandRunConfigurationHandlerProvider";
+ }
+
+ /** A mock {@link BlazeCommandRunConfigurationHandler}. */
+ private static class MockBlazeCommandRunConfigurationHandler
+ implements BlazeCommandRunConfigurationHandler {
+
+ final BlazeCommandRunConfiguration configuration;
+
+ MockBlazeCommandRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ // Don't throw anything.
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ // Don't read anything.
+ }
+
+ @Override
+ public void writeExternal(Element element) {
+ // Don't write anything.
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler cloneFor(
+ BlazeCommandRunConfiguration configuration) {
+ return new MockBlazeCommandRunConfigurationHandler(configuration);
+ }
+
+ @Override
+ public RunProfileState getState(Executor executor, ExecutionEnvironment environment)
+ throws ExecutionException {
+ return null;
+ }
+
+ @Override
+ public boolean executeBeforeRunTask(ExecutionEnvironment environment) {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public String suggestedName() {
+ return null;
+ }
+
+ @Override
+ public boolean isGeneratedName(boolean hasGeneratedFlag) {
+ return hasGeneratedFlag;
+ }
+
+ @Nullable
+ @Override
+ public String getCommandName() {
+ return null;
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "Mock Handler";
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(RunConfiguration configuration, Executor executor) {
+ return null;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandlerEditor getHandlerEditor() {
+ return new BlazeCommandRunConfigurationHandlerEditor() {
+ @Override
+ public void resetEditorFrom(BlazeCommandRunConfigurationHandler handler) {
+ // Do nothing.
+ }
+
+ @Override
+ public void applyEditorTo(BlazeCommandRunConfigurationHandler handler) {
+ // Do nothing.
+ }
+
+ @Nullable
+ @Override
+ public JComponent createEditor() {
+ return null;
+ }
+ };
+ }
+ }
+}
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/scope/ErrorCollector.java b/base/tests/utils/unit/com/google/idea/blaze/base/scope/ErrorCollector.java
new file mode 100644
index 0000000..3362bae
--- /dev/null
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/scope/ErrorCollector.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.base.scope;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** Test class that collects issues. */
+public class ErrorCollector implements OutputSink<IssueOutput> {
+ List<IssueOutput> issues = Lists.newArrayList();
+
+ @Override
+ public Propagation onOutput(@NotNull IssueOutput output) {
+ issues.add(output);
+ return Propagation.Continue;
+ }
+
+ public void assertNoIssues() {
+ assertThat(issues).isEmpty();
+ }
+
+ public void assertIssues(@NotNull String... requiredMessages) {
+ List<String> messages = Lists.newArrayList();
+ for (IssueOutput issue : issues) {
+ messages.add(issue.getMessage());
+ }
+ assertThat(messages).containsExactly((Object[]) requiredMessages);
+ }
+
+ public void assertIssueContaining(@NotNull String s) {
+ assertThat(issues.stream().anyMatch((issue) -> issue.getMessage().contains(s)))
+ .named("Issues must contain: " + s)
+ .isTrue();
+ }
+}
diff --git a/blaze-base/BUILD b/blaze-base/BUILD
deleted file mode 100644
index 2473778..0000000
--- a/blaze-base/BUILD
+++ /dev/null
@@ -1,85 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-java_library(
- name = "blaze-base",
- srcs = glob(["src/**/*.java"]),
- resources = glob(["resources/**/*"]),
- deps = [
- ":proto-deps",
- "//intellij-platform-sdk:plugin_api",
- "//third_party:jsr305",
- "//third_party:trickle",
- ],
-)
-
-java_import(
- name = "proto-deps",
- jars = ["lib/proto_deps.jar"],
-)
-
-filegroup(
- name = "plugin_xml",
- srcs = ["src/META-INF/blaze-base.xml"],
-)
-
-java_library(
- name = "unit_test_utils",
- srcs = glob(["tests/utils/unit/**/*.java"]),
- deps = [
- ":blaze-base",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
-
-java_library(
- name = "integration_test_utils",
- srcs = glob(["tests/utils/integration/**/*.java"]),
- deps = [
- ":blaze-base",
- ":proto-deps",
- ":unit_test_utils",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
-
-load(
- "//intellij_test:test_defs.bzl",
- "intellij_test",
-)
-
-intellij_test(
- name = "unit_tests",
- srcs = glob(["tests/unittests/**/*.java"]),
- test_package_root = "com.google.idea.blaze.base",
- deps = [
- ":blaze-base",
- ":proto-deps",
- ":unit_test_utils",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//intellij_test:lib",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
-
-intellij_test(
- name = "integration_tests",
- srcs = glob(["tests/integrationtests/**/*.java"]),
- integration_tests = True,
- required_plugins = "com.google.idea.blaze.ijwb",
- test_package_root = "com.google.idea.blaze.base",
- deps = [
- ":blaze-base",
- ":integration_test_utils",
- ":unit_test_utils",
- "//ijwb:ijwb_bazel",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//intellij_test:lib",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
diff --git a/blaze-base/lib/proto_deps.jar b/blaze-base/lib/proto_deps.jar
deleted file mode 100755
index d9241ab..0000000
--- a/blaze-base/lib/proto_deps.jar
+++ /dev/null
Binary files differ
diff --git a/blaze-base/resources/binaries/bazel-buildifier b/blaze-base/resources/binaries/bazel-buildifier
deleted file mode 100755
index c7347bb..0000000
--- a/blaze-base/resources/binaries/bazel-buildifier
+++ /dev/null
Binary files differ
diff --git a/blaze-base/src/META-INF/blaze-base.xml b/blaze-base/src/META-INF/blaze-base.xml
deleted file mode 100644
index 4668d85..0000000
--- a/blaze-base/src/META-INF/blaze-base.xml
+++ /dev/null
@@ -1,262 +0,0 @@
-<!--
- ~ Copyright 2016 The Bazel Authors. All rights reserved.
- ~
- ~ 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.
- -->
-<idea-plugin>
- <actions>
- <action id="MakeBlazeProject" class="com.google.idea.blaze.base.actions.BlazeMakeProjectAction" use-shortcut-of="CompileDirty" icon="AllIcons.Actions.Compile">
- </action>
- <action id="MakeBlazeModule" class="com.google.idea.blaze.base.actions.BlazeCompileFileAction">
- </action>
- <action id="Blaze.IncrementalSyncProject" class="com.google.idea.blaze.base.sync.actions.IncrementalSyncProjectAction" icon="BlazeIcons.Blaze">
- </action>
- <action id="Blaze.FullSyncProject" class="com.google.idea.blaze.base.sync.actions.FullSyncProjectAction" icon="BlazeIcons.BlazeSlow">
- </action>
- <action id="Blaze.ExpandSyncToWorkingSet" class="com.google.idea.blaze.base.sync.actions.ExpandSyncToWorkingSetAction" text="Expand Sync to Working Set">
- </action>
- <action id="Blaze.ShowPerformanceWarnings" class="com.google.idea.blaze.base.sync.actions.ShowPerformanceWarningsToggleAction" text="Show Performance Warnings">
- </action>
- <action id="Blaze.EditProjectView" class="com.google.idea.blaze.base.settings.ui.EditProjectViewAction" text="Edit Project View..." icon="BlazeIcons.Blaze">
- </action>
-
- <action class="com.google.idea.blaze.base.buildmap.OpenCorrespondingBuildFile"
- id="Blaze.OpenCorrespondingBuildFile"
- icon="BlazeIcons.Blaze"
- text="Open Corresponding BUILD File">
- </action>
- <action class="com.google.idea.blaze.base.sync.actions.PartialSyncAction"
- id="Blaze.PartialSync"
- icon="BlazeIcons.Blaze">
- </action>
-
- <group id="Blaze.MainMenuActionGroup" class="com.google.idea.blaze.base.actions.BlazeMenuGroup">
- <add-to-group group-id="MainMenu" anchor="before" relative-to-action="HelpMenu"/>
- <reference id="MakeBlazeProject"/>
- <reference id="MakeBlazeModule"/>
- <separator/>
- <reference id="Blaze.EditProjectView"/>
- <separator/>
- <reference id="Blaze.IncrementalSyncProject"/>
- <reference id="Blaze.FullSyncProject"/>
- <reference id="Blaze.PartialSync"/>
- <reference id="Blaze.ExpandSyncToWorkingSet"/>
- <reference id="Blaze.ShowPerformanceWarnings"/>
- </group>
-
- <group id="Blaze.MainToolBarActionGroup">
- <add-to-group group-id="MainToolBar" anchor="before" relative-to-action="HelpTopics" />
- <add-to-group group-id="NavBarToolBarOthers" anchor="last"/>
- <reference id="Blaze.IncrementalSyncProject"/>
- </group>
-
- <group id="Blaze.NewActions" text="Edit Blaze structure" description="Create new Blaze packages, rules, etc.">
- <add-to-group group-id="NewGroup" anchor="first"/>
- <action id="Blaze.NewPackageAction" class="com.google.idea.blaze.base.ide.NewBlazePackageAction" popup="true"/>
- <action id="Blaze.NewRuleAction" class="com.google.idea.blaze.base.ide.NewBlazeRuleAction" popup="true"/>
- <separator/>
- </group>
-
- <group id="Blaze.ProjectViewPopupMenu">
- <add-to-group anchor="after" group-id="ProjectViewPopupMenu" relative-to-action="EditSource"/>
- <separator/>
- <reference ref="Blaze.PartialSync"/>
- <reference ref="Blaze.OpenCorrespondingBuildFile"/>
- </group>
-
- <group id="Blaze.EditorTabPopupMenu">
- <add-to-group anchor="after" group-id="EditorTabPopupMenu" relative-to-action="CopyReference"/>
- <separator/>
- <reference ref="Blaze.PartialSync"/>
- <reference ref="Blaze.OpenCorrespondingBuildFile"/>
- </group>
- </actions>
-
- <extensions defaultExtensionNs="com.intellij">
- <postStartupActivity implementation="com.google.idea.blaze.base.sync.BlazeSyncStartupActivity"/>
-
- <toolWindow id="Blaze Console"
- anchor="bottom"
- secondary="true"
- conditionClass="com.google.idea.blaze.base.settings.IsBlazeProjectCondition"
- icon="BlazeIcons.BlazeToolWindow"
- factoryClass="com.google.idea.blaze.base.console.BlazeConsoleToolWindowFactory"/>
- <projectService serviceImplementation="com.google.idea.blaze.base.console.BlazeConsoleView"/>
- <fileTypeFactory implementation="com.google.idea.blaze.base.plugin.BlazeFileTypeFactory" />
- <applicationService serviceInterface="com.google.idea.blaze.base.experiments.ExperimentService"
- serviceImplementation="com.google.idea.blaze.base.experiments.ExperimentServiceImpl"/>
-
- <projectConfigurable instance="com.google.idea.blaze.base.settings.ui.BlazeUserSettingsConfigurable"
- id ="blaze.view" displayName="Blaze settings"/>
-
- <projectService serviceInterface="com.google.idea.blaze.base.sync.data.BlazeProjectDataManager"
- serviceImplementation="com.google.idea.blaze.base.sync.data.BlazeProjectDataManagerImpl"/>
- <projectService serviceImplementation="com.google.idea.blaze.base.sync.BlazeSyncManager"/>
- <projectService serviceInterface="com.google.idea.blaze.base.sync.status.BlazeSyncStatus"
- serviceImplementation="com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl"/>
-
- <applicationService serviceInterface="com.google.idea.blaze.base.async.executor.BlazeExecutor"
- serviceImplementation="com.google.idea.blaze.base.async.executor.BlazeExecutorImpl"/>
- <projectService serviceInterface="com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy"
- serviceImplementation="com.google.idea.blaze.base.vcs.BlazeDefaultVcsRootPolicy"
- overrides="true"/>
- <fileDocumentManagerListener implementation="com.google.idea.blaze.base.buildmodifier.FileSaveHandler" order="first"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.io.InputStreamProvider"
- serviceImplementation="com.google.idea.blaze.base.io.InputStreamProviderImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.io.FileAttributeProvider"
- serviceImplementation="com.google.idea.blaze.base.io.FileAttributeProvider"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.io.WorkspaceScanner"
- serviceImplementation="com.google.idea.blaze.base.io.VfsWorkspaceScanner"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.buildmodifier.BuildFileModifier"
- serviceImplementation="com.google.idea.blaze.base.lang.buildfile.actions.BuildFileModifierImpl"/>
- <projectService serviceInterface="com.google.idea.blaze.base.buildmodifier.FileSystemModifier"
- serviceImplementation="com.google.idea.blaze.base.buildmodifier.FileSystemModifierImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.run.rulefinder.RuleFinder"
- serviceImplementation="com.google.idea.blaze.base.run.rulefinder.RuleFinderImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.command.info.BlazeInfo"
- serviceImplementation="com.google.idea.blaze.base.command.info.BlazeInfoImpl"/>
-
- <treeStructureProvider implementation="com.google.idea.blaze.base.treeview.BlazeTreeStructureProvider" id="blaze"/>
-
- <applicationService serviceInterface="com.google.idea.blaze.base.projectview.ProjectViewStorageManager"
- serviceImplementation="com.google.idea.blaze.base.projectview.ProjectViewStorageManagerImpl"/>
- <projectService serviceInterface="com.google.idea.blaze.base.projectview.ProjectViewManager"
- serviceImplementation="com.google.idea.blaze.base.projectview.ProjectViewManagerImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface"
- serviceImplementation="com.google.idea.blaze.base.sync.aspects.BlazeIdeInterfaceAspectsImpl"/>
- <projectService serviceInterface="com.google.idea.blaze.base.run.TestRuleFinder"
- serviceImplementation="com.google.idea.blaze.base.run.testmap.TestRuleFinderImpl"/>
- <projectService serviceInterface="com.google.idea.blaze.base.console.BlazeConsoleService"
- serviceImplementation="com.google.idea.blaze.base.console.BlazeConsoleServiceImpl"/>
- <projectService serviceImplementation="com.google.idea.blaze.base.buildmap.FileToBuildMap"/>
- <projectService serviceInterface="com.google.idea.blaze.base.rulemaps.SourceToRuleMap"
- serviceImplementation="com.google.idea.blaze.base.rulemaps.SourceToRuleMapImpl"/>
- <projectService serviceImplementation="com.google.idea.blaze.base.settings.BlazeImportSettingsManager"/>
- <applicationService serviceImplementation="com.google.idea.blaze.base.settings.BlazeUserSettings"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider"
- serviceImplementation="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProviderImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider"
- serviceImplementation="com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProviderImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.prefetch.PrefetchService"
- serviceImplementation="com.google.idea.blaze.base.prefetch.PrefetchServiceImpl"/>
- <applicationService serviceImplementation="com.google.idea.blaze.base.wizard2.BlazeWizardUserSettingsStorage"/>
- <projectService serviceInterface="com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider"
- serviceImplementation="com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProviderImpl"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.intellij">
- <fileTypeFactory implementation="com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileTypeFactory"/>
- <lang.parserDefinition language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.parser.ProjectViewParserDefinition"/>
- <lang.commenter language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.formatting.ProjectViewCommenter"/>
- <lang.syntaxHighlighterFactory language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.highlighting.ProjectViewSyntaxHighlighterFactory"/>
- <completion.contributor language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.completion.ProjectViewKeywordCompletionContributor"/>
- <completion.contributor language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.completion.WorkspaceTypeCompletionContributor"/>
- <completion.contributor language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.completion.AdditionalLanguagesCompletionContributor"/>
- <enterHandlerDelegate implementation="com.google.idea.blaze.base.lang.projectview.formatting.ProjectViewEnterHandler"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.intellij">
- <fileTypeFactory implementation="com.google.idea.blaze.base.lang.buildfile.language.BuildFileTypeFactory"/>
- <annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.HighlightingAnnotator"/>
- <!--<annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.ErrorAnnotator"/>-->
- <annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.GlobErrorAnnotator"/>
- <colorSettingsPage implementation="com.google.idea.blaze.base.lang.buildfile.highlighting.BuildColorsPage"/>
- <projectService serviceImplementation="com.google.idea.blaze.base.lang.buildfile.psi.util.BuildElementGenerator"/>
- <projectService serviceImplementation="com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager"/>
- <referencesSearch implementation="com.google.idea.blaze.base.lang.buildfile.search.BuildLabelReferenceSearcher"/>
- <referencesSearch implementation="com.google.idea.blaze.base.lang.buildfile.search.GlobReferenceSearcher"/>
- <readWriteAccessDetector implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildReadWriteAccessDetector"/>
- <elementDescriptionProvider implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildElementDescriptionProvider"/>
- <usageGroupingRuleProvider implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildUsageGroupingRuleProvider"/>
- <useScopeOptimizer implementation="com.google.idea.blaze.base.lang.buildfile.search.ExcludeBuildFilesScope"/>
- <targetElementEvaluator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.findusages.BuildTargetElementEvaluator"/>
- <quoteHandler fileType="BUILD" className="com.google.idea.blaze.base.lang.buildfile.editor.BuildQuoteHandler"/>
- <enterHandlerDelegate implementation="com.google.idea.blaze.base.lang.buildfile.editor.BuildEnterBetweenBracketsHandler" order="before EnterBetweenBracesHandler"/>
- <enterHandlerDelegate implementation="com.google.idea.blaze.base.lang.buildfile.editor.BuildEnterHandler" order="after EnterBetweenBracesHandler"/>
- <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.ParameterCompletionContributor"/>
- <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.BuiltInFunctionCompletionContributor"/>
- <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.BuiltInFunctionAttributeCompletionContributor"/>
- <completion.contributor language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.completion.ArgumentCompletionContributor"/>
- <langCodeStyleSettingsProvider implementation="com.google.idea.blaze.base.lang.buildfile.formatting.BuildLanguageCodeStyleSettingsProvider"/>
- <codeStyleSettingsProvider implementation="com.google.idea.blaze.base.lang.buildfile.formatting.BuildCodeStyleSettingsProvider"/>
- <editor.backspaceModeOverride language="BUILD" implementationClass="com.intellij.codeInsight.editorActions.SmartBackspaceDisabler"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.intellij.lang">
- <syntaxHighlighterFactory language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.highlighting.BuildSyntaxHighlighterFactory"/>
- <parserDefinition language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.parser.BuildParserDefinition"/>
- <namesValidator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.refactor.BuildNamesValidator"/>
- <braceMatcher language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.formatting.BuildBraceMatcher"/>
- <commenter language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.formatting.BuildCommenter"/>
- <foldingBuilder language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.formatting.BuildFileFoldingBuilder"/>
- <psiStructureViewFactory language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.views.BuildStructureViewFactory"/>
- <findUsagesProvider language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.findusages.BuildFindUsagesProvider"/>
- <refactoringSupport language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.refactor.BuildRefactoringSupportProvider"/>
- </extensions>
-
- <extensionPoints>
- <extensionPoint qualifiedName="com.google.idea.blaze.base.lang.buildfile.DumbAnnotator" interface="com.google.idea.blaze.base.lang.buildfile.validation.BuildAnnotator"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.base.lang.buildfile.Annotator" interface="com.google.idea.blaze.base.lang.buildfile.validation.BuildAnnotator"/>
- </extensionPoints>
-
- <application-components>
- <component>
- <implementation-class>com.google.idea.blaze.base.plugin.BlazeSpecificInitializer</implementation-class>
- </component>
- <component>
- <implementation-class>com.google.idea.blaze.base.plugin.dependency.ProjectDependencyMigration</implementation-class>
- </component>
- </application-components>
-
- <project-components>
- <component>
- <implementation-class>com.google.idea.blaze.base.prefetch.PrefetchServiceProjectComponent</implementation-class>
- <skipForDefaultProject/>
- </component>
- </project-components>
-
- <extensionPoints>
- <extensionPoint qualifiedName="com.google.idea.blaze.SyncListener" interface="com.google.idea.blaze.base.sync.SyncListener"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.SyncPlugin" interface="com.google.idea.blaze.base.sync.BlazeSyncPlugin"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.RuleConfigurationFactory" interface="com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.Prefetcher"
- interface="com.google.idea.blaze.base.prefetch.Prefetcher"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.PsiFileProvider" interface="com.google.idea.blaze.base.lang.buildfile.search.PsiFileProvider"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.VcsHandler"
- interface="com.google.idea.blaze.base.vcs.BlazeVcsHandler"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.BlazeWizardOptionProvider"
- interface="com.google.idea.blaze.base.wizard2.BlazeWizardOptionProvider"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.DefaultSdkProvider"
- interface="com.google.idea.blaze.base.sync.sdk.DefaultSdkProvider"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.BuildFlagsProvider" interface="com.google.idea.blaze.base.command.BuildFlagsProvider"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.BuildSystemProvider" interface="com.google.idea.blaze.base.bazel.BuildSystemProvider"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.BuildifierBinaryProvider" interface="com.google.idea.blaze.base.buildmodifier.BuildifierBinaryProvider"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.LoggingService" interface="com.google.idea.blaze.base.metrics.LoggingService"/>
- </extensionPoints>
-
- <extensions defaultExtensionNs="com.google.idea.blaze">
- <SyncListener implementation="com.google.idea.blaze.base.run.BlazeRunConfigurationSyncListener"/>
- <SyncListener implementation="com.google.idea.blaze.base.sync.status.BlazeSyncStatusListener"/>
- <SyncListener implementation="com.google.idea.blaze.base.run.testmap.TestRuleFinderImpl$ClearTestMap"/>
- <SyncListener implementation="com.google.idea.blaze.base.rulemaps.SourceToRuleMapImpl$ClearSourceToTargetMap"/>
- <SyncListener implementation="com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProviderImpl"/>
- <SyncPlugin implementation="com.google.idea.blaze.base.lang.buildfile.sync.BuildLangSyncPlugin"/>
- <BlazeWizardOptionProvider implementation="com.google.idea.blaze.base.wizard2.BazelWizardOptionProvider"/>
- <BuildFlagsProvider implementation="com.google.idea.blaze.base.command.BuildFlagsProviderImpl"/>
- <VcsHandler implementation="com.google.idea.blaze.base.vcs.git.GitBlazeVcsHandler"/>
- <VcsHandler implementation="com.google.idea.blaze.base.vcs.FallbackBlazeVcsHandler" order="last" id="fallback"/>
- <BuildSystemProvider implementation="com.google.idea.blaze.base.bazel.BazelBuildSystemProvider" order="last"/>
- <BuildifierBinaryProvider implementation="com.google.idea.blaze.base.buildmodifier.BazelBuildifierBinaryProvider"/>
- </extensions>
-
-</idea-plugin>
diff --git a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeAction.java b/blaze-base/src/com/google/idea/blaze/base/actions/BlazeAction.java
deleted file mode 100644
index 47babbc..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeAction.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.actions;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * Base class action that hides for non-blaze projects.
- */
-public abstract class BlazeAction extends AnAction {
- protected BlazeAction() {
- }
-
- protected BlazeAction(Icon icon) {
- super(icon);
- }
-
- protected BlazeAction(@Nullable String text) {
- super(text);
- }
-
- protected BlazeAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
- super(text, description, icon);
- }
-
- @Override
- public final void update(AnActionEvent e) {
- if (!isBlazeProject(e)) {
- e.getPresentation().setEnabledAndVisible(false);
- return;
- }
-
- e.getPresentation().setEnabledAndVisible(true);
- doUpdate(e);
- }
-
- protected void doUpdate(@NotNull AnActionEvent e) {
- }
-
- private static boolean isBlazeProject(@NotNull AnActionEvent e) {
- Project project = e.getProject();
- return project != null && Blaze.isBlazeProject(project);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeCompileFileAction.java b/blaze-base/src/com/google/idea/blaze/base/actions/BlazeCompileFileAction.java
deleted file mode 100644
index 13dbaa8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeCompileFileAction.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.actions;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.experiments.ExperimentScope;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ScopedTask;
-import com.google.idea.blaze.base.scope.scopes.*;
-import com.google.idea.blaze.base.util.SaveUtil;
-import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.util.List;
-
-public class BlazeCompileFileAction extends BlazeAction {
- private static final Logger LOG = Logger.getInstance(BlazeCompileFileAction.class);
-
- public BlazeCompileFileAction() {
- super("Compile file");
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent e) {
- // IntelliJ uses different logic for 1 vs many module selection. When many modules are selected
- // modules with more than 1 content root are ignored
- // (ProjectViewImpl#moduleBySingleContentRoot).
- if (getTargets(e).isEmpty()) {
- Presentation presentation = e.getPresentation();
- presentation.setEnabled(false);
- }
- }
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- if (project != null) {
- ImmutableCollection<Label> targets = getTargets(e);
- buildSourceFile(project, targets);
- }
- }
-
- private ImmutableCollection<Label> getTargets(AnActionEvent e) {
- Project project = e.getProject();
- VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
- if (project != null && virtualFile != null) {
- return SourceToRuleMap.getInstance(project).getTargetsForSourceFile(new File(virtualFile.getPath()));
- }
- return ImmutableList.of();
- }
-
- private static void buildSourceFile(
- @NotNull Project project,
- @NotNull ImmutableCollection<Label> targets) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null || targets.isEmpty()) {
- return;
- }
- final ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- return;
- }
- BlazeExecutor.submitTask(project, new ScopedTask() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- context
- .push(new ExperimentScope())
- .push(new BlazeConsoleScope.Builder(project).build())
- .push(new IssuesScope(project))
- .push(new TimingScope("Make"))
- .push(new LoggedTimingScope(project, Action.MAKE_MODULE_TOTAL_TIME))
- .push(new NotificationScope(
- project,
- "Make",
- "Make module",
- "Make module completed successfully",
- "Make module failed"
- ))
- ;
-
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
-
- SaveUtil.saveAllFiles();
- BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
-
- List<TargetExpression> targetExpressions = Lists.newArrayList(targets);
- blazeIdeInterface.resolveIdeArtifacts(project, context, workspaceRoot, projectViewSet, targetExpressions);
- LocalFileSystem.getInstance().refresh(true);
- }
- });
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java b/blaze-base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java
deleted file mode 100644
index 51acab9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.actions;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.util.SaveUtil;
-import com.google.idea.blaze.base.experiments.ExperimentScope;
-import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ScopedTask;
-import com.google.idea.blaze.base.scope.scopes.*;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public class BlazeMakeProjectAction extends BlazeAction {
-
- public BlazeMakeProjectAction() {
- super("Make Project");
- }
-
- @Override
- public final void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- if (project != null && Blaze.isBlazeProject(project)) {
- buildBlazeProject(project);
- }
- }
-
- protected void buildBlazeProject(@NotNull final Project project) {
-
- BlazeExecutor.submitTask(project, new ScopedTask() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- context
- .push(new ExperimentScope())
- .push(new BlazeConsoleScope.Builder(project).build())
- .push(new IssuesScope(project))
- .push(new TimingScope("Make"))
- .push(new LoggedTimingScope(project, Action.MAKE_PROJECT_TOTAL_TIME))
- .push(new NotificationScope(
- project,
- "Make",
- "Make project",
- "Make project completed successfully",
- "Make project failed"))
- ;
-
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return;
- }
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).reloadProjectView(
- context,
- blazeProjectData.workspacePathResolver
- );
- if (projectViewSet == null) {
- return;
- }
-
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
-
- List<TargetExpression> targets = Lists.newArrayList();
- targets.addAll(projectViewSet.listItems(TargetSection.KEY));
-
- SaveUtil.saveAllFiles();
- BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
- blazeIdeInterface.resolveIdeArtifacts(project, context, workspaceRoot, projectViewSet, targets);
- LocalFileSystem.getInstance().refresh(true);
- }
- });
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeMenuGroup.java b/blaze-base/src/com/google/idea/blaze/base/actions/BlazeMenuGroup.java
deleted file mode 100644
index 36b45c9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeMenuGroup.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.actions;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.DefaultActionGroup;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-public class BlazeMenuGroup extends DefaultActionGroup {
- @Override
- public final void update(AnActionEvent e) {
- if (!isBlazeProject(e)) {
- e.getPresentation().setEnabledAndVisible(false);
- return;
- }
-
- e.getPresentation().setEnabledAndVisible(true);
- e.getPresentation().setText(Blaze.buildSystemName(e.getProject()));
- }
-
- @Override
- public boolean isDumbAware() {
- return true;
- }
-
- private static boolean isBlazeProject(@NotNull AnActionEvent e) {
- Project project = e.getProject();
- return project != null && Blaze.isBlazeProject(project);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeToggleAction.java b/blaze-base/src/com/google/idea/blaze/base/actions/BlazeToggleAction.java
deleted file mode 100644
index 9480fec..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/actions/BlazeToggleAction.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.actions;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.ToggleAction;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * Base class toggle action that hides for non-blaze projects.
- */
-public abstract class BlazeToggleAction extends ToggleAction {
- protected BlazeToggleAction() {
- }
-
- protected BlazeToggleAction(@Nullable String text) {
- super(text);
- }
-
- protected BlazeToggleAction(@Nullable String text, @Nullable String description, @Nullable Icon icon) {
- super(text, description, icon);
- }
-
- @Override
- public final void update(AnActionEvent e) {
- if (!isBlazeProject(e)) {
- e.getPresentation().setEnabledAndVisible(false);
- return;
- }
-
- e.getPresentation().setEnabledAndVisible(true);
- super.update(e);
- doUpdate(e);
- }
-
- protected void doUpdate(@NotNull AnActionEvent e) {
- }
-
- private static boolean isBlazeProject(@NotNull AnActionEvent e) {
- Project project = e.getProject();
- return project != null && Blaze.isBlazeProject(project);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/AsyncUtil.java b/blaze-base/src/com/google/idea/blaze/base/async/AsyncUtil.java
deleted file mode 100644
index 1e8a525..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/AsyncUtil.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async;
-
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Async utilities.
- */
-public class AsyncUtil {
- public static void executeProjectChangeAction(@NotNull final Runnable task) throws Throwable {
- final ValueHolder<Throwable> error = new ValueHolder<Throwable>();
-
- executeOnEdt(new Runnable() {
- @Override
- public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- try {
- task.run();
- } catch (Throwable t) {
- error.value = t;
- }
- }
- });
- }
- });
-
- if (error.value != null) {
- throw error.value;
- }
- }
-
- private static void executeOnEdt(@NotNull Runnable task) {
- if (ApplicationManager.getApplication().isDispatchThread()) {
- task.run();
- }
- else {
- UIUtil.invokeAndWaitIfNeeded(task);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/FutureUtil.java b/blaze-base/src/com/google/idea/blaze/base/async/FutureUtil.java
deleted file mode 100644
index 3c6b9e3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/FutureUtil.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.intellij.openapi.diagnostic.Logger;
-
-import java.util.concurrent.ExecutionException;
-
-/**
- * Utilities operating on futures.
- */
-public class FutureUtil {
- public static class FutureResult<T> {
- private final T result;
- private final boolean success;
-
- FutureResult(T result) {
- this.result = result;
- this.success = true;
- }
-
- FutureResult() {
- this.result = null;
- this.success = false;
- }
-
- public T result() {
- return result;
- }
-
- public boolean success() {
- return success;
- }
- }
-
- public static class Builder<T> {
- private static final Logger LOG = Logger.getInstance(FutureUtil.class);
- private final BlazeContext context;
- private final ListenableFuture<T> future;
- private String timingCategory;
- private String errorMessage;
- private String progressMessage;
-
- Builder(BlazeContext context, ListenableFuture<T> future) {
- this.context = context;
- this.future = future;
- }
-
- public Builder<T> timed(String timingCategory) {
- this.timingCategory = timingCategory;
- return this;
- }
- public Builder<T> withProgressMessage(String message) {
- this.progressMessage = message;
- return this;
- }
- public Builder<T> onError(String errorMessage) {
- this.errorMessage = errorMessage;
- return this;
- }
- public FutureResult<T> run() {
- return Scope.push(context, (childContext) -> {
- if (timingCategory != null) {
- childContext.push(new TimingScope(timingCategory));
- }
- if (progressMessage != null) {
- childContext.output(new PrintOutput(progressMessage));
- }
- try {
- return new FutureResult<>(future.get());
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- context.setCancelled();
- }
- catch (ExecutionException e) {
- LOG.error(e);
- if (errorMessage != null) {
- IssueOutput.error(errorMessage).submit(childContext);
- }
- context.setHasError();
- }
- return new FutureResult<>();
- });
- }
- }
-
- public static <T> Builder<T> waitForFuture(BlazeContext context, ListenableFuture<T> future) {
- return new Builder<>(context, future);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/ValueHolder.java b/blaze-base/src/com/google/idea/blaze/base/async/ValueHolder.java
deleted file mode 100644
index 97f514d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/ValueHolder.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async;
-
-/**
- * Simple wrapper to work around Java's final limitation.
- */
-public class ValueHolder<T> {
- public T value;
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java b/blaze-base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java
deleted file mode 100644
index 49d11c0..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.executor;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.progress.PerformInBackgroundOption;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Progressive;
-import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
-import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase;
-import com.intellij.openapi.progress.util.ProgressWindow;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Computable;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.concurrent.Callable;
-
-/**
- * Shared thread pool for blaze tasks.
- */
-public abstract class BlazeExecutor {
- public static enum Modality {
- MODAL, // This task must start in the foreground and stay there.
- BACKGROUNDABLE, // This task will start in the foreground, but can be sent to the background.
- ALWAYS_BACKGROUND // This task will start in the background and stay there.
- }
-
- @NotNull
- public static BlazeExecutor getInstance() {
- return ServiceManager.getService(BlazeExecutor.class);
- }
-
- public abstract <T> ListenableFuture<T> submit(Callable<T> callable);
-
- public abstract ListeningExecutorService getExecutor();
-
- public static ListenableFuture<Void> submitTask(
- @Nullable final Project project,
- @NotNull final Progressive progressive) {
- return submitTask(project, "", progressive);
- }
-
- public static ListenableFuture<Void> submitTask(
- @Nullable final Project project,
- @NotNull final String title,
- @NotNull final Progressive progressive) {
- return submitTask(
- project,
- title,
- true /* cancelable */,
- Modality.ALWAYS_BACKGROUND,
- progressive);
- }
-
- public static ListenableFuture<Void> submitTask(
- @Nullable final Project project,
- @NotNull final String title,
- final boolean cancelable,
- final Modality modality,
- @NotNull final Progressive progressive) {
-
- // The progress indicator must be created on the UI thread.
- final ProgressWindow indicator = UIUtil.invokeAndWaitIfNeeded(new Computable<ProgressWindow>() {
- @Override
- public ProgressWindow compute() {
- if (modality == Modality.MODAL) {
- ProgressWindow indicator = new ProgressWindow(cancelable, project);
- indicator.setTitle(title);
- return indicator;
- }
- else {
- PerformInBackgroundOption backgroundOption = modality == Modality.BACKGROUNDABLE ?
- PerformInBackgroundOption.DEAF :
- PerformInBackgroundOption.ALWAYS_BACKGROUND;
- return new BackgroundableProcessIndicator(
- project,
- title,
- backgroundOption,
- "Cancel",
- "Cancel",
- cancelable
- );
- }
- }
- });
-
- indicator.setIndeterminate(true);
- indicator.start();
- final Runnable process = new Runnable() {
- @Override
- public void run() {
- progressive.run(indicator);
- }
- };
- final ListenableFuture<Void> future = getInstance().submit(new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- ProgressManager.getInstance().runProcess(process, indicator);
- return null;
- }
- });
- if (cancelable) {
- indicator.addStateDelegate(new AbstractProgressIndicatorExBase() {
- @Override
- public void cancel() {
- super.cancel();
- future.cancel(true);
- }
- });
- }
- return future;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/executor/BlazeExecutorImpl.java b/blaze-base/src/com/google/idea/blaze/base/async/executor/BlazeExecutorImpl.java
deleted file mode 100644
index f8407b6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/executor/BlazeExecutorImpl.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.executor;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import java.util.concurrent.*;
-
-/**
- * Executes blaze tasks on the an executor.
- */
-public class BlazeExecutorImpl extends BlazeExecutor {
-
- private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(16));
-
- @Override
- public <T> ListenableFuture<T> submit(Callable<T> callable) {
- return executorService.submit(callable);
- }
-
- @Override
- public ListeningExecutorService getExecutor() {
- return executorService;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/executor/TransientExecutor.java b/blaze-base/src/com/google/idea/blaze/base/async/executor/TransientExecutor.java
deleted file mode 100644
index f08b0c2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/executor/TransientExecutor.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.executor;
-
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An executor that grows to a finite number of threads and times them out quickly.
- */
-public class TransientExecutor extends ThreadPoolExecutor {
- public TransientExecutor(int maxThreads) {
- super(maxThreads, maxThreads, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
- allowCoreThreadTimeOut(true);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/process/ExternalTask.java b/blaze-base/src/com/google/idea/blaze/base/async/process/ExternalTask.java
deleted file mode 100644
index 8fd2de2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/process/ExternalTask.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.process;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Throwables;
-import com.google.common.io.ByteStreams;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.progress.ProcessCanceledException;
-import com.intellij.util.SystemProperties;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-
-/**
- * Invokes an external process
- */
-public class ExternalTask {
- private static final Logger LOG = Logger.getInstance(ExternalTask.class);
-
- static final OutputStream NULL_STREAM = ByteStreams.nullOutputStream();
-
- public static class Builder {
- @NotNull
- private final File workingDirectory;
- @NotNull
- private final List<String> command;
- @Nullable
- private BlazeContext context;
- @Nullable
- private OutputStream stdout;
- @Nullable
- private OutputStream stderr;
- boolean redirectErrorStream = false;
-
- private Builder(
- @NotNull WorkspaceRoot workspaceRoot,
- @NotNull List<String> command) {
- this(workspaceRoot.directory(), command);
- }
-
- private Builder(
- @NotNull File workingDirectory,
- @NotNull List<String> command) {
- this.workingDirectory = workingDirectory;
- this.command = command;
- }
-
- @NotNull
- public Builder context(@Nullable BlazeContext context) {
- this.context = context;
- return this;
- }
-
- @NotNull
- public Builder redirectStderr(boolean redirectStderr) {
- this.redirectErrorStream = redirectStderr;
- return this;
- }
-
- @NotNull
- public Builder stdout(@Nullable OutputStream stdout) {
- this.stdout = stdout;
- return this;
- }
-
- @NotNull
- public Builder stderr(@Nullable OutputStream stderr) {
- this.stderr = stderr;
- return this;
- }
-
- @NotNull
- public ExternalTask build() {
- return new ExternalTask(
- context,
- workingDirectory,
- command,
- stdout,
- stderr,
- redirectErrorStream
- );
- }
- }
-
- @NotNull
- private final File workingDirectory;
-
- @NotNull
- private final List<String> command;
-
- @Nullable
- private final BlazeContext parentContext;
-
- private final boolean redirectErrorStream;
-
- @NotNull
- private final OutputStream stdout;
-
- @NotNull
- private final OutputStream stderr;
-
- private ExternalTask(
- @Nullable BlazeContext context,
- @NotNull File workingDirectory,
- @NotNull List<String> command,
- @Nullable OutputStream stdout,
- @Nullable OutputStream stderr,
- boolean redirectErrorStream) {
- this.workingDirectory = workingDirectory;
- this.command = command;
- this.parentContext = context;
- this.redirectErrorStream = redirectErrorStream;
- this.stdout = stdout != null ? stdout : NULL_STREAM;
- this.stderr = stderr != null ? stderr : NULL_STREAM;
- }
-
- public int run(BlazeScope... scopes) {
- Integer returnValue = Scope.push(parentContext, context -> {
- for (BlazeScope scope : scopes) {
- context.push(scope);
- }
- try {
- return invokeCommand(context);
- } catch (ProcessCanceledException e) {
- // Logging a ProcessCanceledException is an IJ error - mark context canceled instead.
- context.setCancelled();
- }
- return -1;
- });
- return returnValue != null ? returnValue : -1;
- }
-
- private static void closeQuietly(OutputStream stream) {
- try {
- stream.close();
- } catch (IOException e) {
- Throwables.propagate(e);
- }
- }
-
- private int invokeCommand(BlazeContext context) {
- String executingTasksText = "Command: "
- + Joiner.on(" ").join(command)
- + SystemProperties.getLineSeparator()
- + SystemProperties.getLineSeparator();
-
- context.output(new PrintOutput(executingTasksText));
-
- try {
- if (context.isEnding()) {
- return -1;
- }
- ProcessBuilder builder = new ProcessBuilder()
- .command(command)
- .redirectErrorStream(redirectErrorStream)
- .directory(workingDirectory);
- try {
- final Process process = builder.start();
- Thread shutdownHook = new Thread(process::destroy);
- try {
- Runtime.getRuntime().addShutdownHook(shutdownHook);
- Thread stdoutThread = ProcessUtil.forwardAsync(process.getInputStream(), stdout);
- Thread stderrThread = null;
- if (!redirectErrorStream) {
- stderrThread = ProcessUtil.forwardAsync(process.getErrorStream(), stderr);
- }
- process.waitFor();
- stdoutThread.join();
- if (!redirectErrorStream) {
- stderrThread.join();
- }
- int exitValue = process.exitValue();
- if (exitValue != 0) {
- context.setHasError();
- }
- return exitValue;
- }
- catch (InterruptedException e) {
- process.destroy();
- throw new ProcessCanceledException();
- }
- finally {
- try {
- Runtime.getRuntime().removeShutdownHook(shutdownHook);
- } catch (IllegalStateException e) {
- // we can't remove a shutdown hook if we are shutting down, do nothing about it
- }
- }
- }
- catch (IOException e) {
- LOG.warn(e);
- IssueOutput.error(e.getMessage()).submit(context);
- }
- }
- finally {
- closeQuietly(stdout);
- closeQuietly(stderr);
- }
- return -1;
- }
-
- public static Builder builder(
- @NotNull File workingDirectory,
- @NotNull List<String> command) {
- return new Builder(workingDirectory, command);
- }
-
- public static Builder builder(
- @NotNull WorkspaceRoot workspaceRoot,
- @NotNull List<String> command) {
- return new Builder(workspaceRoot, command);
- }
-
- public static Builder builder(
- @NotNull WorkspaceRoot workspaceRoot,
- @NotNull BlazeCommand command) {
- return new Builder(workspaceRoot, command.toList());
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java b/blaze-base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java
deleted file mode 100644
index a0bab3d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.process;
-
-import com.google.common.collect.Lists;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-
-/**
- * An base output stream which marshals output into newline-delimited segments for processing.
- */
-public final class LineProcessingOutputStream extends OutputStream {
-
- public interface LineProcessor {
- /**
- * Process a single, complete line of output.
- *
- * @return Whether line processing should continue
- */
- boolean processLine(@NotNull String line);
- }
-
- @NotNull
- private final StringBuffer stringBuffer = new StringBuffer();
- private volatile boolean closed;
- @NotNull
- private final List<LineProcessor> lineProcessors;
-
- LineProcessingOutputStream(@NotNull LineProcessor... lineProcessors) {
- this.lineProcessors = Lists.newArrayList(lineProcessors);
- }
-
- public static LineProcessingOutputStream of(@NotNull LineProcessor... lineProcessors) {
- return new LineProcessingOutputStream(lineProcessors);
- }
-
- @Override
- public synchronized void write(byte[] b, int off, int len) {
- if (!closed) {
- String text = new String(b, off, len);
- stringBuffer.append(text);
-
- while (true) {
- int lineBreakIndex = -1;
- int lineBreakLength = 0;
- for (int i = 0; i < stringBuffer.length(); ++i) {
- char c = stringBuffer.charAt(i);
- if (c == '\r' || c == '\n') {
- lineBreakIndex = i;
- lineBreakLength = 1;
- if (c == '\r' && (i + 1) < stringBuffer.length() && stringBuffer.charAt(i + 1) == '\n') {
- ++lineBreakLength;
- }
- break;
- }
- }
-
- if (lineBreakIndex == -1) {
- return;
- }
-
- String line = stringBuffer.substring(0, lineBreakIndex);
-
- stringBuffer.delete(0, lineBreakIndex + lineBreakLength);
-
- for (LineProcessor lineProcessor : lineProcessors) {
- if (!lineProcessor.processLine(line)) {
- break;
- }
- }
- }
- }
- }
-
- @Override
- public void write(int b) throws IOException {
- write(new byte[]{(byte)b}, 0, 1);
- }
-
- @Override
- public void close() throws IOException {
- closed = true;
- super.close();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/process/PrintOutputLineProcessor.java b/blaze-base/src/com/google/idea/blaze/base/async/process/PrintOutputLineProcessor.java
deleted file mode 100644
index 562b648..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/process/PrintOutputLineProcessor.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.process;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Simple adapter between stdout and context print output.
- */
-public class PrintOutputLineProcessor implements LineProcessingOutputStream.LineProcessor {
- private final BlazeContext context;
- public PrintOutputLineProcessor(BlazeContext context) {
- this.context = context;
- }
- @Override
- public boolean processLine(@NotNull String line) {
- context.output(new PrintOutput(line));
- return true;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/async/process/ProcessUtil.java b/blaze-base/src/com/google/idea/blaze/base/async/process/ProcessUtil.java
deleted file mode 100644
index 608f4d3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/async/process/ProcessUtil.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.process;
-
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-
-public class ProcessUtil {
- private static final Logger LOG = Logger.getInstance(ProcessUtil.class);
-
- public static Thread forwardAsync(final InputStream input, final OutputStream output) {
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- int bufferSize = 4096;
- byte[] buffer = new byte[bufferSize];
-
- int read = 0;
- try {
- read = input.read(buffer);
- while (read != -1) {
- output.write(buffer, 0, read);
- read = input.read(buffer);
- }
- }
- catch (IOException e) {
- LOG.warn("Error redirecting output", e);
- }
- }
- });
- thread.start();
- return thread;
- }
-
- @NotNull
- public static String runCommand(
- @NotNull WorkspaceRoot workspaceRoot,
- @NotNull List<String> command
- ) {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- ExternalTask.Builder builder = ExternalTask.builder(workspaceRoot, command);
- ExternalTask task = builder
- .redirectStderr(true)
- .stdout(output)
- .build();
- task.run();
- return output.toString();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java b/blaze-base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
deleted file mode 100644
index a0e22a2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.bazel;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-
-/**
- * Provides the bazel build system name string.
- */
-public class BazelBuildSystemProvider implements BuildSystemProvider {
- @Override
- public BuildSystem buildSystem() {
- return BuildSystem.Bazel;
- }
-
- @Override
- public WorkspaceRootProvider getWorkspaceRootProvider() {
- return BazelWorkspaceRootProvider.INSTANCE;
- }
-
- @Override
- public ImmutableList<String> buildArtifactDirectories(WorkspaceRoot root) {
- String rootDir = root.directory().getName();
- return ImmutableList.of(
- "bazel-bin",
- "bazel-genfiles",
- "bazel-out",
- "bazel-testlogs",
- "bazel-" + rootDir
- );
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/bazel/BazelWorkspaceRootProvider.java b/blaze-base/src/com/google/idea/blaze/base/bazel/BazelWorkspaceRootProvider.java
deleted file mode 100644
index 95512d8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/bazel/BazelWorkspaceRootProvider.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.bazel;
-
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Implementation of WorkspaceHelper.
- */
-public class BazelWorkspaceRootProvider implements WorkspaceRootProvider {
-
- public static final BazelWorkspaceRootProvider INSTANCE = new BazelWorkspaceRootProvider();
-
- private BazelWorkspaceRootProvider() {}
-
- /**
- * Checks for the existence of a WORKSPACE file in the given directory.
- */
- @Override
- public boolean isWorkspaceRoot(File file) {
- return FileAttributeProvider.getInstance().isFile(new File(file, "WORKSPACE"));
- }
-
- @Nullable
- @Override
- public WorkspaceRoot findWorkspaceRoot(File file) {
- while (file != null) {
- if (isWorkspaceRoot(file)) {
- return new WorkspaceRoot(file);
- }
- file = file.getParentFile();
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java b/blaze-base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
deleted file mode 100644
index 030e599..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.bazel;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-import javax.annotation.Nullable;
-
-/**
- * Extension points specify the build systems supported by this plugin.<br>
- * The order of the extension points establishes a priority (highest priority first),
- * for situations where we don't have an existing project to use for context
- * (e.g. the 'import project' action).
- */
-public interface BuildSystemProvider {
-
- ExtensionPointName<BuildSystemProvider> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.BuildSystemProvider");
-
- static BuildSystemProvider defaultBuildSystem() {
- return EP_NAME.getExtensions()[0];
- }
-
- @Nullable
- static BuildSystemProvider getBuildSystemProvider(BuildSystem buildSystem) {
- for (BuildSystemProvider provider : EP_NAME.getExtensions()) {
- if (provider.buildSystem() == buildSystem) {
- return provider;
- }
- }
- return null;
- }
-
- static boolean isBuildSystemAvailable(BuildSystem buildSystem) {
- return getBuildSystemProvider(buildSystem) != null;
- }
-
- static WorkspaceRootProvider getWorkspaceRootProvider(BuildSystem buildSystem) {
- BuildSystemProvider provider = getBuildSystemProvider(buildSystem);
- if (provider == null) {
- throw new RuntimeException(String.format("Build system '%s' not supported by this plugin", buildSystem));
- }
- return provider.getWorkspaceRootProvider();
- }
-
- static BuildSystemProvider getInstance() {
- return ServiceManager.getService(BuildSystemProvider.class);
- }
-
- /**
- * Returns the default build system for this application. This should only be
- * called in situations where it doesn't make sense to use the current project.<br>
- * Otherwise, use {@link com.google.idea.blaze.base.settings.Blaze#getBuildSystem}
- */
- BuildSystem buildSystem();
-
- WorkspaceRootProvider getWorkspaceRootProvider();
-
- /**
- * Directories containing artifacts produced during the build process.
- */
- ImmutableList<String> buildArtifactDirectories(WorkspaceRoot root);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/bazel/WorkspaceRootProvider.java b/blaze-base/src/com/google/idea/blaze/base/bazel/WorkspaceRootProvider.java
deleted file mode 100644
index a9bf30d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/bazel/WorkspaceRootProvider.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.bazel;
-
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Utility methods for working with workspace paths.
- */
-public interface WorkspaceRootProvider {
-
- /**
- * Checks whether the given directory is a valid workspace root.
- */
- boolean isWorkspaceRoot(File file);
-
- /**
- * Checks whether the file or one of its ancestors is a valid workspace root.<br>
- * This should only be called when no Project is available. Otherwise, use WorkspaceRoot.isInWorkspace.
- */
- default boolean isInWorkspace(File file) {
- return findWorkspaceRoot(file) != null;
- }
-
- /**
- * If the given file is inside a workspace, returns the workspace root. Otherwise returns null.
- */
- @Nullable
- WorkspaceRoot findWorkspaceRoot(File file);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmap/FileToBuildMap.java b/blaze-base/src/com/google/idea/blaze/base/buildmap/FileToBuildMap.java
deleted file mode 100644
index ca19f19..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmap/FileToBuildMap.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmap;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-/**
- * Map of file -> BUILD files.
- */
-public class FileToBuildMap {
- private final Project project;
-
- public static FileToBuildMap getInstance(Project project) {
- return ServiceManager.getService(project, FileToBuildMap.class);
- }
-
- public FileToBuildMap(Project project) {
- this.project = project;
- }
-
- public Collection<File> getBuildFilesForFile(File file) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return ImmutableList.of();
- }
- return SourceToRuleMap.getInstance(project).getTargetsForSourceFile(file)
- .stream()
- .map(blazeProjectData.ruleMap::get)
- .filter(Objects::nonNull)
- .map((ruleIdeInfo) -> ruleIdeInfo.buildFile)
- .filter(Objects::nonNull)
- .map(ArtifactLocation::getFile)
- .collect(Collectors.toList());
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmap/OpenCorrespondingBuildFile.java b/blaze-base/src/com/google/idea/blaze/base/buildmap/OpenCorrespondingBuildFile.java
deleted file mode 100644
index afb3c62..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmap/OpenCorrespondingBuildFile.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmap;
-
-import com.google.common.collect.Iterables;
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.metrics.LoggingService;
-import com.intellij.ide.actions.OpenFileAction;
-import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.Collection;
-
-public class OpenCorrespondingBuildFile extends BlazeAction {
- @Override
- public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- if (project == null) {
- return;
- }
- VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
- File file = getBuildFile(project, virtualFile);
- if (file == null) {
- return;
- }
- OpenFileAction.openFile(file.getPath(), project);
- LoggingService.reportEvent(project, Action.OPEN_CORRESPONDING_BUILD_FILE);
- }
-
- @Nullable
- private File getBuildFile(@Nullable Project project, @Nullable VirtualFile virtualFile) {
- if (project == null) {
- return null;
- }
- if (virtualFile == null) {
- return null;
- }
- File file = new File(virtualFile.getPath());
- Collection<File> fileInfoList = FileToBuildMap.getInstance(project).getBuildFilesForFile(file);
- return Iterables.getFirst(fileInfoList, null);
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent e) {
- Presentation presentation = e.getPresentation();
- DataContext dataContext = e.getDataContext();
- VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
- Project project = CommonDataKeys.PROJECT.getData(dataContext);
- boolean visible = (project != null && virtualFile != null);
- boolean enabled = getBuildFile(project, virtualFile) != null;
- presentation.setVisible(visible || ActionPlaces.isMainMenuOrActionSearch(e.getPlace()));
- presentation.setEnabled(enabled);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BazelBuildifierBinaryProvider.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BazelBuildifierBinaryProvider.java
deleted file mode 100644
index caf6389..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BazelBuildifierBinaryProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import com.google.idea.blaze.base.util.BlazeHelperBinaryUtil;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Provides the bazel buildifier binary.
- */
-public class BazelBuildifierBinaryProvider implements BuildifierBinaryProvider {
-
- private static final String BUILDIFIER_BINARY_PATH = "/blaze-base/resources/binaries/bazel-buildifier";
-
- @Nullable
- @Override
- public File getBuildifierBinary() {
- return BlazeHelperBinaryUtil.getBlazeHelperBinary(BUILDIFIER_BINARY_PATH);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildFileFormatter.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildFileFormatter.java
deleted file mode 100644
index bb7f66d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildFileFormatter.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import javax.annotation.Nullable;
-import java.io.*;
-
-/**
- * Formats BUILD files using 'buildifier'
- */
-public class BuildFileFormatter {
-
- @Nullable
- private static File getBuildifierBinary() {
- for (BuildifierBinaryProvider provider : BuildifierBinaryProvider.EP_NAME.getExtensions()) {
- File file = provider.getBuildifierBinary();
- if (file != null) {
- return file;
- }
- }
- return null;
- }
-
- static String formatText(String text) {
- try {
- File buildifierBinary = getBuildifierBinary();
- if (buildifierBinary == null) {
- return null;
- }
- File file = createTempFile(text);
- formatFile(file, buildifierBinary.getPath());
- String formattedFile = readFile(file);
- file.delete();
- return formattedFile;
- } catch (IOException e) {
- e.printStackTrace();
- }
- return text;
- }
-
- private static void formatFile(File file, String buildifierBinaryPath) throws IOException {
- ProcessBuilder builder = new ProcessBuilder(buildifierBinaryPath, file.getAbsolutePath());
- try {
- builder.start().waitFor();
- } catch (InterruptedException e) {
- throw new IOException("buildifier execution failed", e);
- }
- }
-
-
- private static String readFile(File file) throws IOException {
- try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
- StringBuilder formattedFile = new StringBuilder();
- char[] buf = new char[1024];
- int numRead;
- while ((numRead = reader.read(buf)) >= 0) {
- formattedFile.append(buf, 0, numRead);
- }
- return formattedFile.toString();
- }
- }
-
- private static File createTempFile(String text) throws IOException {
- File file = File.createTempFile("ijwb", ".tmp");
- try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
- writer.write(text);
- }
- return file;
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildFileModifier.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildFileModifier.java
deleted file mode 100644
index c8c570c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildFileModifier.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-public interface BuildFileModifier {
-
- static BuildFileModifier getInstance() {
- return ServiceManager.getService(BuildFileModifier.class);
- }
-
- /**
- * Add a new rule to a build file. The rule name and rule kind must be validated before this
- * method, but no guarantees are made about actually being able to add this rule to the build
- * file. An example of why it might fail is the build file might already have a rule with the
- * requested name.
- *
- * @param context Blaze context to operate in
- * @param newRule new rule to create
- * @param ruleKind valid kind of rule (android_library, java_library, etc.)
- * @return true if rule is added to file, false otherwise
- */
- boolean addRule(
- Project project,
- final BlazeContext context,
- final Label newRule,
- final Kind ruleKind);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildifierBinaryProvider.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildifierBinaryProvider.java
deleted file mode 100644
index 3390002..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/BuildifierBinaryProvider.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Provides a buildifier binary.
- */
-public interface BuildifierBinaryProvider {
-
- ExtensionPointName<BuildifierBinaryProvider> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.BuildifierBinaryProvider");
-
- @Nullable
- File getBuildifierBinary();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSaveHandler.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSaveHandler.java
deleted file mode 100644
index c77d34b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSaveHandler.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.command.CommandProcessor;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.DocumentRunnable;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
-import com.intellij.openapi.fileEditor.FileDocumentManagerAdapter;
-import com.intellij.openapi.vfs.VirtualFile;
-
-/**
- * Runs the buildifier command on file save.
- */
-public class FileSaveHandler extends FileDocumentManagerAdapter {
-
- @Override
- public void beforeDocumentSaving(final Document document) {
- if (!document.isWritable()) {
- return;
- }
- FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
- VirtualFile file = fileDocumentManager.getFile(document);
- if (file == null || !file.isValid()) {
- return;
- }
-
- if (!isBuildFile(file)) {
- return;
- }
- int lines = document.getLineCount();
- if (lines > 0) {
- String text = document.getText();
- String formattedText = BuildFileFormatter.formatText(text);
- updateDocument(document, formattedText);
- }
- }
-
- private void updateDocument(final Document document, final String formattedContent) {
- ApplicationManager.getApplication().runWriteAction(new DocumentRunnable(document, null) {
- @Override
- public void run() {
- CommandProcessor.getInstance().runUndoTransparentAction(() -> document.setText(formattedContent));
- }
- });
- }
-
- private static boolean isBuildFile(VirtualFile file) {
- return file.getName().equals("BUILD");
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
deleted file mode 100644
index 6606b23..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-
-public abstract class FileSystemModifier {
-
- public static FileSystemModifier getInstance(@NotNull Project project) {
- return ServiceManager.getService(project, FileSystemModifier.class);
- }
-
- @Nullable
- public abstract File makeWorkspacePathDirs(@NotNull WorkspacePath workspacePath);
-
- @Nullable
- public abstract File createFile(@NotNull WorkspacePath parentDir, @NotNull String name);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java b/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
deleted file mode 100644
index 40470d7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.buildmodifier;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-
-public class FileSystemModifierImpl extends FileSystemModifier {
-
- private final Project project;
-
- public FileSystemModifierImpl(@NotNull Project project) {
- this.project = project;
- }
-
- @Nullable
- @Override
- public File makeWorkspacePathDirs(@NotNull WorkspacePath workspacePath) {
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- File dir = workspaceRoot.fileForPath(workspacePath);
- boolean success = dir.mkdirs();
- return success ? dir : null;
- }
-
- @Nullable
- @Override
- public File createFile(
- @NotNull WorkspacePath parentDirectory,
- @NotNull String name) {
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- File dir = workspaceRoot.fileForPath(parentDirectory);
- File f = new File(dir, name);
- boolean success;
- try {
- success = f.createNewFile();
- }
- catch (IOException e) {
- success = false;
- }
- return success ? f : null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/BlazeCommand.java b/blaze-base/src/com/google/idea/blaze/base/command/BlazeCommand.java
deleted file mode 100644
index 21a8a4d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/BlazeCommand.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.annotation.concurrent.Immutable;
-
-/**
- * A command to issue to Blaze/Bazel on the command line.
- */
-@Immutable
-public final class BlazeCommand {
-
- private final BuildSystem buildSystem;
- private final BlazeCommandName name;
- private final ImmutableList<String> arguments;
-
- private BlazeCommand(BuildSystem buildSystem, BlazeCommandName name, ImmutableList<String> arguments) {
- this.buildSystem = buildSystem;
- this.name = name;
- this.arguments = arguments;
- }
-
- public BlazeCommandName getName() {
- return name;
- }
-
- public ImmutableList<String> toList() {
- ImmutableList.Builder<String> commandLine = ImmutableList.builder();
- commandLine.add(getBinaryPath(buildSystem), name.toString());
- commandLine.addAll(arguments);
- return commandLine.build();
- }
-
- private static String getBinaryPath(BuildSystem buildSystem) {
- BlazeUserSettings settings = BlazeUserSettings.getInstance();
- switch (buildSystem) {
- case Blaze:
- return settings.getBlazeBinaryPath();
- case Bazel:
- return settings.getBazelBinaryPath();
- default:
- throw new RuntimeException("Unrecognized build system type: " + buildSystem);
- }
- }
-
- @Override
- public String toString() {
- return Joiner.on(' ').join(toList());
- }
-
- public static Builder builder(BuildSystem buildSystem, BlazeCommandName name) {
- return new Builder(buildSystem, name);
- }
-
- public static class Builder {
- private final BuildSystem buildSystem;
- private final BlazeCommandName name;
- private final ImmutableList.Builder<TargetExpression> targets = ImmutableList.builder();
- private final ImmutableList.Builder<String> blazeFlags = ImmutableList.builder();
- private final ImmutableList.Builder<String> exeFlags = ImmutableList.builder();
-
- public Builder(BuildSystem buildSystem, BlazeCommandName name) {
- this.buildSystem = buildSystem;
- this.name = name;
- // Tell forge what tool we used to call blaze so we can track usage.
- addBlazeFlags(BlazeFlags.getToolTagFlag());
- }
-
- public BlazeCommand build() {
- ImmutableList.Builder<String> arguments = ImmutableList.builder();
- arguments.addAll(blazeFlags.build());
- arguments.add("--");
-
- // Trust the user's ordering of the targets since order matters to blaze
- for (TargetExpression targetExpression : targets.build()) {
- arguments.add(targetExpression.toString());
- }
-
- arguments.addAll(exeFlags.build());
- return new BlazeCommand(buildSystem, name, arguments.build());
- }
-
- public Builder addTargets(TargetExpression... targets) {
- return this.addTargets(Arrays.asList(targets));
- }
-
- public Builder addTargets(List<? extends TargetExpression> targets) {
- this.targets.addAll(targets);
- return this;
- }
-
- public Builder addExeFlags(String... flags) {
- return addExeFlags(Arrays.asList(flags));
- }
-
- public Builder addExeFlags(List<String> flags) {
- this.exeFlags.addAll(flags);
- return this;
- }
-
- public Builder addBlazeFlags(String... flags) {
- return addBlazeFlags(Arrays.asList(flags));
- }
-
- public Builder addBlazeFlags(List<String> flags) {
- this.blazeFlags.addAll(flags);
- return this;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/BlazeCommandName.java b/blaze-base/src/com/google/idea/blaze/base/command/BlazeCommandName.java
deleted file mode 100644
index dc27d08..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/BlazeCommandName.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.concurrent.Immutable;
-import java.util.Collection;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * A class for Blaze/Bazel command names. We enumerate the commands we use (and that we expect users to be
- * interested in), but do NOT use an enum because we want to allow users to specify arbitrary
- * commands.
- */
-@Immutable
-public final class BlazeCommandName {
- @NotNull
- private static final ConcurrentMap<String, BlazeCommandName> knownCommands = Maps.newConcurrentMap();
-
- public static final BlazeCommandName BUILD = fromString("build");
- public static final BlazeCommandName TEST = fromString("test");
- public static final BlazeCommandName MOBILE_INSTALL = fromString("mobile-install");
- public static final BlazeCommandName RUN = fromString("run");
- public static final BlazeCommandName QUERY = fromString("query");
- public static final BlazeCommandName INFO = fromString("info");
-
-
- public static BlazeCommandName fromString(@NotNull String name) {
- knownCommands.putIfAbsent(name, new BlazeCommandName(name));
- return knownCommands.get(name);
- }
-
- private final String name;
-
- private BlazeCommandName(@NotNull String name) {
- Preconditions.checkArgument(!name.isEmpty(), "Command should be non-empty.");
- this.name = name;
- }
-
- @Override
- public String toString() {
- return name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof BlazeCommandName)) {
- return false;
- }
- BlazeCommandName that = (BlazeCommandName)o;
- return name.equals(that.name);
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-
- /**
- * @return An unmodifiable view of the Blaze commands we know about (including those that the user
- * has specified, in addition to those we have hard-coded).
- */
- @NotNull
- public static Collection<BlazeCommandName> knownCommands() {
- return ImmutableList.copyOf(knownCommands.values());
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/BlazeFlags.java b/blaze-base/src/com/google/idea/blaze/base/command/BlazeFlags.java
deleted file mode 100644
index 7e83d40..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/BlazeFlags.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.sections.BuildFlagsSection;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.util.PlatformUtils;
-
-import java.util.List;
-
-import javax.annotation.Nullable;
-
-/**
- * The collection of all the Bazel flag strings we use.
- */
-public final class BlazeFlags {
-
- // Build the maximum number of possible dependencies of the project and to show all the build
- // errors in single go.
- public static final String KEEP_GOING = "--keep_going";
- // Tells Blaze to open a debug port and wait for a connection while running tests
- // It expands to: --test_arg=--wrapper_script_flag=--debug --test_output=streamed
- // --test_strategy=exclusive --test_timeout=9999 --nocache_test_results
- public static final String JAVA_TEST_DEBUG = "--java_debug";
- // Tells the Java wrapper stub to launch JVM in remote debugging mode, waiting for a connection
- public static final String JAVA_BINARY_DEBUG = "--debug";
- // Runs tests locally, in sequence (rather than parallel), and streams their results to stdout.
- public static final String TEST_OUTPUT_STREAMED = "--test_output=streamed";
- // Filters the unit tests that are run (used with regexp for Java/Robolectric tests).
- public static final String TEST_FILTER = "--test_filter";
- // Skips checking for output file modifications (reduced statting -> faster).
- public static final String NO_CHECK_OUTPUTS = "--noexperimental_check_output_files";
- // Ignores implicit dependencies (e.g. java_library rules depending implicitly on
- // "//transconsole/tools:aggregate_messages" in order to support translations).
- public static final String NO_IMPLICIT_DEPS = "--noimplicit_deps";
- // Ignores host dependencies.
- public static final String NO_HOST_DEPS = "--nohost_deps";
- // When used with mobile-install, deploys the an app incrementally.
- public static final String INCREMENTAL = "--incremental";
- // When used with mobile-install, deploys the an app incrementally
- // can be used for API 23 or higher, for which it is preferred to --incremental
- public static final String SPLIT_APKS = "--split_apks";
- // Re-run the test even if the results are cached.
- public static final String NO_CACHE_TEST_RESULTS = "--nocache_test_results";
- // Avoids node GC between ide_build_info and blaze build
- public static final String VERSION_WINDOW_FOR_DIRTY_NODE_GC =
- "--version_window_for_dirty_node_gc=-1";
-
- public static final String EXPERIMENTAL_SHOW_ARTIFACTS =
- "--experimental_show_artifacts";
-
- public static List<String> buildFlags(Project project, ProjectViewSet projectViewSet) {
- BuildSystem buildSystem = Blaze.getBuildSystem(project);
- List<String> flags = Lists.newArrayList();
- for (BuildFlagsProvider buildFlagsProvider : BuildFlagsProvider.EP_NAME.getExtensions()) {
- buildFlagsProvider.addBuildFlags(buildSystem, projectViewSet, flags);
- }
- flags.addAll(projectViewSet.listItems(BuildFlagsSection.KEY));
- return flags;
- }
-
- // Pass-through arg for sending adb options during mobile-install.
- public static final String ADB_ARG = "--adb_arg=";
-
- public static ImmutableList<String> adbSerialFlags(String serial) {
- return ImmutableList.of(ADB_ARG + "-s ", ADB_ARG + serial);
- }
-
- // Pass-through arg for sending test arguments.
- public static final String TEST_ARG = "--test_arg=";
-
- private static final String TOOL_TAG = "--tool_tag=ijwb:";
-
- // We add this to every single BlazeCommand instance. It's for tracking usage.
- public static String getToolTagFlag() {
- String platformPrefix = PlatformUtils.getPlatformPrefix();
-
- // IDEA Community Edition is "Idea", whereas IDEA Ultimate Edition is "idea". That's dumb. Let's make them more useful.
- if (PlatformUtils.isIdeaCommunity()) {
- platformPrefix = "IDEA:community";
- } else if (PlatformUtils.isIdeaUltimate()) {
- platformPrefix = "IDEA:ultimate";
- }
- return TOOL_TAG + platformPrefix;
- }
-
- public static String testFilterFlagForClass(String className) {
- return testFilterFlagForClassAndMethod(className, null);
- }
-
- public static String testFilterFlagForClassAndMethod(String className, @Nullable String methodName) {
- StringBuilder output = new StringBuilder(TEST_FILTER);
- output.append('=');
- output.append(className);
-
- if (!Strings.isNullOrEmpty(methodName)) {
- output.append('#');
- output.append(methodName);
- }
-
- return output.toString();
- }
-
- private BlazeFlags() {
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/BlazeQuery.java b/blaze-base/src/com/google/idea/blaze/base/command/BlazeQuery.java
deleted file mode 100644
index cb5c583..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/BlazeQuery.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.OutputStream;
-
-/**
- * Code for issuing a blaze query.
- */
-public class BlazeQuery {
-
- public static void query(
- @NotNull final Project project,
- @NotNull BlazeContext context,
- @NotNull final String query,
- @NotNull OutputStream stdout) {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project)
- .getImportSettings();
- assert importSettings != null;
- final WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
-
- final BlazeCommand command = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.QUERY)
- .addBlazeFlags(BlazeFlags.KEEP_GOING, BlazeFlags.NO_IMPLICIT_DEPS, BlazeFlags.NO_HOST_DEPS)
- .addBlazeFlags(query)
- .build();
-
- ExternalTask.builder(workspaceRoot, command)
- .context(context)
- .stdout(stdout)
- .stderr(LineProcessingOutputStream.of(new IssueOutputLineProcessor(project, context, workspaceRoot)))
- .build()
- .run();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/BuildFlagsProvider.java b/blaze-base/src/com/google/idea/blaze/base/command/BuildFlagsProvider.java
deleted file mode 100644
index 2533bdc..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/BuildFlagsProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-import java.util.List;
-
-/**
- * Provides additional build flags for bazel/blaze commands.
- */
-public interface BuildFlagsProvider {
-
- ExtensionPointName<BuildFlagsProvider> EP_NAME = ExtensionPointName
- .create("com.google.idea.blaze.BuildFlagsProvider");
-
- void addBuildFlags(BuildSystem buildSystem, ProjectViewSet projectViewSet, List<String> flags);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java b/blaze-base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
deleted file mode 100644
index f6c3a7f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.experiments.IntExperiment;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-
-import java.util.List;
-
-import static com.google.idea.blaze.base.command.BlazeFlags.NO_CHECK_OUTPUTS;
-import static com.google.idea.blaze.base.command.BlazeFlags.VERSION_WINDOW_FOR_DIRTY_NODE_GC;
-
-/**
- * Flags added to blaze/bazel build commands.
- */
-public class BuildFlagsProviderImpl implements BuildFlagsProvider {
-
- private static final BoolExperiment EXPERIMENT_USE_VERSION_WINDOW_FOR_DIRTY_NODE_GC =
- new BoolExperiment("ide_build_info.use_version_window_for_dirty_node_gc", false);
- private static final BoolExperiment EXPERIMENT_NO_EXPERIMENTAL_CHECK_OUTPUT_FILES =
- new BoolExperiment("build.noexperimental_check_output_files", false);
- private static final IntExperiment EXPERIMENT_MIN_PKG_COUNT_FOR_CT_NODE_EVICTION =
- new IntExperiment("min_pkg_count_for_ct_node_eviction", 0);
-
- // Avoids blaze state invalidation from non-overlapping transitive closures
- // This is caused by our search for the android_sdk
- private static final String MIN_PKG_COUNT_FOR_CT_NODE_EVICTION =
- "--min_pkg_count_for_ct_node_eviction=";
-
- private static String minPkgCountForCtNodeEviction(int value) {
- return MIN_PKG_COUNT_FOR_CT_NODE_EVICTION + value;
- }
-
- @Override
- public void addBuildFlags(BuildSystem buildSystem, ProjectViewSet projectViewSet, List<String> flags) {
- if (EXPERIMENT_USE_VERSION_WINDOW_FOR_DIRTY_NODE_GC.getValue()) {
- flags.add(VERSION_WINDOW_FOR_DIRTY_NODE_GC);
- }
- if (EXPERIMENT_NO_EXPERIMENTAL_CHECK_OUTPUT_FILES.getValue()) {
- flags.add(NO_CHECK_OUTPUTS);
- }
- int minPkgCountForCtNodeEviction = EXPERIMENT_MIN_PKG_COUNT_FOR_CT_NODE_EVICTION.getValue();
- if (minPkgCountForCtNodeEviction > 0) {
- flags.add(minPkgCountForCtNodeEviction(minPkgCountForCtNodeEviction));
- }
- }
-
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java b/blaze-base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java
deleted file mode 100644
index b8d82d2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Collects the output of --experimental_show_artifacts
- */
-public class ExperimentalShowArtifactsLineProcessor implements LineProcessingOutputStream.LineProcessor {
- private static final String OUTPUT_START = "Build artifacts:";
- private static final String OUTPUT_MARKER = ">>>";
-
- final List<File> fileList;
- private final String fileType;
- boolean insideBuildResult = false;
-
- public ExperimentalShowArtifactsLineProcessor(List<File> fileList,
- String fileType) {
- this.fileList = fileList;
- this.fileType = fileType;
- }
-
- @Override
- public boolean processLine(@NotNull String line) {
- if (insideBuildResult) {
- // Workaround for --experimental_ui: Extra newlines are inserted
- if (line.isEmpty()) {
- return false;
- }
-
- insideBuildResult = line.startsWith(OUTPUT_MARKER);
- if (insideBuildResult) {
- String fileName = line.substring(OUTPUT_MARKER.length());
- if (fileName.endsWith(fileType)) {
- fileList.add(new File(fileName));
- }
- }
- }
- if (!insideBuildResult) {
- insideBuildResult = line.equals(OUTPUT_START);
- }
- return !insideBuildResult;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java b/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java
deleted file mode 100644
index 510d042..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command.info;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.components.ServiceManager;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * Runs the blaze info command. The results may be cached in the workspace.
- */
-public abstract class BlazeInfo {
- public static final String EXECUTION_ROOT_KEY = "execution_root";
- public static final String PACKAGE_PATH_KEY = "package_path";
- public static final String BUILD_LANGUAGE = "build-language";
-
- public static String blazeBinKey(BuildSystem buildSystem) {
- switch (buildSystem) {
- case Blaze:
- return "blaze-bin";
- case Bazel:
- return "bazel-bin";
- default:
- throw new IllegalArgumentException("Unrecognized build system: " + buildSystem);
- }
- }
-
- public static String blazeGenfilesKey(BuildSystem buildSystem) {
- switch (buildSystem) {
- case Blaze:
- return "blaze-genfiles";
- case Bazel:
- return "bazel-genfiles";
- default:
- throw new IllegalArgumentException("Unrecognized build system: " + buildSystem);
- }
- }
-
- public static BlazeInfo getInstance() {
- return ServiceManager.getService(BlazeInfo.class);
- }
-
- /**
- * @param blazeFlags The blaze flags that will be passed to Blaze.
- * @param key The key passed to blaze info
- * @return The blaze info value associated with the specified key
- */
- public abstract ListenableFuture<String> runBlazeInfo(
- @Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags,
- String key);
-
- /**
- * @param blazeFlags The blaze flags that will be passed to Blaze.
- * @param key The key passed to blaze info
- * @return The blaze info value associated with the specified key
- */
- public abstract ListenableFuture<byte[]> runBlazeInfoGetBytes(
- @Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags,
- String key);
-
- /**
- * This calls blaze info without any specific key so blaze info will return all keys and values that it has. There could be a performance
- * cost for doing this, so the user should verify that calling this method is actually faster than calling
- * {@link #runBlazeInfo(WorkspaceRoot, List, String)}.
- *
- * @param blazeFlags The blaze flags that will be passed to Blaze.
- * @return The blaze info data fields.
- */
- public abstract ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(
- @Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java b/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java
deleted file mode 100644
index aeef5a1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command.info;
-
-import javax.annotation.concurrent.Immutable;
-
-@Immutable
-public final class BlazeInfoException extends Exception {
- private final int exitCode;
- private final String stdout;
- private final String stderr;
-
- public BlazeInfoException(int exitCode, String stdout, String stderr) {
- this.exitCode = exitCode;
- this.stdout = stdout;
- this.stderr = stderr;
- }
-
- @Override
- public String getMessage() {
- return "blaze info failed with exit code: " + exitCode + " and error stream: " + stderr;
- }
-
- public int getExitCode() {
- return exitCode;
- }
-
- public String getStdout() {
- return stdout;
- }
-
- public String getStderr() {
- return stderr;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java b/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java
deleted file mode 100644
index 285f276..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command.info;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import java.io.ByteArrayOutputStream;
-import java.util.List;
-
-public class BlazeInfoImpl extends BlazeInfo {
- private static final Logger LOG = Logger.getInstance(BlazeInfoImpl.class);
-
- @Override
- public ListenableFuture<String> runBlazeInfo(@Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags,
- String key) {
- return BlazeExecutor.getInstance().submit(() -> runBlazeInfo(buildSystem, workspaceRoot, key, blazeFlags, context).toString().trim());
- }
-
- @Override
- public ListenableFuture<byte[]> runBlazeInfoGetBytes(@Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags,
- String key) {
- return BlazeExecutor.getInstance().submit(() -> runBlazeInfo(buildSystem, workspaceRoot, key, blazeFlags, context).toByteArray());
- }
-
- @Override
- public ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(@Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags) {
- return BlazeExecutor.getInstance().submit(() -> {
- String blazeInfoString = runBlazeInfo(buildSystem, workspaceRoot, null /* key */, blazeFlags, context).toString().trim();
- return parseBlazeInfoResult(blazeInfoString);
- });
- }
-
- private static ByteArrayOutputStream runBlazeInfo(
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- @Nullable String key,
- List<String> blazeFlags,
- @Nullable BlazeContext context) throws BlazeInfoException {
- BlazeCommand.Builder builder = BlazeCommand.builder(buildSystem, BlazeCommandName.INFO);
- if (key != null) {
- builder.addBlazeFlags(key);
- }
- BlazeCommand command = builder.addBlazeFlags(blazeFlags).build();
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
- int exitCode = ExternalTask.builder(workspaceRoot, command)
- .context(context)
- .stdout(stdout)
- .stderr(stderr)
- .build()
- .run();
- if (exitCode != 0) {
- throw new BlazeInfoException(exitCode, stdout.toString(), stderr.toString());
- }
- return stdout;
- }
-
- private static ImmutableMap<String, String> parseBlazeInfoResult(String blazeInfoString) {
- ImmutableMap.Builder<String, String> blazeInfoMapBuilder = ImmutableMap.builder();
- String[] blazeInfoLines = blazeInfoString.split("\n");
- for (String blazeInfoLine : blazeInfoLines) {
- // Just split on the first ":".
- String[] keyValue = blazeInfoLine.split(":", 2);
- LOG.assertTrue(keyValue.length == 2, blazeInfoLine);
- String key = keyValue[0].trim();
- String value = keyValue[1].trim();
- blazeInfoMapBuilder.put(key, value);
- }
- return blazeInfoMapBuilder.build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java b/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
deleted file mode 100644
index 3a92c75..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.console;
-
-import com.intellij.execution.ui.ConsoleViewContentType;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Prints text to the blaze console.
- */
-public interface BlazeConsoleService {
- static BlazeConsoleService getInstance(@NotNull Project project) {
- return ServiceManager.getService(project, BlazeConsoleService.class);
- }
-
- void print(@NotNull String text, @NotNull ConsoleViewContentType contentType);
-
- void clear();
-
- void setStopHandler(@Nullable Runnable runnable);
-
- void activateConsoleWindow();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java b/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
deleted file mode 100644
index 61e8826..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.console;
-
-import com.intellij.execution.ui.ConsoleViewContentType;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.openapi.wm.ToolWindowManager;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Implementation for BlazeConsoleService
- */
-public class BlazeConsoleServiceImpl implements BlazeConsoleService {
- @NotNull private final Project project;
- @NotNull private final BlazeConsoleView blazeConsoleView;
-
- BlazeConsoleServiceImpl(@NotNull Project project) {
- this.project = project;
- blazeConsoleView = BlazeConsoleView.getInstance(project);
- }
-
- @Override
- public void print(@NotNull String text, @NotNull ConsoleViewContentType contentType) {
- blazeConsoleView.print(text, contentType);
- }
-
- @Override
- public void clear() {
- blazeConsoleView.clear();
- }
-
- @Override
- public void setStopHandler(@Nullable Runnable runnable) {
- blazeConsoleView.setStopHandler(runnable);
- }
-
- @Override
- public void activateConsoleWindow() {
- ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(
- BlazeConsoleToolWindowFactory.ID);
- if (toolWindow != null) {
- toolWindow.activate(null);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleToolWindowFactory.java b/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleToolWindowFactory.java
deleted file mode 100644
index 2ff82fa..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleToolWindowFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.console;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.openapi.wm.ToolWindowFactory;
-import org.jetbrains.annotations.NotNull;
-
-public class BlazeConsoleToolWindowFactory implements DumbAware, ToolWindowFactory {
-
- public static final String ID = "Blaze Console";
-
- @Override
- public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
- String title = Blaze.buildSystemName(project) + " Console";
- toolWindow.setTitle(title);
- toolWindow.setStripeTitle(title);
- BlazeConsoleView.getInstance(project).createToolWindowContent(toolWindow);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java b/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
deleted file mode 100644
index ebbb630..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.console;
-
-import com.intellij.codeEditor.printing.PrintAction;
-import com.intellij.execution.impl.ConsoleViewImpl;
-import com.intellij.execution.ui.ConsoleViewContentType;
-import com.intellij.execution.ui.RunnerLayoutUi;
-import com.intellij.execution.ui.layout.PlaceInGrid;
-import com.intellij.icons.AllIcons;
-import com.intellij.ide.IdeBundle;
-import com.intellij.ide.actions.NextOccurenceToolbarAction;
-import com.intellij.ide.actions.PreviousOccurenceToolbarAction;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.DumbAwareAction;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.ui.content.Content;
-import com.intellij.ui.content.ContentFactory;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-
-public class BlazeConsoleView implements Disposable {
-
- private static final Class<?>[] IGNORED_CONSOLE_ACTION_TYPES =
- {PreviousOccurenceToolbarAction.class, NextOccurenceToolbarAction.class,
- ConsoleViewImpl.ClearAllAction.class, PrintAction.class};
-
- @NotNull
- private final Project myProject;
- @NotNull
- private final ConsoleViewImpl myConsoleView;
-
- private JPanel myConsolePanel;
- private volatile Runnable myStopHandler;
-
- public BlazeConsoleView(@NotNull Project project) {
- myProject = project;
- myConsoleView = new ConsoleViewImpl(myProject, false);
- Disposer.register(this, myConsoleView);
- setupUI();
- }
-
- public static BlazeConsoleView getInstance(@NotNull Project project) {
- return ServiceManager.getService(project, BlazeConsoleView.class);
- }
-
- public void setStopHandler(@Nullable Runnable stopHandler) {
- myStopHandler = stopHandler;
- }
-
- private static boolean shouldIgnoreAction(@NotNull AnAction action) {
- for (Class<?> actionType : IGNORED_CONSOLE_ACTION_TYPES) {
- if (actionType.isInstance(action)) {
- return true;
- }
- }
- return false;
- }
-
- public void createToolWindowContent(@NotNull ToolWindow toolWindow) {
- //Create runner UI layout
- RunnerLayoutUi.Factory factory = RunnerLayoutUi.Factory.getInstance(myProject);
- RunnerLayoutUi layoutUi = factory.create("", "", "session", myProject);
-
- Content console = layoutUi.createContent(BlazeConsoleToolWindowFactory.ID, myConsoleView.getComponent(), "", null, null);
- layoutUi.addContent(console, 0, PlaceInGrid.right, false);
-
- // Adding actions
- DefaultActionGroup group = new DefaultActionGroup();
- layoutUi.getOptions().setLeftToolbar(group, ActionPlaces.UNKNOWN);
-
- AnAction[] consoleActions = myConsoleView.createConsoleActions();
- for (AnAction action : consoleActions) {
- if (!shouldIgnoreAction(action)) {
- group.add(action);
- }
- }
- group.add(new StopAction());
-
- JComponent layoutComponent = layoutUi.getComponent();
- myConsolePanel.add(layoutComponent, BorderLayout.CENTER);
-
- //noinspection ConstantConditions
- Content content =
- ContentFactory.SERVICE.getInstance().createContent(layoutComponent, null, true);
- toolWindow.getContentManager().addContent(content);
- }
-
- public void clear() {
- myConsoleView.clear();
- }
-
- public void print(@NotNull String text, @NotNull ConsoleViewContentType contentType) {
- myConsoleView.print(text, contentType);
- }
-
- @Override
- public void dispose() {
- }
-
- private void setupUI() {
- myConsolePanel = new JPanel();
- myConsolePanel.setLayout(new BorderLayout(0, 0));
- }
-
- private class StopAction extends DumbAwareAction {
- public StopAction() {
- super(IdeBundle.message("action.stop"), null, AllIcons.Actions.Suspend);
- }
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- Runnable handler = myStopHandler;
- if (handler != null) {
- handler.run();
- myStopHandler = null;
- }
- }
-
- @Override
- public void update(AnActionEvent event) {
- Presentation presentation = event.getPresentation();
- boolean isNowVisible = myStopHandler != null;
- if (presentation.isEnabled() != isNowVisible) {
- presentation.setEnabled(isNowVisible);
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/BoolExperiment.java b/blaze-base/src/com/google/idea/blaze/base/experiments/BoolExperiment.java
deleted file mode 100644
index 98da296..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/BoolExperiment.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Boolean-valued experiment.
- */
-public class BoolExperiment extends Experiment {
- private final boolean defaultValue;
-
- public BoolExperiment(@NotNull String key, boolean defaultValue) {
- super(key);
- this.defaultValue = defaultValue;
- }
-
- public boolean getValue() {
- return ExperimentService.getInstance().getExperiment(key, defaultValue);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/DevOverride.java b/blaze-base/src/com/google/idea/blaze/base/experiments/DevOverride.java
deleted file mode 100644
index d990178..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/DevOverride.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Developer override for string experiments.
- */
-public class DevOverride extends Experiment {
- private final String defaultValue;
-
- public DevOverride(@NotNull String key, @NotNull String defaultValue) {
- super(key);
- this.defaultValue = defaultValue;
- }
-
- @NotNull
- public String getValue() {
- return ExperimentService.getInstance().getExperimentString(key, defaultValue);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/DeveloperFlag.java b/blaze-base/src/com/google/idea/blaze/base/experiments/DeveloperFlag.java
deleted file mode 100644
index 6813bde..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/DeveloperFlag.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * This is an experiment that always defaults to off. Use to document that this is for devs only.
- */
-public class DeveloperFlag extends BoolExperiment {
- public DeveloperFlag(@NotNull String key) {
- super(key, false);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/Experiment.java b/blaze-base/src/com/google/idea/blaze/base/experiments/Experiment.java
deleted file mode 100644
index a320391..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/Experiment.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.intellij.openapi.components.ServiceManager;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Experiment class.
- */
-public abstract class Experiment {
- @NotNull protected final String key;
-
- protected Experiment(@NotNull String key) {
- this.key = key;
- }
-
- public String getKey() {
- return key;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentLoader.java b/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentLoader.java
deleted file mode 100644
index b9450c8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentLoader.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Map;
-
-interface ExperimentLoader {
- Map<String, String> getExperiments();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentScope.java b/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentScope.java
deleted file mode 100644
index 3787678..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentScope.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Reloads experiments at the start of the scope.
- */
-public class ExperimentScope implements BlazeScope {
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- ExperimentService.getInstance().reloadExperiments();
- ExperimentService.getInstance().startExperimentScope();
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- ExperimentService.getInstance().endExperimentScope();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentService.java b/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentService.java
deleted file mode 100644
index 4a80be3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentService.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.intellij.openapi.components.ServiceManager;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Reads experiments.
- */
-public interface ExperimentService {
-
- static ExperimentService getInstance() {
- return ServiceManager.getService(ExperimentService.class);
- }
-
- /**
- * Returns an experiment if it exists, else defaultValue
- */
- boolean getExperiment(@NotNull String key, boolean defaultValue);
-
- /**
- * Returns a string-valued experiment if it exists, else defaultValue.
- */
- String getExperimentString(@NotNull String key, @Nullable String defaultValue);
-
- /**
- * Returns an int-valued experiment if it exists, else defaultValue.
- */
- int getExperimentInt(@NotNull String key, int defaultValue);
-
- /**
- * Reloads all experiments.
- */
- void reloadExperiments();
-
- /**
- * Starts an experiment scope. During an experiment scope,
- * experiments won't be reloaded.
- */
- void startExperimentScope();
-
- /**
- * Ends an experiment scope.
- */
- void endExperimentScope();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentServiceImpl.java b/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentServiceImpl.java
deleted file mode 100644
index 2c2911d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/ExperimentServiceImpl.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.SystemProperties;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * An experiment service that delegates to {@link ExperimentLoader ExperimentLoaders}, in a
- * specific order.
- *
- * It will check system properties first, then an experiment file in the user's home directory, then
- * finally all files specified by the system property blaze.experiments.file.
- */
-public class ExperimentServiceImpl implements ExperimentService {
- private static final Logger LOG = Logger.getInstance(ExperimentServiceImpl.class);
-
- private static final String USER_EXPERIMENT_OVERRIDES_FILE =
- SystemProperties.getUserHome() + File.separator + ".blaze-experiments";
-
- private final List<ExperimentLoader> services;
- private Map<String, String> experiments;
- private AtomicInteger experimentScopeCounter = new AtomicInteger(0);
-
- public ExperimentServiceImpl() {
- this(
- new SystemPropertyExperimentLoader(),
- new FileExperimentLoader(USER_EXPERIMENT_OVERRIDES_FILE),
- new WebExperimentLoader());
- }
-
- @VisibleForTesting
- protected ExperimentServiceImpl(ExperimentLoader... loaders) {
- services = ImmutableList.copyOf(loaders);
- }
-
- @Override
- public synchronized void reloadExperiments() {
- if (experimentScopeCounter.get() > 0) {
- return;
- }
-
- Map<String, String> experiments = Maps.newHashMap();
- for (ExperimentLoader loader : Lists.reverse(services)) {
- experiments.putAll(loader.getExperiments());
- }
- this.experiments = experiments;
- }
-
- @Override
- public synchronized void startExperimentScope() {
- this.experimentScopeCounter.incrementAndGet();
- }
-
- @Override
- public synchronized void endExperimentScope() {
- int value = this.experimentScopeCounter.decrementAndGet();
- LOG.assertTrue(value >= 0);
- }
-
- @Override
- public boolean getExperiment(@NotNull String key, boolean defaultValue) {
- String property = getExperiment(key);
- return property != null ? property.equals("1") : defaultValue;
- }
-
- @Override
- public String getExperimentString(@NotNull String key, String defaultValue) {
- String property = getExperiment(key);
- return property != null ? property : defaultValue;
- }
-
- @Override
- public int getExperimentInt(@NotNull String key, int defaultValue) {
- String property = getExperiment(key);
- try {
- return property != null ? Integer.parseInt(property) : defaultValue;
- } catch (NumberFormatException e) {
- LOG.warn("Could not parse int for experiment: " + key, e);
- return defaultValue;
- }
- }
-
- String getExperiment(@NotNull String key) {
- if (experiments == null) {
- reloadExperiments();
- }
- LOG.assertTrue(experiments != null, "Failure to load experiments.");
- return experiments.get(key);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/FileExperimentLoader.java b/blaze-base/src/com/google/idea/blaze/base/experiments/FileExperimentLoader.java
deleted file mode 100644
index 07d5f55..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/FileExperimentLoader.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.intellij.openapi.diagnostic.Logger;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * Reads experiments from a property file.
- */
-class FileExperimentLoader implements ExperimentLoader {
-
- private static final Logger LOG = Logger.getInstance(FileExperimentLoader.class);
-
- private final String filename;
-
- public FileExperimentLoader(String filename) {
- this.filename = filename;
- }
-
- @Override
- public Map<String, String> getExperiments() {
- Properties properties = new Properties();
-
- File file = new File(filename);
- if (!file.exists()) {
- LOG.info("File " + filename + " does not exist, skipping.");
- return ImmutableMap.of();
- }
-
- Map<String, String> result = Maps.newHashMap();
- try (InputStream inputStream = new FileInputStream(filename)) {
- properties.load(inputStream);
- Enumeration<?> enumeration = properties.propertyNames();
- while (enumeration.hasMoreElements()) {
- String key = (String)enumeration.nextElement();
- String value = properties.getProperty(key);
- result.put(key, value);
- }
- } catch (IOException e) {
- LOG.warn("Could not load experiments from file: " + filename, e);
- }
- return result;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/IntExperiment.java b/blaze-base/src/com/google/idea/blaze/base/experiments/IntExperiment.java
deleted file mode 100644
index 412e6f1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/IntExperiment.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Integer valued experiment.
- */
-public class IntExperiment extends Experiment {
- private final int defaultValue;
-
- public IntExperiment(@NotNull String key, int defaultValue) {
- super(key);
- this.defaultValue = defaultValue;
- }
-
- public int getValue() {
- return ExperimentService.getInstance().getExperimentInt(key, defaultValue);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/StringExperiment.java b/blaze-base/src/com/google/idea/blaze/base/experiments/StringExperiment.java
deleted file mode 100644
index b881bf1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/StringExperiment.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * String-valued experiment.
- */
-public class StringExperiment extends Experiment {
-
- public StringExperiment(@NotNull String key) {
- super(key);
- }
-
- @Nullable
- public String getValue() {
- return ExperimentService.getInstance().getExperimentString(key, null);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/SystemPropertyExperimentLoader.java b/blaze-base/src/com/google/idea/blaze/base/experiments/SystemPropertyExperimentLoader.java
deleted file mode 100644
index 8a02670..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/SystemPropertyExperimentLoader.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.collect.ImmutableMap;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Map;
-
-class SystemPropertyExperimentLoader implements ExperimentLoader {
- private static final String BLAZE_EXPERIMENT_OVERRIDE = "blaze.experiment.";
-
- @Override
- public Map<String, String> getExperiments() {
- // Cache the current values of the experiments so that they don't change in the
- // current ExperimentScope.
- ImmutableMap.Builder<String, String> mapBuilder = ImmutableMap.builder();
- System.getProperties()
- .stringPropertyNames()
- .stream()
- .filter(name -> name.startsWith(BLAZE_EXPERIMENT_OVERRIDE))
- .forEach(
- name ->
- mapBuilder.put(
- name.substring(BLAZE_EXPERIMENT_OVERRIDE.length()), System.getProperty(name)));
- return mapBuilder.build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/WebExperimentLoader.java b/blaze-base/src/com/google/idea/blaze/base/experiments/WebExperimentLoader.java
deleted file mode 100644
index 67e51f3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/WebExperimentLoader.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.collect.ImmutableMap;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Map;
-
-class WebExperimentLoader implements ExperimentLoader {
- @Override
- public Map<String, String> getExperiments() {
- return WebExperimentSyncer.getInstance().getExperimentValues();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/experiments/WebExperimentSyncer.java b/blaze-base/src/com/google/idea/blaze/base/experiments/WebExperimentSyncer.java
deleted file mode 100644
index e4675f9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/experiments/WebExperimentSyncer.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListenableScheduledFuture;
-import com.google.common.util.concurrent.ListeningScheduledExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.gson.JsonParseException;
-import com.google.idea.blaze.base.util.SerializationUtil;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.io.HttpRequests;
-import org.jetbrains.io.JsonReaderEx;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.*;
-
-/**
- * A singleton class that retrieves the experiments from the experiments service</a>.
- *
- * The first time {@link #getExperimentValues()} is called, fresh data will be retrieved in the
- * current thread. Thereafter, data will be retrieved every 5 minutes in a background thread. If
- * there is a failure retrieving data, new attempts will be made every minute.
- */
-class WebExperimentSyncer {
- private static final String DEFAULT_EXPERIMENT_URL =
- "https://intellij-experiments.appspot.com/api/experiments";
- private static final String EXPERIMENTS_URL_PROPERTY = "blaze.experiments.url";
-
- private static final int SUCESSFUL_DOWNLOAD_DELAY_MINUTES = 5;
- private static final int DOWNLOAD_FAILURE_DELAY_MINUTES = 1;
-
- private static final String CACHE_FILE_NAME = "blaze.experiments.cache.dat";
-
- private static final Logger LOG = Logger.getInstance(WebExperimentSyncer.class);
-
- private static final WebExperimentSyncer INSTANCE = new WebExperimentSyncer();
-
- // null indicates no fetch attempt has been made. After the first attempt, this will always be a
- // (possibly empty) map.
- private Map<String, String> experimentValues = null;
-
- private ListeningScheduledExecutorService executor =
- MoreExecutors.listeningDecorator(
- MoreExecutors.getExitingScheduledExecutorService(
- new ScheduledThreadPoolExecutor(1), 0, TimeUnit.SECONDS));
-
- private WebExperimentSyncer() {}
-
- public static WebExperimentSyncer getInstance() {
- return INSTANCE;
- }
-
- /**
- * Get the last-retrieved set of experiment values.
- *
- * The first time this method is called, an attempt to retrieve the values will take place.
- * Thereafter, the values will be retrieved every five minutes on a background thread and this
- * method will return the most recent successfully retrieved values.
- */
- public synchronized Map<String, String> getExperimentValues() {
- if (experimentValues == null) {
- initialize();
- }
-
- return experimentValues;
- }
-
- private synchronized void setExperimentValues(HashMap<String, String> experimentValues) {
- this.experimentValues = experimentValues;
- saveCache(experimentValues);
- }
-
- /**
- * Fetch and process the experiments on the current thread.
- */
- private void initialize() {
- ListenableFuture<String> response =
- MoreExecutors.sameThreadExecutor().submit(new WebExperimentsDownloader());
- response.addListener(
- new WebExperimentsResultProcessor(response, false), MoreExecutors.sameThreadExecutor());
-
- // Failed to fetch, try to load cache from disk
- if (experimentValues == null) {
- experimentValues = loadCache();
- }
-
- // There must have been an error retrieving the experiments.
- if (experimentValues == null) {
- experimentValues = ImmutableMap.of();
- }
- }
-
- private void scheduleNextRefresh(boolean refreshWasSuccessful) {
- int delayInMinutes =
- refreshWasSuccessful ? SUCESSFUL_DOWNLOAD_DELAY_MINUTES : DOWNLOAD_FAILURE_DELAY_MINUTES;
- ListenableScheduledFuture<String> refreshResults =
- executor.schedule(new WebExperimentsDownloader(), delayInMinutes, TimeUnit.MINUTES);
- refreshResults.addListener(
- new WebExperimentsResultProcessor(refreshResults, true), MoreExecutors.sameThreadExecutor());
- }
-
- private static class WebExperimentsDownloader implements Callable<String> {
-
- @Override
- public String call() throws Exception {
- LOG.debug("About to fetch experiments.");
- return HttpRequests.request(
- System.getProperty(EXPERIMENTS_URL_PROPERTY, DEFAULT_EXPERIMENT_URL))
- .readString(null /* progress indicator */);
- }
- }
-
- private class WebExperimentsResultProcessor implements Runnable {
-
- private final Future<String> resultFuture;
- private final boolean triggerExperimentsReload;
-
- private WebExperimentsResultProcessor(Future<String> resultFuture,
- boolean triggerExperimentsReload) {
- this.resultFuture = resultFuture;
- this.triggerExperimentsReload = triggerExperimentsReload;
- }
-
- @Override
- public void run() {
- LOG.debug("Experiments fetched. Processing results.");
- try {
- HashMap<String, String> mapBuilder = Maps.newHashMap();
- String result = resultFuture.get();
- try (JsonReaderEx reader = new JsonReaderEx(result)) {
- reader.beginObject();
- while (reader.hasNext()) {
- String experimentName = reader.nextName();
- String experimentValue = reader.nextString();
- mapBuilder.put(experimentName, experimentValue);
- }
- }
- setExperimentValues(mapBuilder);
-
- if (triggerExperimentsReload) {
- ExperimentService.getInstance().reloadExperiments();
- }
- LOG.debug("Successfully fetched experiments: " + getExperimentValues());
- scheduleNextRefresh(true /* refreshWasSuccessful */);
- } catch (InterruptedException | ExecutionException | JsonParseException e) {
- LOG.debug("Error fetching experiments", e);
- scheduleNextRefresh(false /* refreshWasSuccessful */);
- }
- }
- }
-
- private static void saveCache(HashMap<String, String> experiments) {
- try {
- SerializationUtil.saveToDisk(getCacheFile(), experiments);
- } catch (IOException e) {
- LOG.warn("Could not save experiments cache to disk: " + getCacheFile());
- }
- }
-
- @SuppressWarnings("unchecked")
- private static HashMap<String, String> loadCache() {
- try {
- return (HashMap<String, String>)SerializationUtil.loadFromDisk(getCacheFile(), ImmutableList.of());
- }
- catch (IOException e) {
- // This is normal, we might be offline and have never loaded the cache.
- LOG.info("Could not load experiments file: " + getCacheFile());
- }
- return null;
- }
-
- private static File getCacheFile() {
- return new File(new File(PathManager.getSystemPath(), "blaze"), CACHE_FILE_NAME).getAbsoluteFile();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/help/BlazeHelpHandler.java b/blaze-base/src/com/google/idea/blaze/base/help/BlazeHelpHandler.java
deleted file mode 100644
index 145748c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/help/BlazeHelpHandler.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.help;
-
-import com.intellij.openapi.components.ServiceManager;
-
-/**
- * Handles help requests.
- */
-public interface BlazeHelpHandler {
- static BlazeHelpHandler getInstance() {
- return ServiceManager.getService(BlazeHelpHandler.class);
- }
-
- void handleHelp(String urlFragment);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazePackageAction.java b/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazePackageAction.java
deleted file mode 100644
index 3471e5f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazePackageAction.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ide;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.buildmodifier.BuildFileModifier;
-import com.google.idea.blaze.base.buildmodifier.FileSystemModifier;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.ScopedOperation;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.output.StatusOutput;
-import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.projectview.ImportRoots;
-import com.intellij.history.LocalHistory;
-import com.intellij.history.LocalHistoryAction;
-import com.intellij.ide.IdeView;
-import com.intellij.ide.util.DirectoryChooserUtil;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
-import com.intellij.util.PlatformIcons;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class NewBlazePackageAction extends BlazeAction implements DumbAware {
- private static final Logger LOG = Logger.getInstance(NewBlazePackageAction.class);
-
- private static final String BUILD_FILE_NAME = "BUILD";
-
- public NewBlazePackageAction() {
- super();
- }
-
- @Override
- public void actionPerformed(AnActionEvent event) {
- final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
- final Project project = event.getData(CommonDataKeys.PROJECT);
- Scope.root(new ScopedOperation() {
- @Override
- public void execute(@NotNull final BlazeContext context) {
- context.push(new LoggedTimingScope(project, Action.CREATE_BLAZE_PACKAGE));
-
- if (view == null || project == null) {
- return;
- }
- PsiDirectory directory = getOrChooseDirectory(project, view);
-
- if (directory == null) {
- return;
- }
-
- NewBlazePackageDialog newBlazePackageDialog = new NewBlazePackageDialog(project, directory);
- boolean isOk = newBlazePackageDialog.showAndGet();
- if (!isOk) {
- return;
- }
-
- final Label newRule = newBlazePackageDialog.getNewRule();
- final Kind newRuleKind = newBlazePackageDialog.getNewRuleKind();
- // If we returned OK, we should have a non null result
- LOG.assertTrue(newRule != null);
- LOG.assertTrue(newRuleKind != null);
-
- context.output(new StatusOutput(String.format("Setting up a new %s package", Blaze.buildSystemName(project))));
-
- boolean success = createPackageOnDisk(
- project,
- context,
- newRule,
- newRuleKind
- );
-
- if (!success) {
- return;
- }
-
- File newDirectory = WorkspaceRoot.fromProject(project).fileForPath(newRule.blazePackage());
- VirtualFile virtualFile = VfsUtil.findFileByIoFile(newDirectory, true);
- // We just created this file, it should exist
- LOG.assertTrue(virtualFile != null);
- PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
- view.selectElement(psiFile);
- }
- });
- }
-
- private static Boolean createPackageOnDisk(
- @NotNull Project project,
- @NotNull BlazeContext context,
- @NotNull Label newRule,
- @NotNull Kind ruleKind) {
- LocalHistoryAction action;
-
- String actionName = String.format("Creating %s package: %s", Blaze.buildSystemName(project), newRule.toString());
- LocalHistory localHistory = LocalHistory.getInstance();
- action = localHistory.startAction(actionName);
-
- // Create the package + BUILD file + rule
- FileSystemModifier fileSystemModifier = FileSystemModifier.getInstance(project);
- WorkspacePath newWorkspacePath = newRule.blazePackage();
- File newDirectory = fileSystemModifier.makeWorkspacePathDirs(newWorkspacePath);
- if (newDirectory == null) {
- String errorMessage = "Could not create new package directory: " + newWorkspacePath.toString();
- context.output(PrintOutput.error(errorMessage));
- return false;
- }
- File buildFile = fileSystemModifier.createFile(newWorkspacePath, BUILD_FILE_NAME);
- if (buildFile == null) {
- String errorMessage =
- "Could not create new BUILD file in package: " + newWorkspacePath.toString();
- context.output(PrintOutput.error(errorMessage));
- return false;
- }
- BuildFileModifier buildFileModifier = BuildFileModifier.getInstance();
- buildFileModifier.addRule(project, context, newRule, ruleKind);
- action.finish();
-
- return true;
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent event) {
- Presentation presentation = event.getPresentation();
- if (isEnabled(event)) {
- String text = String.format("New %s Package", Blaze.buildSystemName(event.getProject()));
- presentation.setEnabledAndVisible(true);
- presentation.setText(text);
- presentation.setDescription(text);
- presentation.setIcon(PlatformIcons.PACKAGE_ICON);
- } else {
- presentation.setEnabledAndVisible(false);
- }
- }
-
- private boolean isEnabled(AnActionEvent event) {
- Project project = event.getProject();
- IdeView view = event.getData(LangDataKeys.IDE_VIEW);
- if (project == null || view == null) {
- return false;
- }
-
- List<PsiDirectory> directories = filterDirectories(project, view.getDirectories());
- if (directories.isEmpty()) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Filter out directories that do not live under the project's directories.
- */
- private static List<PsiDirectory> filterDirectories(Project project, PsiDirectory[] directories) {
- if (directories.length == 0) {
- return ImmutableList.of();
- }
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- return ImmutableList.of();
- }
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project)).add(projectViewSet).build();
- return Lists.newArrayList(directories).stream()
- .filter(directory -> isUnderProjectViewDirectory(workspaceRoot, importRoots, directory))
- .collect(Collectors.toList());
- }
-
- private static boolean isUnderProjectViewDirectory(WorkspaceRoot workspaceRoot,
- ImportRoots importRoots,
- PsiDirectory directory) {
- VirtualFile virtualFile = directory.getVirtualFile();
- // Ignore jars, etc. and their contents, which are in an ArchiveFileSystem.
- if (!(virtualFile.isInLocalFileSystem())) {
- return false;
- }
- if (!workspaceRoot.isInWorkspace(virtualFile)) {
- return false;
- }
- WorkspacePath workspacePath = workspaceRoot.workspacePathFor(virtualFile);
- return importRoots.rootDirectories().stream()
- .anyMatch(importRoot -> FileUtil.isAncestor(importRoot.relativePath(), workspacePath.relativePath(), false));
- }
-
- @Nullable
- private static PsiDirectory getOrChooseDirectory(Project project, IdeView view) {
- List<PsiDirectory> dirs = filterDirectories(project, view.getDirectories());
- if (dirs.size() == 0) {
- return null;
- }
- if (dirs.size() == 1) {
- return dirs.get(0);
- }
- else {
- return DirectoryChooserUtil.selectDirectory(project, dirs.toArray(new PsiDirectory[dirs.size()]), null, "");
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java b/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
deleted file mode 100644
index d99d254..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ide;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.*;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.CommonBundle;
-import com.intellij.ide.IdeBundle;
-import com.intellij.ide.actions.CreateElementActionBase;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.ui.ValidationInfo;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.ui.components.JBTextField;
-import com.intellij.util.IncorrectOperationException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-import java.util.List;
-
-public class NewBlazePackageDialog extends DialogWrapper {
- private static final Logger LOG = Logger.getInstance(NewBlazePackageDialog.class);
-
- @NotNull private final Project project;
- @NotNull private final PsiDirectory parentDirectory;
-
- @Nullable private Label newRule;
- @Nullable private Kind newRuleKind;
-
- private static final int UI_INDENT_LEVEL = 0;
- private static final int TEXT_FIELD_LENGTH = 40;
- @NotNull private final JPanel component = new JPanel(new GridBagLayout());
- @NotNull private final JBLabel packageLabel = new JBLabel("Package name:");
- @NotNull private final JBTextField packageNameField = new JBTextField(TEXT_FIELD_LENGTH);
- @NotNull private final NewRuleUI newRuleUI = new NewRuleUI(TEXT_FIELD_LENGTH);
-
- public NewBlazePackageDialog(@NotNull Project project,
- @NotNull PsiDirectory currentDirectory) {
- super(project);
- this.project = project;
- this.parentDirectory = currentDirectory;
-
- initializeUI();
- }
-
- private void initializeUI() {
- component.add(packageLabel);
- component.add(packageNameField, UiUtil.getFillLineConstraints(UI_INDENT_LEVEL));
- newRuleUI.fillUI(component, UI_INDENT_LEVEL);
- UiUtil.fillBottom(component);
- init();
- }
-
- @Nullable
- @Override
- protected JComponent createCenterPanel() {
- return component;
- }
-
- @Nullable
- @Override
- protected ValidationInfo doValidate() {
- String packageName = packageNameField.getText();
- if (packageName == null) {
- return new ValidationInfo("Internal error, package was null");
- }
- if (packageName.length() == 0) {
- return new ValidationInfo(
- IdeBundle.message("error.name.should.be.specified"),
- packageNameField
- );
- }
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (!Label.validatePackagePath(packageName, errors)) {
- BlazeValidationError validationResult = errors.get(0);
- return new ValidationInfo(validationResult.getError(), packageNameField);
- }
-
- return newRuleUI.validate();
- }
-
- @Override
- protected void doOKAction() {
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- LOG.assertTrue(parentDirectory.getVirtualFile().isInLocalFileSystem());
- File parentDirectoryFile = new File(parentDirectory.getVirtualFile().getPath());
- String newPackageName = packageNameField.getText();
- File newPackageDirectory = new File(parentDirectoryFile, newPackageName);
- WorkspacePath newPackagePath = workspaceRoot.workspacePathFor(newPackageDirectory);
-
- RuleName newRuleName = newRuleUI.getRuleName();
- Label newRule = new Label(newPackagePath, newRuleName);
- Kind ruleKind = newRuleUI.getSelectedRuleKind();
- try {
- parentDirectory.checkCreateSubdirectory(newPackageName);
- }
- catch (IncorrectOperationException ex) {
- showErrorDialog(CreateElementActionBase.filterMessage(ex.getMessage()));
- // do not close the dialog
- return;
- }
- this.newRule = newRule;
- this.newRuleKind = ruleKind;
- super.doOKAction();
- }
-
- private void showErrorDialog(@NotNull String message) {
- String title = CommonBundle.getErrorTitle();
- Icon icon = Messages.getErrorIcon();
- Messages.showMessageDialog(component, message, title, icon);
- }
-
- @Nullable
- public Label getNewRule() {
- return newRule;
- }
-
- @Nullable
- public Kind getNewRuleKind() {
- return newRuleKind;
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazeRuleAction.java b/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazeRuleAction.java
deleted file mode 100644
index 4efe8d6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazeRuleAction.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ide;
-
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.experiments.ExperimentScope;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.ScopedOperation;
-import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
-import com.google.idea.blaze.base.scope.scopes.IssuesScope;
-import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-
-public class NewBlazeRuleAction extends BlazeAction implements DumbAware {
-
- public NewBlazeRuleAction() {
- super();
- }
-
- @Override
- public void actionPerformed(AnActionEvent event) {
- final Project project = event.getData(CommonDataKeys.PROJECT);
- if (project == null) {
- return;
- }
- final VirtualFile virtualFile = event.getData(CommonDataKeys.VIRTUAL_FILE);
- if (virtualFile == null) {
- return;
- }
-
- Scope.root(new ScopedOperation() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- context
- .push(new ExperimentScope())
- .push(new BlazeConsoleScope.Builder(project).build())
- .push(new IssuesScope(project))
- .push(new LoggedTimingScope(project, Action.CREATE_BLAZE_RULE))
- ;
- NewBlazeRuleDialog newBlazeRuleDialog = new NewBlazeRuleDialog(context, project, virtualFile);
- newBlazeRuleDialog.show();
- }
- });
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent event) {
- Presentation presentation = event.getPresentation();
- DataContext dataContext = event.getDataContext();
- VirtualFile file = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
- Project project = CommonDataKeys.PROJECT.getData(dataContext);
- boolean enabled = (project != null && file != null && file.getName().equals("BUILD"));
- presentation.setVisible(enabled || ActionPlaces.isMainMenuOrActionSearch(event.getPlace()));
- presentation.setEnabled(enabled);
- presentation.setText(getText(project));
- }
-
- private static String getText(@Nullable Project project) {
- String buildSystem = Blaze.buildSystemName(project);
- return String.format("New %s Rule", buildSystem);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java b/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
deleted file mode 100644
index 5cfc981..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ide;
-
-import com.google.idea.blaze.base.buildmodifier.BuildFileModifier;
-import com.google.idea.blaze.base.model.primitives.*;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.openapi.ui.ValidationInfo;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-
-public class NewBlazeRuleDialog extends DialogWrapper {
- private static final Logger LOG = Logger.getInstance(NewBlazeRuleDialog.class);
-
- private static final int UI_INDENT = 0;
- private static final int TEXT_BOX_WIDTH = 40;
-
- private final BlazeContext context;
- private final Project project;
- private final VirtualFile buildFile;
- private final String buildSystemName;
-
- private JPanel component = new JPanel(new GridBagLayout());
- private final NewRuleUI newRuleUI = new NewRuleUI(TEXT_BOX_WIDTH);
- private static final Dimension componentSize = new Dimension(500, 500);
-
- public NewBlazeRuleDialog(BlazeContext context,
- Project project,
- VirtualFile buildFile) {
- super(project);
- this.context = context;
- this.project = project;
- this.buildFile = buildFile;
- this.buildSystemName = Blaze.buildSystemName(project);
- initComponent();
- }
-
- private void initComponent() {
- setTitle(String.format("Create a New %s Rule", buildSystemName));
- setOKButtonText("Create");
- setCancelButtonText("Cancel");
-
- component.setPreferredSize(componentSize);
- component.setMinimumSize(componentSize);
-
- newRuleUI.fillUI(component, UI_INDENT);
- UiUtil.fillBottom(component);
-
- init();
- }
-
- @Nullable
- @Override
- protected JComponent createCenterPanel() {
- return component;
- }
-
- @Nullable
- @Override
- protected ValidationInfo doValidate() {
- return newRuleUI.validate();
- }
-
- @Override
- protected void doOKAction() {
- RuleName ruleName = newRuleUI.getRuleName();
- Kind ruleKind = newRuleUI.getSelectedRuleKind();
-
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- WorkspacePath workspacePath = workspaceRoot.workspacePathFor(new File(buildFile.getParent().getPath()));
- Label newRule = new Label(workspacePath, ruleName);
- BuildFileModifier buildFileModifier = BuildFileModifier.getInstance();
- boolean success = buildFileModifier.addRule(project, context, newRule, ruleKind);
-
- if (success) {
- super.doOKAction();
- }
- else {
- super.setErrorText(String.format("Could not create new rule, see %s Console for details", buildSystemName));
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ide/NewRuleUI.java b/blaze-base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
deleted file mode 100644
index de090d9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ide;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.RuleName;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.ide.IdeBundle;
-import com.intellij.openapi.ui.ComboBox;
-import com.intellij.openapi.ui.ValidationInfo;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.ui.components.JBTextField;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.util.Collection;
-import java.util.List;
-
-final class NewRuleUI {
-
- private static final String[] POSSIBLE_RULES = {
- "android_library",
- "java_library",
- "cc_library",
- "cc_binary",
- "proto_library"
- };
-
- @NotNull private final ComboBox ruleComboBox = new ComboBox(POSSIBLE_RULES);
- @NotNull private final JBLabel ruleNameLabel = new JBLabel("Rule name:");
- @NotNull private final JBTextField ruleNameField;
-
- public NewRuleUI(int textFieldLength) {
- this.ruleNameField = new JBTextField(textFieldLength);
- }
-
- public void fillUI(@NotNull JPanel component, int indentLevel) {
- component.add(ruleNameLabel);
- component.add(ruleNameField, UiUtil.getFillLineConstraints(indentLevel));
- component.add(ruleComboBox, UiUtil.getFillLineConstraints(indentLevel));
- }
-
- @NotNull
- public Kind getSelectedRuleKind() {
- return Kind.fromString((String)ruleComboBox.getSelectedItem());
- }
-
- @NotNull
- public RuleName getRuleName() {
- return RuleName.create(ruleNameField.getText());
- }
-
- @Nullable
- public ValidationInfo validate() {
- String ruleName = ruleNameField.getText();
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (!validateRuleName(ruleName, errors)) {
- BlazeValidationError issue = errors.get(0);
- return new ValidationInfo(issue.getError(), ruleNameField);
- }
- return null;
- }
-
- private static boolean validateRuleName(@NotNull String inputString, @Nullable Collection<BlazeValidationError> errors) {
- if (inputString.length() == 0) {
- BlazeValidationError.collect(errors, new BlazeValidationError(IdeBundle.message("error.name.should.be.specified")));
- return false;
- }
-
- return RuleName.validate(inputString, errors);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/AndroidRuleIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/AndroidRuleIdeInfo.java
deleted file mode 100644
index fa567a5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/AndroidRuleIdeInfo.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * Ide info specific to android rules.
- */
-public final class AndroidRuleIdeInfo implements Serializable {
- private static final long serialVersionUID = 5L;
-
- public final Collection<ArtifactLocation> resources;
- @Nullable public final ArtifactLocation manifest;
- @Nullable public final LibraryArtifact idlJar;
- @Nullable public final LibraryArtifact resourceJar;
- public final boolean hasIdlSources;
- @Nullable public final String resourceJavaPackage;
- public boolean generateResourceClass;
- @Nullable public Label legacyResources;
-
- public AndroidRuleIdeInfo(Collection<ArtifactLocation> resources,
- @Nullable String resourceJavaPackage,
- boolean generateResourceClass,
- @Nullable ArtifactLocation manifest,
- @Nullable LibraryArtifact idlJar,
- @Nullable LibraryArtifact resourceJar,
- boolean hasIdlSources,
- @Nullable Label legacyResources) {
- this.resources = resources;
- this.resourceJavaPackage = resourceJavaPackage;
- this.generateResourceClass = generateResourceClass;
- this.manifest = manifest;
- this.idlJar = idlJar;
- this.resourceJar = resourceJar;
- this.hasIdlSources = hasIdlSources;
- this.legacyResources = legacyResources;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private Collection<ArtifactLocation> resources = Lists.newArrayList();
- private ArtifactLocation manifest;
- private LibraryArtifact idlJar;
- private LibraryArtifact resourceJar;
- private boolean hasIdlSources;
- private String resourceJavaPackage;
- private boolean generateResourceClass;
- private Label legacyResources;
-
- public Builder setManifestFile(ArtifactLocation artifactLocation) {
- this.manifest = artifactLocation;
- return this;
- }
- public Builder addResource(ArtifactLocation artifactLocation) {
- this.resources.add(artifactLocation);
- return this;
- }
- public Builder setIdlJar(LibraryArtifact idlJar) {
- this.idlJar = idlJar;
- return this;
- }
- public Builder setHasIdlSources(boolean hasIdlSources) {
- this.hasIdlSources = hasIdlSources;
- return this;
- }
- public Builder setResourceJar(LibraryArtifact.Builder resourceJar) {
- this.resourceJar = resourceJar.build();
- return this;
- }
- public Builder setResourceJavaPackage(@Nullable String resourceJavaPackage) {
- this.resourceJavaPackage = resourceJavaPackage;
- return this;
- }
- public Builder setGenerateResourceClass(boolean generateResourceClass) {
- this.generateResourceClass = generateResourceClass;
- return this;
- }
- public Builder setLegacyResources(@Nullable Label legacyResources) {
- this.legacyResources = legacyResources;
- return this;
- }
- public AndroidRuleIdeInfo build() {
- if (!resources.isEmpty() || manifest != null) {
- if (!generateResourceClass) {
- throw new IllegalStateException("Must set generateResourceClass if manifest or resources set");
- }
- }
-
- return new AndroidRuleIdeInfo(
- resources,
- resourceJavaPackage,
- generateResourceClass,
- manifest,
- idlJar,
- resourceJar,
- hasIdlSources,
- legacyResources
- );
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
deleted file mode 100644
index f40e633..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.base.Objects;
-
-import java.io.File;
-import java.io.Serializable;
-import java.nio.file.Paths;
-
-/**
- * Represents a blaze-produced artifact.
- */
-public final class ArtifactLocation implements Serializable {
- private static final long serialVersionUID = 2L;
-
- public final String rootPath;
- public final String rootExecutionPathFragment;
- public final String relativePath;
- public final boolean isSource;
-
- private ArtifactLocation(String rootPath,
- String rootExecutionPathFragment,
- String relativePath,
- boolean isSource) {
- this.rootPath = rootPath;
- this.rootExecutionPathFragment = rootExecutionPathFragment;
- this.relativePath = relativePath;
- this.isSource = isSource;
- }
-
- /**
- * Returns the root path of the artifact, eg. blaze-out
- */
- public String getRootPath() {
- return rootPath;
- }
-
- /**
- * Gets the path relative to the root path.
- */
- public String getRelativePath() {
- return relativePath;
- }
-
- public boolean isSource() {
- return isSource;
- }
-
- public boolean isGenerated() {
- return !isSource;
- }
-
- public File getFile() {
- return new File(getRootPath(), getRelativePath());
- }
-
- /**
- * Returns rootExecutionPathFragment + relativePath.
- * For source artifacts, this is simply relativePath
- */
- public String getExecutionRootRelativePath() {
- return Paths.get(rootExecutionPathFragment, relativePath).toString();
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- String rootPath;
- String relativePath;
- String rootExecutionPathFragment = "";
- boolean isSource;
-
- public Builder setRootPath(String rootPath) {
- this.rootPath = rootPath;
- return this;
- }
-
- public Builder setRelativePath(String relativePath) {
- this.relativePath = relativePath;
- return this;
- }
-
- public Builder setRootExecutionPathFragment(String rootExecutionPathFragment) {
- this.rootExecutionPathFragment = rootExecutionPathFragment;
- return this;
- }
-
- public Builder setIsSource(boolean isSource) {
- this.isSource = isSource;
- return this;
- }
-
- public ArtifactLocation build() {
- return new ArtifactLocation(rootPath, rootExecutionPathFragment, relativePath, isSource);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ArtifactLocation that = (ArtifactLocation)o;
- return Objects.equal(rootPath, that.rootPath)
- && Objects.equal(rootExecutionPathFragment, that.rootExecutionPathFragment)
- && Objects.equal(relativePath, that.relativePath)
- && Objects.equal(isSource, that.isSource);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(rootPath, rootExecutionPathFragment, relativePath, isSource);
- }
-
- @Override
- public String toString() {
- return getFile().toString();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/CRuleIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/CRuleIdeInfo.java
deleted file mode 100644
index 641bf35..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/CRuleIdeInfo.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-
-import java.io.Serializable;
-
-/**
- * Sister class to {@link JavaRuleIdeInfo}
- */
-public class CRuleIdeInfo implements Serializable {
- private static final long serialVersionUID = 6L;
-
- public final ImmutableList<ArtifactLocation> sources;
-
- // From the cpp compilation context provider. These should all be for the entire transitive closure.
- public final ImmutableList<ExecutionRootPath> transitiveIncludeDirectories;
- public final ImmutableList<ExecutionRootPath> transitiveQuoteIncludeDirectories;
- public final ImmutableList<String> transitiveDefines;
- public final ImmutableList<ExecutionRootPath> transitiveSystemIncludeDirectories;
-
- public CRuleIdeInfo(
- ImmutableList<ArtifactLocation> sources,
- ImmutableList<ExecutionRootPath> transitiveIncludeDirectories,
- ImmutableList<ExecutionRootPath> transitiveQuoteIncludeDirectories,
- ImmutableList<String> transitiveDefines,
- ImmutableList<ExecutionRootPath> transitiveSystemIncludeDirectories
- ) {
- this.sources = sources;
- this.transitiveIncludeDirectories = transitiveIncludeDirectories;
- this.transitiveQuoteIncludeDirectories = transitiveQuoteIncludeDirectories;
- this.transitiveDefines = transitiveDefines;
- this.transitiveSystemIncludeDirectories = transitiveSystemIncludeDirectories;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private final ImmutableList.Builder<ArtifactLocation> sources = ImmutableList.builder();
-
- private final ImmutableList.Builder<ExecutionRootPath> transitiveIncludeDirectories = ImmutableList.builder();
- private final ImmutableList.Builder<ExecutionRootPath> transitiveQuoteIncludeDirectories = ImmutableList.builder();
- private final ImmutableList.Builder<String> transitiveDefines = ImmutableList.builder();
- private final ImmutableList.Builder<ExecutionRootPath> transitiveSystemIncludeDirectories = ImmutableList.builder();
-
- public Builder addSources(Iterable<ArtifactLocation> sources) {
- this.sources.addAll(sources);
- return this;
- }
-
- public Builder addTransitiveIncludeDirectories(Iterable<ExecutionRootPath> transitiveIncludeDirectories) {
- this.transitiveIncludeDirectories.addAll(transitiveIncludeDirectories);
- return this;
- }
-
- public Builder addTransitiveQuoteIncludeDirectories(Iterable<ExecutionRootPath> transitiveQuoteIncludeDirectories) {
- this.transitiveQuoteIncludeDirectories.addAll(transitiveQuoteIncludeDirectories);
- return this;
- }
-
- public Builder addTransitiveDefines(Iterable<String> transitiveDefines) {
- this.transitiveDefines.addAll(transitiveDefines);
- return this;
- }
-
- public Builder addTransitiveSystemIncludeDirectories(Iterable<ExecutionRootPath> transitiveSystemIncludeDirectories) {
- this.transitiveSystemIncludeDirectories.addAll(transitiveSystemIncludeDirectories);
- return this;
- }
-
- public CRuleIdeInfo build() {
- return new CRuleIdeInfo(
- sources.build(),
- transitiveIncludeDirectories.build(),
- transitiveQuoteIncludeDirectories.build(),
- transitiveDefines.build(),
- transitiveSystemIncludeDirectories.build()
- );
- }
- }
-
- @Override
- public String toString() {
- return "CRuleIdeInfo{" + "\n" +
- " sources=" + sources + "\n" +
- " transitiveIncludeDirectories=" + transitiveIncludeDirectories + "\n" +
- " transitiveQuoteIncludeDirectories=" + transitiveQuoteIncludeDirectories + "\n" +
- " transitiveDefines=" + transitiveDefines + "\n" +
- " transitiveSystemIncludeDirectories=" + transitiveSystemIncludeDirectories + "\n" +
- '}';
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java
deleted file mode 100644
index 1f6b0f0..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-
-import java.io.Serializable;
-
-/**
- * Sister class to {@link JavaRuleIdeInfo}
- */
-public class CToolchainIdeInfo implements Serializable {
- private static final long serialVersionUID = 3L;
-
- public final ImmutableList<String> baseCompilerOptions;
- public final ImmutableList<String> cCompilerOptions;
- public final ImmutableList<String> cppCompilerOptions;
- public final ImmutableList<String> linkOptions;
- public final ImmutableList<ExecutionRootPath> builtInIncludeDirectories;
- public final ExecutionRootPath cppExecutable;
- public final ExecutionRootPath preprocessorExecutable;
- public final String targetName;
-
- public final ImmutableList<String> unfilteredCompilerOptions;
- public final ImmutableList<ExecutionRootPath> unfilteredToolchainSystemIncludes;
-
- public CToolchainIdeInfo(
- ImmutableList<String> baseCompilerOptions,
- ImmutableList<String> cCompilerOptions,
- ImmutableList<String> cppCompilerOptions,
- ImmutableList<String> linkOptions,
- ImmutableList<ExecutionRootPath> builtInIncludeDirectories,
- ExecutionRootPath cppExecutable,
- ExecutionRootPath preprocessorExecutable,
- String targetName,
- ImmutableList<String> unfilteredCompilerOptions,
- ImmutableList<ExecutionRootPath> unfilteredToolchainSystemIncludes
- ) {
- this.baseCompilerOptions = baseCompilerOptions;
- this.cCompilerOptions = cCompilerOptions;
- this.cppCompilerOptions = cppCompilerOptions;
- this.linkOptions = linkOptions;
- this.builtInIncludeDirectories = builtInIncludeDirectories;
- this.cppExecutable = cppExecutable;
- this.preprocessorExecutable = preprocessorExecutable;
- this.targetName = targetName;
- this.unfilteredCompilerOptions = unfilteredCompilerOptions;
- this.unfilteredToolchainSystemIncludes = unfilteredToolchainSystemIncludes;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private final ImmutableList.Builder<String> baseCompilerOptions = ImmutableList.builder();
- private final ImmutableList.Builder<String> cCompilerOptions = ImmutableList.builder();
- private final ImmutableList.Builder<String> cppCompilerOptions = ImmutableList.builder();
- private final ImmutableList.Builder<String> linkOptions = ImmutableList.builder();
-
- private final ImmutableList.Builder<ExecutionRootPath> builtInIncludeDirectories = ImmutableList.builder();
-
- ExecutionRootPath cppExecutable;
- ExecutionRootPath preprocessorExecutable;
-
- String targetName = "";
-
- private final ImmutableList.Builder<String> unfilteredCompilerOptions = ImmutableList.builder();
- private final ImmutableList.Builder<ExecutionRootPath> unfilteredToolchainSystemIncludes = ImmutableList.builder();
-
- public Builder addBaseCompilerOptions(Iterable<String> baseCompilerOptions) {
- this.baseCompilerOptions.addAll(baseCompilerOptions);
- return this;
- }
-
- public Builder addCCompilerOptions(Iterable<String> cCompilerOptions) {
- this.cCompilerOptions.addAll(cCompilerOptions);
- return this;
- }
-
- public Builder addCppCompilerOptions(Iterable<String> cppCompilerOptions) {
- this.cppCompilerOptions.addAll(cppCompilerOptions);
- return this;
- }
-
- public Builder addLinkOptions(Iterable<String> linkOptions) {
- this.linkOptions.addAll(linkOptions);
- return this;
- }
-
- public Builder addBuiltInIncludeDirectories(Iterable<ExecutionRootPath> builtInIncludeDirectories) {
- this.builtInIncludeDirectories.addAll(builtInIncludeDirectories);
- return this;
- }
-
- public Builder setCppExecutable(ExecutionRootPath cppExecutable) {
- this.cppExecutable = cppExecutable;
- return this;
- }
-
- public Builder setPreprocessorExecutable(ExecutionRootPath preprocessorExecutable) {
- this.preprocessorExecutable = preprocessorExecutable;
- return this;
- }
-
- public Builder setTargetName(String targetName) {
- this.targetName = targetName;
- return this;
- }
-
- public Builder addUnfilteredCompilerOptions(Iterable<String> unfilteredCompilerOptions) {
- this.unfilteredCompilerOptions.addAll(unfilteredCompilerOptions);
- return this;
- }
-
- public Builder addUnfilteredToolchainSystemIncludes(Iterable<ExecutionRootPath> unfilteredToolchainSystemIncludes) {
- this.unfilteredToolchainSystemIncludes.addAll(unfilteredToolchainSystemIncludes);
- return this;
- }
-
- public CToolchainIdeInfo build() {
- return new CToolchainIdeInfo(
- baseCompilerOptions.build(),
- cCompilerOptions.build(),
- cppCompilerOptions.build(),
- linkOptions.build(),
- builtInIncludeDirectories.build(),
- cppExecutable,
- preprocessorExecutable,
- targetName,
- unfilteredCompilerOptions.build(),
- unfilteredToolchainSystemIncludes.build()
- );
- }
- }
-
- @Override
- public String toString() {
- return "CToolchainIdeInfo{" + "\n" +
- " baseCompilerOptions=" + baseCompilerOptions + "\n" +
- " cCompilerOptions=" + cCompilerOptions + "\n" +
- " cppCompilerOptions=" + cppCompilerOptions + "\n" +
- " linkOptions=" + linkOptions + "\n" +
- " builtInIncludeDirectories=" + builtInIncludeDirectories + "\n" +
- " cppExecutable='" + cppExecutable + '\'' + "\n" +
- " preprocessorExecutable='" + preprocessorExecutable + '\'' + "\n" +
- " targetName='" + targetName + '\'' + "\n" +
- " unfilteredCompilerOptions=" + unfilteredCompilerOptions + "\n" +
- " unfilteredToolchainSystemIncludes=" + unfilteredToolchainSystemIncludes + "\n" +
- '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- CToolchainIdeInfo that = (CToolchainIdeInfo)o;
- return
- Objects.equal(baseCompilerOptions, that.baseCompilerOptions) &&
- Objects.equal(cCompilerOptions, that.cCompilerOptions) &&
- Objects.equal(cppCompilerOptions, that.cppCompilerOptions) &&
- Objects.equal(linkOptions, that.linkOptions) &&
- Objects.equal(builtInIncludeDirectories, that.builtInIncludeDirectories) &&
- Objects.equal(cppExecutable, that.cppExecutable) &&
- Objects.equal(preprocessorExecutable, that.preprocessorExecutable) &&
- Objects.equal(targetName, that.targetName) &&
- Objects.equal(unfilteredCompilerOptions, that.unfilteredCompilerOptions) &&
- Objects.equal(unfilteredToolchainSystemIncludes, that.unfilteredToolchainSystemIncludes)
- ;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(
- baseCompilerOptions,
- cCompilerOptions,
- cppCompilerOptions,
- linkOptions,
- builtInIncludeDirectories,
- cppExecutable,
- preprocessorExecutable,
- targetName,
- unfilteredCompilerOptions,
- unfilteredToolchainSystemIncludes
- );
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/JavaRuleIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/JavaRuleIdeInfo.java
deleted file mode 100644
index 31eb533..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/JavaRuleIdeInfo.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.collect.ImmutableList;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * Ide info specific to java rules.
- */
-public final class JavaRuleIdeInfo implements Serializable {
- private static final long serialVersionUID = 1L;
-
- /**
- * The main jar(s) produced by this java rule.
- *
- * <p>Usually this will be a single jar, but java_imports support importing multiple jars.
- */
- public final Collection<LibraryArtifact> jars;
-
- /**
- * A jar containing annotation processing.
- */
- public final Collection<LibraryArtifact> generatedJars;
-
- /**
- * File containing a map from .java files to their corresponding package.
- */
- @Nullable public final ArtifactLocation packageManifest;
-
- /**
- * File containing dependencies.
- */
- @Nullable public final ArtifactLocation jdepsFile;
-
- public JavaRuleIdeInfo(Collection<LibraryArtifact> jars,
- Collection<LibraryArtifact> generatedJars,
- @Nullable ArtifactLocation packageManifest,
- @Nullable ArtifactLocation jdepsFile) {
- this.jars = jars;
- this.generatedJars = generatedJars;
- this.packageManifest = packageManifest;
- this.jdepsFile = jdepsFile;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- ImmutableList.Builder<LibraryArtifact> jars = ImmutableList.builder();
- ImmutableList.Builder<LibraryArtifact> generatedJars = ImmutableList.builder();
-
- public Builder addJar(LibraryArtifact.Builder jar) {
- jars.add(jar.build());
- return this;
- }
-
- public Builder addGeneratedJar(LibraryArtifact.Builder jar) {
- generatedJars.add(jar.build());
- return this;
- }
-
- public JavaRuleIdeInfo build() {
- return new JavaRuleIdeInfo(jars.build(), generatedJars.build(), null, null);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/JavaToolchainIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/JavaToolchainIdeInfo.java
deleted file mode 100644
index 1fcbf41..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/JavaToolchainIdeInfo.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import java.io.Serializable;
-
-/**
- * Represents the java_toolchain class
- */
-public class JavaToolchainIdeInfo implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public final String sourceVersion;
- public final String targetVersion;
-
- public JavaToolchainIdeInfo(String sourceVersion, String targetVersion) {
- this.sourceVersion = sourceVersion;
- this.targetVersion = targetVersion;
- }
-
- @Override
- public String toString() {
- return "JavaToolchainIdeInfo{" + "\n" +
- " sourceVersion=" + sourceVersion + "\n" +
- " targetVersion=" + targetVersion + "\n" +
- '}';
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- String sourceVersion;
- String targetVersion;
-
- public Builder setSourceVersion(String sourceVersion) {
- this.sourceVersion = sourceVersion;
- return this;
- }
-
- public Builder setTargetVersion(String targetVersion) {
- this.targetVersion = targetVersion;
- return this;
- }
-
- public JavaToolchainIdeInfo build() {
- return new JavaToolchainIdeInfo(sourceVersion, targetVersion);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
deleted file mode 100644
index 44f581c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.base.Objects;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.Serializable;
-
-/**
- * Represents a jar artifact.
- */
-public class LibraryArtifact implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public final ArtifactLocation jar;
- @Nullable public final ArtifactLocation runtimeJar;
- @Nullable public final ArtifactLocation sourceJar;
-
- public LibraryArtifact(ArtifactLocation jar, @Nullable ArtifactLocation runtimeJar, @Nullable ArtifactLocation sourceJar) {
- this.jar = jar;
- this.runtimeJar = runtimeJar;
- this.sourceJar = sourceJar;
- }
-
- @Override
- public String toString() {
- return String.format("jar=%s, ijar=%s, srcjar=%s", runtimeJar, jar, sourceJar);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- LibraryArtifact that = (LibraryArtifact)o;
- return
- Objects.equal(jar, that.jar) &&
- Objects.equal(runtimeJar, that.runtimeJar) &&
- Objects.equal(sourceJar, that.sourceJar);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(jar, runtimeJar, sourceJar);
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private ArtifactLocation jar;
- private ArtifactLocation runtimeJar;
- private ArtifactLocation sourceJar;
-
- public Builder setJar(ArtifactLocation artifactLocation) {
- this.jar = artifactLocation;
- return this;
- }
- public Builder setRuntimeJar(@Nullable ArtifactLocation artifactLocation) {
- this.runtimeJar = artifactLocation;
- return this;
- }
- public Builder setSourceJar(@Nullable ArtifactLocation artifactLocation) {
- this.sourceJar = artifactLocation;
- return this;
- }
- public LibraryArtifact build() {
- return new LibraryArtifact(jar, runtimeJar, sourceJar);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/ProtoLibraryLegacyInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/ProtoLibraryLegacyInfo.java
deleted file mode 100644
index 18f6b69..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/ProtoLibraryLegacyInfo.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.collect.ImmutableList;
-
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * Proto library info for legacy proto libraries.
- *
- * Replicates blaze semantics.
- */
-public class ProtoLibraryLegacyInfo implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public enum ApiFlavor {
- VERSION_1,
- MUTABLE,
- IMMUTABLE,
- BOTH,
- NONE,
- }
-
- public final ApiFlavor apiFlavor;
-
- public final Collection<LibraryArtifact> jarsV1;
- public final Collection<LibraryArtifact> jarsMutable;
- public final Collection<LibraryArtifact> jarsImmutable;
-
- public ProtoLibraryLegacyInfo(ApiFlavor apiFlavor,
- Collection<LibraryArtifact> jarsV1,
- Collection<LibraryArtifact> jarsMutable,
- Collection<LibraryArtifact> jarsImmutable) {
- this.apiFlavor = apiFlavor;
- this.jarsV1 = jarsV1;
- this.jarsMutable = jarsMutable;
- this.jarsImmutable = jarsImmutable;
- }
-
- public static Builder builder(ApiFlavor apiFlavor) {
- return new Builder(apiFlavor);
- }
-
- public static class Builder {
- private final ApiFlavor apiFlavor;
- private ImmutableList.Builder<LibraryArtifact> jarsV1 = ImmutableList.builder();
- private ImmutableList.Builder<LibraryArtifact> jarsMutable = ImmutableList.builder();
- private ImmutableList.Builder<LibraryArtifact> jarsImmutable = ImmutableList.builder();
-
- Builder(ApiFlavor apiFlavor) {
- this.apiFlavor = apiFlavor;
- }
-
- public Builder addJarV1(LibraryArtifact.Builder library) {
- jarsV1.add(library.build());
- return this;
- }
-
- public Builder addJarMutable(LibraryArtifact.Builder library) {
- jarsMutable.add(library.build());
- return this;
- }
-
- public Builder addJarImmutable(LibraryArtifact.Builder library) {
- jarsImmutable.add(library.build());
- return this;
- }
-
- public ProtoLibraryLegacyInfo build() {
- return new ProtoLibraryLegacyInfo(apiFlavor, jarsV1.build(), jarsMutable.build(), jarsImmutable.build());
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/RuleIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/RuleIdeInfo.java
deleted file mode 100644
index 896e60d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/RuleIdeInfo.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Simple implementation of RuleIdeInfo.
- */
-public final class RuleIdeInfo implements Serializable {
- private static final long serialVersionUID = 10L;
-
- public final Label label;
- public final Kind kind;
- @Nullable public final ArtifactLocation buildFile;
- public final Collection<Label> dependencies;
- public final Collection<Label> runtimeDeps;
- public final Collection<String> tags;
- public final Collection<ArtifactLocation> sources;
- @Nullable public final CRuleIdeInfo cRuleIdeInfo;
- @Nullable public final CToolchainIdeInfo cToolchainIdeInfo;
- @Nullable public final JavaRuleIdeInfo javaRuleIdeInfo;
- @Nullable public final AndroidRuleIdeInfo androidRuleIdeInfo;
- @Nullable public final TestIdeInfo testIdeInfo;
- @Nullable public final ProtoLibraryLegacyInfo protoLibraryLegacyInfo;
- @Nullable public final JavaToolchainIdeInfo javaToolchainIdeInfo;
-
- public RuleIdeInfo(Label label,
- Kind kind,
- @Nullable ArtifactLocation buildFile,
- Collection<Label> dependencies,
- Collection<Label> runtimeDeps,
- Collection<String> tags,
- Collection<ArtifactLocation> sources,
- @Nullable CRuleIdeInfo cRuleIdeInfo,
- @Nullable CToolchainIdeInfo cToolchainIdeInfo,
- @Nullable JavaRuleIdeInfo javaRuleIdeInfo,
- @Nullable AndroidRuleIdeInfo androidRuleIdeInfo,
- @Nullable TestIdeInfo testIdeInfo,
- @Nullable ProtoLibraryLegacyInfo protoLibraryLegacyInfo,
- @Nullable JavaToolchainIdeInfo javaToolchainIdeInfo) {
- this.label = label;
- this.kind = kind;
- this.buildFile = buildFile;
- this.dependencies = dependencies;
- this.runtimeDeps = runtimeDeps;
- this.tags = tags;
- this.sources = sources;
- this.cRuleIdeInfo = cRuleIdeInfo;
- this.cToolchainIdeInfo = cToolchainIdeInfo;
- this.javaRuleIdeInfo = javaRuleIdeInfo;
- this.androidRuleIdeInfo = androidRuleIdeInfo;
- this.testIdeInfo = testIdeInfo;
- this.protoLibraryLegacyInfo = protoLibraryLegacyInfo;
- this.javaToolchainIdeInfo = javaToolchainIdeInfo;
- }
-
- @Override
- public String toString() {
- return label.toString();
- }
-
- /**
- * Returns whether this rule is one of the kinds.
- */
- public boolean kindIsOneOf(Kind... kinds) {
- return kindIsOneOf(Arrays.asList(kinds));
- }
-
- /**
- * Returns whether this rule is one of the kinds.
- */
- public boolean kindIsOneOf(List<Kind> kinds) {
- if (kind != null) {
- return kind.isOneOf(kinds);
- }
- return false;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private Label label;
- private Kind kind;
- private ArtifactLocation buildFile;
- private final List<Label> dependencies = Lists.newArrayList();
- private final List<Label> runtimeDeps = Lists.newArrayList();
- private final List<String> tags = Lists.newArrayList();
- private final List<ArtifactLocation> sources = Lists.newArrayList();
- private final List<LibraryArtifact> libraries = Lists.newArrayList();
- private CRuleIdeInfo cRuleIdeInfo;
- private CToolchainIdeInfo cToolchainIdeInfo;
- private JavaRuleIdeInfo javaRuleIdeInfo;
- private AndroidRuleIdeInfo androidRuleIdeInfo;
- private TestIdeInfo testIdeInfo;
- private ProtoLibraryLegacyInfo protoLibraryLegacyInfo;
- private JavaToolchainIdeInfo javaToolchainIdeInfo;
-
- public Builder setLabel(String label) {
- return setLabel(new Label(label));
- }
- public Builder setLabel(Label label) {
- this.label = label;
- return this;
- }
- public Builder setBuildFile(ArtifactLocation buildFile) {
- this.buildFile = buildFile;
- return this;
- }
- public Builder setKind(String kind) {
- return setKind(Kind.fromString(kind));
- }
- public Builder setKind(Kind kind) {
- this.kind = kind;
- return this;
- }
- public Builder addSource(ArtifactLocation source) {
- this.sources.add(source);
- return this;
- }
- public Builder addSource(ArtifactLocation.Builder source) {
- return addSource(source.build());
- }
- public Builder setJavaInfo(JavaRuleIdeInfo.Builder builder) {
- javaRuleIdeInfo = builder.build();
- return this;
- }
- public Builder setCInfo(CRuleIdeInfo cInfo) {
- this.cRuleIdeInfo = cInfo;
- return this;
- }
- public Builder setCInfo(CRuleIdeInfo.Builder cInfo) {
- return setCInfo(cInfo.build());
- }
- public Builder setCToolchainInfo(CToolchainIdeInfo info) {
- this.cToolchainIdeInfo = info;
- return this;
- }
- public Builder setCToolchainInfo(CToolchainIdeInfo.Builder info) {
- return setCToolchainInfo(info.build());
- }
- public Builder setAndroidInfo(AndroidRuleIdeInfo androidInfo) {
- this.androidRuleIdeInfo = androidInfo;
- return this;
- }
- public Builder setAndroidInfo(AndroidRuleIdeInfo.Builder androidInfo) {
- return setAndroidInfo(androidInfo.build());
- }
- public Builder setTestInfo(TestIdeInfo.Builder testInfo) {
- this.testIdeInfo = testInfo.build();
- return this;
- }
- public Builder setProtoLibraryLegacyInfo(ProtoLibraryLegacyInfo.Builder protoLibraryLegacyInfo) {
- this.protoLibraryLegacyInfo = protoLibraryLegacyInfo.build();
- return this;
- }
- public Builder setJavaToolchainIdeInfo(JavaToolchainIdeInfo.Builder javaToolchainIdeInfo) {
- this.javaToolchainIdeInfo = javaToolchainIdeInfo.build();
- return this;
- }
- public Builder addTag(String s) {
- this.tags.add(s);
- return this;
- }
- public Builder addDependency(String s) {
- return addDependency(new Label(s));
- }
- public Builder addDependency(Label label) {
- this.dependencies.add(label);
- return this;
- }
- public Builder addRuntimeDep(String s) {
- return addRuntimeDep(new Label(s));
- }
- public Builder addRuntimeDep(Label label) {
- this.runtimeDeps.add(label);
- return this;
- }
- public RuleIdeInfo build() {
- return new RuleIdeInfo(
- label,
- kind,
- buildFile,
- dependencies,
- runtimeDeps,
- tags,
- sources,
- cRuleIdeInfo,
- cToolchainIdeInfo,
- javaRuleIdeInfo,
- androidRuleIdeInfo,
- testIdeInfo,
- protoLibraryLegacyInfo,
- javaToolchainIdeInfo
- );
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/Tags.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/Tags.java
deleted file mode 100644
index 82af46f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/Tags.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-/**
- * Tag constants used by our rules.
- */
-public class Tags {
- /**
- * Forces import of the target output.
- */
- public static final String RULE_TAG_IMPORT_TARGET_OUTPUT = "intellij-import-target-output";
- public static final String RULE_TAG_IMPORT_AS_LIBRARY_LEGACY = "aswb-import-as-library";
-
- /**
- * Signals to the import process that the output of this rule will be provided by the IntelliJ SDK.
- */
- public static final String RULE_TAG_PROVIDED_BY_SDK = "intellij-provided-by-sdk";
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ideinfo/TestIdeInfo.java b/blaze-base/src/com/google/idea/blaze/base/ideinfo/TestIdeInfo.java
deleted file mode 100644
index 534f09c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ideinfo/TestIdeInfo.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-
-/**
- * Test info.
- */
-public class TestIdeInfo implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public enum TestSize {
- SMALL,
- MEDIUM,
- LARGE,
- ENORMOUS
- }
-
- // Rules are "medium" test size by default
- public static final TestSize DEFAULT_RULE_TEST_SIZE = TestSize.MEDIUM;
-
- // Non-annotated methods and classes are "small" by default
- public static final TestSize DEFAULT_NON_ANNOTATED_TEST_SIZE = TestSize.SMALL;
-
- public final TestSize testSize;
-
- public TestIdeInfo(TestSize testSize) {
- this.testSize = testSize;
- }
-
- @Nullable
- static public TestSize getTestSize(RuleIdeInfo rule) {
- TestIdeInfo testIdeInfo = rule.testIdeInfo;
- if (testIdeInfo == null) {
- return null;
- }
- return testIdeInfo.testSize;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private TestSize testSize = DEFAULT_RULE_TEST_SIZE;
-
- public Builder setTestSize(TestSize testSize) {
- this.testSize = testSize;
- return this;
- }
-
- public TestIdeInfo build() {
- return new TestIdeInfo(testSize);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/io/FileAttributeProvider.java b/blaze-base/src/com/google/idea/blaze/base/io/FileAttributeProvider.java
deleted file mode 100644
index 829d262..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/io/FileAttributeProvider.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.io;
-
-import com.intellij.openapi.components.ServiceManager;
-
-import java.io.File;
-
-/**
- * Simple file system checks (existence, isDirectory)
- */
-public class FileAttributeProvider {
-
- public static FileAttributeProvider getInstance() {
- return ServiceManager.getService(FileAttributeProvider.class);
- }
-
- public boolean exists(File file) {
- return file.exists();
- }
-
- public boolean isDirectory(File file) {
- return file.isDirectory();
- }
-
- public boolean isFile(File file) {
- return file.isFile();
- }
-
- public long getFileModifiedTime(File file) {
- return file.lastModified();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/io/InputStreamProvider.java b/blaze-base/src/com/google/idea/blaze/base/io/InputStreamProvider.java
deleted file mode 100644
index 542992f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/io/InputStreamProvider.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.io;
-
-import com.intellij.openapi.components.ServiceManager;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Provides input streams for files.
- */
-public interface InputStreamProvider {
-
- static InputStreamProvider getInstance() {
- return ServiceManager.getService(InputStreamProvider.class);
- }
-
- InputStream getFile(File file) throws IOException;
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/io/InputStreamProviderImpl.java b/blaze-base/src/com/google/idea/blaze/base/io/InputStreamProviderImpl.java
deleted file mode 100644
index a4f0d64..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/io/InputStreamProviderImpl.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.io;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-
-/**
- * Default implementation of InputStreamProvider.
- */
-final class InputStreamProviderImpl implements InputStreamProvider {
-
- @Override
- public InputStream getFile(@NotNull File file) throws FileNotFoundException {
- return new FileInputStream(file);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/io/VfsWorkspaceScanner.java b/blaze-base/src/com/google/idea/blaze/base/io/VfsWorkspaceScanner.java
deleted file mode 100644
index 5ca8daf..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/io/VfsWorkspaceScanner.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.io;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-
-/**
- * Checks the workspace using the VFS.
- */
-class VfsWorkspaceScanner implements WorkspaceScanner {
- private final LocalFileSystem localFileSystem;
-
- public VfsWorkspaceScanner() {
- this.localFileSystem = LocalFileSystem.getInstance();
- }
-
- @Override
- public boolean exists(WorkspaceRoot workspaceRoot, WorkspacePath workspacePath) {
- VirtualFile virtualFile = localFileSystem.refreshAndFindFileByPath(
- workspaceRoot.fileForPath(workspacePath).getPath()
- );
- return virtualFile != null && virtualFile.exists();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/io/WorkspaceScanner.java b/blaze-base/src/com/google/idea/blaze/base/io/WorkspaceScanner.java
deleted file mode 100644
index bf4b4e0..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/io/WorkspaceScanner.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.io;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.openapi.components.ServiceManager;
-
-/**
- * Used to scan the file system
- */
-public interface WorkspaceScanner {
- static WorkspaceScanner getInstance() {
- return ServiceManager.getService(WorkspaceScanner.class);
- }
-
- boolean exists(WorkspaceRoot workspaceRoot, WorkspacePath workspacePath);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java b/blaze-base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
deleted file mode 100644
index 0890bf5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.issueparser;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.Section;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static com.google.common.base.Preconditions.checkState;
-
-/**
- * Parses blaze output for compile errors.
- */
-public class BlazeIssueParser {
-
- private static class ParseResult {
-
- public static final ParseResult NEEDS_MORE_INPUT = new ParseResult(true, null);
-
- public static final ParseResult NO_RESULT = new ParseResult(false, null);
-
- private boolean needsMoreInput;
- @Nullable private IssueOutput output;
-
- private ParseResult(boolean needsMoreInput, IssueOutput output) {
- this.needsMoreInput = needsMoreInput;
- this.output = output;
- }
-
- public static ParseResult needsMoreInput() {
- return NEEDS_MORE_INPUT;
- }
-
- public static ParseResult output(IssueOutput output) {
- return new ParseResult(false, output);
- }
-
- public static ParseResult noResult() {
- return NO_RESULT;
- }
- }
-
- interface Parser {
- @NotNull
- ParseResult parse(@NotNull String currentLine, @NotNull List<String> previousLines);
- }
-
- static abstract class SingleLineParser implements Parser {
- @NotNull
- Pattern pattern;
-
- SingleLineParser(@NotNull String regex) {
- pattern = Pattern.compile(regex);
- }
-
- @Override
- public ParseResult parse(@NotNull String currentLine, @NotNull List<String> multilineMatchResult) {
- checkState(multilineMatchResult.isEmpty(), "SingleLineParser recieved multiple lines of input");
- return parse(currentLine);
- }
-
- ParseResult parse(@NotNull String line) {
- Matcher matcher = pattern.matcher(line);
- if (matcher.find()) {
- return ParseResult.output(createIssue(matcher));
- }
- return ParseResult.noResult();
- }
-
- @Nullable
- protected abstract IssueOutput createIssue(@NotNull Matcher matcher);
- }
-
- static class CompileParser extends SingleLineParser {
- @NotNull
- private final WorkspaceRoot workspaceRoot;
-
- public CompileParser(@NotNull WorkspaceRoot workspaceRoot) {
- super("(.*?):([0-9]+):([0-9]+:)? (error|warning): (.*)");
- this.workspaceRoot = workspaceRoot;
- }
-
- @Override
- protected IssueOutput createIssue(@NotNull Matcher matcher) {
- final File file;
- try {
- String fileName = matcher.group(1);
- final WorkspacePath workspacePath;
- if (fileName.startsWith("//depot/google3/")) {
- workspacePath = new WorkspacePath(fileName.substring("//depot/google3/".length()));
- } else if (fileName.startsWith("/")) {
- workspacePath = workspaceRoot.workspacePathFor(new File(fileName));
- } else {
- workspacePath = new WorkspacePath(fileName);
- }
- file = workspaceRoot.fileForPath(workspacePath);
- }
- catch (IllegalArgumentException e) {
- // Ignore -- malformed error message
- return null;
- }
-
- IssueOutput.Category type = matcher.group(4).equals("error")
- ? IssueOutput.Category.ERROR
- : IssueOutput.Category.WARNING;
- return IssueOutput.issue(type, matcher.group(5))
- .inFile(file)
- .onLine(Integer.parseInt(matcher.group(2)))
- .build();
- }
- }
-
- static class TracebackParser implements Parser {
- private static final Pattern PATTERN = Pattern.compile("(ERROR): (.*?):([0-9]+):([0-9]+): (Traceback \\(most recent call last\\):)");
-
- @NotNull
- @Override
- public ParseResult parse(@NotNull String currentLine, @NotNull List<String> previousLines) {
- if (previousLines.isEmpty()) {
- if (PATTERN.matcher(currentLine).find()) {
- return ParseResult.needsMoreInput();
- }
- else {
- return ParseResult.noResult();
- }
- }
-
- if (currentLine.startsWith("\t")) {
- return ParseResult.needsMoreInput();
- }
- else {
- Matcher matcher = PATTERN.matcher(previousLines.get(0));
- checkState(matcher.find(), "Found a match in the first line previously, but now it isn't there.");
- StringBuilder message = new StringBuilder(matcher.group(5));
- for (int i = 1; i < previousLines.size(); ++i) {
- message.append(System.lineSeparator())
- .append(previousLines.get(i));
- }
- message.append(System.lineSeparator())
- .append(currentLine);
- return ParseResult.output(IssueOutput.error(message.toString())
- .inFile(new File(matcher.group(2)))
- .onLine(Integer.parseInt(matcher.group(3)))
- .build());
- }
- }
- }
-
- static class BuildParser extends SingleLineParser {
- BuildParser() {
- super("(ERROR): (.*?):([0-9]+):([0-9]+): (.*)");
- }
-
- @Override
- protected IssueOutput createIssue(@NotNull Matcher matcher) {
- return IssueOutput.error(matcher.group(5))
- .inFile(new File(matcher.group(2)))
- .onLine(Integer.parseInt(matcher.group(3)))
- .build();
- }
- }
-
- static class LinelessBuildParser extends SingleLineParser {
- LinelessBuildParser() {
- super("(ERROR): (.*?):char offsets [0-9]+--[0-9]+: (.*)");
- }
-
- @Override
- protected IssueOutput createIssue(@NotNull Matcher matcher) {
- return IssueOutput.error(matcher.group(3))
- .inFile(new File(matcher.group(2)))
- .build();
- }
- }
-
- static class ProjectViewLabelParser extends SingleLineParser {
-
- @Nullable private final ProjectViewSet projectViewSet;
-
- ProjectViewLabelParser(
- @Nullable ProjectViewSet projectViewSet) {
- super("no such target '(.*)': target .*? not declared in package .*? defined by");
- this.projectViewSet = projectViewSet;
- }
-
- @Override
- protected IssueOutput createIssue(@NotNull Matcher matcher) {
- File file = null;
- if (projectViewSet != null) {
- String targetString = matcher.group(1);
- final TargetExpression targetExpression = TargetExpression.fromString(targetString);
- file = projectViewFileWithSection(projectViewSet, TargetSection.KEY, new Predicate<ListSection<TargetExpression>>() {
- @Override
- public boolean apply(@NotNull ListSection<TargetExpression> targetSection) {
- return targetSection.items().contains(targetExpression);
- }
- });
- }
-
- return IssueOutput.error(matcher.group(0))
- .inFile(file)
- .build();
- }
- }
-
- static class InvalidTargetProjectViewPackageParser extends SingleLineParser {
- @Nullable private final ProjectViewSet projectViewSet;
-
- InvalidTargetProjectViewPackageParser(
- @Nullable ProjectViewSet projectViewSet,
- String regex) {
- super(regex);
- this.projectViewSet = projectViewSet;
- }
-
- @Override
- protected IssueOutput createIssue(@NotNull Matcher matcher) {
- File file = null;
- if (projectViewSet != null) {
- final String packageString = matcher.group(1);
- file = projectViewFileWithSection(projectViewSet, TargetSection.KEY, targetSection -> {
- for (TargetExpression targetExpression : targetSection.items()) {
- if (targetExpression.toString().startsWith("//" + packageString + ":")) {
- return true;
- }
- }
- return false;
- });
- }
-
- return IssueOutput.error(matcher.group(0))
- .inFile(file)
- .build();
- }
- }
-
- @Nullable
- private static <T, SectionType extends Section<T>> File projectViewFileWithSection(
- @NotNull ProjectViewSet projectViewSet,
- @NotNull SectionKey<T, SectionType> key,
- @NotNull Predicate<SectionType> predicate) {
- for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
- SectionType section = projectViewFile.projectView.getSectionOfType(key);
- if (section != null && predicate.apply(section)) {
- return projectViewFile.projectViewFile;
- }
- }
- return null;
- }
-
- @NotNull private List<Parser> parsers = Lists.newArrayList();
- /** The parser that requested more lines of input during the last call to {@link #parseIssue(String)}. */
- @Nullable private Parser multilineMatchingParser;
- @NotNull private List<String> multilineMatchResult = new ArrayList<>();
-
- public BlazeIssueParser(
- @Nullable Project project,
- @NotNull WorkspaceRoot workspaceRoot) {
-
- ProjectViewSet projectViewSet = project != null ? ProjectViewManager.getInstance(project).getProjectViewSet() : null;
-
- parsers.add(new CompileParser(workspaceRoot));
- parsers.add(new TracebackParser());
- parsers.add(new BuildParser());
- parsers.add(new LinelessBuildParser());
- parsers.add(new ProjectViewLabelParser(projectViewSet));
- parsers.add(new InvalidTargetProjectViewPackageParser(projectViewSet, "no such package '(.*)': BUILD file not found on package path"));
- parsers.add(new InvalidTargetProjectViewPackageParser(projectViewSet, "no targets found beneath '(.*)'"));
- parsers.add(new InvalidTargetProjectViewPackageParser(projectViewSet, "ERROR: invalid target format '(.*)'"));
- }
-
-
- @Nullable
- public IssueOutput parseIssue(String line) {
-
- List<Parser> parsers = this.parsers;
- if (multilineMatchingParser != null) {
- parsers = Lists.newArrayList(multilineMatchingParser);
- }
-
- for (Parser parser : parsers) {
- ParseResult issue = parser.parse(line, multilineMatchResult);
- if (issue.needsMoreInput) {
- multilineMatchingParser = parser;
- multilineMatchResult.add(line);
- return null;
- }
- else {
- multilineMatchingParser = null;
- multilineMatchResult = new ArrayList<>();
- }
-
- if (issue.output != null) {
- return issue.output;
- }
- }
-
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java b/blaze-base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
deleted file mode 100644
index 3b34a42..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.issueparser;
-
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput.OutputType;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Forwards output to PrintOutputs, colored by whether or not
- * an issue is found per-line.
- * <p/>
- * Also creates IssueOutput if issues are found.
- */
-public class IssueOutputLineProcessor
- implements LineProcessingOutputStream.LineProcessor {
-
- @NotNull
- private final BlazeContext context;
-
- @NotNull
- private final BlazeIssueParser blazeIssueParser;
-
- public IssueOutputLineProcessor(
- @Nullable Project project,
- @NotNull BlazeContext context,
- @NotNull WorkspaceRoot workspaceRoot) {
- this.context = context;
- this.blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- }
-
- @Override
- public boolean processLine(@NotNull String line) {
- IssueOutput issue = blazeIssueParser.parseIssue(line);
- if (issue != null) {
- if (issue.getCategory() == IssueOutput.Category.ERROR) {
- context.setHasError();
- }
- context.output(issue);
- }
-
- OutputType outputType = issue == null
- ? OutputType.NORMAL : OutputType.ERROR;
-
- context.output(new PrintOutput(line, outputType));
- return true;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierImpl.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierImpl.java
deleted file mode 100644
index e455a6e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierImpl.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.actions;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.buildmodifier.BuildFileModifier;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.BuildElementGenerator;
-import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.intellij.openapi.command.WriteCommandAction;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Computable;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.psi.PsiElement;
-
-import java.io.File;
-
-/**
- * Implementation of BuildFileModifier. Modifies the PSI tree directly.
- */
-public class BuildFileModifierImpl implements BuildFileModifier {
-
- private static final Logger LOG = Logger.getInstance(BuildFileModifierImpl.class);
-
- @Override
- public boolean addRule(Project project,
- BlazeContext context,
- Label newRule,
- Kind ruleKind) {
- return WriteCommandAction.runWriteCommandAction(project, (Computable<Boolean>) () -> {
- BuildReferenceManager manager = BuildReferenceManager.getInstance(project);
- File file = manager.resolvePackage(newRule.blazePackage());
- if (file == null) {
- return null;
- }
- LocalFileSystem.getInstance().refreshIoFiles(ImmutableList.of(file));
- BuildFile buildFile = manager.resolveBlazePackage(newRule.blazePackage());
- if (buildFile == null) {
- LOG.error("No BUILD file found at location: " + newRule.blazePackage());
- return false;
- }
- buildFile.add(createRule(project, ruleKind, newRule.ruleName().toString()));
- return true;
- });
- }
-
- private PsiElement createRule(Project project, Kind ruleKind, String ruleName) {
- String text = Joiner.on("\n").join(
- ruleKind.toString() + "(",
- " name = \"" + ruleName + "\"",
- ")"
- );
- Expression expr = BuildElementGenerator.getInstance(project).createExpressionFromText(text);
- assert(expr instanceof FuncallExpression);
- return expr;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributor.java
deleted file mode 100644
index f0eff50..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributor.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.util.ProcessingContext;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * We can't rely solely keyword arg references, because as the user is typing a new keyword arg,
- * the PsiElement will be a ReferenceExpression (with different completion results
- * not relevant to keyword args).
- */
-public class ArgumentCompletionContributor extends CompletionContributor {
-
- @Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
- // auto-insert the obvious only case; else show other cases.
- final LookupElement[] items = context.getItems();
- if (items.length == 1) {
- return AutoCompletionDecision.insertItem(items[0]);
- }
- return AutoCompletionDecision.SHOW_LOOKUP;
- }
-
- public ArgumentCompletionContributor() {
- extend(
- CompletionType.BASIC,
- psiElement()
- .withLanguage(BuildFileLanguage.INSTANCE)
- .withElementType(BuildToken.fromKind(TokenKind.IDENTIFIER))
- .withParents(ReferenceExpression.class, Argument.Positional.class)
- .andNot(psiElement().afterLeaf("="))
- .andNot(psiElement().afterLeaf(psiElement(BuildToken.fromKind(TokenKind.IDENTIFIER)))),
- new CompletionProvider<CompletionParameters>() {
- @Override
- protected void addCompletions(CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
- Argument.Positional arg = PsiTreeUtil.getParentOfType(parameters.getPosition(), Argument.Positional.class);
- if (arg != null) {
- Object[] lookups = arg.getReference().getVariants();
- for (Object lookup : lookups) {
- if (lookup instanceof LookupElement) {
- result.addElement((LookupElement) lookup);
- }
- }
- }
- }
- }
- );
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java
deleted file mode 100644
index 812c2b5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.intellij.codeInsight.completion.InsertionContext;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementPresentation;
-import com.intellij.openapi.editor.Document;
-import com.intellij.psi.PsiElement;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * Handles some boilerplate, and allows lazy calculation of some expensive
- * components, which aren't required if the element is filtered out by IJ.
- */
-public abstract class BuildLookupElement extends LookupElement {
-
- public static final BuildLookupElement[] EMPTY_ARRAY = new BuildLookupElement[0];
-
- protected final String baseName;
- protected final QuoteType quoteWrapping;
- protected final boolean wrapWithQuotes;
-
- public BuildLookupElement(String baseName, QuoteType quoteWrapping) {
- this.baseName = baseName;
- this.quoteWrapping = quoteWrapping;
- this.wrapWithQuotes = quoteWrapping != QuoteType.NoQuotes;
- }
-
- @Override
- public String getLookupString() {
- return quoteWrapping.wrap(baseName);
- }
-
- @Nullable
- public abstract Icon getIcon();
-
- protected String getItemText() {
- return baseName;
- }
-
- @Nullable
- protected String getTypeText() {
- return null;
- }
-
- @Nullable
- protected String getTailText() {
- return null;
- }
-
- @Override
- public void renderElement(LookupElementPresentation presentation) {
- presentation.setItemText(getItemText());
- presentation.setTailText(getTailText());
- presentation.setTypeText(getTypeText());
- presentation.setIcon(getIcon());
- }
-
- /**
- * If we're wrapping with quotes, handle the (very common) case where we have
- * a closing quote after the caret -- we want to remove this quote.
- * @param context
- */
- @Override
- public void handleInsert(InsertionContext context) {
- if (!wrapWithQuotes) {
- super.handleInsert(context);
- return;
- }
- Document document = context.getDocument();
- context.commitDocument();
- PsiElement suffix = context.getFile().findElementAt(context.getTailOffset());
- if (suffix.getText().startsWith(quoteWrapping.quoteString)) {
- int offset = suffix.getTextOffset();
- document.deleteString(offset, offset + 1);
- context.commitDocument();
- }
- if (caretInsideQuotes()) {
- context.getEditor().getCaretModel().moveCaretRelatively(-1, 0, false, false, true);
- }
- }
-
- /**
- * If true, and we're wrapping with quotes, the caret is moved inside
- * the closing quote after the insert operation is performed.
- */
- protected boolean caretInsideQuotes() {
- return false;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributor.java
deleted file mode 100644
index 9970994..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributor.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.icons.AllIcons;
-import com.intellij.psi.PsiElement;
-import com.intellij.util.ProcessingContext;
-
-import javax.annotation.Nullable;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * Known attributes for built-in blaze functions.
- */
-public class BuiltInFunctionAttributeCompletionContributor extends CompletionContributor {
-
- @Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
- // auto-insert the obvious only case; else show other cases.
- final LookupElement[] items = context.getItems();
- if (items.length == 1) {
- return AutoCompletionDecision.insertItem(items[0]);
- }
- return AutoCompletionDecision.SHOW_LOOKUP;
- }
-
- public BuiltInFunctionAttributeCompletionContributor() {
- extend(
- CompletionType.BASIC,
- psiElement()
- .withLanguage(BuildFileLanguage.INSTANCE)
- .inside(psiElement(FuncallExpression.class))
- .andNot(psiElement().afterLeaf("."))
- .andOr(
- psiElement().withSuperParent(2, FuncallExpression.class),
- psiElement().withSuperParent(2, Argument.class)
- .andNot(psiElement().afterLeaf("="))
- .andNot(psiElement().afterLeaf(psiElement(BuildToken.fromKind(TokenKind.IDENTIFIER))))
- ),
- new CompletionProvider<CompletionParameters>() {
- @Override
- protected void addCompletions(CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
- BuildLanguageSpec spec = BuildLanguageSpecProvider.getInstance().getLanguageSpec(parameters.getPosition().getProject());
- if (spec == null) {
- return;
- }
- RuleDefinition rule = spec.getRule(getEnclosingFuncallName(parameters.getPosition()));
- if (rule == null) {
- return;
- }
- for (String attributeName : rule.getKnownAttributeNames()) {
- result.addElement(
- LookupElementBuilder
- .create(attributeName)
- .withIcon(AllIcons.Nodes.Parameter));
- }
- }
- }
- );
- }
-
- @Nullable
- private static String getEnclosingFuncallName(PsiElement element) {
- FuncallExpression funcall = PsiUtils.getParentOfType(element, FuncallExpression.class);
- return funcall != null ? funcall.getFunctionName() : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributor.java
deleted file mode 100644
index f3bff83..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributor.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.StatementList;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.util.ProcessingContext;
-import icons.BlazeIcons;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * Completes built-in blaze function names.
- */
-public class BuiltInFunctionCompletionContributor extends CompletionContributor {
-
- @Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
- // auto-insert the obvious only case; else show other cases.
- final LookupElement[] items = context.getItems();
- if (items.length == 1) {
- return AutoCompletionDecision.insertItem(items[0]);
- }
- return AutoCompletionDecision.SHOW_LOOKUP;
- }
-
- public BuiltInFunctionCompletionContributor() {
- extend(
- CompletionType.BASIC,
- psiElement()
- .withLanguage(BuildFileLanguage.INSTANCE)
- .andOr(
- // Handles only top-level rules, and rules inside a function statement.
- // There are several other possibilities (e.g. inside top-level list comprehension), but leaving out less common cases
- // to avoid cluttering the autocomplete suggestions when it's not valid to enter a rule.
- psiElement().withParents(ReferenceExpression.class, BuildFile.class), // leaf node => BuildReference => BuildFile
- psiElement()
- .inside(psiElement(StatementList.class).inside(psiElement(FunctionStatement.class)))
- .afterLeaf(psiElement().withText(".").afterLeaf(psiElement().withText("native")))
- ),
- new CompletionProvider<CompletionParameters>() {
- @Override
- protected void addCompletions(CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
- BuildLanguageSpec spec = BuildLanguageSpecProvider.getInstance().getLanguageSpec(parameters.getPosition().getProject());
- if (spec == null) {
- return;
- }
- for (String ruleName : spec.getKnownRuleNames()) {
- result.addElement(
- LookupElementBuilder
- .create(ruleName)
- .withIcon(BlazeIcons.BuildRule)
- .withInsertHandler(ParenthesesInsertHandler.getInstance(true)));
- }
- }
- }
- );
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/CompletionResultsProcessor.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/CompletionResultsProcessor.java
deleted file mode 100644
index 65b0e21..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/CompletionResultsProcessor.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNamedElement;
-import com.intellij.util.Processor;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * Collects completion results, removing duplicate entries.
- */
-public class CompletionResultsProcessor implements Processor<BuildElement> {
-
- private final Map<String, LookupElement> results = Maps.newHashMap();
- private final PsiElement originalElement;
- private final QuoteType quoteType;
-
- public CompletionResultsProcessor(PsiElement originalElement, QuoteType quoteType) {
- this.originalElement = originalElement;
- this.quoteType = quoteType;
- }
-
- @Override
- public boolean process(BuildElement buildElement) {
- if (buildElement == originalElement) {
- return true;
- }
- if (buildElement instanceof StringLiteral) {
- StringLiteral literal = (StringLiteral)buildElement;
- results.put(literal.getStringContents(), new StringLiteralReferenceLookupElement((StringLiteral)buildElement, quoteType));
- }
- else if (buildElement instanceof PsiNamedElement) {
- PsiNamedElement namedElement = (PsiNamedElement)buildElement;
- results.put(namedElement.getName(), new NamedBuildLookupElement((PsiNamedElement)buildElement, quoteType));
- }
- return true;
- }
-
- public Collection<LookupElement> getResults() {
- return results.values();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java
deleted file mode 100644
index 28292e5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.intellij.openapi.util.NullableLazyValue;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * Code completion support for package paths.
- */
-public class FilePathLookupElement extends BuildLookupElement {
-
- private final String itemText;
- private final NullableLazyValue<Icon> icon;
-
- public FilePathLookupElement(String fullLabel, String itemText, QuoteType quoteWrapping, NullableLazyValue<Icon> icon) {
- super(fullLabel, quoteWrapping);
- this.itemText = itemText;
- this.icon = icon;
- }
-
- @Override
- protected String getItemText() {
- return itemText;
- }
-
- @Nullable
- @Override
- public Icon getIcon() {
- return icon.getValue();
- }
-
- @Override
- protected boolean caretInsideQuotes() {
- // after completing, leave the caret inside the closing quote, so the user can
- // continue typing the path.
- return true;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.java
deleted file mode 100644
index b0d9f20..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.intellij.patterns.ElementPattern;
-import com.intellij.patterns.PatternCondition;
-import com.intellij.psi.PsiElement;
-import com.intellij.util.ProcessingContext;
-import org.jetbrains.annotations.NotNull;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * Filter patterns used by completion contributors.
- */
-public class FilterPatterns {
-
- public static final ElementPattern<PsiElement> indexInParentsChildren(final int childIndex) {
- return psiElement().with(new PatternCondition<PsiElement>("isIndexInParentsChildren") {
- @Override
- public boolean accepts(@NotNull PsiElement psiElement, ProcessingContext context) {
- final PsiElement parent = psiElement.getParent();
- if (parent != null) {
- final PsiElement[] children = parent.getChildren();
- if (childIndex < children.length && psiElement.equals(children[childIndex])) {
- return true;
- }
- }
- return false;
- }
- });
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java
deleted file mode 100644
index b7f0314..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Given a label fragment containing a (possibly implicit) package path,
- * provides a lookup element to a rule target in that package.
- */
-public class LabelRuleLookupElement extends BuildLookupElement {
-
- public static BuildLookupElement[] collectAllRules(
- BuildFile file,
- String originalString,
- String packagePrefix,
- @Nullable String excluded,
- QuoteType quoteType) {
- if (packagePrefix.startsWith("//") || originalString.startsWith(":")) {
- packagePrefix += ":";
- }
-
- String ruleFragment = LabelUtils.getRuleComponent(originalString);
- List<BuildLookupElement> lookups = Lists.newArrayList();
- // TODO: Handle rules generated via functions? (e.g. via blaze sync)
- BuildLanguageSpec spec = BuildLanguageSpecProvider.getInstance().getLanguageSpec(file.getProject());
- for (FuncallExpression target : file.findChildrenByClass(FuncallExpression.class)) {
- String targetName = target.getName();
- if (targetName == null || Objects.equals(target.getName(), excluded) || !targetName.startsWith(ruleFragment)) {
- continue;
- }
- String ruleType = target.getFunctionName();
- if (ruleType == null || (spec != null && !spec.hasRule(ruleType))) {
- continue;
- }
- lookups.add(new LabelRuleLookupElement(packagePrefix, target, targetName, ruleType, quoteType));
- }
- return lookups.isEmpty() ? BuildLookupElement.EMPTY_ARRAY : lookups.toArray(new BuildLookupElement[lookups.size()]);
- }
-
- private final FuncallExpression target;
- private final String targetName;
- private final String ruleType;
-
- private LabelRuleLookupElement(String packagePrefix, FuncallExpression target, String targetName, String ruleType, QuoteType quoteType) {
- super(packagePrefix + targetName, quoteType);
- this.target = target;
- this.targetName = targetName;
- this.ruleType = ruleType;
-
- assert(packagePrefix.isEmpty() || packagePrefix.endsWith(":"));
- }
-
- @Override
- public Icon getIcon() {
- return target.getIcon(0);
- }
-
- @Override
- protected String getTypeText() {
- return ruleType;
- }
-
- @Override
- protected String getItemText() {
- return targetName;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/NamedBuildLookupElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/NamedBuildLookupElement.java
deleted file mode 100644
index 287e823..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/NamedBuildLookupElement.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.intellij.psi.PsiNamedElement;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * Generic implementation for {@link com.intellij.psi.PsiNamedElement}s
- */
-public class NamedBuildLookupElement extends BuildLookupElement {
-
- private final PsiNamedElement element;
-
- public NamedBuildLookupElement(PsiNamedElement element, QuoteType quoteType) {
- super(element.getName(), quoteType);
- this.element = element;
- }
-
- @Nullable
- @Override
- public Icon getIcon() {
- return element.getIcon(0);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributor.java
deleted file mode 100644
index 48eb0f3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributor.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.icons.AllIcons;
-import com.intellij.util.ProcessingContext;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * {@link CompletionContributor} for starred function parameters.
- */
-public class ParameterCompletionContributor extends CompletionContributor {
-
- public ParameterCompletionContributor() {
- extend(CompletionType.BASIC,
- psiElement().inside(ParameterList.class).afterLeaf("*"),
- new ParameterCompletionProvider("args"));
- extend(CompletionType.BASIC,
- psiElement().inside(ParameterList.class).afterLeaf("**"),
- new ParameterCompletionProvider("kwargs"));
- }
-
- private static class ParameterCompletionProvider extends CompletionProvider<CompletionParameters> {
- private String myName;
-
- private ParameterCompletionProvider(String name) {
- myName = name;
- }
-
- @Override
- protected void addCompletions(CompletionParameters parameters,
- ProcessingContext context,
- CompletionResultSet result) {
- result.addElement(LookupElementBuilder.create(myName).withIcon(AllIcons.Nodes.Parameter));
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/StringLiteralReferenceLookupElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/StringLiteralReferenceLookupElement.java
deleted file mode 100644
index 0d8f3fe..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/completion/StringLiteralReferenceLookupElement.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.intellij.openapi.util.NullableLazyValue;
-import com.intellij.psi.PsiElement;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * We calculate the referenced element lazily, as it often won't be needed
- * (e.g. when the string doesn't match the string fragment being completed.
- */
-public class StringLiteralReferenceLookupElement extends BuildLookupElement {
-
- private final StringLiteral literal;
- private NullableLazyValue<PsiElement> referencedElement = new NullableLazyValue<PsiElement>() {
- @Nullable
- @Override
- protected PsiElement compute() {
- return literal.getReferencedElement();
- }
- };
-
- public StringLiteralReferenceLookupElement(StringLiteral literal, QuoteType quoteType) {
- super(literal.getStringContents(), quoteType);
- this.literal = literal;
- }
-
- @Nullable
- @Override
- public Icon getIcon() {
- PsiElement ref = referencedElement.getValue();
- return ref != null ? ref.getIcon(0) : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterBetweenBracketsHandler.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterBetweenBracketsHandler.java
deleted file mode 100644
index 3231550..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterBetweenBracketsHandler.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.codeInsight.editorActions.enter.EnterBetweenBracesHandler;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
-import com.intellij.openapi.util.Ref;
-import com.intellij.psi.PsiFile;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Extends IntelliJ's {@link EnterBetweenBracesHandler}, including square brackets as a valid
- * brace pair type.
- */
-public class BuildEnterBetweenBracketsHandler extends EnterBetweenBracesHandler {
- @Override
- public Result preprocessEnter(@NotNull PsiFile file,
- @NotNull Editor editor,
- @NotNull Ref<Integer> caretOffsetRef,
- @NotNull Ref<Integer> caretAdvance,
- @NotNull DataContext dataContext,
- EditorActionHandler originalHandler) {
- if (!(file instanceof BuildFile)) {
- return Result.Continue;
- }
- return super.preprocessEnter(file, editor, caretOffsetRef, caretAdvance, dataContext, originalHandler);
- }
-
- @Override
- protected boolean isBracePair(char c1, char c2) {
- return c1 == '[' && c2 == ']';
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterHandler.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterHandler.java
deleted file mode 100644
index 044280c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildEnterHandler.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter;
-import com.intellij.ide.DataManager;
-import com.intellij.injected.editor.EditorWindow;
-import com.intellij.lang.injection.InjectedLanguageManager;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.LogicalPosition;
-import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
-import com.intellij.openapi.editor.actions.SplitLineAction;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.*;
-import com.intellij.psi.codeStyle.CodeStyleSettings;
-import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
-import com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptions;
-import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
-import com.intellij.util.text.CharArrayUtil;
-
-import javax.annotation.Nullable;
-
-/**
- * Inserts indents as appropriate when enter is pressed.<br>
- * This is a substitute for implementing a full FormattingModel for the BUILD language.
- * If we ever decide to do that, this code should be removed.
- */
-public class BuildEnterHandler extends EnterHandlerDelegateAdapter {
-
- @Override
- public Result preprocessEnter(PsiFile file,
- Editor editor,
- Ref<Integer> caretOffset,
- Ref<Integer> caretAdvance,
- DataContext dataContext,
- EditorActionHandler originalHandler) {
- int offset = caretOffset.get();
- if (editor instanceof EditorWindow) {
- file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
- editor = InjectedLanguageUtil.getTopLevelEditor(editor);
- offset = editor.getCaretModel().getOffset();
- }
- if (!isApplicable(file, dataContext)) {
- return Result.Continue;
- }
-
- // Previous enter handler's (e.g. EnterBetweenBracesHandler) can introduce a mismatch
- // between the editor's caret model and the offset we've been provided with.
- editor.getCaretModel().moveToOffset(offset);
-
- Document doc = editor.getDocument();
- PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
-
- CodeStyleSettings currentSettings = CodeStyleSettingsManager.getSettings(file.getProject());
- IndentOptions indentOptions = currentSettings.getIndentOptions(file.getFileType());
-
- Integer indent = determineIndent(file, editor, offset, indentOptions);
- if (indent == null) {
- return Result.Continue;
- }
-
- removeTrailingWhitespace(doc, file, offset);
- originalHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
- LogicalPosition position = editor.getCaretModel().getLogicalPosition();
- if (position.column == indent) {
- return Result.Stop;
- }
- if (position.column > indent) {
- //default enter handler has added too many spaces -- remove them
- int excess = position.column - indent;
- doc.deleteString(editor.getCaretModel().getOffset() - excess, editor.getCaretModel().getOffset());
- } else if (position.column < indent) {
- String spaces = StringUtil.repeatSymbol(' ', indent - position.column);
- doc.insertString(editor.getCaretModel().getOffset(), spaces);
- }
- editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(position.line, indent));
- return Result.Stop;
- }
-
- private static void removeTrailingWhitespace(Document doc, PsiFile file, int offset) {
- CharSequence chars = doc.getCharsSequence();
- int start = offset;
- while (offset < chars.length() && chars.charAt(offset) == ' ') {
- PsiElement element = file.findElementAt(offset);
- if (element == null || !(element instanceof PsiWhiteSpace)) {
- break;
- }
- offset++;
- }
- if (start != offset) {
- doc.deleteString(start, offset);
- }
- }
-
- private static boolean isApplicable(PsiFile file, DataContext dataContext) {
- if (!(file instanceof BuildFile)) {
- return false;
- }
- Boolean isSplitLine = DataManager.getInstance().loadFromDataContext(dataContext, SplitLineAction.SPLIT_LINE_KEY);
- if (isSplitLine != null) {
- return false;
- }
- return true;
- }
-
- /**
- * Returns null if an appropriate indent cannot be found. In that case we do nothing,
- * and pass it along to the next EnterHandler.
- */
- @Nullable
- private static Integer determineIndent(PsiFile file, Editor editor, int offset, IndentOptions indentOptions) {
- if (offset == 0) {
- return null;
- }
- Document doc = editor.getDocument();
- PsiElement element = getRelevantElement(file, doc, offset);
- PsiElement parent = element != null ? element.getParent() : null;
- if (parent == null) {
- return null;
- }
- if (endsBlock(element)) {
- // current line indent subtract block indent
- return Math.max(0, getIndent(doc, element) - indentOptions.INDENT_SIZE);
- }
-
- if (parent instanceof BuildListType) {
- BuildListType list = (BuildListType) parent;
- int listOffset = list.getStartOffset();
- LogicalPosition caretPosition = editor.getCaretModel().getLogicalPosition();
- LogicalPosition listStart = editor.offsetToLogicalPosition(listOffset);
- if (listStart.line != caretPosition.line) {
- // take the minimum of the current line's indent and the current caret position
- return indentOfLineUpToCaret(doc, caretPosition.line, offset);
- }
- BuildElement firstChild = ((BuildListType) parent).getFirstElement();
- if (firstChild != null && firstChild.getNode().getStartOffset() < offset) {
- return getIndent(doc, firstChild);
- }
- return lineIndent(doc, listStart.line) + additionalIndent(parent, indentOptions);
- }
- if (parent instanceof StatementListContainer && afterColon(doc, offset)) {
- return getIndent(doc, parent) + additionalIndent(parent, indentOptions);
- }
- return null;
- }
-
- private static int additionalIndent(PsiElement parent, IndentOptions indentOptions) {
- return parent instanceof StatementListContainer
- ? indentOptions.INDENT_SIZE : indentOptions.CONTINUATION_INDENT_SIZE;
- }
-
- private static int lineIndent(Document doc, int line) {
- int startOffset = doc.getLineStartOffset(line);
- int indentOffset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
- return indentOffset - startOffset;
- }
-
- private static int getIndent(Document doc, PsiElement element) {
- int offset = element.getNode().getStartOffset();
- int lineNumber = doc.getLineNumber(offset);
- return offset - doc.getLineStartOffset(lineNumber);
- }
-
- private static int indentOfLineUpToCaret(Document doc, int line, int caretOffset) {
- int startOffset = doc.getLineStartOffset(line);
- int indentOffset = CharArrayUtil.shiftForward(doc.getCharsSequence(), startOffset, " \t");
- return Math.min(indentOffset, caretOffset) - startOffset;
- }
-
- private static boolean endsBlock(PsiElement element) {
- return element instanceof ReturnStatement
- || element instanceof PassStatement;
- }
-
- private static PsiElement getBlockEndingParent(PsiElement element) {
- while (element != null && !(element instanceof PsiFileSystemItem)) {
- if (endsBlock(element)) {
- return element;
- }
- element = element.getParent();
- }
- return null;
- }
-
- @Nullable
- private static PsiElement getRelevantElement(PsiFile file, Document doc, int offset) {
- if (offset == 0) {
- return null;
- }
- if (offset == doc.getTextLength()) {
- offset--;
- }
- PsiElement element = file.findElementAt(offset);
- while (element != null && isWhiteSpace(element)) {
- element = PsiUtils.getPreviousNodeInTree(element);
- }
- PsiElement blockTerminator = getBlockEndingParent(element);
- if (blockTerminator != null
- && blockTerminator.getTextRange().getEndOffset() == element.getTextRange().getEndOffset()) {
- return blockTerminator;
- }
- while (element != null && skipElement(element, offset)) {
- element = element.getParent();
- }
- return element;
- }
-
- private static boolean isWhiteSpace(PsiElement element) {
- if (element instanceof PsiWhiteSpace) {
- return true;
- }
- return BuildToken.WHITESPACE_AND_NEWLINE.contains(element.getNode().getElementType());
- }
-
- private static boolean skipElement(PsiElement element, int offset) {
- PsiElement parent = element.getParent();
- if (parent == null || parent.getNode() == null || parent instanceof PsiFileSystemItem) {
- return false;
- }
- TextRange childRange = element.getNode().getTextRange();
- return childRange.equals(parent.getNode().getTextRange())
- || childRange.getStartOffset() == offset && (parent instanceof Argument || parent instanceof Parameter);
- }
-
- private static boolean afterColon(Document doc, int offset) {
- CharSequence text = doc.getCharsSequence();
- int previousOffset = CharArrayUtil.shiftBackward(text, offset - 1, " \t");
- return text.charAt(previousOffset) == ':';
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandler.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandler.java
deleted file mode 100644
index ecde586..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandler.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.codeInsight.editorActions.MultiCharQuoteHandler;
-import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.highlighter.HighlighterIterator;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.tree.IElementType;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides quote auto-closing support.
- */
-public class BuildQuoteHandler extends SimpleTokenSetQuoteHandler implements MultiCharQuoteHandler {
-
- public BuildQuoteHandler() {
- super(BuildToken.fromKind(TokenKind.STRING));
- }
-
- @Override
- public boolean isOpeningQuote(HighlighterIterator iterator, int offset) {
- if (!myLiteralTokenSet.contains(iterator.getTokenType())) {
- return false;
- }
- int start = iterator.getStart();
- if (offset == start) {
- return true;
- }
- final Document document = iterator.getDocument();
- if (document == null) {
- return false;
- }
- CharSequence text = document.getCharsSequence();
- char theQuote = text.charAt(offset);
- if (offset >= 2 &&
- text.charAt(offset - 1) == theQuote &&
- text.charAt(offset - 2) == theQuote &&
- (offset < 3 || text.charAt(offset - 3) != theQuote))
- if (super.isOpeningQuote(iterator, offset)) {
- return true;
- }
- return false;
- }
-
- private static int getLiteralStartOffset(CharSequence text, int start) {
- char c = Character.toUpperCase(text.charAt(start));
- if (c == 'U' || c == 'B') {
- start++;
- c = Character.toUpperCase(text.charAt(start));
- }
- if (c == 'R') {
- start++;
- }
- return start;
- }
-
- @Override
- protected boolean isNonClosedLiteral(HighlighterIterator iterator, CharSequence chars) {
- int end = iterator.getEnd();
- if (getLiteralStartOffset(chars, iterator.getStart()) >= end - 1) {
- return true;
- }
- char endSymbol = chars.charAt(end - 1);
- if (endSymbol != '"' && endSymbol != '\'') {
- return true;
- }
-
- //for triple quoted string
- if (end >= 3 &&
- (endSymbol == chars.charAt(end - 2)) && (chars.charAt(end - 2) == chars.charAt(end - 3)) &&
- (end < 4 || chars.charAt(end - 4) != endSymbol)) {
- return true;
- }
-
- return false;
- }
-
- @Override
- public boolean isClosingQuote(HighlighterIterator iterator, int offset) {
- final IElementType tokenType = iterator.getTokenType();
- if (!myLiteralTokenSet.contains(tokenType)) {
- return false;
- }
- int start = iterator.getStart();
- int end = iterator.getEnd();
- if (end - start >= 1 && offset == end - 1) {
- return true; // single quote
- }
- if (end - start < 3 || offset < end - 3) {
- return false;
- }
- // check for triple quote
- Document doc = iterator.getDocument();
- if (doc == null) {
- return false;
- }
- CharSequence chars = doc.getCharsSequence();
- char quote = chars.charAt(start);
- boolean tripleQuote = quote == chars.charAt(start + 1)
- && quote == chars.charAt(start + 2);
- if (!tripleQuote) {
- return false;
- }
- for (int i = offset; i < Math.min(offset + 2, end); i++) {
- if (quote != chars.charAt(i)) {
- return false;
- }
- }
- return true;
- }
-
- @Nullable
- @Override
- public CharSequence getClosingQuote(HighlighterIterator iterator, int offset) {
- char theQuote = iterator.getDocument().getCharsSequence().charAt(offset - 1);
- if (super.isOpeningQuote(iterator, offset - 1)) {
- return String.valueOf(theQuote);
- }
- if (super.isOpeningQuote(iterator, offset - 3)) {
- return StringUtil.repeat(String.valueOf(theQuote), 3);
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildElementDescriptionProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildElementDescriptionProvider.java
deleted file mode 100644
index 817a158..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildElementDescriptionProvider.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
-import com.intellij.psi.ElementDescriptionLocation;
-import com.intellij.psi.ElementDescriptionProvider;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNameIdentifierOwner;
-import com.intellij.usageView.UsageViewLongNameLocation;
-import com.intellij.usageView.UsageViewShortNameLocation;
-
-import javax.annotation.Nullable;
-
-/**
- * Controls text shown for target in the 'find usages' dialog.
- */
-public class BuildElementDescriptionProvider implements ElementDescriptionProvider {
- @Nullable
- @Override
- public String getElementDescription(PsiElement element, ElementDescriptionLocation location) {
- if (!(element instanceof BuildElement)) {
- return null;
- }
- if (location instanceof UsageViewLongNameLocation) {
- return ((BuildElement) element).getPresentableText();
- }
- if (location instanceof UsageViewShortNameLocation) {
- if (element instanceof PsiNameIdentifierOwner) {
- // this is used by rename operations, so needs to be accurate
- return ((PsiNameIdentifierOwner) element).getName();
- }
- return ((BuildElement) element).getPresentableText();
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFileGroupingRuleProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFileGroupingRuleProvider.java
deleted file mode 100644
index 73a9d4f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFileGroupingRuleProvider.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.usages.Usage;
-import com.intellij.usages.UsageGroup;
-import com.intellij.usages.UsageView;
-import com.intellij.usages.impl.FileStructureGroupRuleProvider;
-import com.intellij.usages.impl.rules.FileGroupingRule;
-import com.intellij.usages.rules.UsageGroupingRule;
-import com.intellij.usages.rules.UsageInFile;
-
-import javax.swing.*;
-
-/**
- * Allows us to customize the filename string in the 'find usages' dialog, rather than displaying them all as 'BUILD'.
- */
-public class BuildFileGroupingRuleProvider implements FileStructureGroupRuleProvider {
-
- public static UsageGroupingRule getGroupingRule(Project project) {
- return new BuildFileGroupingRule(project);
- }
-
- @Override
- public UsageGroupingRule getUsageGroupingRule(Project project) {
- return getGroupingRule(project);
- }
-
- private static class BuildFileGroupingRule extends FileGroupingRule {
-
- private final Project project;
-
- BuildFileGroupingRule(Project project) {
- super(project);
- this.project = project;
- }
-
- @Override
- public UsageGroup groupUsage(Usage usage) {
- if (!(usage instanceof UsageInFile)) {
- return null;
- }
- final VirtualFile virtualFile = ((UsageInFile) usage).getFile();
- if (virtualFile.getFileType() != BuildFileType.INSTANCE) {
- return null;
- }
- return new FileUsageGroup(project, virtualFile) {
- String name;
-
- @Override
- public void update() {
- if (isValid()) {
- super.update();
- name = BuildFile.getBuildFileString(project, virtualFile.getPath());
- }
- }
-
- @Override
- public String getPresentableName() {
- return name;
- }
-
- @Override
- public String getText(UsageView view) {
- return name;
- }
-
- @Override
- public Icon getIcon(boolean isOpen) {
- return null; // already shown by default usage group (which we can't remove...)
- }
- };
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFindUsagesProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFindUsagesProvider.java
deleted file mode 100644
index 792bda8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildFindUsagesProvider.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase.LexerMode;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.intellij.lang.HelpID;
-import com.intellij.lang.cacheBuilder.DefaultWordsScanner;
-import com.intellij.lang.cacheBuilder.WordsScanner;
-import com.intellij.lang.findUsages.FindUsagesProvider;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNamedElement;
-import com.intellij.psi.tree.TokenSet;
-
-/**
- * Required for highlighting references (among other things we don't currently support).
- * Currently only used by the fallback 'DefaultFindUsagesHandlerFactory'.
- */
-public class BuildFindUsagesProvider implements FindUsagesProvider {
-
- @Override
- public boolean canFindUsagesFor(PsiElement psiElement) {
- return psiElement instanceof FuncallExpression
- || psiElement instanceof PsiNamedElement
- || psiElement instanceof ReferenceExpression;
- }
-
- @Override
- public String getHelpId(PsiElement psiElement) {
- if (psiElement instanceof FunctionStatement) {
- return "reference.dialogs.findUsages.method";
- }
- if (psiElement instanceof TargetExpression
- || psiElement instanceof Parameter
- || psiElement instanceof ReferenceExpression) {
- return "reference.dialogs.findUsages.variable";
- }
- // typically build rules and imported Skylark functions, but also all other function calls
- return HelpID.FIND_OTHER_USAGES;
- }
-
- @Override
- public String getType(PsiElement element) {
- if (element instanceof FunctionStatement) {
- return "function";
- }
- if (element instanceof Parameter) {
- return "parameter";
- }
- if (element instanceof ReferenceExpression
- || element instanceof TargetExpression) {
- return "variable";
- }
- if (element instanceof Argument.Keyword) {
- return "keyword argument";
- }
- if (element instanceof FuncallExpression) {
- return "rule";
- }
- return "";
- }
-
- /**
- * Controls text shown for target element in the 'find usages' dialog
- */
- @Override
- public String getDescriptiveName(PsiElement element) {
- if (element instanceof BuildElement) {
- return ((BuildElement) element).getPresentableText();
- }
- return element.toString();
- }
-
- @Override
- public String getNodeText(PsiElement element, boolean useFullName) {
- return getDescriptiveName(element);
- }
-
- @Override
- public WordsScanner getWordsScanner() {
- return new DefaultWordsScanner(
- new BuildLexer(LexerMode.SyntaxHighlighting),
- tokenSet(TokenKind.IDENTIFIER),
- tokenSet(TokenKind.COMMENT),
- tokenSet(TokenKind.STRING));
- }
-
- private static TokenSet tokenSet(TokenKind token) {
- return TokenSet.create(BuildToken.fromKind(token));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildReadWriteAccessDetector.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildReadWriteAccessDetector.java
deleted file mode 100644
index 91d6810..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildReadWriteAccessDetector.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.AugmentedAssignmentStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-/**
- * Used by find usages tools.
- */
-public class BuildReadWriteAccessDetector extends ReadWriteAccessDetector {
- @Override
- public boolean isReadWriteAccessible(PsiElement element) {
- return element instanceof TargetExpression || element instanceof ReferenceExpression;
- }
-
- @Override
- public boolean isDeclarationWriteAccess(PsiElement element) {
- return element instanceof TargetExpression;
- }
-
- @Override
- public Access getReferenceAccess(PsiElement referencedElement, PsiReference reference) {
- return getExpressionAccess(reference.getElement());
- }
-
- @Override
- public Access getExpressionAccess(PsiElement expression) {
- if (isDeclarationWriteAccess(expression)) {
- return Access.Write;
- }
- if (expression instanceof ReferenceExpression) {
- if (PsiUtils.getParentOfType(expression, AugmentedAssignmentStatement.class) != null) {
- return Access.ReadWrite;
- }
- }
- return Access.Read;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildTargetElementEvaluator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildTargetElementEvaluator.java
deleted file mode 100644
index 8c0ca79..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildTargetElementEvaluator.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument.Keyword;
-import com.google.idea.blaze.base.lang.buildfile.psi.ArgumentList;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.intellij.codeInsight.TargetElementEvaluatorEx2;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.impl.source.resolve.reference.impl.PsiMultiReference;
-
-import javax.annotation.Nullable;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.Objects;
-
-/**
- * StringLiterals can reference multiple targets (e.g. "package:target" references both the package and the target).
- * IntelliJ defaults to highlighting / navigating to the innermost reference, but in this case, we want the
- * opposite behavior (the target reference should trump the package reference).
- */
-public class BuildTargetElementEvaluator extends TargetElementEvaluatorEx2 {
-
- @Override
- public boolean includeSelfInGotoImplementation(PsiElement element) {
- return false;
- }
-
- /**
- * Returns null in the cases where we're happy with the default behavior.
- */
- @Nullable
- @Override
- public PsiElement getElementByReference(PsiReference ref, int flags) {
- if (!(ref instanceof PsiMultiReference) || !(ref.getElement() instanceof StringLiteral)) {
- return null;
- }
- // choose the outer-most reference
- PsiReference[] refs = ((PsiMultiReference) ref).getReferences().clone();
- Arrays.sort(refs, COMPARATOR);
- return refs[0].resolve();
- }
-
- private static final Comparator<PsiReference> COMPARATOR = new Comparator<PsiReference>() {
- @Override
- public int compare(final PsiReference ref1, final PsiReference ref2) {
- boolean resolves1 = ref1.resolve() != null;
- boolean resolves2 = ref2.resolve() != null;
- if (resolves1 && !resolves2) return -1;
- if (!resolves1 && resolves2) return 1;
-
- final TextRange range1 = ref1.getRangeInElement();
- final TextRange range2 = ref2.getRangeInElement();
-
- if(TextRange.areSegmentsEqual(range1, range2)) return 0;
- if(range1.getStartOffset() >= range2.getStartOffset() && range1.getEndOffset() <= range2.getEndOffset()) return 1;
- if(range2.getStartOffset() >= range1.getStartOffset() && range2.getEndOffset() <= range1.getEndOffset()) return -1;
-
- return 0;
- }
- };
-
- /**
- * Redirect 'name' funcall argument values to the funcall expression (b/29088829).
- */
- @Nullable
- @Override
- public PsiElement getNamedElement(PsiElement element) {
- return getParentFuncallIfNameString(element);
- }
-
- @Nullable
- private static FuncallExpression getParentFuncallIfNameString(PsiElement element) {
- PsiElement parent = element.getParent();
- if (!(parent instanceof StringLiteral)) {
- return null;
- }
- parent = parent.getParent();
- if (!(parent instanceof Keyword)) {
- return null;
- }
- if (!Objects.equals(((Keyword) parent).getName(), "name")) {
- return null;
- }
- parent = parent.getParent();
- if (!(parent instanceof ArgumentList)) {
- return null;
- }
- parent = parent.getParent();
- return parent instanceof FuncallExpression ? (FuncallExpression) parent : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildUsageGroupingRuleProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildUsageGroupingRuleProvider.java
deleted file mode 100644
index 9371a92..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/findusages/BuildUsageGroupingRuleProvider.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.project.Project;
-import com.intellij.usages.UsageView;
-import com.intellij.usages.rules.UsageGroupingRule;
-import com.intellij.usages.rules.UsageGroupingRuleProvider;
-
-/**
- * This is a gross hack. We want to always include file paths for BUILD files in the 'find usages' dialog.<br>
- * This achieves that by inserting an additional UsageGroupingRule for each file usage,
- * regardless of whether we're grouping by file structure
- */
-public class BuildUsageGroupingRuleProvider implements UsageGroupingRuleProvider {
- @Override
- public UsageGroupingRule[] getActiveRules(Project project) {
- return new UsageGroupingRule[] {BuildFileGroupingRuleProvider.getGroupingRule(project)};
- }
-
- @Override
- public AnAction[] createGroupingActions(UsageView view) {
- return new AnAction[0];
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildBraceMatcher.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildBraceMatcher.java
deleted file mode 100644
index 29f9528..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildBraceMatcher.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.lang.BracePair;
-import com.intellij.lang.PairedBraceMatcher;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.tree.TokenSet;
-
-import javax.annotation.Nullable;
-import java.util.Arrays;
-
-/**
- * This adds a close brace automatically once an opening brace is typed by the user in the editor.
- */
-public class BuildBraceMatcher implements PairedBraceMatcher {
-
- private static final BracePair[] PAIRS = new BracePair[] {
- new BracePair(BuildToken.fromKind(TokenKind.LPAREN), BuildToken.fromKind(TokenKind.RPAREN), true),
- new BracePair(BuildToken.fromKind(TokenKind.LBRACKET), BuildToken.fromKind(TokenKind.RBRACKET), true),
- new BracePair(BuildToken.fromKind(TokenKind.LBRACE), BuildToken.fromKind(TokenKind.RBRACE), true)
- };
-
- private static final TokenSet BRACES_ALLOWED_BEFORE = tokenSet(
- TokenKind.NEWLINE,
- TokenKind.WHITESPACE,
- TokenKind.COMMENT,
- TokenKind.COLON,
- TokenKind.COMMA,
- TokenKind.RPAREN,
- TokenKind.RBRACKET,
- TokenKind.RBRACE,
- TokenKind.LBRACE
- );
-
- @Override
- public BracePair[] getPairs() {
- return PAIRS;
- }
-
- @Override
- public boolean isPairedBracesAllowedBeforeType(IElementType lbraceType, @Nullable IElementType contextType) {
- return contextType == null || BRACES_ALLOWED_BEFORE.contains(contextType);
- }
-
- @Override
- public int getCodeConstructStart(PsiFile file, int openingBraceOffset) {
- return openingBraceOffset;
- }
-
- private static TokenSet tokenSet(TokenKind... kind) {
- return TokenSet.create(
- Arrays.stream(kind)
- .map(BuildToken::fromKind)
- .toArray(IElementType[]::new)
- );
- }
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCodeStyleSettingsProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCodeStyleSettingsProvider.java
deleted file mode 100644
index ac31695..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCodeStyleSettingsProvider.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.intellij.application.options.CodeStyleAbstractConfigurable;
-import com.intellij.application.options.CodeStyleAbstractPanel;
-import com.intellij.application.options.TabbedLanguageCodeStylePanel;
-import com.intellij.openapi.options.Configurable;
-import com.intellij.psi.codeStyle.CodeStyleSettings;
-import com.intellij.psi.codeStyle.CodeStyleSettingsProvider;
-import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
-
-import javax.annotation.Nullable;
-
-/**
- * Separate configurable code-style settings for BUILD language.
- */
-public class BuildCodeStyleSettingsProvider extends CodeStyleSettingsProvider {
-
- @Override
- public Configurable createSettingsPage(CodeStyleSettings settings, CodeStyleSettings originalSettings) {
- return new CodeStyleAbstractConfigurable(settings, originalSettings, BuildFileType.INSTANCE.getDescription()) {
- @Override
- protected CodeStyleAbstractPanel createPanel(final CodeStyleSettings settings) {
- return new TabbedLanguageCodeStylePanel(BuildFileLanguage.INSTANCE, getCurrentSettings(), settings) {
- @Override
- protected void initTabs(CodeStyleSettings settings) {
- LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(getDefaultLanguage());
- addIndentOptionsTab(settings);
- }
- };
- }
-
- @Override
- public String getHelpTopic() {
- return null;
- }
- };
- }
-
- @Nullable
- @Override
- public String getConfigurableDisplayName() {
- return BuildFileType.INSTANCE.getDescription();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCommenter.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCommenter.java
deleted file mode 100644
index ad9d849..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildCommenter.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.lang.CodeDocumentationAwareCommenter;
-import com.intellij.psi.PsiComment;
-import com.intellij.psi.tree.IElementType;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Supports (un)commenting lines via IntelliJ
- */
-public class BuildCommenter implements CodeDocumentationAwareCommenter {
-
- @Nullable
- @Override
- public String getLineCommentPrefix() {
- return "#";
- }
-
- @Nullable
- @Override
- public String getBlockCommentPrefix() {
- return null;
- }
-
- @Nullable
- @Override
- public String getBlockCommentSuffix() {
- return null;
- }
-
- @Nullable
- @Override
- public String getCommentedBlockCommentPrefix() {
- return null;
- }
-
- @Nullable
- @Override
- public String getCommentedBlockCommentSuffix() {
- return null;
- }
-
- @Override
- public IElementType getLineCommentTokenType() {
- return BuildToken.fromKind(TokenKind.COMMENT);
- }
-
- @Override
- public IElementType getBlockCommentTokenType() {
- return null;
- }
-
- @Override
- public IElementType getDocumentationCommentTokenType() {
- return null;
- }
-
- @Override
- public String getDocumentationCommentPrefix() {
- return null;
- }
-
- @Override
- public String getDocumentationCommentLinePrefix() {
- return null;
- }
-
- @Override
- public String getDocumentationCommentSuffix() {
- return null;
- }
-
- @Override
- public boolean isDocumentationComment(PsiComment element) {
- return false;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilder.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilder.java
deleted file mode 100644
index d17ebfe..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilder.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.FileASTNode;
-import com.intellij.lang.folding.FoldingBuilder;
-import com.intellij.lang.folding.FoldingDescriptor;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.TokenType;
-import com.intellij.psi.tree.IElementType;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * Simple code block folding for BUILD files.
- */
-public class BuildFileFoldingBuilder implements FoldingBuilder {
-
- /**
- * Currently only folding top-level nodes.
- */
- @Override
- public FoldingDescriptor[] buildFoldRegions(ASTNode node, Document document) {
- List<FoldingDescriptor> descriptors = Lists.newArrayList();
- if (node instanceof FileASTNode) {
- for (ASTNode child : node.getChildren(null)) {
- addDescriptors(descriptors, child);
- }
- } else if (isTopLevel(node)) {
- addDescriptors(descriptors, node);
- }
- return descriptors.toArray(new FoldingDescriptor[0]);
- }
-
- /**
- * Only folding top-level statements
- */
- private void addDescriptors(List<FoldingDescriptor> descriptors, ASTNode node) {
- IElementType type = node.getElementType();
- if (type == BuildElementTypes.FUNCTION_STATEMENT) {
- ASTNode colon = node.findChildByType(BuildToken.fromKind(TokenKind.COLON));
- if (colon == null) {
- return;
- }
- ASTNode stmtList = node.findChildByType(BuildElementTypes.STATEMENT_LIST);
- if (stmtList == null) {
- return;
- }
- int start = colon.getStartOffset() + 1;
- int end = endOfList(stmtList);
- descriptors.add(new FoldingDescriptor(node, range(start, end)));
-
- } else if (type == BuildElementTypes.FUNCALL_EXPRESSION || type == BuildElementTypes.LOAD_STATEMENT) {
- ASTNode listNode = type == BuildElementTypes.FUNCALL_EXPRESSION ? node.findChildByType(BuildElementTypes.ARGUMENT_LIST) : node;
- if (listNode == null) {
- return;
- }
- ASTNode lParen = listNode.findChildByType(BuildToken.fromKind(TokenKind.LPAREN));
- ASTNode rParen = listNode.findChildByType(BuildToken.fromKind(TokenKind.RPAREN));
- if (lParen == null || rParen == null) {
- return;
- }
- int start = lParen.getStartOffset() + 1;
- int end = rParen.getTextRange().getEndOffset() - 1;
- descriptors.add(new FoldingDescriptor(node, range(start, end)));
- }
- }
-
- private static TextRange range(int start, int end) {
- if (start >= end) {
- return new TextRange(start, start + 1);
- }
- return new TextRange(start, end);
- }
-
- /**
- * Don't include whitespace and newlines at the end of the function.<br>
- * Could do this in the lexer instead, with additional look-ahead checks.
- */
- private int endOfList(ASTNode stmtList) {
- ASTNode child = stmtList.getLastChildNode();
- while (child != null) {
- IElementType type = child.getElementType();
- if (type != TokenType.WHITE_SPACE
- && type != BuildToken.fromKind(TokenKind.NEWLINE)) {
- return child.getTextRange().getEndOffset();
- }
- child = child.getTreePrev();
- }
- return stmtList.getTextRange().getEndOffset();
- }
-
- private boolean isTopLevel(ASTNode node) {
- return node.getTreeParent() instanceof FileASTNode;
- }
-
- @Override
- @Nullable
- public String getPlaceholderText(ASTNode node) {
- PsiElement psi = node.getPsi();
- if (psi instanceof FuncallExpression) {
- FuncallExpression expr = (FuncallExpression) psi;
- String name = expr.getNameArgumentValue();
- if (name != null) {
- return "name = \"" + name + "\"...";
- }
- }
- if (psi instanceof LoadStatement) {
- String fileName = ((LoadStatement) psi).getImportedPath();
- if (fileName != null) {
- return "\"" + fileName + "\"...";
- }
- }
- return "...";
- }
-
- @Override
- public boolean isCollapsedByDefault(ASTNode node) {
- return false;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildLanguageCodeStyleSettingsProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildLanguageCodeStyleSettingsProvider.java
deleted file mode 100644
index 3300a97..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/formatting/BuildLanguageCodeStyleSettingsProvider.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.intellij.application.options.IndentOptionsEditor;
-import com.intellij.application.options.SmartIndentOptionsEditor;
-import com.intellij.lang.Language;
-import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
-import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Allows BUILD language-specific code style settings
- */
-public class BuildLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider {
-
- @Override
- public Language getLanguage() {
- return BuildFileLanguage.INSTANCE;
- }
-
- @Override
- public IndentOptionsEditor getIndentOptionsEditor() {
- return new SmartIndentOptionsEditor();
- }
-
- @Override
- public String getCodeSample(@NotNull SettingsType settingsType) {
- return "";
- }
-
- @Nullable
- @Override
- public CommonCodeStyleSettings getDefaultCommonSettings() {
- CommonCodeStyleSettings defaultSettings = new CommonCodeStyleSettings(BuildFileLanguage.INSTANCE);
- CommonCodeStyleSettings.IndentOptions indentOptions = defaultSettings.initIndentOptions();
- indentOptions.TAB_SIZE = 2;
- indentOptions.INDENT_SIZE = 2;
- indentOptions.CONTINUATION_INDENT_SIZE = 4;
- return defaultSettings;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java
deleted file mode 100644
index 6a0200d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/globbing/UnixGlob.java
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.globbing;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.base.Throwables;
-import com.google.common.cache.Cache;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.ForwardingListenableFuture;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.lang.buildfile.validation.GlobPatternValidator;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileSystem;
-import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Predicate;
-import java.util.regex.Pattern;
-
-/**
- * Implementation of a subset of UNIX-style file globbing, expanding "*" and "?" as wildcards, but
- * not [a-z] ranges.
- *
- * <p><code>**</code> gets special treatment in include patterns. If it is used as a complete path
- * segment it matches the filenames in subdirectories recursively.
- *
- * Largely copied from {@link com.google.devtools.build.lib.vfs.UnixGlob}
- */
-public final class UnixGlob {
- private UnixGlob() {}
-
- private static List<File> globInternal(File base,
- Collection<String> patterns,
- Collection<String> excludePatterns,
- boolean excludeDirectories,
- Predicate<File> dirPred,
- ThreadPoolExecutor threadPool)
- throws IOException, InterruptedException {
-
- GlobVisitor visitor = (threadPool == null)
- ? new GlobVisitor()
- : new GlobVisitor(threadPool);
- return visitor.glob(base, patterns, excludePatterns, excludeDirectories, dirPred);
- }
-
- private static Future<List<File>> globAsyncInternal(File base,
- Collection<String> patterns,
- Collection<String> excludePatterns,
- boolean excludeDirectories,
- Predicate<File> dirPred,
- ThreadPoolExecutor threadPool) {
- Preconditions.checkNotNull(threadPool, "%s %s", base, patterns);
- try {
- return new GlobVisitor(threadPool)
- .globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred);
- } catch (IOException e) {
- // We are evaluating asynchronously, so no exceptions should be thrown until the future is
- // retrieved.
- throw new IllegalStateException(e);
- }
- }
-
- /**
- * Checks that each pattern is valid, splits it into segments and checks
- * that each segment contains only valid wildcards.
- *
- * @return list of segment arrays
- */
- private static List<String[]> checkAndSplitPatterns(Collection<String> patterns) {
- List<String[]> list = Lists.newArrayListWithCapacity(patterns.size());
- for (String pattern : patterns) {
- String error = GlobPatternValidator.validate(pattern);
- if (error != null) {
- throw new IllegalArgumentException(error);
- }
- Iterable<String> segments = Splitter.on('/').split(pattern);
- list.add(Iterables.toArray(segments, String.class));
- }
- return list;
- }
-
- private static boolean excludedOnMatch(File path,
- List<String[]> excludePatterns,
- int idx,
- Cache<String, Pattern> cache) {
- for (String[] excludePattern : excludePatterns) {
- String text = path.getName();
- if (idx == excludePattern.length
- && matches(excludePattern[idx - 1], text, cache)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the exclude patterns in {@code excludePatterns} which could
- * apply to the children of {@code base}
- *
- * @param idx index into {@code excludePatterns} for the part of the pattern
- * which might match {@code base}
- */
- private static List<String[]> getRelevantExcludes(
- final File base,
- List<String[]> excludePatterns,
- final int idx,
- final Cache<String, Pattern> cache) {
-
- if (excludePatterns.isEmpty()) {
- return excludePatterns;
- }
- List<String[]> list = new ArrayList<>();
- for (String[] patterns : excludePatterns) {
- if (excludePatternMatches(patterns, idx, base, cache)) {
- list.add(patterns);
- }
- }
- return list;
- }
-
- /**
- * @param patterns a list of patterns
- * @param idx index into {@code patterns}
- */
- private static boolean excludePatternMatches(String[] patterns,
- int idx,
- File base,
- Cache<String, Pattern> cache) {
- if (idx == 0) {
- return true;
- }
- String text = base.getName();
- return patterns.length > idx && matches(patterns[idx - 1], text, cache);
- }
-
- /**
- * Calls {@link #matches(String, String, Cache) matches(pattern, str, null)}
- */
- public static boolean matches(String pattern, String str) {
- return matches(pattern, str, null);
- }
-
- /**
- * Returns whether {@code str} matches the glob pattern {@code pattern}. This
- * method may use the {@code patternCache} to speed up the matching process.
- *
- * @param pattern a glob pattern
- * @param str the string to match
- * @param patternCache a cache from patterns to compiled Pattern objects, or
- * {@code null} to skip caching
- */
- public static boolean matches(String pattern,
- String str,
- Cache<String, Pattern> patternCache) {
- if (pattern.length() == 0 || str.length() == 0) {
- return false;
- }
-
- // Common case: **
- if (pattern.equals("**")) {
- return true;
- }
-
- // Common case: *
- if (pattern.equals("*")) {
- return true;
- }
-
- // If a filename starts with '.', this char must be matched explicitly.
- if (str.charAt(0) == '.' && pattern.charAt(0) != '.') {
- return false;
- }
-
- // Common case: *.xyz
- if (pattern.charAt(0) == '*' && pattern.lastIndexOf('*') == 0) {
- return str.endsWith(pattern.substring(1));
- }
- // Common case: xyz*
- int lastIndex = pattern.length() - 1;
- // The first clause of this if statement is unnecessary, but is an
- // optimization--charAt runs faster than indexOf.
- if (pattern.charAt(lastIndex) == '*' && pattern.indexOf('*') == lastIndex) {
- return str.startsWith(pattern.substring(0, lastIndex));
- }
-
- Pattern regex = patternCache == null ? null : patternCache.getIfPresent(pattern);
- if (regex == null) {
- regex = makePatternFromWildcard(pattern);
- if (patternCache != null) {
- patternCache.put(pattern, regex);
- }
- }
- return regex.matcher(str).matches();
- }
-
- /**
- * Returns a regular expression implementing a matcher for "pattern", in which
- * "*" and "?" are wildcards.
- *
- * <p>e.g. "foo*bar?.java" -> "foo.*bar.\\.java"
- */
- private static Pattern makePatternFromWildcard(String pattern) {
- StringBuilder regexp = new StringBuilder();
- for(int i = 0, len = pattern.length(); i < len; i++) {
- char c = pattern.charAt(i);
- switch(c) {
- case '*':
- int toIncrement = 0;
- if (len > i + 1 && pattern.charAt(i + 1) == '*') {
- // The pattern '**' is interpreted to match 0 or more directory separators, not 1 or
- // more. We skip the next * and then find a trailing/leading '/' and get rid of it.
- toIncrement = 1;
- if (len > i + 2 && pattern.charAt(i + 2) == '/') {
- // We have '**/' -- skip the '/'.
- toIncrement = 2;
- } else if (len == i + 2 && i > 0 && pattern.charAt(i - 1) == '/') {
- // We have '/**' -- remove the '/'.
- regexp.delete(regexp.length() - 1, regexp.length());
- }
- }
- regexp.append(".*");
- i += toIncrement;
- break;
- case '?':
- regexp.append('.');
- break;
- //escape the regexp special characters that are allowed in wildcards
- case '^': case '$': case '|': case '+':
- case '{': case '}': case '[': case ']':
- case '\\': case '.':
- regexp.append('\\');
- regexp.append(c);
- break;
- default:
- regexp.append(c);
- break;
- }
- }
- return Pattern.compile(regexp.toString());
- }
-
- public static Builder forPath(File path) {
- return new Builder(path);
- }
-
- /**
- * Builder class for UnixGlob.
- *
- *
- */
- public static class Builder {
- private File base;
- private List<String> patterns;
- private List<String> excludes;
- private boolean excludeDirectories;
- private Predicate<File> pathFilter;
- private ThreadPoolExecutor threadPool;
-
- /**
- * Creates a glob builder with the given base path.
- */
- public Builder(File base) {
- this.base = base;
- this.patterns = Lists.newArrayList();
- this.excludes = Lists.newArrayList();
- this.excludeDirectories = false;
- this.pathFilter = file -> true;
- }
-
- /**
- * Adds a pattern to include to the glob builder.
- *
- * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
- */
- public Builder addPattern(String pattern) {
- this.patterns.add(pattern);
- return this;
- }
-
- /**
- * Adds a pattern to include to the glob builder.
- *
- * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
- */
- public Builder addPatterns(String... patterns) {
- Collections.addAll(this.patterns, patterns);
- return this;
- }
-
- /**
- * Adds a pattern to include to the glob builder.
- *
- * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
- */
- public Builder addPatterns(Collection<String> patterns) {
- this.patterns.addAll(patterns);
- return this;
- }
-
- /**
- * Adds patterns to exclude from the results to the glob builder.
- *
- * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
- */
- public Builder addExcludes(String... excludes) {
- Collections.addAll(this.excludes, excludes);
- return this;
- }
-
- /**
- * Adds patterns to exclude from the results to the glob builder.
- *
- * <p>For a description of the syntax of the patterns, see {@link UnixGlob}.
- */
- public Builder addExcludes(Collection<String> excludes) {
- this.excludes.addAll(excludes);
- return this;
- }
-
- /**
- * If set to true, directories are not returned in the glob result.
- */
- public Builder setExcludeDirectories(boolean excludeDirectories) {
- this.excludeDirectories = excludeDirectories;
- return this;
- }
-
-
- /**
- * Sets the threadpool to use for parallel glob evaluation.
- * If unset, evaluation is done in-thread.
- */
- public Builder setThreadPool(ThreadPoolExecutor pool) {
- this.threadPool = pool;
- return this;
- }
-
-
- /**
- * If set, the given predicate is called for every directory
- * encountered. If it returns false, the corresponding item is not
- * returned in the output and directories are not traversed either.
- */
- public Builder setDirectoryFilter(Predicate<File> pathFilter) {
- this.pathFilter = pathFilter;
- return this;
- }
-
- /**
- * Executes the glob.
- *
- * @throws InterruptedException if the thread is interrupted.
- */
- public List<File> glob() throws IOException, InterruptedException {
- return globInternal(base, patterns, excludes, excludeDirectories, pathFilter, threadPool);
- }
-
- /**
- * Executes the glob asynchronously. {@link #setThreadPool} must have been called already with a
- * non-null argument.
- *
- * @param checkForInterrupt if the returned future may throw InterruptedException.
- */
- public Future<List<File>> globAsync() {
- return globAsyncInternal(base, patterns, excludes, excludeDirectories, pathFilter, threadPool);
- }
- }
-
- /**
- * Adapts the result of the glob visitation as a Future.
- */
- private static class GlobFuture extends ForwardingListenableFuture<List<File>> {
- private final GlobVisitor visitor;
- private final SettableFuture<List<File>> delegate = SettableFuture.create();
-
- public GlobFuture(GlobVisitor visitor) {
- this.visitor = visitor;
- }
-
- @Override
- public List<File> get() throws InterruptedException, ExecutionException {
- return super.get();
- }
-
- @Override
- protected ListenableFuture<List<File>> delegate() {
- return delegate;
- }
-
- public void setException(IOException exception) {
- delegate.setException(exception);
- }
-
- public void set(List<File> paths) {
- delegate.set(paths);
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- // Best-effort interrupt of the in-flight visitation.
- visitor.cancel();
- return true;
- }
-
- public void markCanceled() {
- super.cancel(true);
- }
- }
-
- /**
- * GlobVisitor executes a glob using parallelism, which is useful when
- * the glob() requires many readdir() calls on high latency filesystems.
- */
- private static final class GlobVisitor {
- // These collections are used across workers and must therefore be thread-safe.
- private final Collection<File> results = Sets.newConcurrentHashSet();
- private final Cache<String, Pattern> cache = CacheBuilder.newBuilder().build(
- new CacheLoader<String, Pattern>() {
- @Override
- public Pattern load(String wildcard) {
- return makePatternFromWildcard(wildcard);
- }
- });
-
- private final GlobFuture result;
- private final ThreadPoolExecutor executor;
- private final AtomicLong pendingOps = new AtomicLong(0);
- private final AtomicReference<IOException> failure = new AtomicReference<>();
- private final FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
- private volatile boolean canceled = false;
-
- public GlobVisitor(ThreadPoolExecutor executor) {
- this.executor = executor;
- this.result = new GlobFuture(this);
- }
-
- public GlobVisitor() {
- this(null);
- }
-
- /**
- * Performs wildcard globbing: returns the sorted list of filenames that match any of
- * {@code patterns} relative to {@code base}, but which do not match {@code excludePatterns}.
- * Directories are traversed if and only if they match {@code dirPred}. The predicate is also
- * called for the root of the traversal.
- *
- * <p>Patterns may include "*" and "?", but not "[a-z]".
- *
- * <p><code>**</code> gets special treatment in include patterns. If it is
- * used as a complete path segment it matches the filenames in
- * subdirectories recursively.
- *
- * @throws IllegalArgumentException if any glob or exclude pattern
- * {@linkplain #checkPatternForError(String) contains errors} or if
- * any exclude pattern segment contains <code>**</code> or if any
- * include pattern segment contains <code>**</code> but not equal to
- * it.
- */
- public List<File> glob(File base,
- Collection<String> patterns,
- Collection<String> excludePatterns,
- boolean excludeDirectories,
- Predicate<File> dirPred) throws IOException, InterruptedException {
- try {
- return globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred).get();
- } catch (ExecutionException e) {
- Throwable cause = e.getCause();
- Throwables.propagateIfPossible(cause, IOException.class);
- throw new RuntimeException(e);
- }
- }
-
- public Future<List<File>> globAsync(File base, Collection<String> patterns,
- Collection<String> excludePatterns, boolean excludeDirectories,
- Predicate<File> dirPred) throws IOException {
-
- if (!fileAttributeProvider.exists(base) || patterns.isEmpty()) {
- return Futures.immediateFuture(Collections.emptyList());
- }
- boolean baseIsDirectory = fileAttributeProvider.isDirectory(base);
-
- List<String[]> splitPatterns = checkAndSplitPatterns(patterns);
- List<String[]> splitExcludes = checkAndSplitPatterns(excludePatterns);
-
- // We do a dumb loop, even though it will likely duplicate work
- // (e.g., readdir calls). In order to optimize, we would need
- // to keep track of which patterns shared sub-patterns and which did not
- // (for example consider the glob [*/*.java, sub/*.java, */*.txt]).
- pendingOps.incrementAndGet();
- try {
- for (String[] splitPattern : splitPatterns) {
- queueGlob(base, baseIsDirectory, splitPattern, 0, excludeDirectories, splitExcludes, 0, results, cache, dirPred);
- }
- } finally {
- decrementAndCheckDone();
- }
-
- return result;
- }
-
- private void queueGlob(File base,
- boolean baseIsDirectory,
- String[] patternParts,
- int idx,
- boolean excludeDirectories,
- List<String[]> excludePatterns,
- int excludeIdx,
- Collection<File> results,
- Cache<String, Pattern> cache,
- Predicate<File> dirPred) throws IOException {
- enqueue(() -> {
- try {
- reallyGlob(base, baseIsDirectory, patternParts, idx, excludeDirectories,
- excludePatterns, excludeIdx, results, cache, dirPred);
- } catch (IOException e) {
- failure.set(e);
- }
- });
- }
-
- protected void enqueue(final Runnable r) {
- pendingOps.incrementAndGet();
-
- Runnable wrapped = () -> {
- try {
- if (!canceled && failure.get() == null) {
- r.run();
- }
- } finally {
- decrementAndCheckDone();
- }
- };
-
- if (executor == null) {
- wrapped.run();
- } else {
- executor.execute(wrapped);
- }
- }
-
- protected void cancel() {
- this.canceled = true;
- }
-
- private void decrementAndCheckDone() {
- if (pendingOps.decrementAndGet() == 0) {
- // We get to 0 iff we are done all the relevant work. This is because we always increment
- // the pending ops count as we're enqueuing, and don't decrement until the task is complete
- // (which includes accounting for any additional tasks that one enqueues).
- if (canceled) {
- result.markCanceled();
- } else if (failure.get() != null) {
- result.setException(failure.get());
- } else {
- result.set(Ordering.<File>natural().immutableSortedCopy(results));
- }
- }
- }
-
- /**
- * Expressed in Haskell:
- * <pre>
- * reallyGlob base [] = { base }
- * reallyGlob base [x:xs] = union { reallyGlob(f, xs) | f results "base/x" }
- * </pre>
- */
- private void reallyGlob(File base,
- boolean baseIsDirectory,
- String[] patternParts,
- int idx,
- boolean excludeDirectories,
- List<String[]> excludePatterns,
- int excludeIdx,
- Collection<File> results,
- Cache<String, Pattern> cache,
- Predicate<File> dirPred) throws IOException {
- ProgressManager.checkCanceled();
- if (baseIsDirectory && !dirPred.test(base)) {
- return;
- }
-
- if (idx == patternParts.length) { // Base case.
- if (!(excludeDirectories && baseIsDirectory) &&
- !excludedOnMatch(base, excludePatterns, excludeIdx, cache)) {
- results.add(base);
- }
- return;
- }
-
- if (!baseIsDirectory) {
- // Nothing to find here.
- return;
- }
-
- List<String[]> relevantExcludes = getRelevantExcludes(base, excludePatterns, excludeIdx, cache);
- final String pattern = patternParts[idx];
-
- // ** is special: it can match nothing at all.
- // For example, x/** matches x, **/y matches y, and x/**/y matches x/y.
- if ("**".equals(pattern)) {
- queueGlob(base, baseIsDirectory, patternParts, idx + 1, excludeDirectories, excludePatterns, excludeIdx, results, cache, dirPred);
- }
-
- if (!pattern.contains("*") && !pattern.contains("?")) {
- // We do not need to do a readdir in this case, just a stat.
- File child = new File(base, pattern);
- boolean childIsDir = fileAttributeProvider.isDirectory(child);
- if (!childIsDir && !fileAttributeProvider.isFile(child)) {
- // The file is a dangling symlink, fifo, does not exist, etc.
- return;
- }
-
- queueGlob(child, childIsDir, patternParts, idx + 1, excludeDirectories,
- relevantExcludes, excludeIdx + 1, results, cache, dirPred);
- return;
- }
-
- File[] children = getChildren(base);
- if (children == null) {
- return;
- }
- for (File child : children) {
- boolean childIsDir = fileAttributeProvider.isDirectory(child);
-
- if ("**".equals(pattern)) {
- // Recurse without shifting the pattern.
- if (childIsDir) {
- queueGlob(child, childIsDir, patternParts, idx, excludeDirectories,
- relevantExcludes, excludeIdx + 1, results, cache, dirPred);
- }
- }
- if (matches(pattern, child.getName(), cache)) {
- // Recurse and consume one segment of the pattern.
- if (childIsDir) {
- queueGlob(child, childIsDir, patternParts, idx + 1, excludeDirectories,
- relevantExcludes, excludeIdx + 1, results, cache, dirPred);
- } else {
- // Instead of using an async call, just repeat the base case above.
- if (idx + 1 == patternParts.length &&
- !excludedOnMatch(child, relevantExcludes, excludeIdx + 1, cache)) {
- results.add(child);
- }
- }
- }
- }
- }
-
- private static VirtualFileSystem getFileSystem() {
- if (ApplicationManager.getApplication().isUnitTestMode()) {
- return TempFileSystem.getInstance();
- }
- return LocalFileSystem.getInstance();
- }
-
- @Nullable
- private File[] getChildren(File file) {
- if (!ApplicationManager.getApplication().isUnitTestMode()) {
- return file.listFiles();
- }
- TempFileSystem fs = TempFileSystem.getInstance();
- VirtualFile vf = fs.findFileByIoFile(file);
- VirtualFile[] children = vf.getChildren();
- if (children == null) {
- return null;
- }
- return Arrays.stream(children)
- .map(VirtualFile::getPath)
- .map(File::new)
- .toArray(File[]::new);
- }
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildColorsPage.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildColorsPage.java
deleted file mode 100644
index 79d1d2c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildColorsPage.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.highlighting;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.application.options.colors.InspectionColorSettingsPage;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
-import com.intellij.openapi.fileTypes.SyntaxHighlighter;
-import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
-import com.intellij.openapi.options.colors.AttributesDescriptor;
-import com.intellij.openapi.options.colors.ColorDescriptor;
-import com.intellij.openapi.options.colors.ColorSettingsPage;
-import com.intellij.psi.codeStyle.DisplayPriority;
-import com.intellij.psi.codeStyle.DisplayPrioritySortable;
-import com.intellij.util.PlatformUtils;
-
-import javax.swing.*;
-import java.util.Map;
-
-/**
- * Allows user to customize colors.
- */
-public class BuildColorsPage implements ColorSettingsPage, InspectionColorSettingsPage, DisplayPrioritySortable {
- private static final AttributesDescriptor[] ATTRS = new AttributesDescriptor[] {
- new AttributesDescriptor("Keyword", BuildSyntaxHighlighter.BUILD_KEYWORD),
- new AttributesDescriptor("String", BuildSyntaxHighlighter.BUILD_STRING),
- new AttributesDescriptor("Number", BuildSyntaxHighlighter.BUILD_NUMBER),
- new AttributesDescriptor("Line Comment", BuildSyntaxHighlighter.BUILD_LINE_COMMENT),
- new AttributesDescriptor("Operation Sign", BuildSyntaxHighlighter.BUILD_OPERATION_SIGN),
- new AttributesDescriptor("Parentheses", BuildSyntaxHighlighter.BUILD_PARENS),
- new AttributesDescriptor("Brackets", BuildSyntaxHighlighter.BUILD_BRACKETS),
- new AttributesDescriptor("Braces", BuildSyntaxHighlighter.BUILD_BRACES),
- new AttributesDescriptor("Comma", BuildSyntaxHighlighter.BUILD_COMMA),
- new AttributesDescriptor("Dot", BuildSyntaxHighlighter.BUILD_DOT),
- new AttributesDescriptor("Function definition", BuildSyntaxHighlighter.BUILD_FN_DEFINITION),
- new AttributesDescriptor("Parameter", BuildSyntaxHighlighter.BUILD_PARAMETER),
- new AttributesDescriptor("Keyword argument", BuildSyntaxHighlighter.BUILD_KEYWORD_ARG),
- };
-
- private static final Map<String,TextAttributesKey> ourTagToDescriptorMap = ImmutableMap.<String, TextAttributesKey>builder()
- .put("funcDef", BuildSyntaxHighlighter.BUILD_FN_DEFINITION)
- .put("param", BuildSyntaxHighlighter.BUILD_PARAMETER)
- .put("kwarg", BuildSyntaxHighlighter.BUILD_KEYWORD_ARG)
- .put("comma", BuildSyntaxHighlighter.BUILD_COMMA)
- .put("number", BuildSyntaxHighlighter.BUILD_NUMBER)
- .build();
-
- @Override
- public String getDisplayName() {
- return Blaze.defaultBuildSystemName() + " BUILD files";
- }
-
- @Override
- public Icon getIcon() {
- return BuildFileType.INSTANCE.getIcon();
- }
-
- @Override
- public AttributesDescriptor[] getAttributeDescriptors() {
- return ATTRS;
- }
-
- @Override
- public ColorDescriptor[] getColorDescriptors() {
- return ColorDescriptor.EMPTY_ARRAY;
- }
-
- @Override
- public SyntaxHighlighter getHighlighter() {
- final SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(BuildFileType.INSTANCE, null, null);
- assert highlighter != null;
- return highlighter;
- }
-
- @Override
- public String getDemoText() {
- return
- "def <funcDef>function</funcDef>(<param>x</param>, <kwarg>whatever</kwarg>=1):\n" +
- " s = (\"Test\", 2+3, {'a': 'b'}, <param>x</param>) # Comment\n" +
- " print s[0].lower()\n"+
- "\n"+
- "java_library(\n" +
- " <kwarg>name</kwarg> = \"lib\",\n" +
- " <kwarg>srcs</kwarg> = glob([\"**/*.java\"]),\n" +
- ")\n";
- }
-
- @Override
- public Map<String, TextAttributesKey> getAdditionalHighlightingTagToDescriptorMap() {
- return ourTagToDescriptorMap;
- }
-
- @Override
- public DisplayPriority getPriority() {
- return PlatformUtils.isPyCharm() ? DisplayPriority.KEY_LANGUAGE_SETTINGS : DisplayPriority.LANGUAGE_SETTINGS;
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighter.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighter.java
deleted file mode 100644
index 537027c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighter.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.highlighting;
-
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.lexer.Lexer;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
-import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
-import com.intellij.psi.tree.IElementType;
-
-import java.util.Map;
-
-import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.*;
-
-/**
- * This class maps tokens to highlighting attributes. Each attribute contains the font properties.
- */
-public class BuildSyntaxHighlighter extends SyntaxHighlighterBase {
-
- public static final TextAttributesKey BUILD_KEYWORD = key("BUILD.MODIFIER", KEYWORD);
- public static final TextAttributesKey BUILD_STRING = key("BUILD.STRING", STRING);
- public static final TextAttributesKey BUILD_NUMBER = key("BUILD.NUMBER", NUMBER);
- public static final TextAttributesKey BUILD_LINE_COMMENT = key("BUILD.LINE_COMMENT", LINE_COMMENT);
- public static final TextAttributesKey BUILD_BRACES = key("BUILD.BRACES", BRACES);
- public static final TextAttributesKey BUILD_PARENS = key("BUILD.PARENS", PARENTHESES);
- public static final TextAttributesKey BUILD_BRACKETS = key("BUILD.BRACKETS", BRACKETS);
- public static final TextAttributesKey BUILD_OPERATION_SIGN = key("BUILD.OPERATION_SIGN", OPERATION_SIGN);
- public static final TextAttributesKey BUILD_DOT = key("BUILD.DOT", DOT);
- public static final TextAttributesKey BUILD_SEMICOLON = key("BUILD.SEMICOLON", SEMICOLON);
- public static final TextAttributesKey BUILD_COMMA = key("BUILD.COMMA", COMMA);
- public static final TextAttributesKey BUILD_PARAMETER = key("BUILD.PARAMETER", PARAMETER);
- public static final TextAttributesKey BUILD_KEYWORD_ARG = key("BUILD.KEYWORD.ARG", PARAMETER);
- public static final TextAttributesKey BUILD_FN_DEFINITION = key("BUILD.FN.DEFINITION", FUNCTION_DECLARATION);
-
- private static TextAttributesKey key(String name, TextAttributesKey fallbackKey) {
- return TextAttributesKey.createTextAttributesKey(name, fallbackKey);
- }
-
- private static final Map<IElementType, TextAttributesKey> keys = Maps.newHashMap();
-
- static {
- addAttribute(TokenKind.COMMENT, BUILD_LINE_COMMENT);
- addAttribute(TokenKind.INT, BUILD_NUMBER);
- addAttribute(TokenKind.STRING, BUILD_STRING);
-
- addAttribute(TokenKind.LBRACE, BUILD_BRACES);
- addAttribute(TokenKind.RBRACE, BUILD_BRACES);
- addAttribute(TokenKind.LBRACKET, BUILD_BRACKETS);
- addAttribute(TokenKind.RBRACKET, BUILD_BRACKETS);
-
- addAttribute(TokenKind.LPAREN, BUILD_PARENS);
- addAttribute(TokenKind.RPAREN, BUILD_PARENS);
-
- addAttribute(TokenKind.DOT, BUILD_DOT);
- addAttribute(TokenKind.SEMI, BUILD_SEMICOLON);
- addAttribute(TokenKind.COMMA, BUILD_COMMA);
-
- for (TokenKind kind : TokenKind.OPERATIONS) {
- addAttribute(kind, BUILD_OPERATION_SIGN);
- }
-
- for (TokenKind kind : TokenKind.KEYWORDS) {
- addAttribute(kind, BUILD_KEYWORD);
- }
- }
-
- private static void addAttribute(TokenKind kind, TextAttributesKey key) {
- keys.put(BuildToken.fromKind(kind), key);
- }
-
- @Override
- public Lexer getHighlightingLexer() {
- return new BuildLexer(BuildLexerBase.LexerMode.SyntaxHighlighting);
- }
-
- @Override
- public TextAttributesKey[] getTokenHighlights(IElementType iElementType) {
- return pack(keys.get(iElementType));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighterFactory.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighterFactory.java
deleted file mode 100644
index a1ef7d5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/highlighting/BuildSyntaxHighlighterFactory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.highlighting;
-
-import com.intellij.openapi.fileTypes.SyntaxHighlighter;
-import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-
-/**
- * Factory for BuildSyntaxHighlighter
- */
-public class BuildSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
-
- @Override
- public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) {
- return new BuildSyntaxHighlighter();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileLanguage.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileLanguage.java
deleted file mode 100644
index 46c0b85..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileLanguage.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language;
-
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.intellij.lang.Language;
-
-/**
- * BUILD file language
- */
-public class BuildFileLanguage extends Language {
-
- public static final BoolExperiment BUILD_FILE_SUPPORT_ENABLED = new BoolExperiment("build.file.support.enabled", true);
-
- public static boolean buildFileSupportEnabled() {
- return BUILD_FILE_SUPPORT_ENABLED.getValue() && BlazeUserSettings.getInstance().getBuildFileSupportEnabled();
- }
-
- public static final BuildFileLanguage INSTANCE = new BuildFileLanguage();
-
- private BuildFileLanguage() {
- super("BUILD", "text/python");
- }
-
- @Override
- public String getDisplayName() {
- return "BUILD file";
- }
-
- @Override
- public boolean isCaseSensitive() {
- return true;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileType.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileType.java
deleted file mode 100644
index c09c8b8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileType.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.fileTypes.LanguageFileType;
-import icons.BlazeIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * BUILD file type
- */
-public class BuildFileType extends LanguageFileType {
-
- public static final BuildFileType INSTANCE = new BuildFileType();
-
- private BuildFileType() {
- super(BuildFileLanguage.INSTANCE);
- }
-
- @Override
- public String getName() {
- // Warning: this is conflated with Language.myID in several places...
- // They must be identical.
- return BuildFileLanguage.INSTANCE.getID();
- }
-
- @Override
- public String getDescription() {
- return Blaze.defaultBuildSystemName() + " BUILD language";
- }
-
- @Override
- public String getDefaultExtension() {
- return "";
- }
-
- @Override
- @Nullable
- public Icon getIcon() {
- return BlazeIcons.BuildFile;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeFactory.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeFactory.java
deleted file mode 100644
index 864a036..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeFactory.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language;
-
-import com.google.common.collect.ImmutableList;
-import com.intellij.openapi.fileTypes.*;
-import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Factory for BuildFileType
- */
-public class BuildFileTypeFactory extends FileTypeFactory {
-
- private static ImmutableList<FileNameMatcher> DEFAULT_ASSOCIATIONS = ImmutableList.of(
- new ExactFileNameMatcher("BUILD"),
- new ExtensionFileNameMatcher("bzl")
- );
-
- @Override
- public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
- consumer.consume(BuildFileType.INSTANCE, DEFAULT_ASSOCIATIONS.toArray(new FileNameMatcher[0]));
- }
-
- private static volatile boolean enabled = true;
-
- public static void updateBuildFileLanguageEnabled(boolean supportEnabled) {
- if (enabled == supportEnabled) {
- return;
- }
- enabled = supportEnabled;
- if (!supportEnabled) {
- FileTypeManagerEx.getInstanceEx().unregisterFileType(BuildFileType.INSTANCE);
- } else {
- FileTypeManager.getInstance().registerFileType(BuildFileType.INSTANCE, DEFAULT_ASSOCIATIONS);
- }
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/AttributeDefinition.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/AttributeDefinition.java
deleted file mode 100644
index 3907a58..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/AttributeDefinition.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-
-/**
- * Simple implementation of AttributeDefinition, from build.proto
- */
-public class AttributeDefinition implements Serializable {
-
- public static AttributeDefinition fromProto(Build.AttributeDefinition attr) {
- return new AttributeDefinition(
- attr.getName(),
- attr.getType(),
- attr.getMandatory(),
- attr.hasDocumentation() ? attr.getDocumentation() : null,
- getAllowedRuleClasses(attr)
- );
- }
-
- @Nullable
- private static ImmutableList<String> getAllowedRuleClasses(Build.AttributeDefinition attr) {
- if (!attr.hasAllowedRuleClasses()) {
- return null;
- }
- return ImmutableList.copyOf(attr.getAllowedRuleClasses().getAllowedRuleClassList());
- }
-
- public final String name;
- public final Build.Attribute.Discriminator type;
- public final boolean mandatory;
- public final String documentation;
-
- // the names of rules allowed in this attribute, or null if any rules are allowed.
- @Nullable private final ImmutableList<String> allowedRuleClasses;
-
- @VisibleForTesting
- public AttributeDefinition(
- String name,
- Build.Attribute.Discriminator type,
- boolean mandatory,
- String documentation,
- @Nullable ImmutableList<String> allowedRuleClasses) {
-
- this.name = name;
- this.type = type;
- this.mandatory = mandatory;
- this.documentation = documentation;
- this.allowedRuleClasses = allowedRuleClasses;
- }
-
- /**
- * Only relevant for attributes of type LABEL and LABEL_LIST.
- * Some such attributes can only contain certain rule types.
- */
- public boolean isRuleTypeAllowed(RuleDefinition rule) {
- return allowedRuleClasses == null || allowedRuleClasses.contains(rule.name);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpec.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpec.java
deleted file mode 100644
index 7c2b14e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpec.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-
-/**
- * Specification of the BUILD language, as provided by "blaze info build-language".<p>
- *
- * This constitutes a set of rules, along with their supported attributes, and other
- * useful information. We query this once per blaze workspace (it won't change unless
- * the blaze binary is also changed).<p>
- *
- * This rule list is not exhaustive; it's intended to give information about known
- * rules, not enumerate all possibilities.
- */
-public class BuildLanguageSpec implements Serializable {
-
- public static BuildLanguageSpec fromProto(Build.BuildLanguage proto) {
- ImmutableMap.Builder<String, RuleDefinition> builder = ImmutableMap.builder();
- for (Build.RuleDefinition rule : proto.getRuleList()) {
- builder.put(rule.getName(), RuleDefinition.fromProto(rule));
- }
- return new BuildLanguageSpec(builder.build());
- }
-
- public final ImmutableMap<String, RuleDefinition> rules;
-
- @VisibleForTesting
- public BuildLanguageSpec(ImmutableMap<String, RuleDefinition> rules) {
- this.rules = rules;
- }
-
- public ImmutableSet<String> getKnownRuleNames() {
- return rules.keySet();
- }
-
- public boolean hasRule(@Nullable String ruleName) {
- return getRule(ruleName) != null;
- }
-
- @Nullable
- public RuleDefinition getRule(@Nullable String ruleName) {
- return ruleName != null ? rules.get(ruleName) : null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProvider.java
deleted file mode 100644
index 984c286..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProvider.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
-
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides a BuildLanguageSpec for the given project.
- */
-public interface BuildLanguageSpecProvider {
-
- static BuildLanguageSpecProvider getInstance() {
- return ServiceManager.getService(BuildLanguageSpecProvider.class);
- }
-
- /**
- * Returns null if cancelled or unsuccessful. Also returns null if no WorkspaceRoot can be found for the
- * project (i.e. because BlazeImportSettings has not been set).
- */
- @Nullable
- BuildLanguageSpec getLanguageSpec(Project project);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProviderImpl.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProviderImpl.java
deleted file mode 100644
index eae6d8c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/BuildLanguageSpecProviderImpl.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
-
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.lang.buildfile.sync.LanguageSpecResult;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.SyncListener;
-import com.intellij.openapi.project.Project;
-
-import java.util.Map;
-
-/**
- * Calls 'blaze info build-language', to retrieve the language spec.
- */
-public class BuildLanguageSpecProviderImpl extends SyncListener.Adapter implements BuildLanguageSpecProvider {
-
- private static final Map<Project, LanguageSpecResult> calculatedSpecs = Maps.newHashMap();
-
- @Override
- public BuildLanguageSpec getLanguageSpec(Project project) {
- LanguageSpecResult result = calculatedSpecs.get(project);
- return result != null ? result.spec : null;
- }
-
- @Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- LanguageSpecResult spec = blazeProjectData.syncState.get(LanguageSpecResult.class);
- if (spec != null) {
- calculatedSpecs.put(project, spec);
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/RuleDefinition.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/RuleDefinition.java
deleted file mode 100644
index 6f93ea1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/language/semantics/RuleDefinition.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language.semantics;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-
-/**
- * Simple implementation of RuleDefinition, from build.proto
- */
-public class RuleDefinition implements Serializable {
-
- /**
- * This isn't included in the proto -- all other documented attributes seem to be.
- */
- private static final AttributeDefinition NAME_ATTRIBUTE = new AttributeDefinition(
- "name", Build.Attribute.Discriminator.STRING, true, null, null);
-
- public static RuleDefinition fromProto(Build.RuleDefinition rule) {
- ImmutableMap.Builder<String, AttributeDefinition> map = ImmutableMap.builder();
- for (Build.AttributeDefinition attr : rule.getAttributeList()) {
- map.put(attr.getName(), AttributeDefinition.fromProto(attr));
- }
- map.put(NAME_ATTRIBUTE.name, NAME_ATTRIBUTE);
- return new RuleDefinition(
- rule.getName(),
- map.build(),
- rule.hasDocumentation() ? rule.getDocumentation() : null);
- }
-
- public final String name;
- /**
- * This map is not exhaustive; it only contains documented attributes.
- */
- public final ImmutableMap<String, AttributeDefinition> attributes;
- @Nullable public final String documentation;
-
- public RuleDefinition(String name, ImmutableMap<String, AttributeDefinition> attributes, @Nullable String documentation) {
- this.name = name;
- this.attributes = attributes;
- this.documentation = documentation;
- }
-
- public ImmutableSet<String> getKnownAttributeNames() {
- return attributes.keySet();
- }
-
- @Nullable
- public AttributeDefinition getAttribute(@Nullable String attributeName) {
- return attributeName != null ? attributes.get(attributeName) : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexer.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexer.java
deleted file mode 100644
index 2ac477c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexer.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase.LexerMode;
-import com.intellij.lexer.LexerBase;
-
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Implementation of LexerBase using BuildLexerBase to tokenize the input.
- */
-public class BuildLexer extends LexerBase {
-
- private final LexerMode mode;
-
- private int offsetEnd;
- private int offsetStart;
- private CharSequence buffer;
- private Iterator<Token> tokens;
- private Token currentToken;
- private int currentState;
-
- public BuildLexer(LexerMode mode) {
- this.mode = mode;
- }
-
- @Override
- public void start(CharSequence charSequence, int startOffset, int endOffset, int initialState) {
- buffer = charSequence;
- this.offsetEnd = endOffset;
- this.offsetStart = startOffset;
-
- BuildLexerBase lexer = new BuildLexerBase(charSequence.subSequence(startOffset, endOffset), initialState, mode);
- checkNoCharactersMissing(charSequence.subSequence(startOffset, endOffset).length(), lexer.getTokens());
- tokens = lexer.getTokens().iterator();
- currentToken = null;
- if (tokens.hasNext()) {
- currentToken = tokens.next();
- }
- currentState = lexer.getOpenParenStackDepth();
- }
-
- /**
- * Temporary debugging code. We need to tokenize every character in the input string.
- */
- private void checkNoCharactersMissing(int totalLength, List<Token> tokens) {
- if (!tokens.isEmpty() && tokens.get(tokens.size() - 1).right != totalLength) {
- String error = String.format("Lengths don't match: %s instead of %s",
- tokens.get(tokens.size() - 1).right,
- totalLength);
- throw new RuntimeException(error);
- }
- int start = 0;
- for (int i = 0; i < tokens.size(); i++) {
- Token token = tokens.get(i);
- if (token.left != start) {
- throw new RuntimeException("Gap/inconsistency at: " + start);
- }
- start = token.right;
- }
- }
-
-
- @Override
- public int getState() {
- return currentState;
- }
-
- @Override
- public BuildToken getTokenType() {
- if (currentToken != null) {
- return BuildToken.fromKind(currentToken.kind);
- }
- return null;
- }
-
- @Override
- public int getTokenStart() {
- if (currentToken == null) {
- return 0;
- }
- return currentToken.left + offsetStart;
- }
-
- @Override
- public int getTokenEnd() {
- if (currentToken == null) {
- return 0;
- }
- return currentToken.right + offsetStart;
- }
-
- @Override
- public void advance() {
- if (tokens.hasNext()) {
- currentToken = tokens.next();
- } else {
- currentToken = null;
- }
- }
-
- public TokenKind getTokenKind() {
- return currentToken.kind;
- }
-
- @Override
- public CharSequence getBufferSequence() {
- return buffer;
- }
-
- @Override
- public int getBufferEnd() {
- return offsetEnd;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexerBase.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexerBase.java
deleted file mode 100644
index a71c884..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildLexerBase.java
+++ /dev/null
@@ -1,755 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-import javax.annotation.Nullable;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-
-/**
- * A tokenizer for the BUILD language.
- *
- * Copied from blaze/bazel's lexer. The differences are:
- * 1. Blaze's lexer isn't 'faithful', in that it reorders characters, skips characters, and adds
- * ghost characters. We can't do that, because we need to match the editor's view of the document.
- * 2. Blaze's lexer only lexes entire files (it can't incrementally lex part of a file, starting
- * from a given indent stack depth).
- */
-public class BuildLexerBase {
-
- /**
- * When tokenizing for the purposes of parsing, we handle indentation.<br>
- * For syntax highlighting, we need to tokenize every character, and don't care about indentation.
- */
- public enum LexerMode {
- Parsing,
- SyntaxHighlighting
- }
-
- // Characters that can come immediately prior to an '=' character to generate
- // a different token
- private static final Map<Character, TokenKind> EQUAL_TOKENS =
- ImmutableMap.<Character, TokenKind>builder()
- .put('=', TokenKind.EQUALS_EQUALS)
- .put('!', TokenKind.NOT_EQUALS)
- .put('>', TokenKind.GREATER_EQUALS)
- .put('<', TokenKind.LESS_EQUALS)
- .put('+', TokenKind.PLUS_EQUALS)
- .put('-', TokenKind.MINUS_EQUALS)
- .put('*', TokenKind.STAR_EQUALS)
- .put('/', TokenKind.SLASH_EQUALS)
- .put('%', TokenKind.PERCENT_EQUALS)
- .build();
-
- private final LexerMode mode;
-
- // Input buffer and position
- private final char[] buffer;
- private int pos;
-
- private final List<Token> tokens;
-
- // The number of unclosed open-parens ("(", '{', '[') at the current point in
- // the stream. Whitespace is handled differently when this is nonzero.
- private int openParenStackDepth = 0;
-
- // The stack of enclosing indentation levels; always contains '0' at the
- // bottom.
- private final Stack<Integer> indentStack = new Stack<>();
-
- private boolean containsErrors;
-
- /**
- * Constructs a lexer which tokenizes the contents of the specified
- * InputBuffer. Any errors during lexing are reported on "handler".
- */
- public BuildLexerBase(CharSequence input, int initialStackDepth, LexerMode mode) {
- this.buffer = input.toString().toCharArray();
- // Empirical measurements show roughly 1 token per 8 characters in buffer.
- this.tokens = Lists.newArrayListWithExpectedSize(buffer.length / 8);
- this.pos = 0;
- this.openParenStackDepth = initialStackDepth;
- this.mode = mode;
-
- indentStack.push(0);
- tokenize();
- }
-
- /**
- * The number of unclosed open-parens ("(", '{', '[') at the end of this string.
- */
- public int getOpenParenStackDepth() {
- return openParenStackDepth;
- }
-
- /**
- * Returns true if there were errors during scanning of this input file or
- * string. The BuildLexerBase may attempt to recover from errors, but clients should
- * not rely on the results of scanning if this flag is set.
- */
- public boolean containsErrors() {
- return containsErrors;
- }
-
- /**
- * Returns the (mutable) list of tokens generated by the BuildLexerBase.
- */
- public List<Token> getTokens() {
- return tokens;
- }
-
- private void popParen() {
- if (openParenStackDepth == 0) {
- error("indentation error");
- } else {
- openParenStackDepth--;
- }
- }
-
- private void error(String message) {
- error(message, pos - 1, pos - 1);
- }
-
- protected void error(String message, int start, int end) {
- this.containsErrors = true;
- }
-
- /** invariant: symbol positions are half-open intervals. */
- private void addToken(TokenKind kind, int left, int right) {
- addToken(kind, left, right, null);
- }
-
- private void addToken(TokenKind kind, int left, int right, @Nullable Object value) {
- tokens.add(new Token(kind, left, right, value));
- }
-
- /**
- * Parses an end-of-line sequence, handling statement indentation correctly.
- *
- * <p>UNIX newlines are assumed (LF). Carriage returns are always ignored.
- *
- * <p>ON ENTRY: 'pos' is the index of the char after '\n'.
- * ON EXIT: 'pos' is the index of the next non-space char after '\n'.
- */
- protected void newline() {
- if (mode == LexerMode.SyntaxHighlighting) {
- addToken(TokenKind.NEWLINE, pos - 1, pos);
- return;
- }
- if (openParenStackDepth > 0) {
- newlineInsideExpression(); // in an expression: ignore space
- } else {
- newlineOutsideExpression(); // generate NEWLINE/INDENT/DEDENT tokens
- }
- }
-
- private void newlineInsideExpression() {
- int oldPos = pos - 1;
- while (pos < buffer.length) {
- switch (buffer[pos]) {
- case ' ': case '\t': case '\r':
- pos++;
- break;
- default:
- // ignored by the parser
- addToken(TokenKind.WHITESPACE, oldPos, pos);
- return;
- }
- }
- addToken(TokenKind.WHITESPACE, oldPos, pos);
- }
-
- /**
- * Handle INDENT and DEDENT within statements.<p>
- * Note these tokens have zero length -- this is because we can have an arbitrary number of
- * dedents squeezed into some number of characters, and the size of all the lexical elements
- * must match the number of characters in the file.
- */
- private void newlineOutsideExpression() {
- int oldPos = pos - 1;
- if (pos > 1) { // skip over newline at start of file
- addToken(TokenKind.NEWLINE, oldPos, pos);
- oldPos = pos;
- }
-
- // we're in a stmt: suck up space at beginning of next line
- int indentLen = 0;
- while (pos < buffer.length) {
- char c = buffer[pos];
- if (c == ' ') {
- indentLen++;
- pos++;
- } else if (c == '\t') {
- indentLen += 8 - indentLen % 8;
- pos++;
- } else if (c == '\n') { // entirely blank line: ignore
- indentLen = 0;
- pos++;
- } else if (c == '#') { // line containing only indented comment
- if (oldPos != pos) {
- addToken(TokenKind.WHITESPACE, oldPos, pos);
- oldPos = pos;
- }
- while (pos < buffer.length && c != '\n') {
- c = buffer[pos++];
- }
- addToken(TokenKind.COMMENT, oldPos, pos - 1, bufferSlice(oldPos, pos - 1));
- oldPos = pos - 1;
- indentLen = 0;
- } else { // printing character
- break;
- }
- }
-
- if (oldPos != pos) {
- addToken(TokenKind.WHITESPACE, oldPos, pos);
- }
- if (pos == buffer.length) {
- indentLen = 0;
- } // trailing space on last line
-
- int peekedIndent = indentStack.peek();
- if (peekedIndent < indentLen) { // push a level
- indentStack.push(indentLen);
- addToken(TokenKind.INDENT, pos, pos);
-
- } else if (peekedIndent > indentLen) { // pop one or more levels
- while (peekedIndent > indentLen) {
- indentStack.pop();
- addToken(TokenKind.DEDENT, pos, pos);
- peekedIndent = indentStack.peek();
- }
-
- if (peekedIndent < indentLen) {
- error("indentation error");
- }
- }
- }
-
- /**
- * Collapse adjacent whitespace characters into a single token
- */
- private void addWhitespace() {
- int oldPos = pos - 1;
- while (pos < buffer.length) {
- switch (buffer[pos]) {
- case ' ': case '\t': case '\r':
- pos++;
- break;
- default:
- addToken(TokenKind.WHITESPACE, oldPos, pos, bufferSlice(oldPos, pos));
- return;
- }
- }
- addToken(TokenKind.WHITESPACE, oldPos, pos, bufferSlice(oldPos, pos));
- }
-
- /**
- * Returns true if current position is in the middle of a triple quote
- * delimiter (3 x quot), and advances 'pos' by two if so.
- */
- private boolean skipTripleQuote(char quot) {
- if (pos + 1 < buffer.length && buffer[pos] == quot && buffer[pos + 1] == quot) {
- pos += 2;
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Scans a string literal delimited by 'quot', containing escape sequences.
- *
- * <p>ON ENTRY: 'pos' is 1 + the index of the first delimiter
- * ON EXIT: 'pos' is 1 + the index of the last delimiter.
- */
- private void escapedStringLiteral(char quot, boolean isRaw) {
- int oldPos = isRaw ? pos - 2 : pos - 1;
- boolean inTripleQuote = skipTripleQuote(quot);
-
- // more expensive second choice that expands escaped into a buffer
- StringBuilder literal = new StringBuilder();
- while (pos < buffer.length) {
- char c = buffer[pos];
- pos++;
- switch (c) {
- case '\n':
- if (inTripleQuote) {
- literal.append(c);
- break;
- } else {
- error("unterminated string literal at eol", oldPos, pos);
- addToken(TokenKind.STRING, oldPos, pos, literal.toString());
- newline();
- return;
- }
- case '\\':
- if (pos == buffer.length) {
- error("unterminated string literal at eof", oldPos, pos);
- addToken(TokenKind.STRING, oldPos, pos, literal.toString());
- return;
- }
- if (isRaw) {
- // Insert \ and the following character.
- // As in Python, it means that a raw string can never end with a single \.
- literal.append('\\');
- literal.append(buffer[pos]);
- pos++;
- break;
- }
- c = buffer[pos];
- pos++;
- switch (c) {
- case '\n':
- // ignore end of line character
- break;
- case 'n':
- literal.append('\n');
- break;
- case 'r':
- literal.append('\r');
- break;
- case 't':
- literal.append('\t');
- break;
- case '\\':
- literal.append('\\');
- break;
- case '\'':
- literal.append('\'');
- break;
- case '"':
- literal.append('"');
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7': { // octal escape
- int octal = c - '0';
- if (pos < buffer.length) {
- c = buffer[pos];
- if (c >= '0' && c <= '7') {
- pos++;
- octal = (octal << 3) | (c - '0');
- if (pos < buffer.length) {
- c = buffer[pos];
- if (c >= '0' && c <= '7') {
- pos++;
- octal = (octal << 3) | (c - '0');
- }
- }
- }
- }
- literal.append((char) (octal & 0xff));
- break;
- }
- case 'a': case 'b': case 'f': case 'N': case 'u': case 'U': case 'v': case 'x':
- // exists in Python but not implemented in Blaze => error
- error("escape sequence not implemented: \\" + c, oldPos, pos);
- break;
- default:
- // unknown char escape => "\literal"
- literal.append('\\');
- literal.append(c);
- break;
- }
- break;
- case '\'':
- case '"':
- if (c != quot || (inTripleQuote && !skipTripleQuote(quot))) {
- // Non-matching quote, treat it like a regular char.
- literal.append(c);
- } else {
- // Matching close-delimiter, all done.
- addToken(TokenKind.STRING, oldPos, pos, literal.toString());
- return;
- }
- break;
- default:
- literal.append(c);
- break;
- }
- }
- error("unterminated string literal at eof", oldPos, pos);
- addToken(TokenKind.STRING, oldPos, pos, literal.toString());
- }
-
- /**
- * Scans a string literal delimited by 'quot'.
- *
- * <ul>
- * <li> ON ENTRY: 'pos' is 1 + the index of the first delimiter
- * <li> ON EXIT: 'pos' is 1 + the index of the last delimiter.
- * </ul>
- *
- * @param isRaw if true, do not escape the string.
- */
- private void addStringLiteral(char quot, boolean isRaw) {
- int oldPos = isRaw ? pos - 2 : pos - 1;
- int start = pos;
-
- // Don't even attempt to parse triple-quotes here.
- if (skipTripleQuote(quot)) {
- pos -= 2;
- escapedStringLiteral(quot, isRaw);
- return;
- }
-
- // first quick optimistic scan for a simple non-escaped string
- while (pos < buffer.length) {
- char c = buffer[pos++];
- switch (c) {
- case '\n':
- error("unterminated string literal at eol", oldPos, pos);
- addToken(TokenKind.STRING, oldPos, pos - 1, bufferSlice(start, pos - 1));
- newline();
- return;
- case '\\':
- if (isRaw) {
- // skip the next character
- pos++;
- break;
- }
- // oops, hit an escape, need to start over & build a new string buffer
- pos = oldPos + 1;
- escapedStringLiteral(quot, false);
- return;
- case '\'':
- case '"':
- if (c == quot) {
- // close-quote, all done.
- addToken(TokenKind.STRING, oldPos, pos, bufferSlice(start, pos - 1));
- return;
- }
- }
- }
-
- error("unterminated string literal at eof", oldPos, pos);
- addToken(TokenKind.STRING, oldPos, pos, bufferSlice(start, pos));
- }
-
- private static final ImmutableMap<String, TokenKind> KEYWORD_MAP = createKeywordMap();
-
- private static ImmutableMap<String, TokenKind> createKeywordMap() {
- ImmutableMap.Builder<String, TokenKind> builder = ImmutableMap.builder();
- for (TokenKind kind : TokenKind.KEYWORDS) {
- builder.put(kind.toString(), kind);
- }
- return builder.build();
- }
-
- private TokenKind getTokenKindForIdentfier(String id) {
- TokenKind kind = KEYWORD_MAP.get(id);
- return kind == null ? TokenKind.IDENTIFIER : kind;
- }
-
- private String scanIdentifier() {
- int oldPos = pos - 1;
- while (pos < buffer.length) {
- switch (buffer[pos]) {
- case '_':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case '0': case '1': case '2': case '3': case '4': case '5':
- case '6': case '7': case '8': case '9':
- pos++;
- break;
- default:
- return bufferSlice(oldPos, pos);
- }
- }
- return bufferSlice(oldPos, pos);
- }
-
- /**
- * Scans an identifier or keyword.
- *
- * <p>ON ENTRY: 'pos' is 1 + the index of the first char in the identifier.
- * ON EXIT: 'pos' is 1 + the index of the last char in the identifier.
- *
- * @return the identifier or keyword token.
- */
- private void addIdentifierOrKeyword() {
- int oldPos = pos - 1;
- String id = scanIdentifier();
- TokenKind kind = getTokenKindForIdentfier(id);
- addToken(kind, oldPos, pos,
- (kind == TokenKind.IDENTIFIER) ? id : null);
- }
-
- private String scanInteger() {
- int oldPos = pos - 1;
- while (pos < buffer.length) {
- char c = buffer[pos];
- switch (c) {
- case 'X': case 'x':
- case 'a': case 'A':
- case 'b': case 'B':
- case 'c': case 'C':
- case 'd': case 'D':
- case 'e': case 'E':
- case 'f': case 'F':
- case '0': case '1':
- case '2': case '3':
- case '4': case '5':
- case '6': case '7':
- case '8': case '9':
- pos++;
- break;
- default:
- return bufferSlice(oldPos, pos);
- }
- }
- return bufferSlice(oldPos, pos);
- }
-
- /**
- * Scans an addInteger literal.
- *
- * <p>ON ENTRY: 'pos' is 1 + the index of the first char in the literal.
- * ON EXIT: 'pos' is 1 + the index of the last char in the literal.
- */
- private void addInteger() {
- int oldPos = pos - 1;
- String literal = scanInteger();
-
- final String substring;
- final int radix;
- if (literal.startsWith("0x") || literal.startsWith("0X")) {
- radix = 16;
- substring = literal.substring(2);
- } else if (literal.startsWith("0") && literal.length() > 1) {
- radix = 8;
- substring = literal.substring(1);
- } else {
- radix = 10;
- substring = literal;
- }
-
- int value = 0;
- try {
- value = Integer.parseInt(substring, radix);
- } catch (NumberFormatException e) {
- error("invalid base-" + radix + " integer constant: " + literal);
- }
-
- addToken(TokenKind.INT, oldPos, pos, value);
- }
-
- /**
- * Tokenizes a two-char operator.
- * @return true if it tokenized an operator
- */
- private boolean tokenizeTwoChars() {
- if (pos + 2 >= buffer.length) {
- return false;
- }
- char c1 = buffer[pos];
- char c2 = buffer[pos + 1];
- TokenKind tok = null;
- if (c2 == '=') {
- tok = EQUAL_TOKENS.get(c1);
- } else if (c2 == '*' && c1 == '*') {
- tok = TokenKind.STAR_STAR;
- }
- if (tok == null) {
- return false;
- }
- addToken(tok, pos, pos + 2);
- return true;
- }
-
- /**
- * Performs tokenization of the character buffer of file contents provided to
- * the constructor.
- */
- private void tokenize() {
- while (pos < buffer.length) {
- if (tokenizeTwoChars()) {
- pos += 2;
- continue;
- }
- char c = buffer[pos];
- pos++;
- switch (c) {
- case '{': {
- addToken(TokenKind.LBRACE, pos - 1, pos);
- openParenStackDepth++;
- break;
- }
- case '}': {
- addToken(TokenKind.RBRACE, pos - 1, pos);
- popParen();
- break;
- }
- case '(': {
- addToken(TokenKind.LPAREN, pos - 1, pos);
- openParenStackDepth++;
- break;
- }
- case ')': {
- addToken(TokenKind.RPAREN, pos - 1, pos);
- popParen();
- break;
- }
- case '[': {
- addToken(TokenKind.LBRACKET, pos - 1, pos);
- openParenStackDepth++;
- break;
- }
- case ']': {
- addToken(TokenKind.RBRACKET, pos - 1, pos);
- popParen();
- break;
- }
- case '>': {
- addToken(TokenKind.GREATER, pos - 1, pos);
- break;
- }
- case '<': {
- addToken(TokenKind.LESS, pos - 1, pos);
- break;
- }
- case ':': {
- addToken(TokenKind.COLON, pos - 1, pos);
- break;
- }
- case ',': {
- addToken(TokenKind.COMMA, pos - 1, pos);
- break;
- }
- case '+': {
- addToken(TokenKind.PLUS, pos - 1, pos);
- break;
- }
- case '-': {
- addToken(TokenKind.MINUS, pos - 1, pos);
- break;
- }
- case '|': {
- addToken(TokenKind.PIPE, pos - 1, pos);
- break;
- }
- case '=': {
- addToken(TokenKind.EQUALS, pos - 1, pos);
- break;
- }
- case '%': {
- addToken(TokenKind.PERCENT, pos - 1, pos);
- break;
- }
- case '/': {
- addToken(TokenKind.SLASH, pos - 1, pos);
- break;
- }
- case ';': {
- addToken(TokenKind.SEMI, pos - 1, pos);
- break;
- }
- case '.': {
- addToken(TokenKind.DOT, pos - 1, pos);
- break;
- }
- case '*': {
- addToken(TokenKind.STAR, pos - 1, pos);
- break;
- }
- case ' ':
- case '\t':
- case '\r': {
- addWhitespace();
- break;
- }
- case '\\': {
- // Backslash character is valid only at the end of a line (or in a string)
- if (pos + 1 < buffer.length && buffer[pos] == '\n') {
- // treat end of line backslash and newline char as whitespace (they're ignored by the parser)
- pos++;
- addToken(TokenKind.WHITESPACE, pos - 2, pos, Character.toString(c));
- } else {
- addToken(TokenKind.ILLEGAL, pos - 1, pos, Character.toString(c));
- }
- break;
- }
- case '\n': {
- newline();
- break;
- }
- case '#': {
- int oldPos = pos - 1;
- while (pos < buffer.length) {
- c = buffer[pos];
- if (c == '\n') {
- break;
- } else {
- pos++;
- }
- }
- addToken(TokenKind.COMMENT, oldPos, pos, bufferSlice(oldPos, pos));
- break;
- }
- case '\'':
- case '\"': {
- addStringLiteral(c, false);
- break;
- }
- default: {
- // detect raw strings, e.g. r"str"
- if (c == 'r' && pos < buffer.length
- && (buffer[pos] == '\'' || buffer[pos] == '\"')) {
- c = buffer[pos];
- pos++;
- addStringLiteral(c, true);
- break;
- }
-
- if (Character.isDigit(c)) {
- addInteger();
- } else if (Character.isJavaIdentifierStart(c) && c != '$') {
- addIdentifierOrKeyword();
- } else {
- // Some characters in Python are not recognized in Blaze syntax (e.g. '!')
- addToken(TokenKind.ILLEGAL, pos - 1, pos, Character.toString(c));
- error("invalid character: '" + c + "'");
- }
- break;
- } // default
- } // switch
- } // while
- }
-
- /**
- * Returns parts of the source buffer based on offsets
- *
- * @param start the beginning offset for the slice
- * @param end the offset immediately following the slice
- * @return the text at offset start with length end - start
- */
- private String bufferSlice(int start, int end) {
- return new String(this.buffer, start, end - start);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildToken.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildToken.java
deleted file mode 100644
index 2253bca..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/BuildToken.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.tree.TokenSet;
-
-/**
- * The IElementTypes used by the BUILD language
- */
-public class BuildToken extends IElementType {
-
-
- private static ImmutableMap<TokenKind, BuildToken> types = createMap();
-
- private static ImmutableMap<TokenKind, BuildToken> createMap() {
- ImmutableMap.Builder<TokenKind, BuildToken> builder = ImmutableMap.builder();
- for (TokenKind kind : TokenKind.values()) {
- builder.put(kind, new BuildToken(kind));
- }
- return builder.build();
- }
-
- public static BuildToken fromKind(TokenKind kind) {
- return types.get(kind);
- }
-
- public static final BuildToken IDENTIFIER = fromKind(TokenKind.IDENTIFIER);
-
- public static final TokenSet WHITESPACE_AND_NEWLINE = TokenSet.create(
- fromKind(TokenKind.WHITESPACE),
- fromKind(TokenKind.NEWLINE)
- );
-
- public final TokenKind kind;
-
- private BuildToken(TokenKind kind) {
- super(kind.name(), BuildFileType.INSTANCE.getLanguage());
- this.kind = kind;
- }
-
- @Override
- public String toString() {
- return kind.toString();
- }
-}
-
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/Token.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/Token.java
deleted file mode 100644
index 84e8fe3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/Token.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-/**
- * A Token represents an actual lexeme; that is, a lexical unit, its location in
- * the input text, its lexical kind, and any associated value.
- */
-public class Token {
-
- public final TokenKind kind;
- public final int left;
- public final int right;
- public final Object value;
-
- public Token(TokenKind kind, int left, int right) {
- this(kind, left, right, null);
- }
-
- public Token(TokenKind kind, int left, int right, Object value) {
- this.kind = kind;
- this.left = left;
- this.right = right;
- this.value = value;
- }
-
- /**
- * Constructs an easy-to-read string representation of token, suitable for use
- * in user error messages.
- */
- @Override
- public String toString() {
- if (kind == TokenKind.STRING) {
- return "\"" + value + "\"";
- }
- return value == null ? kind.toString() : value.toString();
- }
-
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/TokenKind.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/TokenKind.java
deleted file mode 100644
index 7ed2e11..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/lexer/TokenKind.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * A TokenKind is an enumeration of each different kind of lexical symbol.
- */
-public enum TokenKind {
-
- ASSERT("assert"),
- AND("and"),
- AS("as"),
- BREAK("break"),
- CLASS("class"),
- COLON(":"),
- COMMA(","),
- COMMENT("comment"),
- CONTINUE("continue"),
- DEF("def"),
- DEL("del"),
- DOT("."),
- ELIF("elif"),
- ELSE("else"),
- EOF("EOF"),
- EQUALS("="),
- EQUALS_EQUALS("=="),
- EXCEPT("except"),
- FALSE("False"),
- FINALLY("finally"),
- FOR("for"),
- FROM("from"),
- GLOBAL("global"),
- GREATER(">"),
- GREATER_EQUALS(">="),
- IDENTIFIER("identifier"),
- IF("if"),
- ILLEGAL("illegal character"),
- IMPORT("import"),
- IN("in"),
- INDENT("indent"),
- INT("integer"),
- IS("is"),
- LAMBDA("lambda"),
- LBRACE("{"),
- LBRACKET("["),
- LESS("<"),
- LESS_EQUALS("<="),
- LOAD("load"),
- LPAREN("("),
- MINUS("-"),
- NEWLINE("newline"),
- NONLOCAL("nonlocal"),
- NOT("not"),
- NOT_EQUALS("!="),
- NOT_IN("not in"), // used internally by the parser; not directly created by the lexer
- OR("or"),
- DEDENT("dedent"),
- PASS("pass"),
- PERCENT("%"),
- PIPE("|"),
- PLUS("+"),
- PLUS_EQUALS("+="),
- MINUS_EQUALS("-="),
- STAR_EQUALS("*="),
- SLASH_EQUALS("/="),
- PERCENT_EQUALS("%="),
- RAISE("raise"),
- RBRACE("}"),
- RBRACKET("]"),
- RETURN("return"),
- RPAREN(")"),
- SEMI(";"),
- SLASH("/"),
- STAR("*"),
- STAR_STAR("**"),
- STRING("string"),
- TRUE("True"),
- TRY("try"),
- WHILE("while"),
- WITH("with"),
- YIELD("yield"),
- // We need to tokenize all characters.
- // Whitespace will be used for all tokens which should be ignored by the parser.
- WHITESPACE("whitespace");
-
- private final String name;
-
- TokenKind(String name) {
- this.name = name;
- }
-
- /**
- * This is a user-friendly name. For keywords (if, yield, True, etc.), it's also
- * the exact character sequence used by the lexer.
- */
- @Override
- public String toString() {
- return name;
- }
-
- public static ImmutableSet<TokenKind> KEYWORDS = ImmutableSet.of(
- AND, AS, ASSERT, BREAK, CLASS, CONTINUE, DEF, DEL, ELIF, ELSE, EXCEPT,
- FALSE, FINALLY, FOR, FROM, GLOBAL, IF, IMPORT, IN, IS, LAMBDA, LOAD,
- NONLOCAL, NOT, OR, PASS, RAISE, RETURN, TRUE, TRY, WHILE, WITH, YIELD
- );
-
- public static ImmutableSet<TokenKind> OPERATIONS = ImmutableSet.of(
- AND, EQUALS_EQUALS, GREATER, GREATER_EQUALS, IN, LESS, LESS_EQUALS,
- MINUS, NOT_EQUALS, NOT_IN, OR, PERCENT, SLASH, PLUS, PIPE, STAR
- );
-
- public static ImmutableSet<TokenKind> AUGMENTED_ASSIGNMENT_OPS = ImmutableSet.of(
- PLUS_EQUALS, MINUS_EQUALS, STAR_EQUALS, SLASH_EQUALS, PERCENT_EQUALS
- );
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserDefinition.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserDefinition.java
deleted file mode 100644
index 07c26af..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserDefinition.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.parser;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.experiments.DeveloperFlag;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementType;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.extapi.psi.ASTWrapperPsiElement;
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.ParserDefinition;
-import com.intellij.lang.PsiBuilder;
-import com.intellij.lang.PsiParser;
-import com.intellij.lexer.Lexer;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.FileViewProvider;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.impl.source.resolve.FileContextUtil;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.tree.IFileElementType;
-import com.intellij.psi.tree.TokenSet;
-
-/**
- * Defines the BUILD file parser
- */
-public class BuildParserDefinition implements ParserDefinition {
-
- private static final DeveloperFlag DEBUG = new DeveloperFlag("build.file.debug.mode");
-
- @Override
- public Lexer createLexer(Project project) {
- return new BuildLexer(BuildLexerBase.LexerMode.Parsing);
- }
-
- @Override
- public PsiParser createParser(Project project) {
- return new BuildParser();
- }
-
- @Override
- public IFileElementType getFileNodeType() {
- return BuildElementTypes.BUILD_FILE;
- }
-
- @Override
- public TokenSet getWhitespaceTokens() {
- return convert(TokenKind.WHITESPACE, TokenKind.ILLEGAL);
- }
-
- @Override
- public TokenSet getCommentTokens() {
- return convert(TokenKind.COMMENT);
- }
-
- @Override
- public TokenSet getStringLiteralElements() {
- return convert(TokenKind.STRING);
- }
-
- @Override
- public PsiElement createElement(ASTNode node) {
- IElementType type = node.getElementType();
- if (type instanceof BuildElementType) {
- return ((BuildElementType) type).createElement(node);
- }
- return new ASTWrapperPsiElement(node);
- }
-
- @Override
- public PsiFile createFile(FileViewProvider viewProvider) {
- return new BuildFile(viewProvider);
- }
-
- @Override
- public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
- return SpaceRequirements.MAY;
- }
-
- private static TokenSet convert(TokenKind... blazeTokens) {
- return TokenSet.create(Lists.newArrayList(blazeTokens)
- .stream()
- .map(BuildToken::fromKind)
- .toArray(IElementType[]::new));
- }
-
- private static class BuildParser implements PsiParser {
- @Override
- public ASTNode parse(IElementType root, PsiBuilder builder) {
- if (DEBUG.getValue()) {
- System.err.println(builder.getUserDataUnprotected(FileContextUtil.CONTAINING_FILE_KEY));
- }
- PsiBuilder.Marker rootMarker = builder.mark();
- ParsingContext context = new ParsingContext(builder);
- context.statementParser.parseFileInput();
- rootMarker.done(root);
- return builder.getTreeBuilt();
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/ExpressionParsing.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/ExpressionParsing.java
deleted file mode 100644
index 949e74e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/ExpressionParsing.java
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.parser;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementType;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
-import com.intellij.lang.PsiBuilder;
-import com.intellij.openapi.diagnostic.Logger;
-
-import java.util.EnumSet;
-import java.util.List;
-
-/**
- * For parsing expressions in BUILD files.
- */
-public class ExpressionParsing extends Parsing {
-
- private static final Logger LOG = Logger.getInstance("com.google.idea.blaze.base.lang.buildfile.parser.ExpressionParsing");
-
- private static final ImmutableSet<TokenKind> LIST_TERMINATOR_SET =
- ImmutableSet.of(
- TokenKind.EOF,
- TokenKind.RBRACKET,
- TokenKind.SEMI);
-
- private static final ImmutableSet<TokenKind> DICT_TERMINATOR_SET =
- ImmutableSet.of(
- TokenKind.EOF,
- TokenKind.RBRACE,
- TokenKind.SEMI);
-
- private static final ImmutableSet<TokenKind> EXPR_LIST_TERMINATOR_SET =
- ImmutableSet.of(
- TokenKind.EOF,
- TokenKind.NEWLINE,
- TokenKind.EQUALS,
- TokenKind.RBRACE,
- TokenKind.RBRACKET,
- TokenKind.RPAREN,
- TokenKind.SEMI);
-
- private static final ImmutableSet<TokenKind> EXPR_TERMINATOR_SET =
- ImmutableSet.of(
- TokenKind.EOF,
- TokenKind.COLON,
- TokenKind.COMMA,
- TokenKind.FOR,
- TokenKind.MINUS,
- TokenKind.PERCENT,
- TokenKind.PLUS,
- TokenKind.RBRACKET,
- TokenKind.RPAREN,
- TokenKind.SLASH);
-
- private static final ImmutableSet<TokenKind> BINARY_OPERATORS =
- ImmutableSet.of(
- TokenKind.AND,
- TokenKind.EQUALS_EQUALS,
- TokenKind.GREATER,
- TokenKind.GREATER_EQUALS,
- TokenKind.IN,
- TokenKind.LESS,
- TokenKind.LESS_EQUALS,
- TokenKind.MINUS,
- TokenKind.NOT_EQUALS,
- TokenKind.NOT_IN,
- TokenKind.OR,
- TokenKind.PERCENT,
- TokenKind.SLASH,
- TokenKind.PLUS,
- TokenKind.PIPE,
- TokenKind.STAR);
-
- private static final ImmutableSet<TokenKind> FUNCALL_TERMINATOR_SET =
- ImmutableSet.of(
- TokenKind.EOF,
- TokenKind.RPAREN,
- TokenKind.SEMI,
- TokenKind.NEWLINE);
-
- /**
- * Highest precedence goes last.
- * Based on: http://docs.python.org/2/reference/expressions.html#operator-precedence
- **/
- private static final List<EnumSet<TokenKind>> OPERATOR_PRECEDENCE = ImmutableList.of(
- EnumSet.of(TokenKind.OR),
- EnumSet.of(TokenKind.AND),
- EnumSet.of(TokenKind.NOT),
- EnumSet.of(TokenKind.EQUALS_EQUALS, TokenKind.NOT_EQUALS, TokenKind.LESS, TokenKind.LESS_EQUALS,
- TokenKind.GREATER, TokenKind.GREATER_EQUALS, TokenKind.IN, TokenKind.NOT_IN),
- EnumSet.of(TokenKind.PIPE),
- EnumSet.of(TokenKind.MINUS, TokenKind.PLUS),
- EnumSet.of(TokenKind.SLASH, TokenKind.STAR, TokenKind.PERCENT));
-
- public ExpressionParsing(ParsingContext context) {
- super(context);
- }
-
- public void parseExpression(boolean insideParens) {
- // handle lists without parens (e.g. 'a,b,c = 1')
- PsiBuilder.Marker marker = insideParens ? null : builder.mark();
- parseNonTupleExpression();
- if (currentToken() == TokenKind.COMMA) {
- parseExpressionList();
- if (marker != null) {
- marker.done(BuildElementTypes.LIST_LITERAL);
- }
- } else if (marker != null) {
- marker.drop();
- }
- }
-
- // expr_list ::= ( ',' expr )* ','?
- private void parseExpressionList() {
- while (matches(TokenKind.COMMA)) {
- if (atAnyOfTokens(EXPR_LIST_TERMINATOR_SET)) {
- break;
- }
- parseNonTupleExpression();
- }
- }
-
- protected void parseNonTupleExpression() {
- parseNonTupleExpression(0);
- // don't bother including conditional expressions for now, just include their components serially
- if (matches(TokenKind.IF)) {
- parseNonTupleExpression(0);
- if (matches(TokenKind.ELSE)) {
- parseNonTupleExpression();
- }
- }
- }
-
- private void parseNonTupleExpression(int prec) {
- if (prec >= OPERATOR_PRECEDENCE.size()) {
- parsePrimaryWithSuffix();
- return;
- }
- if (currentToken() == TokenKind.NOT && OPERATOR_PRECEDENCE.get(prec).contains(TokenKind.NOT)) {
- // special case handling of multi-token 'NOT IN' binary operator
- if (kindFromElement(builder.lookAhead(1)) != TokenKind.IN) {
- // skip the 'not' -- no need for a specific 'not' expression
- builder.advanceLexer();
- parseNonTupleExpression(prec + 1);
- return;
- }
- }
- parseBinOpExpression(prec);
- }
-
- /**
- * binop_expression ::= binop_expression OP binop_expression
- * | parsePrimaryWithSuffix
- * This function takes care of precedence between operators (see OPERATOR_PRECEDENCE for
- * the order), and it assumes left-to-right associativity.
- */
- private void parseBinOpExpression(int prec) {
- PsiBuilder.Marker marker = builder.mark();
- parseNonTupleExpression(prec + 1);
-
- while (true) {
- if (!atBinaryOperator(prec)) {
- marker.drop();
- return;
- }
- parseNonTupleExpression(prec + 1);
- marker.done(BuildElementTypes.BINARY_OP_EXPRESSION);
- marker = marker.precede();
- }
- }
-
- /**
- * Consumes current token iff it's a binary operator at the given precedence level
- * (with special-case handling of 'NOT' 'IN' double token binary operator)
- */
- private boolean atBinaryOperator(int prec) {
- if (matchesAnyOf(OPERATOR_PRECEDENCE.get(prec))) {
- return true;
- }
- if (matchesSequence(TokenKind.NOT, TokenKind.IN)) {
- return true;
- }
- return false;
- }
-
- // primary_with_suffix ::= primary (selector_suffix | substring_suffix)*
- private void parsePrimaryWithSuffix() {
- PsiBuilder.Marker marker = builder.mark();
- parsePrimary();
- while (true) {
- if (matches(TokenKind.DOT)) {
- marker = parseSelectorSuffix(marker);
- } else if (matches(TokenKind.LBRACKET)) {
- marker = parseSubstringSuffix(marker);
- } else {
- break;
- }
- }
- marker.drop();
- }
-
- // selector_suffix ::= '.' IDENTIFIER [funcall_suffix]
- private PsiBuilder.Marker parseSelectorSuffix(PsiBuilder.Marker marker) {
- if (!atToken(TokenKind.IDENTIFIER)) {
- builder.error("expected identifier after dot");
- syncPast(EXPR_TERMINATOR_SET);
- return marker;
- }
- parseTargetOrReferenceIdentifier();
- if (atToken(TokenKind.LPAREN)) {
- parseFuncallSuffix();
- marker.done(BuildElementTypes.FUNCALL_EXPRESSION);
- } else {
- marker.done(BuildElementTypes.DOT_EXPRESSION);
- }
- return marker.precede();
- }
-
- // substring_suffix ::= '[' expression? ':' expression? ':' expression? ']'
- private PsiBuilder.Marker parseSubstringSuffix(PsiBuilder.Marker marker) {
- if (!atToken(TokenKind.COLON)) {
- PsiBuilder.Marker pos = builder.mark();
- parseExpression(false);
- pos.done(BuildElementTypes.POSITIONAL);
- }
- while (!matches(TokenKind.RBRACKET)) {
- if (expect(TokenKind.COLON)) {
- if (!atAnyOfTokens(TokenKind.COLON, TokenKind.RBRACKET)) {
- parseNonTupleExpression();
- }
- } else {
- syncPast(EXPR_LIST_TERMINATOR_SET);
- break;
- }
- }
- marker.done(BuildElementTypes.FUNCALL_EXPRESSION);
- return marker.precede();
- }
-
- private void parseTargetOrReferenceIdentifier() {
- if (!atToken(TokenKind.IDENTIFIER)) {
- builder.error("expected an identifier");
- return;
- }
- // TODO: handle assigning to a list of targets (e.g. "a,b = 1")
- TokenKind next = kindFromElement(builder.lookAhead(1));
- if (next == TokenKind.EQUALS || next == TokenKind.IN) {
- buildTokenElement(BuildElementTypes.TARGET_EXPRESSION);
- } else {
- buildTokenElement(BuildElementTypes.REFERENCE_EXPRESSION);
- }
- }
-
- private void parsePrimary() {
- TokenKind current = currentToken();
- switch (current) {
- case INT:
- buildTokenElement(BuildElementTypes.INTEGER_LITERAL);
- return;
- case STRING:
- parseStringLiteral(true);
- return;
- case IDENTIFIER:
- PsiBuilder.Marker marker = builder.mark();
- String tokenText = builder.getTokenText();
- parseTargetOrReferenceIdentifier();
- if (atToken(TokenKind.LPAREN)) {
- parseFuncallSuffix();
- marker.done(getFuncallExpressionType(tokenText));
- } else {
- marker.drop();
- }
- return;
- case TRUE: // intentional fall-through -- both treated as vanilla identifiers
- case FALSE:
- buildTokenElement(BuildElementTypes.BOOLEAN_LITERAL);
- return;
- case LBRACKET:
- parseListMaker();
- return;
- case LBRACE:
- parseDictExpression();
- return;
- case LPAREN:
- marker = builder.mark();
- builder.advanceLexer();
- if (matches(TokenKind.RPAREN)) {
- marker.done(BuildElementTypes.LIST_LITERAL);
- return;
- }
- parseExpression(true);
- expect(TokenKind.RPAREN, true);
- marker.done(BuildElementTypes.LIST_LITERAL);
- return;
- case MINUS:
- marker = builder.mark();
- builder.advanceLexer();
- parsePrimaryWithSuffix();
- marker.done(BuildElementTypes.POSITIONAL);
- return;
- default:
- builder.error("expected an expression");
- syncPast(EXPR_TERMINATOR_SET);
- }
- }
-
- /**
- * funcall_suffix ::= '(' arg_list? ')'
- * arg_list ::= ((arg ',')* arg ','? )?
- */
- private void parseFuncallSuffix() {
- PsiBuilder.Marker mark = builder.mark();
- expect(TokenKind.LPAREN, true);
- if (matches(TokenKind.RPAREN)) {
- mark.done(BuildElementTypes.ARGUMENT_LIST);
- return;
- }
- parseFuncallArgument();
- while (!atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
- expect(TokenKind.COMMA);
- if (atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
- break;
- }
- parseFuncallArgument();
- }
- expect(TokenKind.RPAREN, true);
- mark.done(BuildElementTypes.ARGUMENT_LIST);
- }
-
- private BuildElementType getFuncallExpressionType(String functionName) {
- if ("glob".equals(functionName)) {
- return BuildElementTypes.GLOB_EXPRESSION;
- }
- return BuildElementTypes.FUNCALL_EXPRESSION;
- }
-
- protected void parseFunctionParameters() {
- if (atToken(TokenKind.RPAREN)) {
- return;
- }
- parseFunctionParameter();
- while (!atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
- expect(TokenKind.COMMA);
- if (atAnyOfTokens(FUNCALL_TERMINATOR_SET)) {
- break;
- }
- parseFunctionParameter();
- }
- }
-
- // arg ::= IDENTIFIER '=' nontupleexpr
- // | expr
- // | *args
- // | **kwargs
- private void parseFuncallArgument() {
- PsiBuilder.Marker marker = builder.mark();
- if (matches(TokenKind.STAR_STAR)) {
- parseNonTupleExpression();
- marker.done(BuildElementTypes.STAR_STAR);
- return;
- }
- if (matches(TokenKind.STAR)) {
- parseNonTupleExpression();
- marker.done(BuildElementTypes.STAR);
- return;
- }
- if (matchesSequence(TokenKind.IDENTIFIER, TokenKind.EQUALS)) {
- parseNonTupleExpression();
- marker.done(BuildElementTypes.KEYWORD);
- return;
- }
- parseNonTupleExpression();
- marker.done(BuildElementTypes.POSITIONAL);
- }
-
- /**
- * arg ::= IDENTIFIER ['=' nontupleexpr]
- */
- private void parseFunctionParameter() {
- PsiBuilder.Marker marker = builder.mark();
- if (matches(TokenKind.STAR_STAR)) {
- expectIdentifier("invalid parameter name");
- marker.done(BuildElementTypes.PARAM_STAR_STAR);
- return;
- }
- if (matches(TokenKind.STAR)) {
- if (atToken(TokenKind.IDENTIFIER)) {
- builder.advanceLexer();
- }
- marker.done(BuildElementTypes.PARAM_STAR);
- return;
- }
- expectIdentifier("invalid parameter name");
- if (matches(TokenKind.EQUALS)) {
- parseNonTupleExpression();
- marker.done(BuildElementTypes.PARAM_OPTIONAL);
- return;
- }
- marker.done(BuildElementTypes.PARAM_MANDATORY);
- }
-
- protected void expectIdentifier(String error) {
- expect(TokenKind.IDENTIFIER, error, true);
- }
-
- // list_maker ::= '[' ']'
- // |'[' expr ']'
- // |'[' expr expr_list ']'
- // |'[' expr ('FOR' loop_variables 'IN' expr)+ ']'
- private void parseListMaker() {
- PsiBuilder.Marker marker = builder.mark();
- expect(TokenKind.LBRACKET);
- if (matches(TokenKind.RBRACKET)) {
- marker.done(BuildElementTypes.LIST_LITERAL);
- return;
- }
- parseNonTupleExpression();
- switch (currentToken()) {
- case RBRACKET:
- builder.advanceLexer();
- marker.done(BuildElementTypes.LIST_LITERAL);
- return;
- case FOR:
- parseComprehensionSuffix(TokenKind.RBRACKET);
- marker.done(BuildElementTypes.LIST_COMPREHENSION_EXPR);
- return;
- case COMMA:
- parseExpressionList();
- if (!matches(TokenKind.RBRACKET)) {
- builder.error("expected 'for' or ']'");
- syncPast(LIST_TERMINATOR_SET);
- }
- marker.done(BuildElementTypes.LIST_LITERAL);
- return;
- default:
- builder.error("expected ',', 'for' or ']'");
- syncPast(LIST_TERMINATOR_SET);
- marker.done(BuildElementTypes.LIST_LITERAL);
- }
- }
-
- // dict_expression ::= '{' '}'
- // |'{' dict_entry_list '}'
- // |'{' dict_entry 'FOR' loop_variables 'IN' expr '}'
- private void parseDictExpression() {
- PsiBuilder.Marker marker = builder.mark();
- expect(TokenKind.LBRACE, true);
- if (matches(TokenKind.RBRACE)) {
- marker.done(BuildElementTypes.DICTIONARY_LITERAL);
- return;
- }
- parseDictEntry();
- if (currentToken() == TokenKind.FOR) {
- parseComprehensionSuffix(TokenKind.RBRACE);
- marker.done(BuildElementTypes.LIST_COMPREHENSION_EXPR);
- return;
- }
- if (matches(TokenKind.COMMA)) {
- parseDictEntryList();
- }
- expect(TokenKind.RBRACE, true);
- marker.done(BuildElementTypes.DICTIONARY_LITERAL);
- }
-
- // dict_entry_list ::= ( (dict_entry ',')* dict_entry ','? )?
- private void parseDictEntryList() {
- if (atAnyOfTokens(DICT_TERMINATOR_SET)) {
- return;
- }
- parseDictEntry();
- while (matches(TokenKind.COMMA)) {
- if (atAnyOfTokens(DICT_TERMINATOR_SET)) {
- return;
- }
- parseDictEntry();
- }
- }
-
- // dict_entry ::= nontupleexpr ':' nontupleexpr
- private void parseDictEntry() {
- PsiBuilder.Marker marker = builder.mark();
- parseNonTupleExpression();
- expect(TokenKind.COLON);
- parseNonTupleExpression();
- marker.done(BuildElementTypes.DICTIONARY_ENTRY_LITERAL);
- }
-
- // comprehension_suffix ::= 'FOR' loop_variables 'IN' expr comprehension_suffix
- // | 'IF' expr comprehension_suffix
- // | ']'
- private void parseComprehensionSuffix(TokenKind closingBracket) {
- while (true) {
- if (matches(TokenKind.FOR)) {
- parseForLoopVariables();
- expect(TokenKind.IN);
- parseNonTupleExpression(0);
- } else if (matches(TokenKind.IF)) {
- parseExpression(true);
- } else if (matches(closingBracket)) {
- return;
- } else {
- builder.error("expected " + closingBracket + ", 'for' or 'if'");
- syncPast(EXPR_LIST_TERMINATOR_SET);
- return;
- }
- }
- }
-
- // Equivalent to 'exprlist' rule in Python grammar.
- // loop_variables ::= primary_with_suffix ( ',' primary_with_suffix )* ','?
- protected void parseForLoopVariables() {
- PsiBuilder.Marker marker = builder.mark();
- parsePrimaryWithSuffix();
- if (currentToken() != TokenKind.COMMA) {
- marker.drop();
- return;
- }
- while (matches(TokenKind.COMMA)) {
- if (atAnyOfTokens(EXPR_LIST_TERMINATOR_SET)) {
- break;
- }
- parsePrimaryWithSuffix();
- }
- marker.done(BuildElementTypes.LIST_LITERAL);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/Parsing.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/Parsing.java
deleted file mode 100644
index 2188c83..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/Parsing.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.parser;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementType;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
-import com.intellij.lang.PsiBuilder;
-import com.intellij.psi.tree.IElementType;
-
-import javax.annotation.Nullable;
-import java.util.EnumSet;
-import java.util.Set;
-
-/**
- * Base class for BUILD file component parsers
- */
-public abstract class Parsing {
-
- // Keywords that exist in Python which we don't parse.
- protected static final EnumSet<TokenKind> FORBIDDEN_KEYWORDS =
- EnumSet.of(TokenKind.AS, TokenKind.ASSERT,
- TokenKind.DEL, TokenKind.EXCEPT, TokenKind.FINALLY, TokenKind.FROM, TokenKind.GLOBAL,
- TokenKind.IMPORT, TokenKind.IS, TokenKind.LAMBDA, TokenKind.NONLOCAL, TokenKind.RAISE,
- TokenKind.TRY, TokenKind.WITH, TokenKind.WHILE, TokenKind.YIELD);
-
- protected ParsingContext context;
- protected PsiBuilder builder;
-
- public Parsing(ParsingContext context) {
- this.context = context;
- this.builder = context.builder;
- }
-
- protected ExpressionParsing getExpressionParser() {
- return context.expressionParser;
- }
-
- /**
- * @return true if a string was parsed
- */
- protected boolean parseStringLiteral(boolean alwaysConsume) {
- if (currentToken() != TokenKind.STRING) {
- expect(TokenKind.STRING, alwaysConsume);
- return false;
- }
- buildTokenElement(BuildElementTypes.STRING_LITERAL);
- if (currentToken() == TokenKind.STRING) {
- builder.error("implicit string concatenation is forbidden; use the '+' operator");
- }
- return true;
- }
-
- protected void buildTokenElement(BuildElementType type) {
- PsiBuilder.Marker marker = builder.mark();
- builder.advanceLexer();
- marker.done(type);
- }
-
- /**
- * Consume tokens until we reach the first token that has a kind that is in the set of terminatingTokens.
- */
- protected void syncTo(Set<TokenKind> terminatingTokens) {
- // read past the problematic token
- while (!atAnyOfTokens(terminatingTokens)) {
- builder.advanceLexer();
- }
- }
-
- /**
- * Consume tokens until we consume the first token that has a kind that is in the set of terminatingTokens.
- */
- protected void syncPast(Set<TokenKind> terminatingTokens) {
- // read past the problematic token
- while (!matchesAnyOf(terminatingTokens)) {
- builder.advanceLexer();
- }
- }
-
- /**
- * Consumes the current token iff it's one of the expected types.<br>
- * Otherwise, returns false and reports an error.
- */
- protected boolean expect(TokenKind kind) {
- return expect(kind, false);
- }
-
- /**
- * Consumes the current token if 'alwaysConsume' is true or if it's one of the expected types.<br>
- * Otherwise, returns false and reports an error.
- */
- protected boolean expect(TokenKind kind, boolean alwaysConsume) {
- return expect(kind, String.format("'%s' expected", kind), alwaysConsume);
- }
-
- /**
- * Consumes the current token if 'alwaysConsume' is true or if it's one of the expected types.<br>
- * Otherwise, returns false and reports an error.
- */
- protected boolean expect(TokenKind kind, String message, boolean alwaysConsume) {
- TokenKind current = currentToken();
- if (current == kind || alwaysConsume) {
- builder.advanceLexer();
- }
- if (current != kind) {
- builder.error(message);
- return false;
- }
- return true;
- }
-
- /**
- * Checks if we're at the current sequence of tokens. If so, consumes them.
- */
- protected boolean matchesSequence(TokenKind... kinds) {
- PsiBuilder.Marker marker = builder.mark();
- for (TokenKind kind : kinds) {
- if (!matches(kind)) {
- marker.rollbackTo();
- return false;
- }
- }
- marker.drop();
- return true;
- }
-
- /**
- * Consumes the current token iff it matches the expected type. Otherwise, returns false
- */
- protected boolean matches(TokenKind kind) {
- if (currentToken() == kind) {
- builder.advanceLexer();
- return true;
- }
- return false;
- }
-
- /**
- * Consumes the current token iff it matches one of the expected types. Otherwise, returns false
- */
- protected boolean matchesAnyOf(TokenKind... kinds) {
- TokenKind current = currentToken();
- for (TokenKind kind : kinds) {
- if (kind == current) {
- builder.advanceLexer();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Consumes the current token iff it's one of the expected types. Otherwise, returns false
- */
- protected boolean matchesAnyOf(Set<TokenKind> kinds) {
- if (kinds.contains(currentToken())) {
- builder.advanceLexer();
- return true;
- }
- return false;
- }
-
- /**
- * Checks if the upcoming sequence of tokens match that expected. Doesn't advance the parser.
- */
- protected boolean atTokenSequence(TokenKind... kinds) {
- for (int i = 0; i < kinds.length; i++) {
- if (kindFromElement(builder.lookAhead(i)) != kinds[i]) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Checks if the current token matches the expected kind. Doesn't advance the parser.
- */
- protected boolean atToken(TokenKind kind) {
- return currentToken() == kind;
- }
-
- /**
- * Checks if the current token matches any one of the expected kinds. Doesn't advance the parser.
- */
- protected boolean atAnyOfTokens(TokenKind... kinds) {
- TokenKind current = currentToken();
- for (TokenKind kind : kinds) {
- if (current == kind) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Checks if the current token matches any one of the expected kinds. Doesn't advance the parser.
- */
- protected boolean atAnyOfTokens(Set<TokenKind> kinds) {
- return kinds.contains(currentToken());
- }
-
- @Nullable
- protected TokenKind currentToken() {
- return builder.eof() ? TokenKind.EOF : kindFromElement(builder.getTokenType());
- }
-
- @Nullable
- protected TokenKind kindFromElement(IElementType type) {
- if (type == null) {
- return null;
- }
- if (!(type instanceof BuildToken)) {
- throw new RuntimeException("Invalid type: " + type + " of class " + type.getClass());
- }
- TokenKind kind = ((BuildToken) type).kind;
- checkForbiddenKeywords(kind);
- return kind;
- }
-
- private void checkForbiddenKeywords(TokenKind kind) {
- if (!FORBIDDEN_KEYWORDS.contains(kind)) {
- return;
- }
- builder.error(forbiddenKeywordError(kind));
- }
-
- protected String forbiddenKeywordError(TokenKind kind) {
- assert FORBIDDEN_KEYWORDS.contains(kind);
- switch (kind) {
- case ASSERT: return "'assert' not supported, use 'fail' instead";
- case TRY: return "'try' not supported, all exceptions are fatal";
- case IMPORT: return "'import' not supported, use 'load' instead";
- case IS: return "'is' not supported, use '==' instead";
- case LAMBDA: return "'lambda' not supported, declare a function instead";
- case RAISE: return "'raise' not supported, use 'fail' instead";
- case WHILE: return "'while' not supported, use 'for' instead";
- default: return "keyword '" + kind + "' not supported";
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/ParsingContext.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/ParsingContext.java
deleted file mode 100644
index de8e5b7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/ParsingContext.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.parser;
-
-import com.intellij.lang.PsiBuilder;
-
-/**
- * Shared context between BUILD file parsing components
- */
-public class ParsingContext {
-
- public final StatementParsing statementParser;
- public final ExpressionParsing expressionParser;
- public final PsiBuilder builder;
-
- public ParsingContext(final PsiBuilder builder) {
- this.builder = builder;
- statementParser = new StatementParsing(this);
- expressionParser = new ExpressionParsing(this);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/StatementParsing.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/StatementParsing.java
deleted file mode 100644
index 762db00..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/parser/StatementParsing.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.parser;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementTypes;
-import com.intellij.lang.PsiBuilder;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.psi.tree.IElementType;
-
-/**
- * For parsing statements in BUILD files.
- */
-public class StatementParsing extends Parsing {
-
- private static final Logger LOG = Logger.getInstance("com.google.idea.blaze.base.lang.buildfile.parser.StatementParsing");
-
- private static final ImmutableSet<TokenKind> STATEMENT_TERMINATOR_SET =
- ImmutableSet.of(TokenKind.EOF, TokenKind.NEWLINE, TokenKind.SEMI);
-
- private static final ImmutableSet<TokenKind> SMALL_STMT_START =
- ImmutableSet.of(TokenKind.IDENTIFIER, TokenKind.RETURN);
-
- public StatementParsing(ParsingContext context) {
- super(context);
- }
-
- /**
- * Called at the start of parsing. Parses an entire file
- */
- public void parseFileInput() {
- builder.setDebugMode(true);
- while (!builder.eof()) {
- if (matches(TokenKind.NEWLINE)) {
- continue;
- }
- parseTopLevelStatement();
- }
- }
-
- // Unlike in Python grammar, 'load' and 'def' are only allowed as a top-level statement
- public void parseTopLevelStatement() {
- if (currentToken() == TokenKind.LOAD) {
- parseLoadStatement();
- } else if (currentToken() == TokenKind.DEF) {
- parseFunctionDefStatement();
- } else {
- parseStatement();
- }
- }
-
- // simple_stmt | compound_stmt
- public void parseStatement() {
- TokenKind current = currentToken();
- if (current == TokenKind.IF) {
- parseIfStatement();
- } else if (current == TokenKind.FOR) {
- parseForStatement();
- } else if (FORBIDDEN_KEYWORDS.contains(current)) {
- PsiBuilder.Marker mark = builder.mark();
- syncTo(STATEMENT_TERMINATOR_SET);
- mark.error(forbiddenKeywordError(current));
- builder.advanceLexer();
- } else {
- parseSimpleStatement();
- }
- }
-
- // func_def_stmt ::= DEF IDENTIFIER funcall_suffix ':' suite
- private void parseFunctionDefStatement() {
- PsiBuilder.Marker marker = builder.mark();
- expect(TokenKind.DEF);
- getExpressionParser().expectIdentifier("expected a function name");
- PsiBuilder.Marker listMarker = builder.mark();
- expect(TokenKind.LPAREN);
- getExpressionParser().parseFunctionParameters();
- expect(TokenKind.RPAREN, true);
- listMarker.done(BuildElementTypes.PARAMETER_LIST);
- expect(TokenKind.COLON);
- parseSuite();
- marker.done(BuildElementTypes.FUNCTION_STATEMENT);
- }
-
- // load '(' STRING (',' [IDENTIFIER '='] STRING)* [','] ')'
- private void parseLoadStatement() {
- PsiBuilder.Marker marker = builder.mark();
- expect(TokenKind.LOAD);
- expect(TokenKind.LPAREN);
- parseStringLiteral(false);
- // Not implementing [IDENTIFIER EQUALS] option -- not a documented feature, so wait for users to complain
- boolean hasSymbols = false;
- while (!matches(TokenKind.RPAREN) && !matchesAnyOf(STATEMENT_TERMINATOR_SET)) {
- expect(TokenKind.COMMA);
- if (matches(TokenKind.RPAREN) || matchesAnyOf(STATEMENT_TERMINATOR_SET)) {
- break;
- }
- hasSymbols |= parseStringLiteral(true);
- }
- if (!hasSymbols) {
- builder.error("'load' statements must include at least one loaded function");
- }
- marker.done(BuildElementTypes.LOAD_STATEMENT);
- }
-
- /**
- * if_stmt ::= IF expr ':' suite (ELIF expr ':' suite)* [ELSE ':' suite]
- */
- private void parseIfStatement() {
- PsiBuilder.Marker marker = builder.mark();
- parseIfStatementPart(TokenKind.IF, BuildElementTypes.IF_PART, true);
- while (currentToken() == TokenKind.ELIF) {
- parseIfStatementPart(TokenKind.ELIF, BuildElementTypes.ELSE_IF_PART, true);
- }
- if (currentToken() == TokenKind.ELSE) {
- parseIfStatementPart(TokenKind.ELSE, BuildElementTypes.ELSE_PART, false);
- }
- marker.done(BuildElementTypes.IF_STATEMENT);
- }
-
- // cond_stmts ::= [EL]IF expr ':' suite
- private void parseIfStatementPart(TokenKind tokenKind, IElementType type, boolean conditional) {
- PsiBuilder.Marker marker = builder.mark();
- expect(tokenKind);
- if (conditional) {
- getExpressionParser().parseNonTupleExpression();
- }
- expect(TokenKind.COLON);
- parseSuite();
- marker.done(type);
- }
-
- // for_stmt ::= FOR IDENTIFIER IN expr ':' suite
- private void parseForStatement() {
- PsiBuilder.Marker marker = builder.mark();
- expect(TokenKind.FOR);
- getExpressionParser().parseForLoopVariables();
- expect(TokenKind.IN);
- getExpressionParser().parseExpression(false);
- expect(TokenKind.COLON);
- parseSuite();
- marker.done(BuildElementTypes.FOR_STATEMENT);
- }
-
- // simple_stmt ::= small_stmt (';' small_stmt)* ';'? NEWLINE
- private void parseSimpleStatement() {
- parseSmallStatementOrPass();
- while (matches(TokenKind.SEMI)) {
- if (matches(TokenKind.NEWLINE)) {
- return;
- }
- parseSmallStatementOrPass();
- }
- if (!builder.eof()) {
- expect(TokenKind.NEWLINE);
- }
- }
-
- // small_stmt | 'pass'
- private void parseSmallStatementOrPass() {
- if (currentToken() == TokenKind.PASS) {
- buildTokenElement(BuildElementTypes.PASS_STATMENT);
- return;
- }
- parseSmallStatement();
- }
-
- private void parseSmallStatement() {
- if (currentToken() == TokenKind.RETURN) {
- parseReturnStatement();
- return;
- }
- if (atAnyOfTokens(TokenKind.BREAK, TokenKind.CONTINUE)) {
- buildTokenElement(BuildElementTypes.FLOW_STATEMENT);
- return;
- }
- PsiBuilder.Marker refMarker = builder.mark();
- getExpressionParser().parseExpression(false);
- if (matches(TokenKind.EQUALS)) {
- getExpressionParser().parseExpression(false);
- refMarker.done(BuildElementTypes.ASSIGNMENT_STATEMENT);
- } else if (matchesAnyOf(TokenKind.AUGMENTED_ASSIGNMENT_OPS)) {
- getExpressionParser().parseExpression(false);
- refMarker.done(BuildElementTypes.AUGMENTED_ASSIGNMENT);
- } else {
- refMarker.drop();
- }
- }
-
- private void parseReturnStatement() {
- PsiBuilder.Marker marker = builder.mark();
- expect(TokenKind.RETURN);
- if (!STATEMENT_TERMINATOR_SET.contains(currentToken())) {
- getExpressionParser().parseExpression(false);
- }
- marker.done(BuildElementTypes.RETURN_STATEMENT);
- }
-
- // suite ::= simple_stmt | (NEWLINE INDENT stmt+ DEDENT)
- private void parseSuite() {
- if (!matches(TokenKind.NEWLINE)) {
- parseSimpleStatement();
- return;
- }
- PsiBuilder.Marker marker = builder.mark();
- if (expect(TokenKind.INDENT)) {
- while (!builder.eof() && !matches(TokenKind.DEDENT)) {
- parseStatement();
- }
- }
- marker.done(BuildElementTypes.STATEMENT_LIST);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Argument.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Argument.java
deleted file mode 100644
index 16ed4f4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Argument.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.references.ArgumentReference;
-import com.google.idea.blaze.base.lang.buildfile.references.KeywordArgumentReference;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.tree.IElementType;
-
-import javax.annotation.Nullable;
-
-/**
- * PSI element for an argument, passed via a function call.
- */
-public abstract class Argument extends BuildElementImpl {
-
- public static final Argument[] EMPTY_ARRAY = new Argument[0];
-
- public Argument(ASTNode node) {
- super(node);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitArgument(this);
- }
-
- /**
- * The value passed by this argument
- */
- @Nullable
- public Expression getValue() {
- // for *args, **kwargs, this should be 'args' or 'kwargs' identifiers.
- // otherwise the expression after the (optional) '='
- ASTNode node = getNode().getLastChildNode();
- while (node != null) {
- IElementType type = node.getElementType();
- if (BuildElementTypes.EXPRESSIONS.contains(type)) {
- return (Expression) node.getPsi();
- }
- if (type == BuildToken.fromKind(TokenKind.EQUALS)
- || type == BuildToken.fromKind(TokenKind.STAR)
- || type == BuildToken.fromKind(TokenKind.STAR_STAR)) {
- break;
- }
- node = node.getTreePrev();
- }
- return null;
- }
-
- public static class Keyword extends Argument {
- public Keyword(ASTNode node) {
- super(node);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitKeywordArgument(this);
- }
-
- @Nullable
- public ASTNode getNameNode() {
- return getNode().findChildByType(BuildToken.IDENTIFIER);
- }
-
- @Override
- @Nullable
- public String getName() {
- ASTNode node = getNameNode();
- return node != null ? node.getText() : null;
- }
-
- @Override
- public KeywordArgumentReference getReference() {
- ASTNode keywordNode = getNameNode();
- if (keywordNode != null) {
- TextRange range = PsiUtils.childRangeInParent(getTextRange(), keywordNode.getTextRange());
- return new KeywordArgumentReference(this, range);
- }
- return null;
- }
- }
-
- public static class Positional extends Argument {
- public Positional(ASTNode node) {
- super(node);
- }
-
- @Override
- public PsiReference getReference() {
- return new ArgumentReference<>(this, getTextRange(), true);
- }
- }
-
- public static class Star extends Argument {
- public Star(ASTNode node) {
- super(node);
- }
- }
-
- public static class StarStar extends Argument {
- public StarStar(ASTNode node) {
- super(node);
- }
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ArgumentList.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ArgumentList.java
deleted file mode 100644
index 6c44e32..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ArgumentList.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Argument list of a function call
- */
-public class ArgumentList extends BuildListType<Argument> {
-
- public ArgumentList(ASTNode astNode) {
- super(astNode, Argument.class);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitFuncallArgList(this);
- }
-
- public Argument[] getArguments() {
- return getElements();
- }
-
- @Nullable
- public Argument.Keyword getKeywordArgument(String name) {
- ASTNode node = getNode().getFirstChildNode();
- while (node != null) {
- if (node.getElementType() == BuildElementTypes.KEYWORD) {
- Argument.Keyword arg = (Argument.Keyword) node.getPsi();
- String keyword = arg.getName();
- if (keyword != null && keyword.equals(name)) {
- return arg;
- }
- }
- node = node.getTreeNext();
- }
- return null;
- }
-
- @Nullable
- public Expression getKeywordArgumentValue(String name) {
- Argument.Keyword keyword = getKeywordArgument(name);
- return keyword != null ? keyword.getValue() : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/AssignmentStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/AssignmentStatement.java
deleted file mode 100644
index 225ab46..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/AssignmentStatement.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-import com.intellij.util.PlatformIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * PSI element for an assignment statement [expr ASSIGN_OP expr]
- */
-public class AssignmentStatement extends BuildElementImpl implements Statement {
-
- public AssignmentStatement(ASTNode astNode) {
- super(astNode);
- }
-
- /**
- * Returns the LHS of the assignment
- */
- @Nullable
- public TargetExpression getLeftHandSideExpression() {
- return findChildByClass(TargetExpression.class);
- }
-
- /**
- * Returns the RHS of the assignment
- */
- @Nullable
- public Expression getAssignedValue() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitAssignmentStatement(this);
- }
-
- @Nullable
- @Override
- public String getName() {
- TargetExpression target = getLeftHandSideExpression();
- return target != null ? target.getName() : super.getName();
- }
-
- @Override
- public Icon getIcon(int flags) {
- return PlatformIcons.FIELD_ICON;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/AugmentedAssignmentStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/AugmentedAssignmentStatement.java
deleted file mode 100644
index acc41cb..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/AugmentedAssignmentStatement.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-import javax.annotation.Nullable;
-
-/**
- * PSI element for an augmented assignment statement [expr += expr]
- */
-public class AugmentedAssignmentStatement extends BuildElementImpl implements Statement {
-
- public AugmentedAssignmentStatement(ASTNode astNode) {
- super(astNode);
- }
-
- /**
- * Returns the LHS of the assignment
- */
- @Nullable
- public TargetExpression getLeftHandSideExpression() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
- }
-
- /**
- * Returns the RHS of the assignment
- */
- @Nullable
- public Expression getAssignedValue() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitAugmentedAssignmentStatement(this);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BinaryOpExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BinaryOpExpression.java
deleted file mode 100644
index 3a35fb1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BinaryOpExpression.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-import javax.annotation.Nullable;
-
-/**
- * PSI element for an binary operation expression [expr BIN_OP expr]
- */
-public class BinaryOpExpression extends BuildElementImpl implements Expression {
-
- public BinaryOpExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitBinaryOpExpression(this);
- }
-
- /**
- * Returns the LHS of the expression
- */
- @Nullable
- public Expression getLhs() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
- }
-
- /**
- * Returns the RHS of the expression
- */
- @Nullable
- public Expression getRhs() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BooleanLiteral.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BooleanLiteral.java
deleted file mode 100644
index 4c8d9f3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BooleanLiteral.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI node for boolean literal expressions
- */
-public class BooleanLiteral extends BuildElementImpl implements LiteralExpression {
-
- public BooleanLiteral(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitBooleanLiteral(this);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElement.java
deleted file mode 100644
index 8e46c7a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElement.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.intellij.psi.NavigatablePsiElement;
-import com.intellij.psi.PsiElement;
-
-import javax.annotation.Nullable;
-
-/**
- * Base class for all BUILD file PSI elements
- */
-public interface BuildElement extends NavigatablePsiElement {
-
- @Nullable
- static BuildElement asBuildElement(PsiElement psiElement) {
- return psiElement instanceof BuildElement ? (BuildElement) psiElement : null;
- }
-
- Statement[] EMPTY_ARRAY = new Statement[0];
-
- String getPresentableText();
-
- @Nullable
- PsiElement getReferencedElement();
-
- <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass);
-
- <P extends PsiElement> P firstChildOfClass(Class<P> psiClass);
-
- WorkspacePath getWorkspacePath();
-
- @Nullable
- BlazePackage getBlazePackage();
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementImpl.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementImpl.java
deleted file mode 100644
index 9195201..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementImpl.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.intellij.extapi.psi.ASTWrapperPsiElement;
-import com.intellij.lang.ASTNode;
-import com.intellij.navigation.ItemPresentation;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiElementVisitor;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.tree.TokenSet;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.lang.reflect.Array;
-import java.util.Arrays;
-
-/**
- * Base PSI class for the BUILD language
- */
-public abstract class BuildElementImpl extends ASTWrapperPsiElement implements BuildElement {
-
- public BuildElementImpl(ASTNode astNode) {
- super(astNode);
- }
-
- public <P extends PsiElement> P getPsiChild(IElementType type, Class<P> psiClass) {
- ASTNode childNode = getNode().findChildByType(type);
- return childNode != null ? (P) childNode.getPsi() : null;
- }
-
- @Override
- public <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass) {
- return findChildrenByClass(psiClass);
- }
-
- @Override
- public <P extends PsiElement> P firstChildOfClass(Class<P> psiClass) {
- return findChildByClass(psiClass);
- }
-
- /**
- * Returns the BuildElement child at the specified index,
- * where index is calculated after filtering out non-BuildElement children.
- * @return null if index >= number of BuildElement children
- */
- @Nullable
- protected BuildElement getBuildElementChild(int index) {
- BuildElement[] children = buildElementChildren();
- return children.length <= index ? null : children[index];
- }
-
- protected BuildElement[] buildElementChildren() {
- return Arrays.stream(getNode().getChildren(null))
- .map(ASTNode::getPsi)
- .filter(psiElement -> psiElement instanceof BuildElement)
- .toArray(BuildElement[]::new);
- }
-
- protected <T extends BuildElement> T[] childrenToPsi(TokenSet filterSet, T[] array) {
- final ASTNode[] nodes = getNode().getChildren(filterSet);
- T[] psiElements = (T[]) Array.newInstance(array.getClass().getComponentType(), nodes.length);
- for (int i = 0; i < nodes.length; i++) {
- psiElements[i] = (T) nodes[i].getPsi();
- }
- return psiElements;
- }
-
- @Nullable
- protected <T extends BuildElement> T childToPsi(TokenSet filterSet, int index) {
- final ASTNode[] nodes = getNode().getChildren(filterSet);
- if (nodes.length <= index) {
- return null;
- }
- return (T) nodes[index].getPsi();
- }
-
- @Nullable
- protected IElementType getParentType() {
- ASTNode node = getNode().getTreeParent();
- return node != null ? node.getElementType() : null;
- }
-
- public String nonNullName() {
- String name = getName();
- return name != null ? name : "<unnamed>";
- }
-
- @Override
- public String getPresentableText() {
- return nonNullName();
- }
-
- @Override
- public String toString() {
- return super.toString() + ": " + getPresentableText();
- }
-
- @Override
- public void accept(PsiElementVisitor visitor) {
- if (visitor instanceof BuildElementVisitor) {
- acceptVisitor(((BuildElementVisitor) visitor));
- } else {
- super.accept(visitor);
- }
- }
-
- protected abstract void acceptVisitor(BuildElementVisitor visitor);
-
- @Nullable
- @Override
- public PsiElement getReferencedElement() {
- PsiReference[] refs = getReferences();
- for (PsiReference ref : refs) {
- PsiElement element = ref.resolve();
- if (element != null) {
- return element;
- }
- }
- return null;
- }
-
- @Override
- public ItemPresentation getPresentation() {
- final BuildElement element = this;
- return new ItemPresentation() {
- @Override
- public String getPresentableText() {
- return element.getPresentableText();
- }
- @Override
- public String getLocationString() {
- return null;
- }
- @Override
- public Icon getIcon(boolean unused) {
- return element.getIcon(0);
- }
- };
- }
-
- @Nullable
- @Override
- public WorkspacePath getWorkspacePath() {
- BuildFile file = (BuildFile) getContainingFile();
- return file.getWorkspacePath();
- }
-
- @Nullable
- @Override
- public BlazePackage getBlazePackage() {
- PsiFile file = getContainingFile();
- return file != null ? BlazePackage.getContainingPackage(file) : null;
- }
-
- @Nullable
- @Override
- public BuildFile getContainingFile() {
- return (BuildFile) super.getContainingFile();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementType.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementType.java
deleted file mode 100644
index a93a210..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementType.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.tree.IElementType;
-
-import java.lang.reflect.Constructor;
-
-/**
- * IElementTypes used in the AST by the parser (as opposed to the types used by the lexer).<br>
- * Modelled on IntelliJ's java and python language support conventions.
- */
-public class BuildElementType extends IElementType {
-
- private static final Class[] PARAMETER_TYPES = new Class[]{ASTNode.class};
- private final Class<? extends PsiElement> psiElementClass;
- private Constructor<? extends PsiElement> constructor;
-
- public BuildElementType(String name, Class<? extends PsiElement> psiElementClass) {
- super(name, BuildFileType.INSTANCE.getLanguage());
- this.psiElementClass = psiElementClass;
- }
-
- public PsiElement createElement(ASTNode node) {
- try {
- if (constructor == null) {
- constructor = psiElementClass.getConstructor(PARAMETER_TYPES);
- }
- return constructor.newInstance(node);
- } catch (Exception e) {
- throw new IllegalStateException("No necessary constructor for " + node.getElementType(), e);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementTypes.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementTypes.java
deleted file mode 100644
index 44ead8a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementTypes.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.intellij.psi.tree.IFileElementType;
-import com.intellij.psi.tree.TokenSet;
-
-/**
- * Collects the types used by the PsiBuilder to construct the AST
- */
-public interface BuildElementTypes {
-
- IFileElementType BUILD_FILE = new IFileElementType(BuildFileType.INSTANCE.getLanguage());
-
- // Statements
- BuildElementType RETURN_STATEMENT = new BuildElementType("return", ReturnStatement.class);
- BuildElementType PASS_STATMENT = new BuildElementType("pass", PassStatement.class);
- BuildElementType ASSIGNMENT_STATEMENT = new BuildElementType("assignment", AssignmentStatement.class);
- BuildElementType AUGMENTED_ASSIGNMENT = new BuildElementType("aug_assign", AugmentedAssignmentStatement.class);
- BuildElementType FLOW_STATEMENT = new BuildElementType("flow", FlowStatement.class);
- BuildElementType LOAD_STATEMENT = new BuildElementType("load", LoadStatement.class);
- BuildElementType FUNCTION_STATEMENT = new BuildElementType("function_def", FunctionStatement.class);
- BuildElementType FOR_STATEMENT = new BuildElementType("for", ForStatement.class);
- BuildElementType IF_STATEMENT = new BuildElementType("if", IfStatement.class);
-
- BuildElementType IF_PART = new BuildElementType("if_part", IfPart.class);
- BuildElementType ELSE_IF_PART = new BuildElementType("else_if_part", ElseIfPart.class);
- BuildElementType ELSE_PART = new BuildElementType("else_part", ElsePart.class);
-
- BuildElementType STATEMENT_LIST = new BuildElementType("stmt_list", StatementList.class);
-
- // passed arguments
- BuildElementType ARGUMENT_LIST = new BuildElementType("arg_list", ArgumentList.class);
- BuildElementType KEYWORD = new BuildElementType("keyword", Argument.Keyword.class);
- BuildElementType POSITIONAL = new BuildElementType("positional", Argument.Positional.class);
- BuildElementType STAR = new BuildElementType("*", Argument.Star.class);
- BuildElementType STAR_STAR = new BuildElementType("**", Argument.StarStar.class);
-
- // parameters
- BuildElementType PARAMETER_LIST = new BuildElementType("parameter_list", ParameterList.class);
- BuildElementType PARAM_OPTIONAL = new BuildElementType("optional_param", Parameter.Optional.class);
- BuildElementType PARAM_MANDATORY = new BuildElementType("mandatory_param", Parameter.Mandatory.class);
- BuildElementType PARAM_STAR = new BuildElementType("*", Parameter.Star.class);
- BuildElementType PARAM_STAR_STAR = new BuildElementType("**", Parameter.StarStar.class);
-
- // Expressions
- BuildElementType DICTIONARY_LITERAL = new BuildElementType("dict", DictionaryLiteral.class);
- BuildElementType DICTIONARY_ENTRY_LITERAL = new BuildElementType("dict_entry", DictionaryEntryLiteral.class);
- BuildElementType BINARY_OP_EXPRESSION = new BuildElementType("binary_op", BinaryOpExpression.class);
- BuildElementType FUNCALL_EXPRESSION = new BuildElementType("function_call", FuncallExpression.class);
- BuildElementType DOT_EXPRESSION = new BuildElementType("dot_expr", DotExpression.class);
- BuildElementType STRING_LITERAL = new BuildElementType("string", StringLiteral.class);
- BuildElementType INTEGER_LITERAL = new BuildElementType("int", IntegerLiteral.class);
- BuildElementType BOOLEAN_LITERAL = new BuildElementType("bool", BooleanLiteral.class);
- BuildElementType LIST_LITERAL = new BuildElementType("list", ListLiteral.class);
- BuildElementType GLOB_EXPRESSION = new BuildElementType("glob", GlobExpression.class);
- BuildElementType REFERENCE_EXPRESSION = new BuildElementType("reference", ReferenceExpression.class);
- BuildElementType TARGET_EXPRESSION = new BuildElementType("target", TargetExpression.class);
- BuildElementType LIST_COMPREHENSION_EXPR = new BuildElementType("list_comp", ListComprehensionExpression.class);
-
- TokenSet EXPRESSIONS = TokenSet.create(
- FUNCALL_EXPRESSION,
- DICTIONARY_LITERAL,
- DICTIONARY_ENTRY_LITERAL,
- BINARY_OP_EXPRESSION,
- DOT_EXPRESSION,
- STRING_LITERAL,
- INTEGER_LITERAL,
- BOOLEAN_LITERAL,
- LIST_LITERAL,
- REFERENCE_EXPRESSION,
- TARGET_EXPRESSION,
- LIST_COMPREHENSION_EXPR,
- GLOB_EXPRESSION
- );
-
- TokenSet STATEMENTS = TokenSet.create(
- RETURN_STATEMENT,
- PASS_STATMENT,
- ASSIGNMENT_STATEMENT,
- FLOW_STATEMENT,
- LOAD_STATEMENT,
- FUNCTION_STATEMENT,
- FOR_STATEMENT,
- IF_STATEMENT
- );
-
- TokenSet ARGUMENTS = TokenSet.create(
- KEYWORD,
- POSITIONAL,
- STAR,
- STAR_STAR
- );
-
- TokenSet PARAMETERS = TokenSet.create(
- PARAM_OPTIONAL,
- PARAM_MANDATORY,
- PARAM_STAR,
- PARAM_STAR_STAR
- );
-
- TokenSet STRINGS = TokenSet.create(STRING_LITERAL);
- TokenSet FUNCTIONS = TokenSet.create(FUNCTION_STATEMENT);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementVisitor.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementVisitor.java
deleted file mode 100644
index 464fa93..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildElementVisitor.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.psi.PsiElementVisitor;
-
-/**
- * Visitor for BUILD file PSI nodes
- */
-public class BuildElementVisitor extends PsiElementVisitor {
-
- public void visitAssignmentStatement(AssignmentStatement node) {
- visitElement(node);
- }
-
- public void visitAugmentedAssignmentStatement(AugmentedAssignmentStatement node) {
- visitElement(node);
- }
-
- public void visitReturnStatement(ReturnStatement node) {
- visitElement(node);
- }
-
- public void visitArgument(Argument node) {
- visitElement(node);
- }
-
- public void visitKeywordArgument(Argument.Keyword node) {
- visitElement(node);
- }
-
- public void visitParameter(Parameter node) {
- visitElement(node);
- }
-
- public void visitLoadStatement(LoadStatement node) {
- visitElement(node);
- }
-
- public void visitIfStatement(IfStatement node) {
- visitElement(node);
- }
-
- public void visitIfPart(IfPart node) {
- visitElement(node);
- }
-
- public void visitElsePart(ElsePart node) {
- visitElement(node);
- }
-
- public void visitElseIfPart(ElseIfPart node) {
- visitElement(node);
- }
-
- public void visitFunctionStatement(FunctionStatement node) {
- visitElement(node);
- }
-
- public void visitFuncallExpression(FuncallExpression node) {
- visitElement(node);
- }
-
- public void visitForStatement(ForStatement node) {
- visitElement(node);
- }
-
- public void visitFlowStatement(FlowStatement node) {
- visitElement(node);
- }
-
- public void visitDotExpression(DotExpression node) {
- visitElement(node);
- }
-
- public void visitDictionaryLiteral(DictionaryLiteral node) {
- visitElement(node);
- }
-
- public void visitDictionaryEntryLiteral(DictionaryEntryLiteral node) {
- visitElement(node);
- }
-
- public void visitBinaryOpExpression(BinaryOpExpression node) {
- visitElement(node);
- }
-
- public void visitStringLiteral(StringLiteral node) {
- visitElement(node);
- }
-
- public void visitIntegerLiteral(IntegerLiteral node) {
- visitElement(node);
- }
-
- public void visitBooleanLiteral(BooleanLiteral node) {
- visitElement(node);
- }
-
- public void visitListLiteral(ListLiteral node) {
- visitElement(node);
- }
-
- public void visitStatementList(StatementList node) {
- visitElement(node);
- }
-
- public void visitFuncallArgList(ArgumentList node) {
- visitElement(node);
- }
-
- public void visitReferenceExpression(ReferenceExpression node) {
- visitElement(node);
- }
-
- public void visitTargetExpression(TargetExpression node) {
- visitElement(node);
- }
-
- public void visitListComprehensionSuffix(ListComprehensionExpression node) {
- visitElement(node);
- }
-
- public void visitFunctionParameterList(ParameterList node) {
- visitElement(node);
- }
-
- public void visitGlobExpression(GlobExpression node) {
- visitElement(node);
- }
-
- public void visitPassStatement(PassStatement node) {
- visitElement(node);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildFile.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildFile.java
deleted file mode 100644
index 4c87720..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildFile.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.intellij.extapi.psi.PsiFileBase;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.FileViewProvider;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNamedElement;
-import com.intellij.psi.tree.TokenSet;
-import com.intellij.util.PathUtil;
-import com.intellij.util.Processor;
-import icons.BlazeIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.io.File;
-import java.util.List;
-
-/**
- * Build file PSI element
- */
-public class BuildFile extends PsiFileBase implements BuildElement {
-
- public enum BlazeFileType {
- SkylarkExtension,
- BuildPackage // "BUILD", plus hacks such as "BUILD.tools", "BUILD.bazel"
- }
-
- @Nullable
- public static WorkspacePath getWorkspacePath(Project project, String filePath) {
- return BuildReferenceManager.getInstance(project).getWorkspaceRelativePath(filePath);
- }
-
- public static String getBuildFileString(Project project, String filePath) {
- WorkspacePath workspacePath = getWorkspacePath(project, PathUtil.getParentPath(filePath));
- if (workspacePath == null) {
- return "BUILD file: " + filePath;
- }
- String fileName = PathUtil.getFileName(filePath);
- if (fileName.startsWith("BUILD")) {
- return "//" + workspacePath + "/" + fileName;
- }
- return "//" + workspacePath + ":" + fileName;
- }
-
- public BuildFile(FileViewProvider viewProvider) {
- super(viewProvider, BuildFileType.INSTANCE.getLanguage());
- }
-
- @Override
- public FileType getFileType() {
- return BuildFileType.INSTANCE;
- }
-
- public BlazeFileType getBlazeFileType() {
- String fileName = getFileName();
- if (fileName.startsWith("BUILD")) {
- return BlazeFileType.BuildPackage;
- }
- return BlazeFileType.SkylarkExtension;
- }
-
- @Nullable
- @Override
- public BlazePackage getBlazePackage() {
- return BlazePackage.getContainingPackage(this);
- }
-
- public String getFileName() {
- return getViewProvider().getVirtualFile().getName();
- }
-
- public String getFilePath() {
- return getOriginalFile().getViewProvider().getVirtualFile().getPath();
- }
-
- public File getFile() {
- return new File(getFilePath());
- }
-
- @Nullable
- @Override
- public WorkspacePath getWorkspacePath() {
- return getWorkspacePath(getProject(), getFilePath());
- }
-
- /**
- * The workspace path of the containing blaze package
- * (this is always the parent directory for BUILD files, but may be a more distant ancestor for Skylark extensions)
- */
- @Nullable
- public WorkspacePath getPackageWorkspacePath() {
- BlazePackage parentPackage = getBlazePackage();
- if (parentPackage == null) {
- return null;
- }
- String filePath = parentPackage.buildFile.getFilePath();
- return filePath != null ? getWorkspacePath(getProject(), PathUtil.getParentPath(filePath)) : null;
- }
-
- @Nullable
- public String getWorkspaceRelativePackagePath() {
- WorkspacePath packagePath = getPackageWorkspacePath();
- return packagePath != null ? packagePath.relativePath() : null;
- }
-
- /**
- * Finds a top-level rule with a "name" keyword argument with the given value.
- */
- @Nullable
- public FuncallExpression findRule(String name) {
- for (FuncallExpression expr : findChildrenByClass(FuncallExpression.class)) {
- String ruleName = expr.getNameArgumentValue();
- if (name.equals(ruleName)) {
- return expr;
- }
- }
- return null;
- }
-
- /**
- * .bzl files referenced in 'load' statements
- */
- @Nullable
- public String[] getImportedPaths() {
- ASTNode[] loadStatements = getNode().getChildren(TokenSet.create(BuildElementTypes.LOAD_STATEMENT));
- if (loadStatements.length == 0) {
- return null;
- }
- List<String> importedPaths = Lists.newArrayListWithCapacity(loadStatements.length);
- for (int i = 0; i < loadStatements.length; i++) {
- String path = ((LoadStatement) loadStatements[i].getPsi()).getImportedPath();
- if (path != null) {
- importedPaths.add(path);
- }
- }
- return importedPaths.toArray(new String[importedPaths.size()]);
- }
-
- @Nullable
- public FunctionStatement findDeclaredFunction(String name) {
- for (FunctionStatement fn : getFunctionDeclarations()) {
- if (name.equals(fn.getName())) {
- return fn;
- }
- }
- return null;
- }
-
- @Nullable
- public TargetExpression findTopLevelVariable(String name) {
- return ResolveUtil.searchChildAssignmentStatements(this, name);
- }
-
- @Nullable
- public FunctionStatement findLoadedFunction(String name) {
- for (LoadStatement loadStatement : findChildrenByClass(LoadStatement.class)) {
- for (StringLiteral importedFunctionNode : loadStatement.getImportedSymbolElements()) {
- if (name.equals(importedFunctionNode.getStringContents())) {
- PsiElement element = importedFunctionNode.getReferencedElement();
- return element instanceof FunctionStatement ? (FunctionStatement) element : null;
- }
- }
- }
- return null;
- }
-
- public BuildElement findSymbolInScope(String name) {
- BuildElement[] resultHolder = new BuildElement[1];
- Processor<BuildElement> processor = buildElement -> {
- if (buildElement instanceof StringLiteral) {
- buildElement = BuildElement.asBuildElement(buildElement.getReferencedElement());
- }
- if (buildElement instanceof PsiNamedElement
- && name.equals(buildElement.getName())) {
- resultHolder[0] = buildElement;
- return false;
- }
- return true;
- };
- searchSymbolsInScope(processor, null);
- return resultHolder[0];
- }
-
- /**
- * Iterates over all top-level assignment statements, function definitions and loaded symbols.
- * @return false if searching was stopped (e.g. because the desired element was found).
- */
- public boolean searchSymbolsInScope(Processor<BuildElement> processor, @Nullable PsiElement stopAtElement) {
- for (BuildElement child : findChildrenByClass(BuildElement.class)) {
- if (child == stopAtElement) {
- return true;
- }
- if (child instanceof AssignmentStatement) {
- TargetExpression target = ((AssignmentStatement) child).getLeftHandSideExpression();
- if (target != null && !processor.process(target)) {
- return false;
- }
- } else if (child instanceof FunctionStatement) {
- if (!processor.process(child)) {
- return false;
- }
- } else if (child instanceof LoadStatement) {
- for (StringLiteral importedSymbol : ((LoadStatement) child).getImportedSymbolElements()) {
- if (!processor.process(importedSymbol)) {
- return false;
- }
- }
- }
- }
- return true;
- }
-
- /**
- * Searches functions declared in this file, then loaded Skylark extensions, if relevant.
- */
- @Nullable
- public FunctionStatement findFunctionInScope(String name) {
- FunctionStatement localFn = findDeclaredFunction(name);
- if (localFn != null) {
- return localFn;
- }
- return findLoadedFunction(name);
- }
-
- public FunctionStatement[] getFunctionDeclarations() {
- return findChildrenByClass(FunctionStatement.class);
- }
-
- @Override
- public Icon getIcon(int flags) {
- return BlazeIcons.BuildFile;
- }
-
- @Override
- public String getPresentableText() {
- return toString();
- }
-
- @Override
- public String toString() {
- return getBuildFileString(getProject(), getFilePath());
- }
-
- @Nullable
- @Override
- public PsiElement getReferencedElement() {
- return null;
- }
-
- @Override
- public <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass) {
- return findChildrenByClass(psiClass);
- }
-
- @Override
- public <P extends PsiElement> P firstChildOfClass(Class<P> psiClass) {
- return findChildByClass(psiClass);
- }
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildListType.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildListType.java
deleted file mode 100644
index 2510bc1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/BuildListType.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-import javax.annotation.Nullable;
-
-/**
- * Common interface for BUILD psi elements containing a list / sequence of child elements.
- */
-public abstract class BuildListType<E extends BuildElement> extends BuildElementImpl {
-
- private final Class<E> elementClass;
-
- public BuildListType(ASTNode astNode, Class<E> elementClass) {
- super(astNode);
- this.elementClass = elementClass;
- }
-
- public E[] getElements() {
- return findChildrenByClass(elementClass);
- }
-
- @Nullable
- public E getFirstElement() {
- return findChildByClass(elementClass);
- }
-
- public boolean isEmpty() {
- return getFirstElement() != null;
- }
-
- /**
- * The offset into the document at which child elements start.
- * For lists wrapped in braces, this is the offset after the opening brace.
- * For statement lists, this is the offset after the colon.
- */
- public int getStartOffset() {
- return getNode().getStartOffset() + 1;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryEntryLiteral.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryEntryLiteral.java
deleted file mode 100644
index 26eb53b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryEntryLiteral.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for an dictionary entry literal (dictEntry ::= nonTupleExpr ':' nonTupleExpr)
- */
-public class DictionaryEntryLiteral extends BuildElementImpl implements LiteralExpression {
-
- public DictionaryEntryLiteral(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitDictionaryEntryLiteral(this);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryLiteral.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryLiteral.java
deleted file mode 100644
index 2b6cdba..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DictionaryLiteral.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for an dictionary literal.
- */
-public class DictionaryLiteral extends BuildListType<DictionaryEntryLiteral> implements LiteralExpression {
-
- public DictionaryLiteral(ASTNode astNode) {
- super(astNode, DictionaryEntryLiteral.class);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitDictionaryLiteral(this);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DotExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DotExpression.java
deleted file mode 100644
index aceedc4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/DotExpression.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for a dot expression.
- */
-public class DotExpression extends BuildElementImpl implements Expression {
-
- public DotExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitDotExpression(this);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElseIfPart.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElseIfPart.java
deleted file mode 100644
index cfce805..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElseIfPart.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for an elif part of an IfStatement.
- */
-public class ElseIfPart extends BuildElementImpl implements Statement, StatementListContainer {
-
- public ElseIfPart(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitElseIfPart(this);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElsePart.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElsePart.java
deleted file mode 100644
index 911089a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ElsePart.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for an else part of an IfStatement.
- */
-public class ElsePart extends BuildElementImpl implements Statement, StatementListContainer {
-
- public ElsePart(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitElsePart(this);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Expression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Expression.java
deleted file mode 100644
index 12b8166..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Expression.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-/**
- * Interface for all expression PSI elements in a BUILD file
- */
-public interface Expression extends BuildElement {
-
- Expression[] EMPTY_ARRAY = new Expression[0];
-
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FlowStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FlowStatement.java
deleted file mode 100644
index e7e93d1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FlowStatement.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for a flow statement.
- */
-public class FlowStatement extends BuildElementImpl implements Statement {
-
- public FlowStatement(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitFlowStatement(this);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ForStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ForStatement.java
deleted file mode 100644
index f87744f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ForStatement.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-
-import java.util.List;
-
-/**
- * PSI element for a for statement.
- */
-public class ForStatement extends BuildElementImpl implements Statement, StatementListContainer {
-
- public ForStatement(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitForStatement(this);
- }
-
- public List<Expression> getForLoopVariables() {
- List<Expression> loopVariableExpressions = Lists.newArrayList();
- for (PsiElement child : getChildren()) {
- if (child.getNode().getElementType() == BuildToken.fromKind(TokenKind.IN)) {
- return loopVariableExpressions;
- }
- if (child instanceof Expression) {
- loopVariableExpressions.add((Expression) child);
- } else if (child instanceof ListLiteral) {
- for (Expression expr : ((ListLiteral) child).childrenOfClass(Expression.class)) {
- loopVariableExpressions.add(expr);
- }
- }
- }
- return loopVariableExpressions;
- }
-
- @Override
- public String getPresentableText() {
- return "for loop";
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FuncallExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FuncallExpression.java
deleted file mode 100644
index d8ff4c7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FuncallExpression.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.references.FuncallReference;
-import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNameIdentifierOwner;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.Processor;
-import icons.BlazeIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * PSI element for an function call.<br>
- * Could be a top-level rule, Skylark function reference, or general some other python function call
- */
-public class FuncallExpression extends BuildElementImpl implements Expression, PsiNameIdentifierOwner {
-
- public FuncallExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitFuncallExpression(this);
- }
-
- /**
- * The name of the function being called.
- */
- @Nullable
- public String getFunctionName() {
- ASTNode node = getFunctionNameNode();
- return node != null ? node.getText() : null;
- }
-
- @Override
- @Nullable
- public String getName() {
- return getNameArgumentValue();
- }
-
- @Nullable
- @Override
- public PsiElement getNameIdentifier() {
- Argument.Keyword name = getNameArgument();
- return name != null ? name.getValue() : null;
- }
-
- @Override
- public PsiElement setName(String name) throws IncorrectOperationException {
- StringLiteral nameNode = getNameArgumentValueNode();
- if (nameNode == null) {
- return this;
- }
- ASTNode newChild = PsiUtils.createNewLabel(getProject(), name);
- nameNode.getNode().replaceChild(nameNode.getNode().getFirstChildNode(), newChild);
- return this;
- }
-
- /**
- * The function name
- */
- @Nullable
- public ASTNode getFunctionNameNode() {
- PsiElement argList = getArgList();
- if (argList != null) {
- // We want the reference expr directly prior to the open parenthesis.
- // This accounts for Skylark native.rule calls.
- PsiElement prev = argList.getPrevSibling();
- if (prev instanceof ReferenceExpression) {
- return prev.getNode();
- }
- }
- return getNode().findChildByType(BuildElementTypes.REFERENCE_EXPRESSION);
- }
-
- /**
- * Top-level funcalls are almost always BUILD rules.
- */
- public boolean isTopLevel() {
- ASTNode parent = getNode().getTreeParent();
- return parent == null || parent.getElementType() == BuildElementTypes.BUILD_FILE;
- }
-
- public boolean mightBeBuildRule() {
- return isTopLevel() || getNameArgument() != null;
- }
-
- @Nullable
- public Label resolveBuildLabel() {
- return LabelUtils.createLabelFromRuleName(getBlazePackage(), getNameArgumentValue());
- }
-
- @Nullable
- public ArgumentList getArgList() {
- return findChildByType(BuildElementTypes.ARGUMENT_LIST);
- }
-
- public Argument[] getArguments() {
- ArgumentList argList = getArgList();
- return argList != null ? argList.getArguments() : Argument.EMPTY_ARRAY;
- }
-
- /**
- * Keyword argument with name "name", if one is present.
- */
- @Nullable
- public Argument.Keyword getNameArgument() {
- return getKeywordArgument("name");
- }
-
- public Argument.Keyword getKeywordArgument(String name) {
- ArgumentList argList = getArgList();
- return argList != null ? argList.getKeywordArgument(name) : null;
- }
-
- /**
- * StringLiteral value of keyword argument with name "name", if one is present.
- */
- @Nullable
- public StringLiteral getNameArgumentValueNode() {
- Argument.Keyword name = getNameArgument();
- Expression expr = name != null ? name.getValue() : null;
- if (expr instanceof StringLiteral) {
- return ((StringLiteral) expr);
- }
- return null;
- }
-
- /**
- * Value of keyword argument with name "name", if one is present.
- */
- @Nullable
- public String getNameArgumentValue() {
- StringLiteral node = getNameArgumentValueNode();
- return node != null ? node.getStringContents() : null;
- }
-
- @Override
- public Icon getIcon(int flags) {
- return mightBeBuildRule() ? BlazeIcons.BuildRule : null;
- }
-
- @Override
- public String getPresentableText() {
- String name = getFunctionName();
- if (name == null) {
- return super.getPresentableText();
- }
- String targetName = getNameArgumentValue();
- return targetName != null ? name + "(\"" + targetName + "\")" : name;
- }
-
- @Override
- @Nullable
- public FuncallReference getReference() {
- ASTNode nameNode = getFunctionNameNode();
- if (nameNode == null) {
- return null;
- }
- BuildLanguageSpec spec = BuildLanguageSpecProvider.getInstance().getLanguageSpec(getProject());
- if (spec != null && spec.hasRule(nameNode.getText())) {
- // don't try to follow references to built-in rules
- return null;
- }
- TextRange range = PsiUtils.childRangeInParent(getTextRange(), nameNode.getTextRange());
- return new FuncallReference(this, range);
- }
-
- /**
- * Searches all StringLiteral children of this element, for one which references the desired target expression.
- */
- @Nullable
- public StringLiteral findChildReferenceToTarget(final FuncallExpression targetRule) {
- final StringLiteral[] child = new StringLiteral[1];
- Processor<StringLiteral> processor = stringLiteral -> {
- PsiElement ref = stringLiteral.getReferencedElement();
- if (targetRule.equals(ref)) {
- child[0] = stringLiteral;
- return false;
- }
- return true;
- };
- PsiUtils.processChildrenOfType(this, processor, StringLiteral.class);
- return child[0];
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FunctionStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FunctionStatement.java
deleted file mode 100644
index ad1dcc8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/FunctionStatement.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-import com.intellij.util.PlatformIcons;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * PSI element for a function definition statement.
- */
-public class FunctionStatement extends NamedBuildElement implements Statement, StatementListContainer {
-
- public FunctionStatement(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitFunctionStatement(this);
- }
-
- @Nullable
- @Override
- public Icon getIcon(int flags) {
- return PlatformIcons.FUNCTION_ICON;
- }
-
- @Nullable
- public ParameterList getParameterList() {
- return getPsiChild(BuildElementTypes.PARAMETER_LIST, ParameterList.class);
- }
-
- public Parameter[] getParameters() {
- ParameterList list = getParameterList();
- return list != null ? list.getElements() : Parameter.EMPTY_ARRAY;
- }
-
- @Override
- public String getPresentableText() {
- return nonNullName() + getParameterList().getPresentableText();
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/GlobExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/GlobExpression.java
deleted file mode 100644
index 622e427..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/GlobExpression.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.references.GlobReference;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-
-import javax.annotation.Nullable;
-
-/**
- * PSI element for a glob expression.
- */
-public class GlobExpression extends BuildElementImpl implements Expression {
-
- public GlobExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitGlobExpression(this);
- }
-
- @Nullable
- public ArgumentList getArgList() {
- return findChildByType(BuildElementTypes.ARGUMENT_LIST);
- }
-
- public Argument[] getArguments() {
- ArgumentList argList = getArgList();
- return argList != null ? argList.getArguments() : Argument.EMPTY_ARRAY;
- }
-
- @Nullable
- public Argument.Keyword getKeywordArgument(String name) {
- ArgumentList list = getArgList();
- return list != null ? list.getKeywordArgument(name) : null;
- }
-
- @Nullable
- public Expression getIncludes() {
- Argument arg = getKeywordArgument("include");
- if (arg == null) {
- Argument[] allArgs = getArguments();
- if (allArgs.length != 0 && allArgs[0] instanceof Argument.Positional) {
- arg = allArgs[0];
- }
- }
- return getArgValue(arg);
- }
-
- @Nullable
- public Expression getExcludes() {
- return getArgValue(getKeywordArgument("exclude"));
- }
-
- @Nullable
- private static Expression getArgValue(@Nullable Argument arg) {
- return arg != null ? arg.getValue() : null;
- }
-
- public boolean areDirectoriesExcluded() {
- Argument.Keyword arg = getKeywordArgument("exclude_directories");
- if (arg != null) {
- // '0' and '1' are the only accepted values
- Expression value = arg.getValue();
- return value == null || !value.getText().equals("0");
- }
- return true;
- }
-
- @Nullable
- public ASTNode getGlobFuncallElement() {
- return getNode().findChildByType(BuildElementTypes.REFERENCE_EXPRESSION);
- }
-
- private volatile GlobReference reference = null;
-
- @Override
- public GlobReference getReference() {
- GlobReference ref = reference;
- if (ref != null) {
- return ref;
- }
- synchronized (this) {
- if (reference == null) {
- reference = new GlobReference(this);
- }
- return reference;
- }
- }
-
- /**
- * The text range within the glob expression used for references.
- * This is the text the user needs to click on for navigation support,
- * and also the destination when finding usages in a glob.
- */
- public TextRange getReferenceTextRange() {
- // Ideally, this would be either the full range of the expression, or the range of the specific pattern matching
- // a given file. However, that leads to conflicts with the individual string references, causing unnecessary
- // and expensive de-globbing.
- // e.g. while typing the glob patterns, IJ will be looking for code-completion possibilities, and need to
- // de-glob to do this (due to a lack of communication between the different code-completion components).
-
- return new TextRange(0, 4);
- }
-
- public boolean matches(String packageRelativePath, boolean isDirectory) {
- return getReference().matches(packageRelativePath, isDirectory);
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfPart.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfPart.java
deleted file mode 100644
index a2477d2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfPart.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for an if part of an IfStatement.
- */
-public class IfPart extends BuildElementImpl implements Statement, StatementListContainer {
-
- public IfPart(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitIfPart(this);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfStatement.java
deleted file mode 100644
index 4747ca8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IfStatement.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for an if statement.
- */
-public class IfStatement extends BuildElementImpl implements Statement {
-
- public IfStatement(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitIfStatement(this);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IntegerLiteral.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IntegerLiteral.java
deleted file mode 100644
index d9bb2ee..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/IntegerLiteral.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI node for integer literal expressions
- */
-public class IntegerLiteral extends BuildElementImpl implements LiteralExpression {
-
- public IntegerLiteral(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitIntegerLiteral(this);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListComprehensionExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListComprehensionExpression.java
deleted file mode 100644
index c341550..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListComprehensionExpression.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for a list comprehension expression
- * (comprehension suffix of: '[' expr ('FOR' loop_variables 'IN' expr)+ ']')
- */
-public class ListComprehensionExpression extends BuildElementImpl implements Expression {
-
- public ListComprehensionExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitListComprehensionSuffix(this);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListLiteral.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListLiteral.java
deleted file mode 100644
index d9b0247..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ListLiteral.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * PSI element for list and tuple literals
- */
-public class ListLiteral extends BuildListType<Expression> implements LiteralExpression {
-
- public ListLiteral(ASTNode astNode) {
- super(astNode, Expression.class);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitListLiteral(this);
- }
-
- @Override
- public String getPresentableText() {
- return "list";
- }
-
- public Expression[] getChildExpressions() {
- return findChildrenByClass(Expression.class);
- }
-
- @Override
- public Expression[] getElements() {
- return getChildExpressions();
- }
-
- @Override
- public boolean isEmpty() {
- return findChildByClass(Expression.class) != null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/LiteralExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/LiteralExpression.java
deleted file mode 100644
index f5c7f20..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/LiteralExpression.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-/**
- * Interface for literal expressions.
- */
-public interface LiteralExpression extends Expression {
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/LoadStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/LoadStatement.java
deleted file mode 100644
index 34fe7e7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/LoadStatement.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
-import com.intellij.lang.ASTNode;
-import com.intellij.util.PlatformIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.util.Arrays;
-
-/**
- * PSI element for a load statement.
- */
-public class LoadStatement extends BuildElementImpl implements Statement {
-
- public LoadStatement(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitLoadStatement(this);
- }
-
- @Nullable
- public ASTNode getImportNode() {
- return getNode().findChildByType(BuildElementTypes.STRING_LITERAL);
- }
-
- @Nullable
- public StringLiteral getImportPsiElement() {
- return findChildByType(BuildElementTypes.STRING_LITERAL);
- }
-
- @Nullable
- public String getImportedPath() {
- ASTNode firstString = getImportNode();
- return firstString != null ? StringLiteral.parseStringContents(firstString.getText()) : null;
- }
-
- /**
- * The string nodes referencing imported functions.
- */
- public FunctionStatement[] getImportedFunctionReferences() {
- return Arrays.stream(getChildStrings())
- .skip(1)
- .map(BuildElement::getReferencedElement)
- .filter(e -> e instanceof FunctionStatement)
- .toArray(FunctionStatement[]::new);
- }
-
- /**
- * The string nodes referencing imported functions.
- */
- public StringLiteral[] getImportedSymbolElements() {
- StringLiteral[] childStrings = getChildStrings();
- return childStrings.length < 2 ? new StringLiteral[0] : Arrays.copyOfRange(childStrings, 1, childStrings.length);
- }
-
- public String[] getImportedSymbolNames() {
- return Arrays.stream(getImportedSymbolElements())
- .map(StringLiteral::getStringContents)
- .toArray(String[]::new);
- }
-
- @Nullable
- public StringLiteral findImportedSymbolElement(String name) {
- for (StringLiteral string : getImportedSymbolElements()) {
- if (name.equals(string.getStringContents())) {
- return string;
- }
- }
- return null;
- }
-
- public StringLiteral[] getChildStrings() {
- return Arrays.stream(getNode().getChildren(BuildElementTypes.STRINGS))
- .map(ASTNode::getPsi)
- .toArray(StringLiteral[]::new);
- }
-
- @Override
- public Icon getIcon(int flags) {
- return PlatformIcons.IMPORT_ICON;
- }
-
- @Override
- public String getPresentableText() {
- String path = LabelUtils.getNiceSkylarkFileName(getImportedPath());
- return path != null ? "load: " + path : "load";
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/NamedBuildElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/NamedBuildElement.java
deleted file mode 100644
index 3de500a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/NamedBuildElement.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNameIdentifierOwner;
-
-import javax.annotation.Nullable;
-
-/**
- * Base class for PsiNamedElements in BUILD files.
- */
-public abstract class NamedBuildElement extends BuildElementImpl implements PsiNameIdentifierOwner {
-
- public NamedBuildElement(ASTNode astNode) {
- super(astNode);
- }
-
- @Nullable
- public ASTNode getNameNode() {
- return getNode().findChildByType(BuildToken.IDENTIFIER);
- }
-
- @Override
- @Nullable
- public String getName() {
- ASTNode node = getNameNode();
- return node != null ? node.getText() : null;
- }
-
- @Override
- @Nullable
- public PsiElement getNameIdentifier() {
- final ASTNode nameNode = getNameNode();
- return nameNode != null ? nameNode.getPsi() : null;
- }
-
- @Override
- public PsiElement setName(String name) {
- final ASTNode nameElement = PsiUtils.createNewName(getProject(), name);
- final ASTNode nameNode = getNameNode();
- if (nameNode != null) {
- getNode().replaceChild(nameNode, nameElement);
- }
- return this;
- }
-
- @Override
- public int getTextOffset() {
- final ASTNode name = getNameNode();
- return name != null ? name.getStartOffset() : super.getTextOffset();
- }
-
- @Override
- public String toString() {
- return super.toString() + "('" + getName() + "')";
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Parameter.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Parameter.java
deleted file mode 100644
index efe5822..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Parameter.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.icons.AllIcons;
-import com.intellij.lang.ASTNode;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * PSI nodes for parameters in a function declaration
- */
-public abstract class Parameter extends NamedBuildElement {
-
- public static final Parameter[] EMPTY_ARRAY = new Parameter[0];
-
- public Parameter(ASTNode node) {
- super(node);
- }
-
- public boolean hasDefaultValue() {
- return false;
- }
-
- @Nullable
- @Override
- public Icon getIcon(int flags) {
- return AllIcons.Nodes.Parameter;
- }
-
- /**
- * Includes stars where relevant.
- */
- public String getPresentableName() {
- return getName();
- }
-
- public static class Optional extends Parameter {
- public Optional(ASTNode node) {
- super(node);
- }
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitParameter(this);
- }
-
- public Expression getDefaultValue() {
- ASTNode node = getNode().getLastChildNode();
- while (node != null) {
- if (BuildElementTypes.EXPRESSIONS.contains(node.getElementType())) {
- return (Expression) node.getPsi();
- }
- if (node.getElementType() == BuildToken.fromKind(TokenKind.EQUALS)) {
- break;
- }
- node = node.getTreePrev();
- }
- return null;
- }
-
- @Override
- public boolean hasDefaultValue() {
- return true;
- }
- }
-
- public static class Mandatory extends Parameter {
- public Mandatory(ASTNode node) {
- super(node);
- }
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitParameter(this);
- }
- }
-
- public static class Star extends Parameter {
- public Star(ASTNode node) {
- super(node);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitParameter(this);
- }
-
- @Override
- public String getPresentableName() {
- return "*" + getName();
- }
- }
-
- public static class StarStar extends Parameter {
- public StarStar(ASTNode node) {
- super(node);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitParameter(this);
- }
-
- @Override
- public String getPresentableName() {
- return "**" + getName();
- }
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ParameterList.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ParameterList.java
deleted file mode 100644
index 623baa8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ParameterList.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-import javax.annotation.Nullable;
-import java.util.StringJoiner;
-
-/**
- * Parameter list in a function declaration
- */
-public class ParameterList extends BuildListType<Parameter> {
-
- public ParameterList(ASTNode astNode) {
- super(astNode, Parameter.class);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitFunctionParameterList(this);
- }
-
- @Nullable
- public Parameter findParameterByName(String name) {
- ASTNode node = getNode().getFirstChildNode();
- while (node != null) {
- if (node.getElementType() == BuildElementTypes.PARAM_OPTIONAL
- || node.getElementType() == BuildElementTypes.PARAM_MANDATORY) {
- Parameter param = (Parameter) node.getPsi();
- if (name.equals(param.getName())) {
- return param;
- }
- }
- node = node.getTreeNext();
- }
- return null;
- }
-
- public boolean hasStarStar() {
- return !findChildrenByType(BuildElementTypes.PARAM_STAR_STAR).isEmpty();
- }
-
- public boolean hasStar() {
- return !findChildrenByType(BuildElementTypes.PARAM_STAR).isEmpty();
- }
-
- @Override
- public String getPresentableText() {
- StringJoiner joiner = new StringJoiner(", ", "(", ")");
- for (Parameter param : getElements()) {
- joiner.add(param.getPresentableName());
- }
- return joiner.toString();
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/PassStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/PassStatement.java
deleted file mode 100644
index ec1f01f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/PassStatement.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * Psi element for pass statement.
- */
-public class PassStatement extends BuildElementImpl implements Statement {
-
- public PassStatement(ASTNode node) {
- super(node);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitPassStatement(this);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReferenceExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReferenceExpression.java
deleted file mode 100644
index 198a778..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReferenceExpression.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.references.LocalReference;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.tree.IElementType;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * References a PsiNamedElement
- */
-public class ReferenceExpression extends BuildElementImpl implements Expression {
-
- public ReferenceExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitReferenceExpression(this);
- }
-
- @Nullable
- public ASTNode getNameElement() {
- return getNode().findChildByType(BuildToken.IDENTIFIER);
- }
-
- @Nullable
- public String getReferencedName() {
- ASTNode node = getNameElement();
- return node != null ? node.getText() : null;
- }
-
- @Override
- public PsiReference getReference() {
- IElementType parentType = getParentType();
- // function names are resolved by the parent funcall node
- if (BuildElementTypes.FUNCALL_EXPRESSION.equals(parentType)) {
- return null;
- }
- if (BuildElementTypes.DOT_EXPRESSION.equals(parentType) && afterDot(getNode())) {
- return null;
- }
- return new LocalReference(this);
- }
-
- @Override
- public String getName() {
- return getReferencedName();
- }
-
- private static boolean afterDot(ASTNode node) {
- ASTNode prev = node.getTreePrev();
- return prev != null && prev.getText().equals(".");
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReturnStatement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReturnStatement.java
deleted file mode 100644
index bde88a3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/ReturnStatement.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-
-import javax.annotation.Nullable;
-
-/**
- * A wrapper Statement class for return expressions.
- */
-public class ReturnStatement extends BuildElementImpl implements Statement {
-
- public ReturnStatement(ASTNode node) {
- super(node);
- }
-
- @Nullable
- public Expression getReturnExpression() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitReturnStatement(this);
- }
-}
-
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Statement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Statement.java
deleted file mode 100644
index e76c2b5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/Statement.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-/**
- * Base class for all statements nodes in the PSI tree
- */
-public interface Statement extends BuildElement {
-
- Statement[] EMPTY_ARRAY = new Statement[0];
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementList.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementList.java
deleted file mode 100644
index d64a99a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementList.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-
-/**
- * PSI element for a list of statements
- */
-public class StatementList extends BuildListType<Statement> {
-
- public StatementList(ASTNode astNode) {
- super(astNode, Statement.class);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitStatementList(this);
- }
-
- @Override
- public int getStartOffset() {
- PsiElement prevSibling = getPrevSibling();
- while (prevSibling != null) {
- if (prevSibling.getText().equals(":")) {
- return prevSibling.getNode().getStartOffset() + 1;
- }
- prevSibling = prevSibling.getPrevSibling();
- }
- return getNode().getStartOffset();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementListContainer.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementListContainer.java
deleted file mode 100644
index c640b0a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StatementListContainer.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-/**
- * Anything of the form type ':' suite
- */
-public interface StatementListContainer extends BuildElement {
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StringLiteral.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StringLiteral.java
deleted file mode 100644
index e6f05e4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/StringLiteral.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.references.LabelReference;
-import com.google.idea.blaze.base.lang.buildfile.references.LoadedSymbolReference;
-import com.google.idea.blaze.base.lang.buildfile.references.PackageReferenceFragment;
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-import javax.annotation.Nullable;
-
-/**
- * PSI node for string literal expressions
- */
-public class StringLiteral extends BuildElementImpl implements LiteralExpression {
-
- public static String stripEndpointQuotes(ASTNode node) {
- assert(node.getElementType() == BuildElementTypes.STRING_LITERAL);
- return parseStringContents(node.getText());
- }
-
- /**
- * Removes the leading and trailing quotes. Naive implementation intended for resolving references
- * (in which case escaped characters, raw strings, etc. are unlikely).
- */
- public static String parseStringContents(String string) {
- // TODO: Handle escaped characters, etc. here? (extract logic from BuildLexerBase.addStringLiteral)
- if (string.startsWith("\"\"\"") || string.startsWith("'''")) {
- return string.length() < 6 ? "" : string.substring(3, string.length() - 3);
- }
- return string.length() < 2 ? "" : string.substring(1, string.length() - 1);
- }
-
- public static QuoteType getQuoteType(@Nullable String rawText) {
- if (rawText == null) {
- return QuoteType.NoQuotes;
- }
- if (rawText.startsWith("\"\"\"")) {
- return QuoteType.TripleDouble;
- }
- if (rawText.startsWith("'''")) {
- return QuoteType.TripleSingle;
- }
- if (rawText.startsWith("'")) {
- return QuoteType.Single;
- }
- if (rawText.startsWith("\"")) {
- return QuoteType.Double;
- }
- return QuoteType.NoQuotes;
- }
-
- public StringLiteral(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitStringLiteral(this);
- }
-
- /**
- * Removes the leading and trailing quotes
- */
- public String getStringContents() {
- return parseStringContents(getText());
- }
-
- public QuoteType getQuoteType() {
- return getQuoteType(getText());
- }
-
- /**
- * Labels are taken to reference:
- * - the actual target they reference
- * - the BUILD package specified before the colon (only if explicitly present)
- */
- @Override
- public PsiReference[] getReferences() {
- PsiReference primaryReference = getReference();
- if (primaryReference instanceof LabelReference) {
- return new PsiReference[] {primaryReference, new PackageReferenceFragment((LabelReference) primaryReference)};
- }
- return primaryReference != null ? new PsiReference[] {primaryReference} : PsiReference.EMPTY_ARRAY;
- }
-
- /**
- * The primary reference -- this is the target referenced by the full label
- */
- @Nullable
- @Override
- public PsiReference getReference() {
- PsiElement parent = getParent();
- if (parent instanceof LoadStatement) {
- LoadStatement load = (LoadStatement) parent;
- StringLiteral importNode = load.getImportPsiElement();
- if (importNode == null) {
- return null;
- }
- LabelReference importReference = new LabelReference(importNode, false);
- if (this.equals(importNode)) {
- return importReference;
- }
- return new LoadedSymbolReference(this, importReference);
- }
- return new LabelReference(this, true);
- }
-
- public boolean insideLoadStatement() {
- return getParentType() == BuildElementTypes.LOAD_STATEMENT;
- }
-
- @Override
- public String getPresentableText() {
- return getText();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/TargetExpression.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/TargetExpression.java
deleted file mode 100644
index d172ede..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/TargetExpression.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.references.TargetReference;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiReference;
-import com.intellij.util.PlatformIcons;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * References a PsiNamedElement
- */
-public class TargetExpression extends NamedBuildElement implements Expression {
-
- public TargetExpression(ASTNode astNode) {
- super(astNode);
- }
-
- @Override
- protected void acceptVisitor(BuildElementVisitor visitor) {
- visitor.visitTargetExpression(this);
- }
-
- @Override
- public PsiReference getReference() {
- return new TargetReference(this);
- }
-
- @Nullable
- @Override
- public Icon getIcon(int flags) {
- return PlatformIcons.VARIABLE_ICON;
- }
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/BuildElementGenerator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/BuildElementGenerator.java
deleted file mode 100644
index ce39f11..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/BuildElementGenerator.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi.util;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildToken;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiFileFactory;
-import com.intellij.psi.impl.PsiFileFactoryImpl;
-import com.intellij.testFramework.LightVirtualFile;
-
-/**
- * Creates dummy BuildElements, e.g. for renaming purposes.
- */
-public class BuildElementGenerator {
-
- public static BuildElementGenerator getInstance(Project project) {
- return ServiceManager.getService(project, BuildElementGenerator.class);
- }
-
- private static final String DUMMY_FILENAME = "dummy.bzl";
-
- private final Project project;
-
- public BuildElementGenerator(Project project) {
- this.project = project;
- }
-
- public PsiFile createDummyFile(String contents) {
- PsiFileFactory factory = PsiFileFactory.getInstance(project);
- LightVirtualFile virtualFile = new LightVirtualFile(DUMMY_FILENAME, BuildFileType.INSTANCE, contents);
- PsiFile psiFile = ((PsiFileFactoryImpl) factory).trySetupPsiForFile(virtualFile, BuildFileLanguage.INSTANCE, false, true);
- assert psiFile != null;
- return psiFile;
- }
-
- public ASTNode createNameIdentifier(String name) {
- PsiFile dummyFile = createDummyFile(name);
- ASTNode referenceNode = dummyFile.getNode().getFirstChildNode();
- ASTNode nameNode = referenceNode.getFirstChildNode();
- if (nameNode.getElementType() != BuildToken.IDENTIFIER) {
- throw new RuntimeException("Expecting an IDENTIFIER node directly below the BuildFile PSI element");
- }
- return nameNode;
- }
-
- public ASTNode createStringNode(String contents) {
- PsiFile dummyFile = createDummyFile('"' + contents + '"');
- ASTNode literalNode = dummyFile.getNode().getFirstChildNode();
- ASTNode stringNode = literalNode.getFirstChildNode();
- assert(stringNode.getElementType() == BuildToken.fromKind(TokenKind.STRING));
- return stringNode;
- }
-
- public Argument.Keyword createKeywordArgument(String keyword, String value) {
- String dummyText = String.format("foo(%s = \"%s\")", keyword, value);
- FuncallExpression funcall = (FuncallExpression) createExpressionFromText(dummyText);
- return (Argument.Keyword) funcall.getArguments()[0];
- }
-
- public Expression createExpressionFromText(String text) {
- PsiFile dummyFile = createDummyFile(text);
- PsiElement element = dummyFile.getFirstChild();
- if (element instanceof Expression) {
- return (Expression) element;
- }
- throw new RuntimeException("Could not parse text as expression: '" + text + "'");
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/PsiUtils.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/PsiUtils.java
deleted file mode 100644
index e27794f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/psi/util/PsiUtils.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.psi.util;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.psi.AssignmentStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.Expression;
-import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.util.CommonProcessors;
-import com.intellij.util.Processor;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * Utility methods for working with PSI elements
- */
-public class PsiUtils {
-
- public static ASTNode createNewName(Project project, String name) {
- return BuildElementGenerator.getInstance(project).createNameIdentifier(name);
- }
-
- public static ASTNode createNewLabel(Project project, String labelString) {
- return BuildElementGenerator.getInstance(project).createStringNode(labelString);
- }
-
- @Nullable
- public static PsiElement getPreviousNodeInTree(PsiElement element) {
- PsiElement prevSibling = null;
- while (element != null && (prevSibling = element.getPrevSibling()) == null) {
- element = element.getParent();
- }
- return prevSibling != null ? lastElementInSubtree(prevSibling) : null;
- }
-
- /**
- * The last element in the tree rooted at the given element.
- */
- public static PsiElement lastElementInSubtree(PsiElement element) {
- PsiElement lastChild;
- while ((lastChild = element.getLastChild()) != null) {
- element = lastChild;
- }
- return element;
- }
-
- /**
- * Walks up PSI tree, looking for a parent of the specified class. Stops searching when it reaches a
- * parent of type PsiDirectory.
- */
- @Nullable
- public static <T extends PsiElement> T getParentOfType(PsiElement element, Class<T> psiClass) {
- PsiElement parent = element.getParent();
- while (parent != null && !(parent instanceof PsiDirectory)) {
- if (psiClass.isInstance(parent)) {
- return (T) parent;
- }
- parent = parent.getParent();
- }
- return null;
- }
-
- @Nullable
- public static <T extends PsiElement> T findFirstChildOfClassRecursive(PsiElement parent, Class<T> psiClass) {
- List<T> holder = Lists.newArrayListWithExpectedSize(1);
- Processor<T> getFirst = t -> {
- holder.add(t);
- return false;
- };
- processChildrenOfType(parent, getFirst, psiClass);
- return holder.isEmpty() ? null : holder.get(0);
- }
-
- @Nullable
- public static <T extends PsiElement> T findLastChildOfClassRecursive(PsiElement parent, Class<T> psiClass) {
- List<T> holder = Lists.newArrayListWithExpectedSize(1);
- Processor<T> getFirst = t -> {
- holder.add(t);
- return false;
- };
- processChildrenOfType(parent, getFirst, psiClass, true);
- return holder.isEmpty() ? null : holder.get(0);
- }
-
- public static <T extends PsiElement> List<T> findAllChildrenOfClassRecursive(PsiElement parent, Class<T> psiClass) {
- List<T> result = Lists.newArrayList();
- processChildrenOfType(parent, new CommonProcessors.CollectProcessor(result), psiClass);
- return result;
- }
-
- /**
- * Walk through entire PSI tree rooted at 'element', processing all children of the given type.
- * @return true if processing was stopped by the processor
- */
- public static <T extends PsiElement> boolean processChildrenOfType(
- PsiElement element,
- Processor<T> processor,
- Class<T> psiClass) {
- return processChildrenOfType(element, processor, psiClass, false);
- }
-
- /**
- * Walk through entire PSI tree rooted at 'element', processing all children of the given type.
- * @return true if processing was stopped by the processor
- */
- private static <T extends PsiElement> boolean processChildrenOfType(
- PsiElement element,
- Processor<T> processor,
- Class<T> psiClass,
- boolean reverseOrder) {
- PsiElement child = reverseOrder ? element.getLastChild() : element.getFirstChild();
- while (child != null) {
- if (psiClass.isInstance(child)) {
- if (!processor.process((T) child)) {
- return true;
- }
- }
- if (processChildrenOfType(child, processor, psiClass, reverseOrder)) {
- return true;
- }
- child = reverseOrder ? child.getPrevSibling() : child.getNextSibling();
- }
- return false;
- }
-
- public static TextRange childRangeInParent(TextRange parentRange, TextRange childRange) {
- return childRange.shiftRight(-parentRange.getStartOffset());
- }
-
- @Nullable
- public static String getFilePath(@Nullable PsiFile file) {
- VirtualFile virtualFile = file != null ? file.getVirtualFile() : null;
- return virtualFile != null ? virtualFile.getPath() : null;
- }
-
- /**
- * For ReferenceExpressions, follows the chain of references until it hits a non-ReferenceExpression.
- * For other types, returns the input expression.
- */
- public static PsiElement getReferencedTarget(Expression expr) {
- PsiElement element = expr;
- while (element instanceof ReferenceExpression) {
- PsiElement referencedElement = ((ReferenceExpression) element).getReferencedElement();
- if (referencedElement == null) {
- return element;
- }
- element = referencedElement;
- }
- return element;
- }
-
- /**
- * For ReferenceExpressions, follows the chain of references until it hits a non-ReferenceExpression, then
- * evaluates the value of that target.
- * For other types, returns the input expression.
- */
- public static PsiElement getReferencedTargetValue(Expression expr) {
- PsiElement element = getReferencedTarget(expr);
- if (element instanceof TargetExpression) {
- PsiElement parent = element.getParent();
- if (parent instanceof AssignmentStatement) {
- return ((AssignmentStatement) parent).getAssignedValue();
- }
- }
- return element;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildNamesValidator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildNamesValidator.java
deleted file mode 100644
index 595fe39..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildNamesValidator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
-
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexer;
-import com.google.idea.blaze.base.lang.buildfile.lexer.BuildLexerBase;
-import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
-import com.intellij.lang.refactoring.NamesValidator;
-import com.intellij.openapi.project.Project;
-
-/**
- * Used for rename validation
- */
-public class BuildNamesValidator implements NamesValidator {
-
- @Override
- public boolean isKeyword(String s, Project project) {
- return false;
- }
-
- @Override
- public boolean isIdentifier(String s, Project project) {
- BuildLexer lexer = new BuildLexer(BuildLexerBase.LexerMode.Parsing);
- lexer.start(s);
- return lexer.getTokenEnd() == s.length() && lexer.getTokenKind() == TokenKind.IDENTIFIER;
- }
-
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildRefactoringSupportProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildRefactoringSupportProvider.java
deleted file mode 100644
index 352252e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/refactor/BuildRefactoringSupportProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
-import com.intellij.lang.refactoring.RefactoringSupportProvider;
-import com.intellij.psi.PsiElement;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Supports 'safe delete'
- */
-public class BuildRefactoringSupportProvider extends RefactoringSupportProvider {
-
- @Override
- public boolean isSafeDeleteAvailable(@NotNull PsiElement element) {
- // basically a promise that 'find usages' works for this element
- return element instanceof FunctionStatement
- || element instanceof TargetExpression
- || element instanceof FuncallExpression;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/ArgumentReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/ArgumentReference.java
deleted file mode 100644
index e3b4f13..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/ArgumentReference.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.completion.NamedBuildLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.psi.util.PsiTreeUtil;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * Only keyword arguments resolve, but we include this class for code completion purposes.
- * As the user is typing a keyword arg, they'll start with a positional arg element.
- */
-public class ArgumentReference<T extends Argument> extends PsiReferenceBase<T> {
-
- public ArgumentReference(T element, TextRange rangeInElement, boolean soft) {
- super(element, rangeInElement, false);
- }
-
- @Nullable
- protected FunctionStatement resolveFunction() {
- FuncallExpression call = PsiTreeUtil.getParentOfType(myElement, FuncallExpression.class);
- if (call == null) {
- return null;
- }
- PsiElement callee = call.getReferencedElement();
- return callee instanceof FunctionStatement ? (FunctionStatement) callee : null;
- }
-
- @Nullable
- @Override
- public PsiElement resolve() {
- return null;
- }
-
- @Override
- public Object[] getVariants() {
- FunctionStatement function = resolveFunction();
- if (function == null) {
- return EMPTY_ARRAY;
- }
- List<LookupElement> params = Lists.newArrayList();
- for (Parameter param : function.getParameters()) {
- params.add(new NamedBuildLookupElement(param, QuoteType.NoQuotes));
- }
- return params.toArray();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java
deleted file mode 100644
index 7ee9a70..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.RuleName;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileSystem;
-import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiFileSystemItem;
-import com.intellij.psi.PsiManager;
-import com.intellij.util.PathUtil;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-
-/**
- * Handles reference caching and resolving labels to PSI elements.
- */
-public class BuildReferenceManager {
-
- public static BuildReferenceManager getInstance(Project project) {
- return ServiceManager.getService(project, BuildReferenceManager.class);
- }
-
- private final Project project;
-
- public BuildReferenceManager(Project project) {
- this.project = project;
- }
-
- /**
- * Finds the PSI element associated with the given label.
- */
- @Nullable
- public PsiElement resolveLabel(Label label) {
- return resolveLabel(label.blazePackage(), label.ruleName(), false);
- }
-
- /**
- * Finds the PSI element associated with the given label.
- */
- @Nullable
- public PsiElement resolveLabel(WorkspacePath packagePath, RuleName ruleName, boolean excludeRules) {
- File packageDir = resolvePackage(packagePath);
- if (packageDir == null) {
- return null;
- }
-
- if (!excludeRules) {
- FuncallExpression target = findRule(packageDir, ruleName);
- if (target != null) {
- return target;
- }
- }
-
- // try a direct file reference (e.g. ":a.java")
- File fullFile = new File(packageDir, ruleName.toString());
- if (FileAttributeProvider.getInstance().exists(fullFile)) {
- return resolveFile(fullFile);
- }
-
- return null;
- }
-
- private FuncallExpression findRule(File packageDir, RuleName ruleName) {
- BuildFile psiFile = findBuildFile(packageDir);
- return psiFile != null ? psiFile.findRule(ruleName.toString()) : null;
- }
-
- @Nullable
- public PsiFileSystemItem resolveFile(File file) {
- VirtualFile vf = getFileSystem().findFileByPath(file.getPath());
- if (vf == null) {
- return null;
- }
- PsiManager manager = PsiManager.getInstance(project);
- return vf.isDirectory() ? manager.findDirectory(vf) : manager.findFile(vf);
- }
-
- @Nullable
- public File resolvePackage(@Nullable WorkspacePath packagePath) {
- return resolveWorkspaceRelativePath(packagePath != null ? packagePath.relativePath() : null);
- }
-
- @Nullable
- private File resolveWorkspaceRelativePath(@Nullable String relativePath) {
- WorkspacePathResolver pathResolver = getWorkspacePathResolver();
- if (pathResolver == null || relativePath == null) {
- return null;
- }
- return pathResolver.resolveToFile(relativePath);
- }
-
- @Nullable
- private WorkspacePathResolver getWorkspacePathResolver() {
- return WorkspacePathResolverProvider.getInstance(project).getPathResolver();
- }
-
- /**
- * Finds all child directories. If exactly one is found, continue traversing (and appending to LookupElement string)
- * until there are multiple options.<br>
- * Used for package path completion suggestions.
- */
- public BuildLookupElement[] resolvePackageLookupElements(FileLookupData lookupData) {
- String relativePath = lookupData.filePathFragment;
- File file = resolveWorkspaceRelativePath(relativePath);
-
- FileAttributeProvider provider = FileAttributeProvider.getInstance();
- String pathFragment = "";
- if (file == null || (!provider.isDirectory(file) && !relativePath.endsWith("/"))) {
- // we might be partway through a file name. Try the parent directory
- relativePath = PathUtil.getParentPath(relativePath);
- file = resolveWorkspaceRelativePath(relativePath);
- pathFragment = StringUtil.trimStart(lookupData.filePathFragment.substring(relativePath.length()), "/");
- }
- if (file == null || !provider.isDirectory(file)) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- VirtualFile vf = getFileSystem().findFileByPath(file.getPath());
- if (vf == null || !vf.isDirectory()) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- BuildLookupElement[] uniqueLookup = new BuildLookupElement[1];
- while (true) {
- VirtualFile[] children = vf.getChildren();
- if (children == null || children.length == 0) {
- return uniqueLookup[0] != null ? uniqueLookup : BuildLookupElement.EMPTY_ARRAY;
- }
- List<VirtualFile> validChildren = Lists.newArrayListWithCapacity(children.length);
- for (VirtualFile child : children) {
- if (child.getName().startsWith(pathFragment) && lookupData.acceptFile(child)) {
- validChildren.add(child);
- }
- }
- if (validChildren.isEmpty()) {
- return uniqueLookup[0] != null ? uniqueLookup : BuildLookupElement.EMPTY_ARRAY;
- }
- if (validChildren.size() > 1) {
- return uniqueLookup[0] != null ?
- uniqueLookup : lookupsForFiles(validChildren, lookupData);
- }
- // continue traversing while there's only one option
- uniqueLookup[0] = lookupForFile(validChildren.get(0), lookupData);
- pathFragment = "";
- vf = validChildren.get(0);
- }
- }
-
- private BuildLookupElement[] lookupsForFiles(List<VirtualFile> files, FileLookupData lookupData) {
- BuildLookupElement[] lookups = new BuildLookupElement[files.size()];
- for (int i = 0; i < files.size(); i++) {
- lookups[i] = lookupForFile(files.get(i), lookupData);
- }
- return lookups;
- }
-
- private BuildLookupElement lookupForFile(VirtualFile file, FileLookupData lookupData) {
- WorkspacePath workspacePath = getWorkspaceRelativePath(file.getPath());
- return lookupData.lookupElementForFile(project, file, workspacePath);
- }
-
- @Nullable
- public BuildFile resolveBlazePackage(String workspaceRelativePath) {
- workspaceRelativePath = StringUtil.trimStart(workspaceRelativePath, "//");
- return resolveBlazePackage(WorkspacePath.createIfValid(workspaceRelativePath));
- }
-
- @Nullable
- public BuildFile resolveBlazePackage(@Nullable WorkspacePath path) {
- return findBuildFile(resolvePackage(path));
- }
-
- @Nullable
- private BuildFile findBuildFile(@Nullable File packageDirectory) {
- FileAttributeProvider provider = FileAttributeProvider.getInstance();
- if (packageDirectory == null || !provider.isDirectory(packageDirectory)) {
- return null;
- }
- File buildFile = new File(packageDirectory, "BUILD");
- if (!provider.exists(buildFile)) {
- return null;
- }
- VirtualFile vf = getFileSystem().findFileByPath(buildFile.getPath());
- if (vf == null) {
- return null;
- }
- PsiFile psiFile = PsiManager.getInstance(project).findFile(vf);
- return psiFile instanceof BuildFile ? (BuildFile) psiFile : null;
- }
-
- /**
- * For files references, returns the parent directory.<br>
- * For rule references, return the blaze package directory.
- */
- @Nullable
- public File resolveParentDirectory(@Nullable Label label) {
- return label != null ? resolveParentDirectory(label.blazePackage(), label.ruleName()) : null;
- }
-
- @Nullable
- private File resolveParentDirectory(WorkspacePath packagePath, RuleName ruleName) {
- File packageFile = resolvePackage(packagePath);
- if (packageFile == null) {
- return null;
- }
- String rulePathParent = PathUtil.getParentPath(ruleName.toString());
- return new File(packageFile, rulePathParent);
- }
-
- @Nullable
- public WorkspacePath getWorkspaceRelativePath(String absolutePath) {
- WorkspacePathResolver pathResolver = getWorkspacePathResolver();
- WorkspaceRoot workspaceRoot = pathResolver != null ? pathResolver.getWorkspaceRoot() : null;
- return workspaceRoot != null ? getWorkspaceRelativePath(workspaceRoot, absolutePath) : null;
- }
-
- @Nullable
- static private WorkspacePath getWorkspaceRelativePath(WorkspaceRoot workspaceRoot, String absolutePath) {
- File file = new File(absolutePath);
- if (workspaceRoot.isInWorkspace(file)) {
- return workspaceRoot.workspacePathFor(file);
- }
- return null;
- }
-
- private static VirtualFileSystem getFileSystem() {
- if (ApplicationManager.getApplication().isUnitTestMode()) {
- return TempFileSystem.getInstance();
- }
- return LocalFileSystem.getInstance();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java
deleted file mode 100644
index 8f2ac8a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.completion.FilePathLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.intellij.icons.AllIcons;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.NullableLazyValue;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileFilter;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
-import com.intellij.util.PathUtil;
-import com.intellij.util.PlatformIcons;
-import icons.BlazeIcons;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-
-/**
- * The data relevant to finding file lookups.
- */
-public class FileLookupData {
-
- public enum PathFormat {
- /** BUILD label without a leading '//', which can only reference targets in the same package. */
- PackageLocal,
- /** a BUILD label with leading '//', which can reference targets in other packages. */
- NonLocal,
- /** a path string which can reference any files, and has no leading '//'. */
- NonLocalWithoutInitialBackslashes
- }
-
- @Nullable
- public static FileLookupData nonLocalFileLookup(String originalLabel, StringLiteral element) {
- return nonLocalFileLookup(originalLabel, element.getContainingFile(), element.getQuoteType(), PathFormat.NonLocal);
- }
-
- @Nullable
- public static FileLookupData nonLocalFileLookup(String originalLabel,
- @Nullable BuildFile containingFile,
- QuoteType quoteType,
- PathFormat pathFormat) {
- if (originalLabel.indexOf(':') != -1) {
- // it's a package-local reference
- return null;
- }
- // handle the single '/' case by calling twice.
- String relativePath = StringUtil.trimStart(StringUtil.trimStart(originalLabel, "/"), "/");
- if (relativePath.startsWith("/")) {
- return null;
- }
- return new FileLookupData(originalLabel, containingFile, null, relativePath, pathFormat, quoteType, null);
- }
-
- @Nullable
- public static FileLookupData packageLocalFileLookup(String originalLabel, StringLiteral element) {
- if (originalLabel.startsWith("/")) {
- return null;
- }
- BlazePackage blazePackage = element.getBlazePackage();
- BuildFile baseBuildFile = blazePackage != null ? blazePackage.buildFile : null;
- return packageLocalFileLookup(originalLabel, element, baseBuildFile, null);
- }
-
- @Nullable
- public static FileLookupData packageLocalFileLookup(String originalLabel,
- StringLiteral element,
- @Nullable BuildFile basePackage,
- @Nullable VirtualFileFilter fileFilter) {
- String basePackagePath = basePackage != null ? basePackage.getWorkspaceRelativePackagePath() : null;
- if (basePackagePath == null) {
- return null;
- }
- String filePath = basePackagePath + "/" + LabelUtils.getRuleComponent(originalLabel);
- return new FileLookupData(originalLabel, basePackage, basePackagePath, filePath, PathFormat.PackageLocal, element.getQuoteType(), fileFilter);
- }
-
-
- private final String originalLabel;
- private final BuildFile containingFile;
- @Nullable
- private final String containingPackage;
- public final String filePathFragment;
- public final PathFormat pathFormat;
- private final QuoteType quoteType;
- @Nullable
- private final VirtualFileFilter fileFilter;
-
- private FileLookupData(
- String originalLabel,
- @Nullable BuildFile containingFile,
- @Nullable String containingPackage,
- String filePathFragment,
- PathFormat pathFormat,
- QuoteType quoteType,
- @Nullable VirtualFileFilter fileFilter) {
-
- this.originalLabel = originalLabel;
- this.containingFile = containingFile;
- this.containingPackage = containingPackage;
- this.fileFilter = fileFilter;
- this.filePathFragment = filePathFragment;
- this.pathFormat = pathFormat;
- this.quoteType = quoteType;
-
- assert(pathFormat != PathFormat.PackageLocal || (containingPackage != null && containingFile != null));
- }
-
- public boolean acceptFile(VirtualFile file) {
- if (fileFilter != null && !fileFilter.accept(file)) {
- return false;
- }
- if (pathFormat != PathFormat.PackageLocal) {
- return file.isDirectory();
- }
- if (file.equals(containingFile.getOriginalFile().getVirtualFile())) {
- return false;
- }
- boolean blazePackage = file.findChild("BUILD") != null;
- return !blazePackage;
- }
-
- public FilePathLookupElement lookupElementForFile(Project project, VirtualFile file, @Nullable WorkspacePath workspacePath) {
- NullableLazyValue<Icon> icon = new NullableLazyValue<Icon>() {
- @Override
- protected Icon compute() {
- if (file.findChild("BUILD") != null) {
- return BlazeIcons.BuildFile;
- }
- if (file.isDirectory()) {
- return PlatformIcons.FOLDER_ICON;
- }
- PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
- return psiFile != null ? psiFile.getIcon(0) : AllIcons.FileTypes.Any_type;
- }
- };
- String fullLabel = workspacePath != null ? getFullLabel(workspacePath.relativePath()) : file.getPath();
- String itemText = workspacePath != null ? getItemText(workspacePath.relativePath()) : fullLabel;
- return new FilePathLookupElement(fullLabel, itemText, quoteType, icon);
- }
-
- private String getFullLabel(String relativePath) {
- if (pathFormat != PathFormat.PackageLocal) {
- if (pathFormat == PathFormat.NonLocal) {
- relativePath = "//" + relativePath;
- }
- return relativePath;
- }
- String prefix;
- int colonIndex = originalLabel.indexOf(':');
- if (originalLabel.startsWith("/")) {
- prefix = colonIndex == -1 ? originalLabel + ":" : originalLabel.substring(0, colonIndex + 1);
- } else {
- prefix = originalLabel.substring(0, colonIndex + 1);
- }
- return prefix + getItemText(relativePath);
- }
-
- private String getItemText(String relativePath) {
- if (pathFormat == PathFormat.PackageLocal) {
- return StringUtil.trimStart(relativePath.substring(containingPackage.length()), "/");
- }
- String parentPath = PathUtil.getParentPath(relativePath);
- while (!parentPath.isEmpty()) {
- if (filePathFragment.startsWith(parentPath + "/")) {
- return StringUtil.trimStart(relativePath, parentPath + "/");
- } else if (filePathFragment.startsWith(parentPath)) {
- return StringUtil.trimStart(relativePath, parentPath);
- }
- parentPath = PathUtil.getParentPath(parentPath);
- }
- return relativePath;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/FuncallReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/FuncallReference.java
deleted file mode 100644
index a028a05..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/FuncallReference.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.IncorrectOperationException;
-
-import javax.annotation.Nullable;
-
-/**
- * Reference from a function call to the function declaration
- */
-public class FuncallReference extends PsiReferenceBase<FuncallExpression> {
-
- public FuncallReference(FuncallExpression element, TextRange rangeInElement) {
- super(element, rangeInElement, /*soft*/ true);
- }
-
- @Nullable
- @Override
- public FunctionStatement resolve() {
- String functionName = myElement.getFunctionName();
- BuildFile file = (BuildFile) myElement.getContainingFile();
- if (functionName == null || file == null) {
- return null;
- }
- return file.findFunctionInScope(functionName);
- }
-
- @Override
- public Object[] getVariants() {
- return EMPTY_ARRAY;
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- ASTNode oldNode = myElement.getFunctionNameNode();
- if (oldNode != null) {
- ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
- myElement.getNode().replaceChild(oldNode, newNode);
- }
- return myElement;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/GlobReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/GlobReference.java
deleted file mode 100644
index 3dfbc81..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/GlobReference.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.lang.buildfile.globbing.UnixGlob;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.*;
-import com.intellij.psi.impl.source.resolve.reference.impl.PsiPolyVariantCachingReference;
-import com.intellij.util.IncorrectOperationException;
-
-import java.io.File;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * References from a glob to a list of files contained in the same blaze package.
- */
-public class GlobReference extends PsiPolyVariantCachingReference {
-
- private static final Logger LOG = Logger.getInstance(GlobReference.class);
-
- private final GlobExpression element;
-
- public GlobReference(GlobExpression element) {
- this.element = element;
- }
-
- /**
- * Returns true iff the complete, resolved glob references the specified file.<p>
- * In particular, it's not concerned with individual patterns referencing
- * the file, only whether the overall glob does
- * (i.e. returns false if the file is explicitly excluded).
- */
- public boolean matches(String packageRelativePath, boolean isDirectory) {
- if (isDirectory && element.areDirectoriesExcluded()) {
- return false;
- }
- for (String exclude : resolveListContents(element.getExcludes())) {
- if (UnixGlob.matches(exclude, packageRelativePath)) {
- return false;
- }
- }
- for (String include : resolveListContents(element.getIncludes())) {
- if (UnixGlob.matches(include, packageRelativePath)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true iff an include pattern *without wildcards* matches the given path and
- * it's not excluded.
- */
- public boolean matchesDirectly(String packageRelativePath, boolean isDirectory) {
- if (isDirectory && element.areDirectoriesExcluded()) {
- return false;
- }
- for (String exclude : resolveListContents(element.getExcludes())) {
- if (UnixGlob.matches(exclude, packageRelativePath)) {
- return false;
- }
- }
- for (String include : resolveListContents(element.getIncludes())) {
- if (!hasWildcard(include) && UnixGlob.matches(include, packageRelativePath)) {
- return true;
- }
- }
- return false;
- }
-
- private static boolean hasWildcard(String pattern) {
- return pattern.contains("*");
- }
-
- @Override
- protected ResolveResult[] resolveInner(boolean incompleteCode, PsiFile containingFile) {
- File containingDirectory = ((BuildFile) containingFile).getFile().getParentFile();
- if (containingDirectory == null) {
- return ResolveResult.EMPTY_ARRAY;
- }
- List<String> includes = resolveListContents(element.getIncludes());
- List<String> excludes = resolveListContents(element.getExcludes());
- boolean directoriesExcluded = element.areDirectoriesExcluded();
- if (includes.isEmpty()) {
- return ResolveResult.EMPTY_ARRAY;
- }
-
- try {
- List<File> files = UnixGlob.forPath(containingDirectory)
- .addPatterns(includes)
- .addExcludes(excludes)
- .setExcludeDirectories(directoriesExcluded)
- .setDirectoryFilter(directoryFilter(containingDirectory.getPath()))
- .glob();
- List<ResolveResult> results = Lists.newArrayListWithCapacity(files.size());
- for (File file : files) {
- PsiFileSystemItem psiFile = BuildReferenceManager.getInstance(element.getProject()).resolveFile(file);
- if (psiFile != null) {
- results.add(new PsiElementResolveResult(psiFile));
- }
- }
- return results.toArray(ResolveResult.EMPTY_ARRAY);
-
- } catch (Exception e) {
- return ResolveResult.EMPTY_ARRAY;
- }
- }
-
- private static Predicate<File> directoryFilter(String base) {
- return file -> {
- if (base.equals(file.getPath())) {
- return true;
- }
- File child = new File(file, "BUILD");
- FileAttributeProvider attributeProvider = FileAttributeProvider.getInstance();
- return !attributeProvider.exists(child) || attributeProvider.isDirectory(child);
- };
- }
-
- private static List<String> resolveListContents(Expression expr) {
- if (expr == null) {
- return ImmutableList.of();
- }
- PsiElement rootElement = PsiUtils.getReferencedTargetValue(expr);
- if (!(rootElement instanceof ListLiteral)) {
- return ImmutableList.of();
- }
- Expression[] children = ((ListLiteral) rootElement).getElements();
- List<String> strings = Lists.newArrayListWithCapacity(children.length);
- for (Expression child : children) {
- if (child instanceof StringLiteral) {
- strings.add(((StringLiteral) child).getStringContents());
- }
- }
- return strings;
- }
-
- @Override
- public GlobExpression getElement() {
- return element;
- }
-
- @Override
- public TextRange getRangeInElement() {
- return element.getReferenceTextRange();
- }
-
- @Override
- public boolean isSoft() {
- return true;
- }
-
- @Override
- public Object[] getVariants() {
- return EMPTY_ARRAY;
- }
-
- @Override
- public String getCanonicalText() {
- return getValue();
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- return element;
- }
-
- @Override
- public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
- return this.element;
- }
-
- public String getValue() {
- String text = element.getText();
- final TextRange range = getRangeInElement();
- try {
- return range.substring(text);
- }
- catch (StringIndexOutOfBoundsException e) {
- LOG.error("Wrong range in reference " + this + ": " + range + ". Reference text: '" + text + "'", e);
- return text;
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/KeywordArgumentReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/KeywordArgumentReference.java
deleted file mode 100644
index da59a2f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/KeywordArgumentReference.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.util.IncorrectOperationException;
-
-import javax.annotation.Nullable;
-
-/**
- * Reference from keyword argument to a named function parameter.
- * TODO: This is soft, because we can't always find the function. However we should implement error highlighting
- * for imported Skylark functions.
- */
-public class KeywordArgumentReference extends ArgumentReference<Argument.Keyword> {
-
- public KeywordArgumentReference(Argument.Keyword element, TextRange rangeInElement) {
- super(element, rangeInElement, false);
- }
-
- /**
- * Find the referenced function. If it has a keyword parameter with matching name,
- * return that. Otherwise if it has a **kwargs param, return that. Else return the
- * function itself.
- */
- @Nullable
- @Override
- public PsiElement resolve() {
- String keyword = myElement.getName();
- if (keyword == null) {
- return null;
- }
- FunctionStatement function = resolveFunction();
- if (function == null) {
- return null;
- }
- Parameter.StarStar kwargsParameter = null;
- for (Parameter param : function.getParameters()) {
- if (param instanceof Parameter.StarStar) {
- kwargsParameter = (Parameter.StarStar) param;
- continue;
- }
- if (keyword.equals(param.getName())) {
- return param;
- }
- }
- if (kwargsParameter != null) {
- return kwargsParameter;
- }
- return null;
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- ASTNode oldNode = myElement.getNameNode();
- if (oldNode != null) {
- ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
- myElement.getNode().replaceChild(oldNode, newNode);
- }
- return myElement;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelReference.java
deleted file mode 100644
index 41870e7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelReference.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.completion.LabelRuleLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile.BlazeFileType;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.vfs.VirtualFileFilter;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.IncorrectOperationException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Converts a blaze label into an absolute path, then resolves that path to a PsiElements
- */
-public class LabelReference extends PsiReferenceBase<StringLiteral> {
-
- public LabelReference(StringLiteral element, boolean soft) {
- super(element, new TextRange(0, element.getTextLength()), soft);
- }
-
- @Nullable
- @Override
- public PsiElement resolve() {
- /* Possibilities:
- * - target
- * - data file (.java, .txt, etc.)
- * - glob contents (not yet handling globs)
- */
- return resolveTarget(myElement.getStringContents());
- }
-
- @Nullable
- private PsiElement resolveTarget(String labelString) {
- Label label = getLabel(labelString);
- if (label == null) {
- return null;
- }
- if (!validLabelLocation(myElement)) {
- return null;
- }
- if (!labelString.startsWith("//") && insideSkylarkExtension(myElement)) {
- return getReferenceManager().resolveLabel(label.blazePackage(), label.ruleName(), true);
- }
- return getReferenceManager().resolveLabel(label);
- }
-
- /**
- * Hack: don't include 'name' keyword arguments -- they'll be a reference to the enclosing function call / rule,
- * and show up as unnecessary references to that rule.
- */
- private static boolean validLabelLocation(StringLiteral element) {
- PsiElement parent = element.getParent();
- if (parent instanceof Argument.Keyword) {
- String argName = ((Argument.Keyword) parent).getName();
- if ("name".equals(argName)) {
- return false;
- }
- }
- return true;
- }
-
- @NotNull
- @Override
- public Object[] getVariants() {
- if (!validLabelLocation(myElement)) {
- return EMPTY_ARRAY;
- }
- String labelString = LabelUtils.trimToDummyIdentifier(myElement.getStringContents());
- return ArrayUtil.mergeArrays(
- getRuleLookups(labelString),
- getFileLookups(labelString));
- }
-
- private BuildLookupElement[] getRuleLookups(String labelString) {
- if (labelString.endsWith("/")
- || (labelString.startsWith("/") && !labelString.contains(":"))
- || skylarkExtensionReference(myElement)) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
- BuildFile referencedBuildFile = LabelUtils.getReferencedBuildFile(myElement.getContainingFile(), packagePrefix);
- if (referencedBuildFile == null) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- String self = null;
- if (referencedBuildFile == myElement.getContainingFile()) {
- FuncallExpression funcall = PsiUtils.getParentOfType(myElement, FuncallExpression.class);
- if (funcall != null) {
- self = funcall.getName();
- }
- }
- return LabelRuleLookupElement.collectAllRules(referencedBuildFile, labelString, packagePrefix, self, myElement.getQuoteType());
- }
-
- private BuildLookupElement[] getFileLookups(String labelString) {
- if (labelString.startsWith("//") || labelString.equals("/")) {
- return getNonLocalFileLookups(labelString);
- }
- return getPackageLocalFileLookups(labelString);
- }
-
- private BuildLookupElement[] getNonLocalFileLookups(String labelString) {
- BuildLookupElement[] skylarkExtLookups = getSkylarkExtensionLookups(labelString);
- FileLookupData lookupData = FileLookupData.nonLocalFileLookup(labelString, myElement);
- BuildLookupElement[] packageLookups = lookupData != null
- ? getReferenceManager().resolvePackageLookupElements(lookupData)
- : BuildLookupElement.EMPTY_ARRAY;
- return ArrayUtil.mergeArrays(skylarkExtLookups, packageLookups);
- }
-
- private BuildLookupElement[] getPackageLocalFileLookups(String labelString) {
- if (skylarkExtensionReference(myElement)) {
- return getSkylarkExtensionLookups(labelString);
- }
- FileLookupData lookupData = FileLookupData.packageLocalFileLookup(labelString, myElement);
- return lookupData != null
- ? getReferenceManager().resolvePackageLookupElements(lookupData)
- : BuildLookupElement.EMPTY_ARRAY;
- }
-
- private BuildLookupElement[] getSkylarkExtensionLookups(String labelString) {
- if (!skylarkExtensionReference(myElement)) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
- BuildFile parentFile = myElement.getContainingFile();
- if (parentFile == null) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- BlazePackage containingPackage = BlazePackage.getContainingPackage(parentFile);
- if (containingPackage == null) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- BuildFile referencedBuildFile = LabelUtils.getReferencedBuildFile(containingPackage.buildFile, packagePrefix);
- VirtualFileFilter filter = file ->
- file.isDirectory() || ("bzl".equals(file.getExtension()) && !file.getPath().equals(parentFile.getFilePath()));
- FileLookupData lookupData = FileLookupData.packageLocalFileLookup(labelString, myElement, referencedBuildFile, filter);
-
- return lookupData != null
- ? getReferenceManager().resolvePackageLookupElements(lookupData)
- : BuildLookupElement.EMPTY_ARRAY;
- }
-
- private BuildReferenceManager getReferenceManager() {
- return BuildReferenceManager.getInstance(myElement.getProject());
- }
-
- @Override
- public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
- PsiFile file = ResolveUtil.asFileSearch(element);
- if (file == null) {
- return super.bindToElement(element);
- }
- if (file.equals(resolve())) {
- return myElement;
- }
- BlazePackage currentPackageDir = myElement.getBlazePackage();
- if (currentPackageDir == null) {
- return myElement;
- }
- BlazePackage newPackageDir = BlazePackage.getContainingPackage(file);
- if (!currentPackageDir.equals(newPackageDir)) {
- return myElement;
- }
-
- String newRuleName = newPackageDir.getPackageRelativePath(file.getViewProvider().getVirtualFile().getPath());
- return handleRename(newRuleName);
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- String currentString = myElement.getStringContents();
- Label label = getLabel(currentString);
- if (label == null) {
- return myElement;
- }
- String ruleName = label.ruleName().toString();
- String newRuleName = newElementName;
-
- // handle subdirectories
- int lastSlashIndex = ruleName.lastIndexOf('/');
- if (lastSlashIndex != -1) {
- newRuleName = ruleName.substring(0, lastSlashIndex + 1) + newElementName;
- }
-
- String packageString = LabelUtils.getPackagePathComponent(currentString);
- if (packageString.isEmpty() && !currentString.contains(":")) {
- return handleRename(newRuleName);
- }
- return handleRename(packageString + ":" + newRuleName);
- }
-
- private PsiElement handleRename(String newStringContents) {
- ASTNode node = myElement.getNode();
- node.replaceChild(node.getFirstChildNode(), PsiUtils.createNewLabel(myElement.getProject(), newStringContents));
- return myElement;
- }
-
- @Nullable
- private Label getLabel(String labelString) {
- if (labelString.indexOf('*') != -1) {
- // don't even try to handle globs, yet.
- return null;
- }
- BlazePackage blazePackage = myElement.getBlazePackage();
- return LabelUtils.createLabelFromString(blazePackage != null ? blazePackage.buildFile : null, labelString);
- }
-
- private static boolean skylarkExtensionReference(StringLiteral element) {
- PsiElement parent = element.getParent();
- if (!(parent instanceof LoadStatement)) {
- return false;
- }
- return ((LoadStatement) parent).getImportPsiElement() == element;
- }
-
- private static boolean insideSkylarkExtension(StringLiteral element) {
- BuildFile containingFile = element.getContainingFile();
- return containingFile != null && containingFile.getBlazeFileType() == BlazeFileType.SkylarkExtension;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelUtils.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelUtils.java
deleted file mode 100644
index 43d84b8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LabelUtils.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.RuleName;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.intellij.codeInsight.completion.CompletionUtilCore;
-import com.intellij.util.PathUtil;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * Utility methods for working with blaze labels.
- */
-public class LabelUtils {
-
- /**
- * Label referring to the given file, or null if it cannot be determined.
- */
- @Nullable
- public static Label createLabelForFile(BlazePackage blazePackage, @Nullable String filePath) {
- if (blazePackage == null || filePath == null) {
- return null;
- }
- String relativeFilePath = blazePackage.getPackageRelativePath(filePath);
- if (relativeFilePath == null) {
- return null;
- }
- return createLabelFromRuleName(blazePackage, relativeFilePath);
- }
-
- /**
- * Returns null if this is not a valid Label (if either the package path or rule name are invalid)
- */
- @Nullable
- public static Label createLabelFromRuleName(@Nullable BlazePackage blazePackage, @Nullable String ruleName) {
- if (blazePackage == null || ruleName == null) {
- return null;
- }
- WorkspacePath packagePath = blazePackage.buildFile.getPackageWorkspacePath();
- RuleName name = RuleName.createIfValid(ruleName);
- if (packagePath == null || name == null) {
- return null;
- }
- // TODO: Is Label too inefficient?
- // (validation done twice,creating List during constructor, re-parsing to extract the package/rule each time)
- return new Label(packagePath, name);
- }
-
- /**
- * Canonicalizes the label (to the form //packagePath:packageRelativeTarget).
- * Returns null if the string does not represent a valid label.
- */
- @Nullable
- public static Label createLabelFromString(@Nullable BuildFile file, @Nullable String labelString) {
- if (labelString == null) {
- return null;
- }
- int colonIndex = labelString.indexOf(':');
- if (labelString.startsWith("//")) {
- if (colonIndex == -1) {
- // add the implicit rule name
- labelString += ":" + PathUtil.getFileName(labelString);
- }
- return Label.createIfValid(labelString);
- }
- WorkspacePath packagePath = file != null ? file.getPackageWorkspacePath() : null;
- if (packagePath == null) {
- return null;
- }
- String localPath = colonIndex == -1 ? labelString : labelString.substring(1);
- return Label.createIfValid("//" + packagePath.relativePath() + ":" + localPath);
- }
-
- /**
- * The blaze file referenced by the label.
- */
- @Nullable
- public static BuildFile getReferencedBuildFile(@Nullable BuildFile containingFile, String packagePathComponent) {
- if (containingFile == null) {
- return null;
- }
- if (!packagePathComponent.startsWith("//")) {
- return containingFile;
- }
- return BuildReferenceManager.getInstance(containingFile.getProject()).resolveBlazePackage(packagePathComponent);
- }
-
- public static String getRuleComponent(String labelString) {
- if (labelString.startsWith("/")) {
- int colonIndex = labelString.indexOf(':');
- return colonIndex == -1 ? "" : labelString.substring(colonIndex + 1);
- }
- return labelString.startsWith(":") ? labelString.substring(1) : labelString;
- }
-
- public static String getPackagePathComponent(String labelString) {
- if (!labelString.startsWith("//")) {
- return "";
- }
- int colonIndex = labelString.indexOf(':');
- return colonIndex == -1 ? labelString : labelString.substring(0, colonIndex);
- }
-
- /**
- * 'load' reference. Of the form [path][/ or :][extra_path/]file_name.bzl
- */
- @Nullable
- public static String getNiceSkylarkFileName(@Nullable String path) {
- if (path == null) {
- return null;
- }
- int colonIndex = path.lastIndexOf(":");
- if (colonIndex != -1) {
- path = path.substring(colonIndex + 1);
- }
- int lastSlash = path.lastIndexOf("/");
- if (lastSlash == -1) {
- return path;
- }
- return path.substring(lastSlash + 1);
- }
-
- /**
- * All the possible strings which could resolve to the given target.
- * @param includePackageLocalLabels if true, include strings omitting the package path
- */
- public static List<String> getAllValidLabelStrings(Label label, boolean includePackageLocalLabels) {
- List<String> strings = Lists.newArrayList();
- strings.add(label.toString());
- String packagePath = label.blazePackage().relativePath();
- if (packagePath.isEmpty()) {
- return strings;
- }
- String ruleName = label.ruleName().toString();
- if (PathUtil.getFileName(packagePath).equals(ruleName)) {
- strings.add("//" + packagePath); // implicit rule name equal to package name
- }
- if (includePackageLocalLabels) {
- strings.add(":" + ruleName);
- strings.add(ruleName);
- }
- return strings;
- }
-
- /**
- * IntelliJ inserts an identifier string at the caret position during code completion.<br>
- * We're only interested in the portion of the string before the caret, so trim the rest.
- */
- public static String trimToDummyIdentifier(String string) {
- int dummyIdentifierIndex = string.indexOf(CompletionUtilCore.DUMMY_IDENTIFIER);
- if (dummyIdentifierIndex == -1) {
- dummyIdentifierIndex = string.indexOf(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED);
- }
- return dummyIdentifierIndex == -1 ? string : string.substring(0, dummyIdentifierIndex);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LoadedSymbolReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LoadedSymbolReference.java
deleted file mode 100644
index 5359f94..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LoadedSymbolReference.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.completion.CompletionResultsProcessor;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.IncorrectOperationException;
-
-import javax.annotation.Nullable;
-
-/**
- * References from load statement string to a function or variable in a Skylark extension
- */
-public class LoadedSymbolReference extends PsiReferenceBase<StringLiteral> {
-
- private final LabelReference bzlFileReference;
-
- public LoadedSymbolReference(StringLiteral element, LabelReference bzlFileReference) {
- super(element, new TextRange(0, element.getTextLength()), /*soft*/ false);
- this.bzlFileReference = bzlFileReference;
- }
-
- @Nullable
- @Override
- public BuildElement resolve() {
- PsiElement bzlFile = bzlFileReference.resolve();
- if (!(bzlFile instanceof BuildFile)) {
- return null;
- }
- return ((BuildFile) bzlFile).findSymbolInScope(myElement.getStringContents());
- }
-
- @Override
- public Object[] getVariants() {
- PsiElement bzlFile = bzlFileReference.resolve();
- if (!(bzlFile instanceof BuildFile)) {
- return EMPTY_ARRAY;
- }
- CompletionResultsProcessor processor = new CompletionResultsProcessor(myElement, myElement.getQuoteType());
- ((BuildFile) bzlFile).searchSymbolsInScope(processor, null);
- return processor.getResults().toArray();
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- ASTNode newNode = PsiUtils.createNewLabel(myElement.getProject(), newElementName);
- myElement.getNode().replaceChild(myElement.getNode().getFirstChildNode(), newNode);
- return myElement;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LocalReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LocalReference.java
deleted file mode 100644
index eb420d5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/LocalReference.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.completion.CompletionResultsProcessor;
-import com.google.idea.blaze.base.lang.buildfile.psi.ReferenceExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.IncorrectOperationException;
-
-import javax.annotation.Nullable;
-
-/**
- * Reference from a ReferenceExpression to a PsiNamedElement in the same scope.
- * This includes symbols accessible via 'load' statments.
- */
-public class LocalReference extends PsiReferenceBase<ReferenceExpression> {
-
- public LocalReference(ReferenceExpression element) {
- super(element, new TextRange(0, element.getTextLength()), /*soft*/ false);
- }
-
- @Nullable
- @Override
- public PsiElement resolve() {
- String referencedName = myElement.getReferencedName();
- if (referencedName == null) {
- return null;
- }
- return ResolveUtil.findInScope(myElement, referencedName);
- }
-
- @Override
- public Object[] getVariants() {
- CompletionResultsProcessor processor = new CompletionResultsProcessor(myElement, QuoteType.NoQuotes);
- ResolveUtil.searchInScope(myElement, processor);
- return processor.getResults().toArray();
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- ASTNode oldNode = myElement.getNameElement();
- if (oldNode != null) {
- ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
- myElement.getNode().replaceChild(oldNode, newNode);
- }
- return myElement;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceFragment.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceFragment.java
deleted file mode 100644
index 572d9bf..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceFragment.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.PathUtil;
-
-import javax.annotation.Nullable;
-
-/**
- * The label component preceeding the colon.
- */
-public class PackageReferenceFragment extends PsiReferenceBase<StringLiteral> {
-
- public PackageReferenceFragment(LabelReference labelReference) {
- super(labelReference.getElement(), labelReference.getRangeInElement(), labelReference.isSoft());
- }
-
- @Nullable
- private WorkspacePath getWorkspacePath(String labelString) {
- if (!labelString.startsWith("//")) {
- return null;
- }
- int colonIndex = labelString.indexOf(':');
- int endIndex = colonIndex != -1 ? colonIndex : labelString.length();
- return WorkspacePath.createIfValid(labelString.substring(2, endIndex));
- }
-
- @Override
- public TextRange getRangeInElement() {
- String rawText = myElement.getText();
- boolean valid = getWorkspacePath(myElement.getStringContents()) != null;
- if (!valid) {
- return TextRange.EMPTY_RANGE;
- }
- int endIndex = rawText.indexOf(':');
- if (endIndex == -1) {
- endIndex = rawText.length() - 1;
- }
- return new TextRange(1, endIndex);
- }
-
- @Nullable
- @Override
- public BuildFile resolve() {
- WorkspacePath workspacePath = getWorkspacePath(myElement.getStringContents());
- return BuildReferenceManager.getInstance(myElement.getProject()).resolveBlazePackage(workspacePath);
- }
-
- @Override
- public Object[] getVariants() {
- return EMPTY_ARRAY;
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- return myElement; // renaming a BUILD file has no effect on the package label fragments
- }
-
- @Override
- public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
- if (!(element instanceof BuildFile)) {
- return super.bindToElement(element);
- }
- if (element.equals(resolve())) {
- return myElement;
- }
- WorkspacePath newPath = ((BuildFile) element).getPackageWorkspacePath();
- if (newPath == null) {
- return myElement;
- }
- String labelString = myElement.getStringContents();
- int colonIndex = labelString.indexOf(':');
- if (colonIndex != -1) {
- return handleRename("//" + newPath + labelString.substring(colonIndex));
- }
- // need to assume there's an implicit rule name
- return handleRename("//" + newPath + ":" + PathUtil.getFileName(labelString));
- }
-
- private PsiElement handleRename(String newStringContents) {
- ASTNode node = myElement.getNode();
- node.replaceChild(node.getFirstChildNode(), PsiUtils.createNewLabel(myElement.getProject(), newStringContents));
- return myElement;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/QuoteType.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/QuoteType.java
deleted file mode 100644
index 40125fd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/QuoteType.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-/**
- * The type of quotes surrounding a PSI element.
- */
-public enum QuoteType {
- Single("'"),
- Double("\""),
- TripleSingle("'''"),
- TripleDouble("\"\"\""),
- NoQuotes("");
-
- public final String quoteString;
-
- QuoteType(String quoteString) {
- this.quoteString = quoteString;
- }
-
- public String wrap(String unquotedText) {
- return quoteString + unquotedText + quoteString;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/TargetReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/TargetReference.java
deleted file mode 100644
index b8144bf..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/references/TargetReference.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.completion.CompletionResultsProcessor;
-import com.google.idea.blaze.base.lang.buildfile.psi.TargetExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiNamedElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.IncorrectOperationException;
-
-import javax.annotation.Nullable;
-
-/**
- * A reference to an earlier declaration of this symbol (to handle cases where a symbol
- * is the target of multiple assignment statements).
- */
-public class TargetReference extends PsiReferenceBase<TargetExpression> {
-
- public TargetReference(TargetExpression element) {
- super(element, new TextRange(0, element.getTextLength()), /*soft*/ true);
- }
-
- @Nullable
- @Override
- public PsiElement resolve() {
- String referencedName = myElement.getName();
- if (referencedName == null) {
- return null;
- }
- PsiNamedElement target = ResolveUtil.findInScope(myElement, referencedName);
- return target != null ? target : null;
- }
-
- @Override
- public Object[] getVariants() {
- CompletionResultsProcessor processor = new CompletionResultsProcessor(myElement, QuoteType.NoQuotes);
- ResolveUtil.searchInScope(myElement, processor);
- return processor.getResults().toArray();
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- ASTNode oldNode = myElement.getNameNode();
- if (oldNode != null) {
- ASTNode newNode = PsiUtils.createNewName(myElement.getProject(), newElementName);
- myElement.getNode().replaceChild(oldNode, newNode);
- }
- return myElement;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackage.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackage.java
deleted file mode 100644
index 301ce93..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackage.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.history.core.Paths;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PackagePrefixFileSystemItem;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiFileSystemItem;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.util.PathUtil;
-import com.intellij.util.Processor;
-
-import javax.annotation.Nullable;
-import java.util.Objects;
-
-/**
- * Defines the files accessible by a given blaze package.
- */
-public class BlazePackage {
-
- @Nullable
- public static BlazePackage getContainingPackage(PsiFileSystemItem file) {
- if (file instanceof PsiFile) {
- file = ((PsiFile) file).getOriginalFile();
- }
- if (file instanceof BuildFile && file.getName().equals("BUILD")) {
- return new BlazePackage((BuildFile) file);
- }
- return getContainingPackage(getPsiDirectory(file));
- }
-
- @Nullable
- private static PsiDirectory getPsiDirectory(PsiFileSystemItem file) {
- if (file instanceof PsiDirectory) {
- return (PsiDirectory) file;
- }
- if (file instanceof PsiFile) {
- return ((PsiFile) file).getContainingDirectory();
- }
- if (file instanceof PackagePrefixFileSystemItem) {
- return ((PackagePrefixFileSystemItem) file).getDirectory();
- }
- return null;
- }
-
- @Nullable
- public static BlazePackage getContainingPackage(@Nullable PsiDirectory dir) {
- while (dir != null) {
- PsiFile buildFile = dir.findFile("BUILD");
- if (buildFile != null) {
- return buildFile instanceof BuildFile ? new BlazePackage((BuildFile) buildFile) : null;
- }
- dir = dir.getParentDirectory();
- }
- return null;
- }
-
- public final BuildFile buildFile;
-
- private BlazePackage(BuildFile buildFile) {
- this.buildFile = buildFile;
- }
-
- @Nullable
- public PsiDirectory getContainingDirectory() {
- return buildFile.getParent();
- }
-
- /**
- * The search scope corresponding to this package (i.e. not crossing package boundaries).
- * @param onlyBlazeFiles if true, the scope is limited to BUILD and Skylark files.
- */
- public GlobalSearchScope getSearchScope(boolean onlyBlazeFiles) {
- return new BlazePackageSearchScope(this, onlyBlazeFiles);
- }
-
- /**
- * Returns the file path relative to this blaze package, or null if it does lie inside this package
- */
- @Nullable
- public String getPackageRelativePath(String filePath) {
- String packageFilePath = PathUtil.getParentPath(buildFile.getFilePath());
- return Paths.relativeIfUnder(filePath, packageFilePath);
- }
-
- /**
- * The path from the blaze package directory to the child file, or null if
- * the package directory is not an ancestor of the provided file.
- */
- @Nullable
- public String getRelativePathToChild(@Nullable VirtualFile child) {
- if (child == null) {
- return null;
- }
- String packagePath = PathUtil.getParentPath(buildFile.getFilePath());
- return Paths.relativeIfUnder(child.getPath(), packagePath);
- }
-
- /**
- * Walks the directory tree, processing all files accessible by this package (i.e. not processing child packages).
- */
- public void processPackageFiles(Processor<PsiFile> processor) {
- PsiDirectory dir = getContainingDirectory();
- if (dir == null) {
- return;
- }
- processPackageFiles(processor, dir);
- }
-
- private static void processPackageFiles(Processor<PsiFile> processor, PsiDirectory directory) {
- processDirectory(processor, directory);
- for (PsiDirectory child : directory.getSubdirectories()) {
- if (!isBlazePackage(child)) {
- processPackageFiles(processor, directory);
- }
- }
- }
-
- private static boolean isBlazePackage(PsiDirectory directory) {
- return directory.findFile("BUILD") != null;
- }
-
- private static void processDirectory(Processor<PsiFile> processor, PsiDirectory directory) {
- for (PsiFile file : directory.getFiles()) {
- processor.process(file);
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof BlazePackage)) {
- return false;
- }
- if (obj == this) {
- return true;
- }
- BlazePackage that = (BlazePackage) obj;
- return Objects.equals(buildFile.getFilePath(), that.buildFile.getFilePath());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(buildFile.getFilePath());
- }
-
- @Override
- public String toString() {
- return String.format("%s package: %s", Blaze.buildSystemName(buildFile.getProject()), buildFile.getPackageWorkspacePath());
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageSearchScope.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageSearchScope.java
deleted file mode 100644
index 750a1be..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageSearchScope.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
-import com.intellij.psi.search.GlobalSearchScope;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Objects;
-
-/**
- * A scope limited to a single blaze/bazel package, which doesn't cross package boundaries.
- */
-public class BlazePackageSearchScope extends GlobalSearchScope {
-
- private final BlazePackage blazePackage;
- private final boolean onlyBlazeFiles;
-
- public BlazePackageSearchScope(BlazePackage blazePackage, boolean onlyBlazeFiles) {
- super(blazePackage.buildFile.getProject());
- this.blazePackage = blazePackage;
- this.onlyBlazeFiles = onlyBlazeFiles;
- }
-
- @Override
- public boolean contains(@NotNull VirtualFile file) {
- PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
- if (onlyBlazeFiles && !(psiFile instanceof BuildFile)) {
- return false;
- }
- return blazePackage.equals(BlazePackage.getContainingPackage(psiFile));
- }
-
- @Override
- public int compare(@NotNull VirtualFile file1, @NotNull VirtualFile file2) {
- return 0;
- }
-
- @Override
- public boolean isSearchInModuleContent(@NotNull Module aModule) {
- return true;
- }
-
- @Override
- public boolean isSearchInLibraries() {
- return false;
- }
-
- @Override
- public String toString() {
- return String.format("%s directory scope: %s", Blaze.buildSystemName(getProject()), blazePackage.buildFile.getPackageWorkspacePath());
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof BlazePackageSearchScope)) {
- return false;
- }
- if (obj == this) {
- return true;
- }
- BlazePackageSearchScope other = (BlazePackageSearchScope) obj;
- return blazePackage.equals(other.blazePackage) && onlyBlazeFiles == other.onlyBlazeFiles;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(blazePackage, onlyBlazeFiles);
- }
-
- @Override
- public String getDisplayName() {
- return blazePackage.toString();
- }
-
- @Override
- public GlobalSearchScope uniteWith(@NotNull GlobalSearchScope scope) {
- if (scope instanceof BlazePackageSearchScope) {
- BlazePackageSearchScope other = (BlazePackageSearchScope) scope;
- if (!blazePackage.equals(other.blazePackage)) {
- return GlobalSearchScope.EMPTY_SCOPE;
- }
- return onlyBlazeFiles ? this : other;
- }
- return super.uniteWith(scope);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java
deleted file mode 100644
index f8ae2e6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile.BlazeFileType;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
-import com.intellij.openapi.application.QueryExecutorBase;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.search.*;
-import com.intellij.psi.search.searches.ReferencesSearch.SearchParameters;
-import com.intellij.util.Processor;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * String search for label references in BUILD files
- */
-public class BuildLabelReferenceSearcher extends QueryExecutorBase<PsiReference, SearchParameters> {
-
- public BuildLabelReferenceSearcher() {
- super(true);
- }
-
- @Override
- public void processQuery(SearchParameters params, Processor<PsiReference> consumer) {
- PsiElement element = params.getElementToSearch();
- if (element instanceof FunctionStatement) {
- String fnName = ((FunctionStatement) element).getName();
- if (fnName != null) {
- searchForString(params, element, fnName);
- }
- return;
- }
- PsiFile file = ResolveUtil.asFileSearch(element);
- if (file != null) {
- processFileReferences(params, file);
- return;
- }
-
- if (!(element instanceof FuncallExpression)) {
- return;
- }
-
- Label label = ((FuncallExpression) element).resolveBuildLabel();
- PsiFile localFile = element.getContainingFile();
- if (label == null || localFile == null) {
- return;
- }
- List<String> stringsToSearch = LabelUtils.getAllValidLabelStrings(label, true);
- for (String string : stringsToSearch) {
- if (string.startsWith("//")) {
- searchForString(params, element, string);
- } else {
- // only a valid reference from local package -- restrict the search scope accordingly
- SearchScope scope = limitScopeToFile(params.getScopeDeterminedByUser(), localFile);
- if (scope != null) {
- searchForString(params, scope, element, string);
- }
- }
- }
- }
-
- /**
- * Find all references to the given file within BUILD files.
- */
- private void processFileReferences(SearchParameters params, PsiFile file) {
- if (file instanceof BuildFile) {
- BuildFile buildFile = (BuildFile) file;
- processBuildFileReferences(params, buildFile);
- if (buildFile.getBlazeFileType() == BlazeFileType.BuildPackage) {
- return;
- }
- // for skylark extensions, we also check for package-local references, below
- }
- BlazePackage blazePackage = BlazePackage.getContainingPackage(file);
- PsiDirectory directory = blazePackage != null ? blazePackage.getContainingDirectory() : null;
- if (directory == null) {
- return;
- }
- Label label = LabelUtils.createLabelForFile(blazePackage, PsiUtils.getFilePath(file));
- if (label == null) {
- return;
- }
-
- // files can only be directly referenced in the containing blaze package
- List<String> stringsToSearch = LabelUtils.getAllValidLabelStrings(label, true);
- SearchScope scope = params.getScopeDeterminedByUser()
- .intersectWith(blazePackage.getSearchScope(true));
-
- for (String string : stringsToSearch) {
- searchForString(params, scope, file, string);
- }
- }
-
- /**
- * Find references to both the file itself, and build targets defined in the file.
- */
- private void processBuildFileReferences(SearchParameters params, BuildFile file) {
- WorkspacePath workspacePath = file.getPackageWorkspacePath();
- if (workspacePath == null) {
- return;
- }
- List<String> stringsToSearch = Lists.newArrayList();
- if (file.getBlazeFileType() == BlazeFileType.BuildPackage) {
- stringsToSearch.add("//" + workspacePath);
- } else {
- stringsToSearch.add("//" + workspacePath + ":" + file.getName());
- stringsToSearch.add("//" + workspacePath + "/" + file.getName()); // deprecated load/subinclude format
- }
- for (String string : stringsToSearch) {
- searchForString(params, file, string);
- }
- }
-
- /**
- * Search for package-local references.<br>
- * Returns null if the resulting scope is empty
- */
- @Nullable
- private static SearchScope limitScopeToFile(SearchScope scope, PsiFile file) {
- if (scope instanceof LocalSearchScope) {
- return ((LocalSearchScope) scope).isInScope(file.getVirtualFile()) ? new LocalSearchScope(file) : null;
- }
- return scope.intersectWith(new LocalSearchScope(file));
- }
-
- private static void searchForString(SearchParameters params, PsiElement element, String string) {
- searchForString(params, params.getScopeDeterminedByUser(), element, string);
- }
-
- private static void searchForString(SearchParameters params, SearchScope scope, PsiElement element, String string) {
- if (scope instanceof GlobalSearchScope) {
- scope = GlobalSearchScope.getScopeRestrictedByFileTypes((GlobalSearchScope) scope, BuildFileType.INSTANCE);
- }
- params.getOptimizer().searchWord(string, scope, UsageSearchContext.IN_STRINGS, true, element);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/ExcludeBuildFilesScope.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/ExcludeBuildFilesScope.java
deleted file mode 100644
index 60c73a4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/ExcludeBuildFilesScope.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileType;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFileSystemItem;
-import com.intellij.psi.search.EverythingGlobalScope;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.UseScopeOptimizer;
-
-import javax.annotation.Nullable;
-
-/**
- * Causes all calls to PsiSearchHelper.getUseScope to exclude BUILD files, when searching for files.<br>
- * BUILD file / BUILD package references are handled by a separate reference searcher.<p>
- *
- * This is a hack, but greatly improves efficiency. The reasoning behind this:
- * - BUILD files have very strict file reference patterns, and very narrow direct reference scopes (a package can't
- * directly reference files in another package).
- * - IJ *constantly* performs global searches on strings when manipulating files (e.g. searching for file uses for
- * highlighting, rename, move operations). This causes us to re-parse every BUILD file in the project, multiple times.
- *
- */
-public class ExcludeBuildFilesScope extends UseScopeOptimizer {
-
- @Nullable
- @Override
- public GlobalSearchScope getScopeToExclude(PsiElement element) {
- if (element instanceof PsiFileSystemItem) {
- return GlobalSearchScope.getScopeRestrictedByFileTypes(new EverythingGlobalScope(), BuildFileType.INSTANCE);
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/FindUsages.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/FindUsages.java
deleted file mode 100644
index 24c9aa8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/FindUsages.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.PsiSearchHelper;
-import com.intellij.psi.search.SearchScope;
-import com.intellij.psi.search.searches.ReferencesSearch;
-
-/**
- * Utility methods for finding all references to a PsiElement
- */
-public class FindUsages {
-
- public static PsiReference[] findAllReferences(PsiElement element) {
- return findReferencesInScope(element, GlobalSearchScope.allScope(element.getProject()));
- }
-
- /**
- * Search scope taken from PsiSearchHelper::getUseScope, which incorporates UseScopeEnlarger / UseScopeOptimizer EPs.
- */
- public static PsiReference[] findReferencesInElementScope(PsiElement element) {
- return findReferencesInScope(element, PsiSearchHelper.SERVICE.getInstance(element.getProject()).getUseScope(element));
- }
-
- public static PsiReference[] findReferencesInScope(PsiElement element, SearchScope scope) {
- return ReferencesSearch.search(element, scope, true).toArray(new PsiReference[0]);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/GlobReferenceSearcher.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/GlobReferenceSearcher.java
deleted file mode 100644
index d9e2e58..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/GlobReferenceSearcher.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.openapi.application.QueryExecutorBase;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFileSystemItem;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.LocalSearchScope;
-import com.intellij.psi.search.SearchScope;
-import com.intellij.psi.search.searches.ReferencesSearch.SearchParameters;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.Processor;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * Searches for references to a file in globs. These aren't picked up by a standard string search, and are only
- * evaluated on demand, so we can't just check a reference cache.<p>
- *
- * Unlike resolving a glob, this requires no file system calls (beyond finding the parent blaze package),
- * because we're only interested in a single file, which is already known to exist.<p>
- *
- * This is always a local search (as glob references can't cross package boundaries).
- */
-public class GlobReferenceSearcher extends QueryExecutorBase<PsiReference, SearchParameters> {
-
- public GlobReferenceSearcher() {
- super(true);
- }
-
- @Override
- public void processQuery(SearchParameters queryParameters, Processor<PsiReference> consumer) {
- PsiFileSystemItem file = ResolveUtil.asFileSystemItemSearch(queryParameters.getElementToSearch());
- if (file == null) {
- return;
- }
- BlazePackage containingPackage = BlazePackage.getContainingPackage(file);
- if (containingPackage == null || !inScope(queryParameters, containingPackage.buildFile)) {
- return;
- }
- String relativePath = containingPackage.getRelativePathToChild(file.getVirtualFile());
- if (relativePath == null) {
- return;
- }
-
- List<GlobExpression> globs = PsiUtils.findAllChildrenOfClassRecursive(containingPackage.buildFile, GlobExpression.class);
- for (GlobExpression glob : globs) {
- if (glob.matches(relativePath, file.isDirectory())) {
- consumer.process(globReference(glob, file));
- }
- }
- }
-
- private static PsiReference globReference(GlobExpression glob, PsiFileSystemItem file) {
- return new PsiReferenceBase.Immediate<GlobExpression>(glob, glob.getReferenceTextRange(), file) {
- @Override
- public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
- return glob;
- }
- };
- }
-
- private static boolean inScope(SearchParameters queryParameters, BuildFile buildFile) {
- SearchScope scope = queryParameters.getScopeDeterminedByUser();
- if (scope instanceof GlobalSearchScope) {
- return ((GlobalSearchScope) scope).contains(buildFile.getVirtualFile());
- }
- return ((LocalSearchScope) scope).isInScope(buildFile.getVirtualFile());
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/PsiFileProvider.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/PsiFileProvider.java
deleted file mode 100644
index 0230744..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/PsiFileProvider.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-
-import javax.annotation.Nullable;
-
-/**
- * Checks if the PsiElement represents a top-level PsiFile (e.g. a top-level java PsiClass can be interchanged with the
- * corresponding PsiFile, when searching for usages).
- */
-public interface PsiFileProvider {
-
- ExtensionPointName<PsiFileProvider> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.PsiFileProvider");
-
- @Nullable
- PsiFile asFileSearch(PsiElement elementToSearch);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/ResolveUtil.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/ResolveUtil.java
deleted file mode 100644
index 4e3a2e2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/search/ResolveUtil.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiFileSystemItem;
-import com.intellij.psi.PsiNamedElement;
-import com.intellij.util.Processor;
-
-import javax.annotation.Nullable;
-
-/**
- * Utilities methods for resolving references
- */
-public class ResolveUtil {
-
- /**
- * Walks up PSI tree of local file, checking PsiNamedElements
- */
- public static void searchInScope(PsiElement originalElement, Processor<BuildElement> processor) {
- // TODO: Handle list comprehension (where variable is defined *later* in the code)
- boolean topLevelScope = true;
- PsiElement element = originalElement;
- while (!(element instanceof PsiFileSystemItem)) {
- PsiElement parent = element.getParent();
- if (parent instanceof BuildFile) {
- if (!((BuildFile) parent).searchSymbolsInScope(processor, topLevelScope ? element : null)) {
- return;
- }
- } else if (parent instanceof FunctionStatement) {
- topLevelScope = false;
- for (Parameter param : ((FunctionStatement) parent).getParameters()) {
- if (!processor.process(param)) {
- return;
- }
- }
- } else if (parent instanceof ForStatement) {
- for (Expression expr : ((ForStatement) parent).getForLoopVariables()) {
- if (expr instanceof TargetExpression && !processor.process(expr)) {
- return;
- }
- }
- } else if (parent instanceof StatementList) {
- if (!visitChildAssignmentStatements((BuildElement) parent, (Processor) processor)) {
- return;
- }
- }
- element = parent;
- }
- }
-
- /**
- * Walks up PSI tree of local file, checking PsiNamedElements
- */
- @Nullable
- public static PsiNamedElement findInScope(PsiElement element, String name) {
- PsiNamedElement[] resultHolder = new PsiNamedElement[1];
- Processor<BuildElement> processor = buildElement -> {
- if (buildElement == element) {
- return true;
- }
- if (buildElement instanceof PsiNamedElement && name.equals(buildElement.getName())) {
- resultHolder[0] = (PsiNamedElement) buildElement;
- return false;
- } else if (buildElement instanceof StringLiteral) {
- StringLiteral stringLiteral = (StringLiteral) buildElement;
- if (name.equals(stringLiteral.getStringContents())) {
- PsiElement referencedSymbol = stringLiteral.getReferencedElement();
- if (referencedSymbol instanceof PsiNamedElement) {
- resultHolder[0] = (PsiNamedElement) referencedSymbol;
- return false;
- }
- }
- }
- return true;
- };
- searchInScope(element, processor);
- return resultHolder[0];
- }
-
- /**
- * @return false if processing was stopped
- */
- public static boolean visitChildAssignmentStatements(BuildElement parent, Processor<TargetExpression> processor) {
- for (AssignmentStatement stmt : parent.childrenOfClass(AssignmentStatement.class)) {
- TargetExpression target = stmt.getLeftHandSideExpression();
- if (target != null && !processor.process(target)) {
- return false;
- }
- }
- return true;
- }
-
- @Nullable
- public static TargetExpression searchChildAssignmentStatements(BuildElement parent, String name) {
- TargetExpression[] resultHolder = new TargetExpression[1];
- visitChildAssignmentStatements(parent, targetExpr -> {
- if (name.equals(targetExpr.getName())) {
- resultHolder[0] = targetExpr;
- return false;
- }
- return true;
- });
- return resultHolder[0];
- }
-
- /**
- * @return false if processing was stopped
- */
- public static boolean visitLoadedSymbols(BuildFile file, Processor<BuildElement> processor) {
- for (LoadStatement loadStatement : file.findChildrenByClass(LoadStatement.class)) {
- for (StringLiteral symbol : loadStatement.getImportedSymbolElements()) {
- if (!processor.process(symbol)) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Checks if the element we're searching for is represented by a file or directory.<br>
- * e.g. a java class PSI element, or an actual PsiFile element.
- */
- @Nullable
- public static PsiFileSystemItem asFileSystemItemSearch(PsiElement elementToSearch) {
- if (elementToSearch instanceof PsiFileSystemItem) {
- return (PsiFileSystemItem) elementToSearch;
- }
- return asFileSearch(elementToSearch);
- }
-
- /**
- * Checks if the element we're searching for is represented by a file.<br>
- * e.g. a java class PSI element, or an actual PsiFile element.
- */
- @Nullable
- public static PsiFile asFileSearch(PsiElement elementToSearch) {
- if (elementToSearch instanceof PsiFile) {
- return (PsiFile) elementToSearch;
- }
- for (PsiFileProvider provider : PsiFileProvider.EP_NAME.getExtensions()) {
- PsiFile file = provider.asFileSearch(elementToSearch);
- if (file != null) {
- return file;
- }
- }
- return null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/sync/BuildLangSyncPlugin.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/sync/BuildLangSyncPlugin.java
deleted file mode 100644
index d4405bd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/sync/BuildLangSyncPlugin.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.sync;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.command.info.BlazeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
-import com.google.repackaged.protobuf.InvalidProtocolBufferException;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.concurrent.ExecutionException;
-
-/**
- * Updates the language specification during the blaze sync process
- */
-public class BuildLangSyncPlugin extends BlazeSyncPlugin.Adapter {
-
- private static final Logger LOG = Logger.getInstance(BuildLangSyncPlugin.class);
-
- @Override
- public void updateSyncState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
-
- LanguageSpecResult spec = getBuildLanguageSpec(project, workspaceRoot, previousSyncState, context);
- if (spec != null) {
- syncStateBuilder.put(LanguageSpecResult.class, spec);
- }
- }
-
- @Nullable
- private static LanguageSpecResult getBuildLanguageSpec(
- Project project,
- WorkspaceRoot workspace,
- @Nullable SyncState previousSyncState,
- BlazeContext parentContext) {
- LanguageSpecResult oldResult = previousSyncState != null ? previousSyncState.get(LanguageSpecResult.class) : null;
- if (oldResult != null && !oldResult.shouldRecalculateSpec()) {
- return oldResult;
- }
- LanguageSpecResult result = Scope.push(parentContext, (context) -> {
- context.push(new TimingScope("BUILD language spec"));
- BuildLanguageSpec spec = parseLanguageSpec(project, workspace, context);
- if (spec != null) {
- return new LanguageSpecResult(spec, System.currentTimeMillis());
- }
- return null;
- });
- return result != null ? result : oldResult;
- }
-
- @Nullable
- private static BuildLanguageSpec parseLanguageSpec(Project project, WorkspaceRoot workspace, BlazeContext context) {
- try {
- // it's wasteful converting to a string and back, but uses existing code, and has a very minor cost
- // (this is only run once per workspace)
- ListenableFuture<byte[]> future = BlazeInfo.getInstance()
- .runBlazeInfoGetBytes(context, Blaze.getBuildSystem(project), workspace, ImmutableList.of(), BlazeInfo.BUILD_LANGUAGE);
-
- return BuildLanguageSpec.fromProto(Build.BuildLanguage.parseFrom(future.get()));
-
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return null;
- } catch (ExecutionException | InvalidProtocolBufferException | NullPointerException e) {
- if (!ApplicationManager.getApplication().isUnitTestMode()) {
- LOG.error(e);
- }
- return null;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/sync/LanguageSpecResult.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/sync/LanguageSpecResult.java
deleted file mode 100644
index 1cd3886..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/sync/LanguageSpecResult.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.sync;
-
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-
-import java.io.Serializable;
-
-/**
- * The BUILD language specifications, serialized along with the sync data.
- */
-public class LanguageSpecResult implements Serializable {
-
- private static final long ONE_DAY_IN_MILLISECONDS = 1000 * 60 * 60;
-
- public final BuildLanguageSpec spec;
- public final long timestampMillis;
-
- public LanguageSpecResult(BuildLanguageSpec spec, long timestampMillis) {
- this.spec = spec;
- this.timestampMillis = timestampMillis;
- }
-
- public boolean shouldRecalculateSpec() {
- return System.currentTimeMillis() - timestampMillis > ONE_DAY_IN_MILLISECONDS;
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildAnnotator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildAnnotator.java
deleted file mode 100644
index c1ab33a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildAnnotator.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.validation;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementVisitor;
-import com.intellij.lang.annotation.AnnotationHolder;
-import com.intellij.lang.annotation.Annotator;
-import com.intellij.psi.PsiElement;
-
-/**
- * Base class for Annotator implementations using type-specific methods in BuildElementVisitor
- */
-public abstract class BuildAnnotator extends BuildElementVisitor implements Annotator {
-
- private volatile AnnotationHolder holder;
-
- protected AnnotationHolder getHolder() {
- return holder;
- }
-
- @Override
- public synchronized void annotate(PsiElement element, AnnotationHolder holder) {
- this.holder = holder;
- try {
- element.accept(this);
- } finally {
- this.holder = null;
- }
- }
-
- protected void markError(PsiElement element, String message) {
- getHolder().createErrorAnnotation(element, message);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/ErrorAnnotator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/ErrorAnnotator.java
deleted file mode 100644
index 2ae4808..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/ErrorAnnotator.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.validation;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.references.LabelReference;
-import com.intellij.psi.PsiElement;
-
-/**
- * Additional error annotations, post parsing.<p>
- * This has been turned off because it's unusable. BuildFile is re-parsed *every* time it's touched, and is never
- * cached. Until this is fixed, we can't run any annotators touching the file.<p>
- *
- * One option: try moving all expensive checks to 'visitFile', so they're not run in parallel
- */
-public class ErrorAnnotator extends BuildAnnotator {
-
- @Override
- public void visitLoadStatement(LoadStatement node) {
- StringLiteral[] strings = node.getChildStrings();
- if (strings.length == 0) {
- return;
- }
- PsiElement skylarkRef = new LabelReference(strings[0], false).resolve();
- if (skylarkRef == null) {
- markError(strings[0], "Cannot find this Skylark module");
- return;
- }
- if (!(skylarkRef instanceof BuildFile)) {
- markError(strings[0], strings[0].getText() + " is not a Skylark module");
- return;
- }
- if (strings.length == 1) {
- markError(node, "No definitions imported from Skylark module");
- return;
- }
- BuildFile skylarkModule = (BuildFile) skylarkRef;
- for (int i = 1; i < strings.length; i++) {
- String text = strings[i].getStringContents();
- FunctionStatement fn = skylarkModule.findDeclaredFunction(text);
- if (fn == null) {
- markError(strings[i], "Function '" + text + "' not found in Skylark module " + skylarkModule.getFileName());
- }
- }
- }
-
- @Override
- public void visitFuncallExpression(FuncallExpression node) {
- FunctionStatement function = (FunctionStatement) node.getReferencedElement();
- if (function == null) {
- // likely a built-in rule. We don't yet recognize these.
- return;
- }
- // check keyword args match function parameters
- ParameterList params = function.getParameterList();
- if (params == null || params.hasStarStar()) {
- return;
- }
- for (Argument arg : node.getArguments()) {
- if (arg instanceof Argument.Keyword) {
- String name = arg.getName();
- if (name != null && params.findParameterByName(name) == null) {
- markError(arg, "No parameter found in '" + node.getFunctionName() + "' with name '" + name + "'");
- }
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobErrorAnnotator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobErrorAnnotator.java
deleted file mode 100644
index f8fa833..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobErrorAnnotator.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.validation;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.psi.PsiElement;
-
-import javax.annotation.Nullable;
-
-/**
- * Checks that glob expressions are valid
- */
-public class GlobErrorAnnotator extends BuildAnnotator {
-
- @Override
- public void visitGlobExpression(GlobExpression node) {
- Argument[] args = node.getArguments();
- boolean hasIncludes = false;
- for (int i = 0; i < args.length; i++) {
- Argument arg = args[i];
- String name = arg instanceof Argument.Keyword ? arg.getName() : null;
- if ("include".equals(name) || (arg instanceof Argument.Positional && i == 0)) {
- hasIncludes = checkIncludes(arg.getValue());
- } else if ("exclude".equals(name)) {
- checkListContents("exclude", arg.getValue());
- } else if ("exclude_directories".equals(name)) {
- checkExcludeDirsNode(arg);
- } else {
- markError(arg, "Unrecognized glob argument");
- }
- }
- if (!hasIncludes) {
- markError(node, "Glob expression must contain at least one included string");
- }
- }
-
- private void checkExcludeDirsNode(Argument arg) {
- Expression value = arg.getValue();
- if (value == null || !(value.getText().equals("0") || value.getText().equals("1"))) {
- markError(arg, "exclude_directories parameter to glob must be 0 or 1");
- }
- }
-
- /**
- * @return true if glob contains at least one included string
- */
- private boolean checkIncludes(@Nullable Expression expr) {
- return checkListContents("include", expr);
- }
-
- /**
- * @return false if 'expr' is known with certainty not to be a list containing at least one string
- */
- private boolean checkListContents(String keyword, @Nullable Expression expr) {
- if (expr == null) {
- return false;
- }
- PsiElement rootElement = PsiUtils.getReferencedTargetValue(expr);
- if (rootElement instanceof ListLiteral) {
- return validatePatternList(keyword, ((ListLiteral) rootElement).getChildExpressions());
- }
- if (rootElement instanceof ReferenceExpression || !possiblyValidListLiteral(rootElement)) {
- markError(expr, "Glob parameter '" + keyword + "' must be a list of strings");
- return false;
- }
- // might possibly be a list, default to not showing any errors
- return true;
- }
-
- /**
- * @return false if 'expr' is known with certainty not to contain at least one string
- */
- private boolean validatePatternList(String keyword, Expression[] expressions) {
- boolean possiblyHasString = false;
- for (Expression expr : expressions) {
- PsiElement rootElement = PsiUtils.getReferencedTargetValue(expr);
- if (rootElement instanceof ReferenceExpression || !possiblyValidStringLiteral(rootElement)) {
- markError(expr, "Glob parameter '" + keyword + "' must be a list of strings");
- } else {
- possiblyHasString = true;
- if (rootElement instanceof StringLiteral) {
- validatePattern((StringLiteral) rootElement);
- }
- }
- }
- return possiblyHasString;
- }
-
- private void validatePattern(StringLiteral pattern) {
- String error = GlobPatternValidator.validate(pattern.getStringContents());
- if (error != null) {
- markError(pattern, error);
- }
- }
-
- /**
- * Returns false iff we know with certainty that the element cannot resolve to a list literal.
- */
- private static boolean possiblyValidListLiteral(PsiElement element) {
- if (element instanceof ListLiteral || element instanceof GlobExpression) {
- return true; // these evaluate directly to list literals
- }
- if (element instanceof LiteralExpression) {
- return false; // all other literals cannot evaluate to a ListLiteral
- }
- if (element instanceof LoadStatement
- || element instanceof FunctionStatement) {
- return false;
- }
- // everything else treated as possibly evaluating to a list
- return true;
- }
-
- /**
- * Returns false iff we know with certainty that the element cannot resolve to a string literal.
- */
- private static boolean possiblyValidStringLiteral(PsiElement element) {
- if (element instanceof StringLiteral ) {
- return true;
- }
- if (element instanceof LiteralExpression) {
- return false; // all other literals cannot evaluate to a StringLiteral
- }
- if (element instanceof LoadStatement
- || element instanceof FunctionStatement
- || element instanceof GlobExpression) {
- return false;
- }
- // everything else treated as possibly evaluating to a string
- return true;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobPatternValidator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobPatternValidator.java
deleted file mode 100644
index 46a0752..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/GlobPatternValidator.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.validation;
-
-import com.google.common.base.Splitter;
-
-import javax.annotation.Nullable;
-
-/**
- * Support for resolving globs.<p>
- */
-public class GlobPatternValidator {
-
- /**
- * Validate a single glob pattern. If it's invalid, returns an error message.
- * Otherwise, returns null.<p>
- */
- @Nullable
- public static String validate(String pattern) {
- String error = checkPatternForError(pattern);
- if (error != null) {
- return "Invalid glob pattern: " + error;
- }
- return null;
- }
-
- @Nullable
- private static String checkPatternForError(String pattern) {
- if (pattern.isEmpty()) {
- return "pattern cannot be empty";
- }
- if (pattern.charAt(0) == '/') {
- return "pattern cannot be absolute";
- }
- for (int i = 0; i < pattern.length(); i++) {
- char c = pattern.charAt(i);
- switch (c) {
- case '(': case ')':
- case '{': case '}':
- case '[': case ']':
- return "illegal character '" + c + "'";
- }
- }
- Iterable<String> segments = Splitter.on('/').split(pattern);
- for (String segment : segments) {
- if (segment.isEmpty()) {
- return "empty segment not permitted";
- }
- if (segment.equals(".") || segment.equals("..")) {
- return "segment '" + segment + "' not permitted";
- }
- if (segment.contains("**") && !segment.equals("**")) {
- return "recursive wildcard must be its own segment";
- }
- }
- return null;
- }
-
-
-
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/HighlightingAnnotator.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/HighlightingAnnotator.java
deleted file mode 100644
index 5f5a1bb..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/validation/HighlightingAnnotator.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.validation;
-
-import com.google.idea.blaze.base.lang.buildfile.highlighting.BuildSyntaxHighlighter;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.Parameter;
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.annotation.Annotation;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.util.PsiTreeUtil;
-
-/**
- * Additional syntax highlighting, based on parsed PSI elements
- * TODO: Special highlighting for blaze built-in names? (e.g. android_library) -- see PyBuiltInAnnotator
- */
-public class HighlightingAnnotator extends BuildAnnotator {
-
- @Override
- public void visitParameter(Parameter node) {
- FunctionStatement function = PsiTreeUtil.getParentOfType(node, FunctionStatement.class);
- if (function != null) {
- PsiElement anchor = node.hasDefaultValue() ? node.getFirstChild() : node;
- final Annotation annotation = getHolder().createInfoAnnotation(anchor, null);
- annotation.setTextAttributes(BuildSyntaxHighlighter.BUILD_PARAMETER);
- }
- }
-
- @Override
- public void visitKeywordArgument(Argument.Keyword node) {
- ASTNode keywordNode = node.getNameNode();
- if (keywordNode != null) {
- Annotation annotation = getHolder().createInfoAnnotation(keywordNode, null);
- annotation.setTextAttributes(BuildSyntaxHighlighter.BUILD_KEYWORD_ARG);
- }
- }
-
- @Override
- public void visitFunctionStatement(FunctionStatement node) {
- ASTNode nameNode = node.getNameNode();
- if (nameNode != null) {
- Annotation annotation = getHolder().createInfoAnnotation(nameNode, null);
- annotation.setTextAttributes(BuildSyntaxHighlighter.BUILD_FN_DEFINITION);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewElement.java
deleted file mode 100644
index 2042ef9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewElement.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.views;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.ListLiteral;
-import com.intellij.ide.structureView.StructureViewTreeElement;
-import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-
-/**
- * Handles nodes in Structure View.
- */
-public class BuildStructureViewElement extends PsiTreeElementBase<BuildElement> {
-
- private final BuildElement element;
-
- public BuildStructureViewElement(BuildElement element) {
- super(element);
- this.element = element;
- }
-
- @NotNull
- @Override
- public Collection<StructureViewTreeElement> getChildrenBase() {
- if (element instanceof ListLiteral) {
-
- }
- if (!(element instanceof BuildFile)) {
- // TODO: show inner build rules in Skylark .bzl extensions
- return ImmutableList.of();
- }
- ImmutableList.Builder<StructureViewTreeElement> builder = ImmutableList.builder();
- for (BuildElement child : ((BuildFile) element).findChildrenByClass(BuildElement.class)) {
- builder.add(new BuildStructureViewElement(child));
- }
- return builder.build();
- }
-
- @Nullable
- @Override
- public String getPresentableText() {
- return element.getPresentableText();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewFactory.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewFactory.java
deleted file mode 100644
index 3bf0369..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.views;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.ide.structureView.StructureViewBuilder;
-import com.intellij.ide.structureView.StructureViewModel;
-import com.intellij.ide.structureView.TreeBasedStructureViewBuilder;
-import com.intellij.lang.PsiStructureViewFactory;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.psi.PsiFile;
-
-import javax.annotation.Nullable;
-
-/**
- * PsiStructureViewFactory implementation
- */
-public class BuildStructureViewFactory implements PsiStructureViewFactory {
- @Override
- @Nullable
- public StructureViewBuilder getStructureViewBuilder(final PsiFile psiFile) {
- if (!(psiFile instanceof BuildFile)) {
- return null;
- }
- return new TreeBasedStructureViewBuilder() {
- @Override
- public StructureViewModel createStructureViewModel(@Nullable Editor editor) {
- return new BuildStructureViewModel((BuildFile) psiFile, editor);
- }
- };
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewModel.java b/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewModel.java
deleted file mode 100644
index 5ce32dd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/buildfile/views/BuildStructureViewModel.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.views;
-
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.intellij.ide.structureView.StructureViewModel;
-import com.intellij.ide.structureView.StructureViewModelBase;
-import com.intellij.ide.structureView.StructureViewTreeElement;
-import com.intellij.ide.util.treeView.smartTree.Sorter;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.psi.PsiFile;
-
-import javax.annotation.Nullable;
-
-/**
- * Implements structure view for a BUILD file.
- * TODO: Include inner build rules for Skylark files (when we can identify them -- e.g. via list of blaze rule types)
- */
-public class BuildStructureViewModel extends StructureViewModelBase
- implements StructureViewModel.ElementInfoProvider, StructureViewModel.ExpandInfoProvider {
-
- public BuildStructureViewModel(BuildFile psiFile, @Nullable Editor editor) {
- this(psiFile, editor, new BuildStructureViewElement(psiFile));
- withSorters(Sorter.ALPHA_SORTER);
- withSuitableClasses(FunctionStatement.class, LoadStatement.class, FuncallExpression.class);
- }
-
- public BuildStructureViewModel(PsiFile file, @Nullable Editor editor, StructureViewTreeElement element) {
- super(file, editor, element);
- }
-
- @Override
- public boolean isAlwaysShowsPlus(StructureViewTreeElement element) {
- final Object value = element.getValue();
- return value instanceof BuildFile;
- }
-
- @Override
- public boolean isAlwaysLeaf(StructureViewTreeElement element) {
- return element.getValue() instanceof TargetExpression;
- }
-
- @Override
- public boolean shouldEnterElement(Object element) {
- return element instanceof BuildFile; // only show top-level elements
- }
-
- @Override
- public boolean isAutoExpand(StructureViewTreeElement element) {
- return element.getValue() instanceof PsiFile;
- }
-
- @Override
- public boolean isSmartExpand() {
- return false;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/AdditionalLanguagesCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/AdditionalLanguagesCompletionContributor.java
deleted file mode 100644
index 10184a9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/AdditionalLanguagesCompletionContributor.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.completion;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiListSection;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.patterns.StandardPatterns;
-import com.intellij.util.ProcessingContext;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * Code completion for additional language types.
- */
-public class AdditionalLanguagesCompletionContributor extends CompletionContributor {
-
- @Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
- // auto-insert the obvious only case; else show other cases.
- final LookupElement[] items = context.getItems();
- if (items.length == 1) {
- return AutoCompletionDecision.insertItem(items[0]);
- }
- return AutoCompletionDecision.SHOW_LOOKUP;
- }
-
- public AdditionalLanguagesCompletionContributor() {
- extend(
- CompletionType.BASIC,
- psiElement()
- .withLanguage(ProjectViewLanguage.INSTANCE)
- .inside(
- psiElement(ProjectViewPsiListSection.class)
- .withText(StandardPatterns.string().startsWith(AdditionalLanguagesSection.KEY.getName()))),
- new CompletionProvider<CompletionParameters>() {
- @Override
- protected void addCompletions(CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
- for (LanguageClass type : LanguageClass.values()) {
- result.addElement(LookupElementBuilder.create(type.getName()));
- }
- }
- }
- );
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/ProjectViewKeywordCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/ProjectViewKeywordCompletionContributor.java
deleted file mode 100644
index 41d9ad9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/ProjectViewKeywordCompletionContributor.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.completion;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.google.idea.blaze.base.projectview.section.ListSectionParser;
-import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.projectview.section.sections.Sections;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.util.ProcessingContext;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * Completes project view section names.
- */
-public class ProjectViewKeywordCompletionContributor extends CompletionContributor {
-
- @Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
- // auto-insert the obvious only case; else show other cases.
- final LookupElement[] items = context.getItems();
- if (items.length == 1) {
- return AutoCompletionDecision.insertItem(items[0]);
- }
- return AutoCompletionDecision.SHOW_LOOKUP;
- }
-
- public ProjectViewKeywordCompletionContributor() {
- extend(
- CompletionType.BASIC,
- psiElement()
- .withLanguage(ProjectViewLanguage.INSTANCE)
- .withElementType(ProjectViewTokenType.IDENTIFIERS)
- .andOr(
- psiElement().afterLeaf("\n"),
- psiElement().afterLeaf(psiElement().isNull())
- ),
- new CompletionProvider<CompletionParameters>() {
- @Override
- protected void addCompletions(CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
- result.addAllElements(keywordLookups);
- }
- }
- );
- }
-
- private static final List<LookupElement> keywordLookups = getLookups();
-
- private static List<LookupElement> getLookups() {
- ImmutableList.Builder<LookupElement> list = ImmutableList.builder();
- for (SectionParser parser : Sections.getUndeprecatedParsers()) {
- list.add(forSectionParser(parser));
- }
- return list.build();
- }
-
- private static LookupElement forSectionParser(SectionParser parser) {
- return LookupElementBuilder.create(parser.getName())
- .withInsertHandler(insertDivider(parser));
- }
-
- private static InsertHandler<LookupElement> insertDivider(SectionParser parser) {
- return (context, item) -> {
- Editor editor = context.getEditor();
- Document document = editor.getDocument();
- context.commitDocument();
-
- String nextTokenText = findNextTokenText(context);
- if (nextTokenText == null || nextTokenText == "\n") {
- document.insertString(context.getTailOffset(), getDivider(parser));
- editor.getCaretModel().moveToOffset(context.getTailOffset());
- }
- };
- }
-
- private static String getDivider(SectionParser parser) {
- if (parser instanceof ListSectionParser) {
- return ":\n ";
- }
- char div = ((ScalarSectionParser) parser).getDivider();
- return div == ' ' ? String.valueOf(div) : (div + " ");
- }
-
- @Nullable
- protected static String findNextTokenText(final InsertionContext context) {
- final PsiFile file = context.getFile();
- PsiElement element = file.findElementAt(context.getTailOffset());
- while (element != null && element.getTextLength() == 0) {
- ASTNode next = element.getNode().getTreeNext();
- element = next != null ? next.getPsi() : null;
- }
- return element != null ? element.getText() : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/WorkspaceTypeCompletionContributor.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/WorkspaceTypeCompletionContributor.java
deleted file mode 100644
index ffb2c85..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/completion/WorkspaceTypeCompletionContributor.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.completion;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiScalarSection;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
-import com.intellij.codeInsight.completion.*;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.util.ProcessingContext;
-
-import static com.intellij.patterns.PlatformPatterns.psiElement;
-
-/**
- * Code completion for workspace types.
- */
-public class WorkspaceTypeCompletionContributor extends CompletionContributor {
-
- @Override
- public AutoCompletionDecision handleAutoCompletionPossibility(AutoCompletionContext context) {
- // auto-insert the obvious only case; else show other cases.
- final LookupElement[] items = context.getItems();
- if (items.length == 1) {
- return AutoCompletionDecision.insertItem(items[0]);
- }
- return AutoCompletionDecision.SHOW_LOOKUP;
- }
-
- public WorkspaceTypeCompletionContributor() {
- extend(
- CompletionType.BASIC,
- psiElement()
- .withLanguage(ProjectViewLanguage.INSTANCE)
- .inside(ProjectViewPsiScalarSection.class)
- .afterLeaf(psiElement().withText(":").afterLeaf(WorkspaceTypeSection.KEY.getName())),
- new CompletionProvider<CompletionParameters>() {
- @Override
- protected void addCompletions(CompletionParameters parameters, ProcessingContext context, CompletionResultSet result) {
- for (WorkspaceType type : WorkspaceType.values()) {
- result.addElement(LookupElementBuilder.create(type.getName()));
- }
- }
- }
- );
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCommenter.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCommenter.java
deleted file mode 100644
index fb00ab6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCommenter.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.formatting;
-
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.intellij.lang.CodeDocumentationAwareCommenter;
-import com.intellij.psi.PsiComment;
-import com.intellij.psi.tree.IElementType;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Supports (un)commenting lines via IntelliJ
- */
-public class ProjectViewCommenter implements CodeDocumentationAwareCommenter {
-
- @Nullable
- @Override
- public String getLineCommentPrefix() {
- return "#";
- }
-
- @Nullable
- @Override
- public String getBlockCommentPrefix() {
- return null;
- }
-
- @Nullable
- @Override
- public String getBlockCommentSuffix() {
- return null;
- }
-
- @Nullable
- @Override
- public String getCommentedBlockCommentPrefix() {
- return null;
- }
-
- @Nullable
- @Override
- public String getCommentedBlockCommentSuffix() {
- return null;
- }
-
- @Override
- public IElementType getLineCommentTokenType() {
- return ProjectViewTokenType.COMMENT;
- }
-
- @Override
- public IElementType getBlockCommentTokenType() {
- return null;
- }
-
- @Override
- public IElementType getDocumentationCommentTokenType() {
- return null;
- }
-
- @Override
- public String getDocumentationCommentPrefix() {
- return null;
- }
-
- @Override
- public String getDocumentationCommentLinePrefix() {
- return null;
- }
-
- @Override
- public String getDocumentationCommentSuffix() {
- return null;
- }
-
- @Override
- public boolean isDocumentationComment(PsiComment element) {
- return false;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewEnterHandler.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewEnterHandler.java
deleted file mode 100644
index 6afd0b9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewEnterHandler.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.formatting;
-
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiFile;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter;
-import com.intellij.ide.DataManager;
-import com.intellij.injected.editor.EditorWindow;
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.injection.InjectedLanguageManager;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.LogicalPosition;
-import com.intellij.openapi.editor.actionSystem.EditorActionHandler;
-import com.intellij.openapi.editor.actions.SplitLineAction;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiWhiteSpace;
-import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
-
-/**
- * Inserts indents as appropriate when enter is pressed.
- */
-public class ProjectViewEnterHandler extends EnterHandlerDelegateAdapter {
-
- @Override
- public Result preprocessEnter(PsiFile file,
- Editor editor,
- Ref<Integer> caretOffset,
- Ref<Integer> caretAdvance,
- DataContext dataContext,
- EditorActionHandler originalHandler) {
- int offset = caretOffset.get();
- if (editor instanceof EditorWindow) {
- file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file);
- editor = InjectedLanguageUtil.getTopLevelEditor(editor);
- offset = editor.getCaretModel().getOffset();
- }
- if (!isApplicable(file, dataContext) || !insertIndent(file, offset)) {
- return Result.Continue;
- }
- int indent = SectionParser.INDENT;
-
- editor.getCaretModel().moveToOffset(offset);
- Document doc = editor.getDocument();
- PsiDocumentManager.getInstance(file.getProject()).commitDocument(doc);
-
-
- originalHandler.execute(editor, editor.getCaretModel().getCurrentCaret(), dataContext);
- LogicalPosition position = editor.getCaretModel().getLogicalPosition();
- if (position.column < indent) {
- String spaces = StringUtil.repeatSymbol(' ', indent - position.column);
- doc.insertString(editor.getCaretModel().getOffset(), spaces);
- }
- editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(position.line, indent));
- return Result.Stop;
- }
-
- private static boolean isApplicable(PsiFile file, DataContext dataContext) {
- if (!(file instanceof ProjectViewPsiFile)) {
- return false;
- }
- Boolean isSplitLine = DataManager.getInstance().loadFromDataContext(dataContext, SplitLineAction.SPLIT_LINE_KEY);
- if (isSplitLine != null) {
- return false;
- }
- return true;
- }
-
- private static boolean insertIndent(PsiFile file, int offset) {
- if (offset == 0) {
- return false;
- }
- PsiElement element = file.findElementAt(offset - 1);
- while (element != null && element instanceof PsiWhiteSpace) {
- element = element.getPrevSibling();
- }
- if (element == null || element.getText() != ":") {
- return false;
- }
- ASTNode prev = element.getNode().getTreePrev();
- return prev != null && prev.getElementType() == ProjectViewTokenType.LIST_KEYWORD;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighter.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighter.java
deleted file mode 100644
index 6653e00..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.highlighting;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexer;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.intellij.lexer.Lexer;
-import com.intellij.openapi.editor.colors.TextAttributesKey;
-import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
-import com.intellij.psi.tree.IElementType;
-
-import java.util.Map;
-
-import static com.intellij.openapi.editor.DefaultLanguageHighlighterColors.*;
-
-/**
- * This class maps tokens to highlighting attributes. Each attribute contains the font properties.
- */
-public class ProjectViewSyntaxHighlighter extends SyntaxHighlighterBase {
-
- private static final Map<IElementType, TextAttributesKey> keys = ImmutableMap.of(
- ProjectViewTokenType.COMMENT, LINE_COMMENT,
- ProjectViewTokenType.COLON, SEMICOLON,
- ProjectViewTokenType.IDENTIFIER, IDENTIFIER,
- ProjectViewTokenType.LIST_KEYWORD, KEYWORD,
- ProjectViewTokenType.SCALAR_KEYWORD, KEYWORD
- );
-
- @Override
- public Lexer getHighlightingLexer() {
- return new ProjectViewLexer();
- }
-
- @Override
- public TextAttributesKey[] getTokenHighlights(IElementType iElementType) {
- return pack(keys.get(iElementType));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighterFactory.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighterFactory.java
deleted file mode 100644
index b1166f8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/highlighting/ProjectViewSyntaxHighlighterFactory.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.highlighting;
-
-import com.intellij.openapi.fileTypes.SyntaxHighlighter;
-import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-
-/**
- * Factory for BuildSyntaxHighlighter
- */
-public class ProjectViewSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
-
- @Override
- public SyntaxHighlighter getSyntaxHighlighter(Project project, VirtualFile virtualFile) {
- return new ProjectViewSyntaxHighlighter();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileType.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileType.java
deleted file mode 100644
index d372937..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileType.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.language;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.fileTypes.LanguageFileType;
-import icons.BlazeIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * Blaze project view file type
- */
-public class ProjectViewFileType extends LanguageFileType {
-
- public static final ProjectViewFileType INSTANCE = new ProjectViewFileType();
-
-
- private ProjectViewFileType() {
- super(ProjectViewLanguage.INSTANCE);
- }
-
- @Override
- public String getName() {
- // Warning: this is conflated with Language.myID in several places...
- // They must be identical.
- return ProjectViewLanguage.INSTANCE.getID();
- }
-
- @Override
- public String getDescription() {
- return Blaze.defaultBuildSystemName() + " project view files";
- }
-
- @Override
- public String getDefaultExtension() {
- // Ideally we'd return a build-system specific extension here, but that would require
- // a hack to guess the current project, or choosing either the blaze or bazel
- // extension. Instead don't specify a default extension.
- return "";
- }
-
- @Override
- @Nullable
- public Icon getIcon() {
- return BlazeIcons.Blaze;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileTypeFactory.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileTypeFactory.java
deleted file mode 100644
index 73b2605..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewFileTypeFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.language;
-
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.intellij.openapi.fileTypes.ExtensionFileNameMatcher;
-import com.intellij.openapi.fileTypes.FileNameMatcher;
-import com.intellij.openapi.fileTypes.FileTypeConsumer;
-import com.intellij.openapi.fileTypes.FileTypeFactory;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Factory for ProjectViewFileType
- */
-public class ProjectViewFileTypeFactory extends FileTypeFactory {
-
- @Override
- public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
- FileNameMatcher[] matchers = ProjectViewStorageManager.VALID_EXTENSIONS.stream()
- .map(ExtensionFileNameMatcher::new)
- .toArray(ExtensionFileNameMatcher[]::new);
- consumer.consume(ProjectViewFileType.INSTANCE, matchers);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewKeywords.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewKeywords.java
deleted file mode 100644
index e22a838..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewKeywords.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.language;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.projectview.section.ListSectionParser;
-import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionParser.ItemType;
-import com.google.idea.blaze.base.projectview.section.sections.Sections;
-
-/**
- * Section parser keywords accepted in project view files.
- */
-public class ProjectViewKeywords {
-
- public static final ImmutableMap<String, ListSectionParser> LIST_KEYWORD_MAP = getListKeywordMap();
- public static final ImmutableMap<String, ScalarSectionParser> SCALAR_KEYWORD_MAP = getScalarKeywordMap();
- public static final ImmutableMap<String, ItemType> ITEM_TYPES = getItemTypes();
-
- private static ImmutableMap<String, ListSectionParser> getListKeywordMap() {
- ImmutableMap.Builder<String, ListSectionParser> builder = ImmutableMap.builder();
- for (SectionParser parser : Sections.getParsers()) {
- if (parser instanceof ListSectionParser) {
- builder.put(parser.getName(), (ListSectionParser) parser);
- }
- }
- return builder.build();
- }
-
- /**
- * We get the parser so we have access to both the keyword and the divider char.
- */
- private static ImmutableMap<String, ScalarSectionParser> getScalarKeywordMap() {
- ImmutableMap.Builder<String, ScalarSectionParser> builder = ImmutableMap.builder();
- for (SectionParser parser : Sections.getParsers()) {
- if (parser instanceof ScalarSectionParser) {
- builder.put(parser.getName(), (ScalarSectionParser) parser);
- }
- }
- return builder.build();
- }
-
- private static ImmutableMap<String, ItemType> getItemTypes() {
- ImmutableMap.Builder<String, ItemType> builder = ImmutableMap.builder();
- for (SectionParser parser : Sections.getParsers()) {
- builder.put(parser.getName(), parser.getItemType());
- }
- return builder.build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewLanguage.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewLanguage.java
deleted file mode 100644
index e0ded02..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/language/ProjectViewLanguage.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.language;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.lang.Language;
-
-/**
- * Blaze project file language
- */
-public class ProjectViewLanguage extends Language {
-
- public static final ProjectViewLanguage INSTANCE = new ProjectViewLanguage();
-
- private ProjectViewLanguage() {
- super("projectview");
- }
-
- @Override
- public String getDisplayName() {
- return Blaze.defaultBuildSystemName() + " project view";
- }
-
- @Override
- public boolean isCaseSensitive() {
- return true;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexer.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexer.java
deleted file mode 100644
index 783a692..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexer.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.lexer;
-
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexerBase.Token;
-import com.intellij.lexer.LexerBase;
-import com.intellij.psi.tree.IElementType;
-
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Implementation of LexerBase using BuildLexerBase to tokenize the input.
- */
-public class ProjectViewLexer extends LexerBase {
-
- private int offsetEnd;
- private int offsetStart;
- private CharSequence buffer;
- private Iterator<Token> tokens;
- private Token currentToken;
-
- @Override
- public void start(CharSequence charSequence, int startOffset, int endOffset, int initialState) {
- buffer = charSequence;
- this.offsetEnd = endOffset;
- this.offsetStart = startOffset;
-
- ProjectViewLexerBase lexer = new ProjectViewLexerBase(charSequence.subSequence(startOffset, endOffset));
- checkNoCharactersMissing(charSequence.subSequence(startOffset, endOffset).length(), lexer.getTokens());
- tokens = lexer.getTokens().iterator();
- currentToken = null;
- if (tokens.hasNext()) {
- currentToken = tokens.next();
- }
- }
-
- /**
- * Temporary debugging code. We need to tokenize every character in the input string.
- */
- private static void checkNoCharactersMissing(int totalLength, List<Token> tokens) {
- if (!tokens.isEmpty() && tokens.get(tokens.size() - 1).right != totalLength) {
- String error = String.format("Lengths don't match: %s instead of %s",
- tokens.get(tokens.size() - 1).right,
- totalLength);
- throw new RuntimeException(error);
- }
- int start = 0;
- for (int i = 0; i < tokens.size(); i++) {
- Token token = tokens.get(i);
- if (token.left != start) {
- throw new RuntimeException("Gap/inconsistency at: " + start);
- }
- start = token.right;
- }
- }
-
-
- @Override
- public int getState() {
- return 0;
- }
-
- @Override
- public IElementType getTokenType() {
- if (currentToken != null) {
- return currentToken.type;
- }
- return null;
- }
-
- @Override
- public int getTokenStart() {
- if (currentToken == null) {
- return 0;
- }
- return currentToken.left + offsetStart;
- }
-
- @Override
- public int getTokenEnd() {
- if (currentToken == null) {
- return 0;
- }
- return currentToken.right + offsetStart;
- }
-
- @Override
- public void advance() {
- if (tokens.hasNext()) {
- currentToken = tokens.next();
- } else {
- currentToken = null;
- }
- }
-
- @Override
- public CharSequence getBufferSequence() {
- return buffer;
- }
-
- @Override
- public int getBufferEnd() {
- return offsetEnd;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerBase.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerBase.java
deleted file mode 100644
index 3a6378b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerBase.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.lexer;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewKeywords;
-
-import java.util.List;
-
-/**
- * Lexer for project view files.
- */
-public class ProjectViewLexerBase {
-
- @VisibleForTesting
- static class Token {
- final ProjectViewTokenType type;
- final int left;
- final int right;
-
- private Token(ProjectViewTokenType type, int left, int right) {
- this.type = type;
- this.left = left;
- this.right = right;
- }
- }
-
- private final List<Token> tokens;
-
- // Input buffer and position
- private final char[] buffer;
- private int pos;
-
- private int identifierStart = -1;
- private boolean lineHasPrecedingNonWhitespaceChar = false;
-
- public ProjectViewLexerBase(CharSequence input) {
- this.buffer = input.toString().toCharArray();
- this.tokens = Lists.newArrayList();
- this.pos = 0;
- tokenize();
- }
-
- public List<Token> getTokens() {
- return tokens;
- }
-
- /**
- * Performs tokenization of the character buffer of file contents provided to
- * the constructor.
- */
- private void tokenize() {
- while (pos < buffer.length) {
- char c = buffer[pos];
- pos++;
- switch (c) {
- case '\n':
- addPrecedingIdentifier(pos - 1);
- tokens.add(new Token(ProjectViewTokenType.NEWLINE, pos - 1, pos));
- lineHasPrecedingNonWhitespaceChar = false;
- break;
- case ' ':
- case '\t':
- case '\r':
- addPrecedingIdentifier(pos - 1);
- handleWhitespace();
- break;
- case ':':
- addPrecedingIdentifier(pos - 1);
- tokens.add(new Token(ProjectViewTokenType.COLON, pos - 1, pos));
- break;
- case '#':
- if (!lineHasPrecedingNonWhitespaceChar) {
- addPrecedingIdentifier(pos - 1);
- addCommentLine(pos - 1);
- break;
- }
- // otherwise '#' treated as part of the identifier; intentional fall-through
- default:
- lineHasPrecedingNonWhitespaceChar = true;
- // all other characters combined into an 'identifier' lexical token
- if (identifierStart == -1) {
- identifierStart = pos - 1;
- }
- }
- }
- addPrecedingIdentifier(pos);
- }
-
- private void addPrecedingIdentifier(int end) {
- if (identifierStart != -1) {
- tokens.add(new Token(getIdentifierToken(identifierStart, end), identifierStart, end));
- identifierStart = -1;
- }
- }
-
- private void addCommentLine(int start) {
- while (pos < buffer.length) {
- char c = buffer[pos];
- if (c == '\n') {
- break;
- }
- pos++;
- }
- tokens.add(new Token(ProjectViewTokenType.COMMENT, start, pos));
- }
-
- /**
- * If the whitespace is followed by an end-of-line comment or a newline, it's combined with those
- * tokens.
- */
- private void handleWhitespace() {
- int oldPos = pos - 1;
- while (pos < buffer.length) {
- char c = buffer[pos];
- switch (c) {
- case ' ': case '\t': case '\r':
- pos++;
- break;
- default:
- if (lineHasPrecedingNonWhitespaceChar || c == '#' || c == '\n') {
- tokens.add(new Token(ProjectViewTokenType.WHITESPACE, oldPos, pos));
- } else {
- tokens.add(new Token(ProjectViewTokenType.INDENT, oldPos, pos));
- }
- return;
- }
- }
- tokens.add(new Token(ProjectViewTokenType.WHITESPACE, oldPos, pos));
- }
-
- private ProjectViewTokenType getIdentifierToken(int start, int end) {
- String string = bufferSlice(start, end);
- if (ProjectViewKeywords.LIST_KEYWORD_MAP.keySet().contains(string)) {
- return ProjectViewTokenType.LIST_KEYWORD;
- }
- if (ProjectViewKeywords.SCALAR_KEYWORD_MAP.keySet().contains(string)) {
- return ProjectViewTokenType.SCALAR_KEYWORD;
- }
- return ProjectViewTokenType.IDENTIFIER;
- }
-
-
- private String bufferSlice(int start, int end) {
- return new String(this.buffer, start, end - start);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewTokenType.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewTokenType.java
deleted file mode 100644
index 80f7495..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewTokenType.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.lexer;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.tree.TokenSet;
-
-/**
- * Lexical elements for the project view language.
- */
-public class ProjectViewTokenType extends IElementType {
-
- // only start-of-line (ignoring whitespace) comments are valid
- public static final ProjectViewTokenType COMMENT = create("comment");
- public static final ProjectViewTokenType WHITESPACE = create("whitespace");
- public static final ProjectViewTokenType NEWLINE = create("newline");
- public static final ProjectViewTokenType COLON = create(":");
-
- // any amount of whitespace at the start of a line, followed by a non-'#', non-newline character
- public static final ProjectViewTokenType INDENT = create("indent");
-
- // all remaining characters that aren't preceded by a start-of-line comments
- public static final ProjectViewTokenType IDENTIFIER = create("identifier");
-
- public static final ProjectViewTokenType LIST_KEYWORD = create("list_keyword");
- public static final ProjectViewTokenType SCALAR_KEYWORD = create("scalar_keyword");
-
- private static ProjectViewTokenType create(String debugName) {
- return new ProjectViewTokenType(debugName);
- }
-
- private ProjectViewTokenType(String debugName) {
- super(debugName, ProjectViewLanguage.INSTANCE);
- }
-
- public static final TokenSet IDENTIFIERS = TokenSet.create(IDENTIFIER, LIST_KEYWORD, SCALAR_KEYWORD);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewParserDefinition.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewParserDefinition.java
deleted file mode 100644
index 902f6e3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewParserDefinition.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.parser;
-
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexer;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementType;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementTypes;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiFile;
-import com.intellij.extapi.psi.ASTWrapperPsiElement;
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.ParserDefinition;
-import com.intellij.lang.PsiBuilder;
-import com.intellij.lang.PsiParser;
-import com.intellij.lexer.Lexer;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.FileViewProvider;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.tree.IFileElementType;
-import com.intellij.psi.tree.TokenSet;
-
-/**
- * Defines the project view file parser
- */
-public class ProjectViewParserDefinition implements ParserDefinition {
-
- @Override
- public Lexer createLexer(Project project) {
- return new ProjectViewLexer();
- }
-
- @Override
- public PsiParser createParser(Project project) {
- return (root, builder) -> {
- PsiBuilder.Marker rootMarker = builder.mark();
- new ProjectViewPsiParser(builder).parseFile();
- rootMarker.done(root);
- return builder.getTreeBuilt();
- };
- }
-
- @Override
- public IFileElementType getFileNodeType() {
- return ProjectViewElementTypes.FILE;
- }
-
- @Override
- public TokenSet getWhitespaceTokens() {
- return TokenSet.create(ProjectViewTokenType.WHITESPACE);
- }
-
- @Override
- public TokenSet getCommentTokens() {
- return TokenSet.create(ProjectViewTokenType.COMMENT);
- }
-
- @Override
- public TokenSet getStringLiteralElements() {
- return TokenSet.EMPTY;
- }
-
- @Override
- public PsiElement createElement(ASTNode node) {
- IElementType type = node.getElementType();
- if (type instanceof ProjectViewElementType) {
- return ((ProjectViewElementType) type).createElement(node);
- }
- return new ASTWrapperPsiElement(node);
- }
-
- @Override
- public PsiFile createFile(FileViewProvider viewProvider) {
- return new ProjectViewPsiFile(viewProvider);
- }
-
- @Override
- public SpaceRequirements spaceExistanceTypeBetweenTokens(ASTNode left, ASTNode right) {
- return null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewPsiParser.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewPsiParser.java
deleted file mode 100644
index 2dcc3ea..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/parser/ProjectViewPsiParser.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.parser;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewKeywords;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementType;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewElementTypes;
-import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
-import com.intellij.lang.PsiBuilder;
-
-import javax.annotation.Nullable;
-
-/**
- * Project view psi parser.
- */
-public class ProjectViewPsiParser {
-
- private final PsiBuilder builder;
-
- public ProjectViewPsiParser(PsiBuilder builder) {
- this.builder = builder;
- }
-
- public void parseFile() {
- builder.setDebugMode(true);
- while (!builder.eof()) {
- if (matches(ProjectViewTokenType.NEWLINE)) {
- continue;
- }
- parseSection();
- }
- }
-
- /**
- * A block is one of:
- * - scalar section
- * - list section
- */
- private void parseSection() {
- PsiBuilder.Marker marker = builder.mark();
- if (matches(ProjectViewTokenType.LIST_KEYWORD)) {
- expect(ProjectViewTokenType.COLON);
- skipPastNewline();
- parseListItems();
- marker.done(ProjectViewElementTypes.LIST_SECTION);
- return;
- }
- if (currentToken() == ProjectViewTokenType.SCALAR_KEYWORD) {
- ScalarSectionParser parser = ProjectViewKeywords.SCALAR_KEYWORD_MAP.get(builder.getTokenText());
- if (parser != null) {
- parseScalarSection(parser);
- marker.done(ProjectViewElementTypes.SCALAR_SECTION);
- return;
- }
- }
- // handle each of the error cases
- if (matches(ProjectViewTokenType.INDENT)) {
- skipBlockAndError(marker, "Invalid indentation. Indented lines must be preceded by a list keyword");
- return;
- }
- if (matches(ProjectViewTokenType.COLON)) {
- skipBlockAndError(marker, "Invalid section: lines cannot begin with a colon.");
- return;
- }
- skipBlockAndError(marker, "Unrecognized keyword: " + builder.getTokenText());
- }
-
- private void parseListItems() {
- while (!builder.eof()) {
- if (matches(ProjectViewTokenType.NEWLINE)) {
- continue;
- }
- if (!matches(ProjectViewTokenType.INDENT)) {
- return;
- }
- PsiBuilder.Marker marker = builder.mark();
- skipToNewlineToken();
- marker.done(ProjectViewElementTypes.LIST_ITEM);
- builder.advanceLexer();
- }
- }
-
- private void parseScalarSection(ScalarSectionParser parser) {
- boolean whitespaceDivider = builder.rawLookup(1) == ProjectViewTokenType.WHITESPACE;
- builder.advanceLexer();
-
- char divider = parser.getDivider();
- if (divider == ' ') {
- if (!whitespaceDivider) {
- builder.error("Whitespace divider expected after '" + parser.getName() + "'");
- builder.advanceLexer();
- }
- parseScalarItem();
- return;
- }
- if (whitespaceDivider || !Character.toString(divider).equals(builder.getTokenText())) {
- builder.error(String.format("'%s' expected", divider));
- }
- if (!whitespaceDivider) {
- builder.advanceLexer();
- }
- parseScalarItem();
- }
-
- private void parseScalarItem() {
- PsiBuilder.Marker marker = builder.mark();
- skipToNewlineToken();
- marker.done(ProjectViewElementTypes.SCALAR_ITEM);
- builder.advanceLexer();
- }
-
- /**
- * Consumes the current token iff it matches the expected type. Otherwise, returns false
- */
- private boolean matches(ProjectViewTokenType kind) {
- if (currentToken() == kind) {
- builder.advanceLexer();
- return true;
- }
- return false;
- }
-
- /**
- * Consumes the current token if it's of the expected type. Otherwise, returns false and reports an error.
- */
- private boolean expect(ProjectViewTokenType kind) {
- if (matches(kind)) {
- return true;
- }
- builder.error(String.format("'%s' expected", kind));
- return false;
- }
-
- /**
- * Checks if the upcoming sequence of tokens match that expected. Doesn't advance the parser.
- */
- private boolean atTokenSequence(ProjectViewTokenType... kinds) {
- for (int i = 0; i < kinds.length; i++) {
- if (builder.lookAhead(i) != kinds[i]) {
- return false;
- }
- }
- return true;
- }
-
- @Nullable
- private ProjectViewTokenType currentToken() {
- return (ProjectViewTokenType) builder.getTokenType();
- }
-
- private void skipBlockAndError(PsiBuilder.Marker marker, String message) {
- skipToNextBlock();
- marker.error(message);
- }
-
- /**
- * Skip to the start of the next unindented line
- */
- private void skipToNextBlock() {
- while (!builder.eof()) {
- if (atTokenSequence(ProjectViewTokenType.NEWLINE, ProjectViewTokenType.IDENTIFIER)) {
- builder.advanceLexer();
- return;
- }
- builder.advanceLexer();
- }
- }
-
- /**
- * Skip to the start of the next line
- */
- private void skipPastNewline() {
- while (!builder.eof()) {
- if (matches(ProjectViewTokenType.NEWLINE)) {
- return;
- }
- builder.advanceLexer();
- }
- }
-
- /**
- * Skip to the end of the current line
- */
- private void skipToNewlineToken() {
- while (!builder.eof()) {
- if (currentToken() == ProjectViewTokenType.NEWLINE) {
- return;
- }
- builder.advanceLexer();
- }
- }
-
- private void buildTokenElement(ProjectViewElementType type) {
- PsiBuilder.Marker marker = builder.mark();
- builder.advanceLexer();
- marker.done(type);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementType.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementType.java
deleted file mode 100644
index 1c0644f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementType.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.tree.IElementType;
-
-import java.lang.reflect.Constructor;
-
-/**
- * IElementTypes used in the AST by the parser (as opposed to the types used by the lexer).<br>
- * Modelled on IntelliJ's core language conventions.
- */
-public class ProjectViewElementType extends IElementType {
-
- private static final Class[] PARAMETER_TYPES = new Class[]{ASTNode.class};
- private final Class<? extends PsiElement> psiElementClass;
- private Constructor<? extends PsiElement> constructor;
-
- public ProjectViewElementType(String name, Class<? extends PsiElement> psiElementClass) {
- super(name, ProjectViewFileType.INSTANCE.getLanguage());
- this.psiElementClass = psiElementClass;
- }
-
- public PsiElement createElement(ASTNode node) {
- try {
- if (constructor == null) {
- constructor = psiElementClass.getConstructor(PARAMETER_TYPES);
- }
- return constructor.newInstance(node);
- } catch (Exception e) {
- throw new IllegalStateException("No necessary constructor for " + node.getElementType(), e);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementTypes.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementTypes.java
deleted file mode 100644
index 1dfb3d5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewElementTypes.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
-import com.intellij.psi.tree.IFileElementType;
-
-/**
- * Collects the types used by the PsiBuilder to construct the AST
- */
-public interface ProjectViewElementTypes {
-
- IFileElementType FILE = new IFileElementType(ProjectViewFileType.INSTANCE.getLanguage());
-
- ProjectViewElementType LIST_SECTION = new ProjectViewElementType("list_section", ProjectViewPsiListSection.class);
- ProjectViewElementType SCALAR_SECTION = new ProjectViewElementType("scalar_section", ProjectViewPsiScalarSection.class);
-
- ProjectViewElementType LIST_ITEM = new ProjectViewElementType("list_item", ProjectViewPsiListItem.class);
- ProjectViewElementType SCALAR_ITEM = new ProjectViewElementType("scalar_item", ProjectViewPsiScalarItem.class);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiElement.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiElement.java
deleted file mode 100644
index 0bd331b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiElement.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.intellij.extapi.psi.ASTWrapperPsiElement;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-/**
- * Base psi element for project view files.
- */
-public abstract class ProjectViewPsiElement extends ASTWrapperPsiElement {
- public ProjectViewPsiElement(ASTNode node) {
- super(node);
- }
-
- @Override
- public PsiReference[] getReferences() {
- return PsiReference.EMPTY_ARRAY;
- }
-
- public <P extends PsiElement> P[] childrenOfClass(Class<P> psiClass) {
- return findChildrenByClass(psiClass);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiFile.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiFile.java
deleted file mode 100644
index 48ff619..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiFile.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
-import com.intellij.extapi.psi.PsiFileBase;
-import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.psi.FileViewProvider;
-
-/**
- * PSI file for project view file.
- */
-public class ProjectViewPsiFile extends PsiFileBase {
-
- public ProjectViewPsiFile(FileViewProvider viewProvider) {
- super(viewProvider, ProjectViewFileType.INSTANCE.getLanguage());
- }
-
- @Override
- public FileType getFileType() {
- return ProjectViewFileType.INSTANCE;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListItem.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListItem.java
deleted file mode 100644
index d198325..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListItem.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * Psi element for a list item.
- */
-public class ProjectViewPsiListItem extends ProjectViewPsiSectionItem {
-
- public ProjectViewPsiListItem(ASTNode node) {
- super(node);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListSection.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListSection.java
deleted file mode 100644
index b942788..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiListSection.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * Psi element for list section.
- */
-public class ProjectViewPsiListSection extends ProjectViewPsiElement {
-
- public ProjectViewPsiListSection(ASTNode node) {
- super(node);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarItem.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarItem.java
deleted file mode 100644
index 397dcb9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarItem.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * Psi element for a scalar item.
- */
-public class ProjectViewPsiScalarItem extends ProjectViewPsiSectionItem {
-
- public ProjectViewPsiScalarItem(ASTNode node) {
- super(node);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarSection.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarSection.java
deleted file mode 100644
index 6d82256..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiScalarSection.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.intellij.lang.ASTNode;
-
-/**
- * Psi element for scalar section.
- */
-public class ProjectViewPsiScalarSection extends ProjectViewPsiElement {
-
- public ProjectViewPsiScalarSection(ASTNode node) {
- super(node);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiSectionItem.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiSectionItem.java
deleted file mode 100644
index d827f10..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewPsiSectionItem.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.references.FileLookupData.PathFormat;
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewKeywords;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
-import com.google.idea.blaze.base.lang.projectview.references.ProjectViewLabelReference;
-import com.google.idea.blaze.base.projectview.section.SectionParser.ItemType;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.impl.SharedPsiElementImplUtil;
-
-import javax.annotation.Nullable;
-
-/**
- * Psi element for a list or scalar item.
- */
-public abstract class ProjectViewPsiSectionItem extends ProjectViewPsiElement {
-
- public ProjectViewPsiSectionItem(ASTNode node) {
- super(node);
- }
-
- @Override
- public PsiReference[] getReferences() {
- return SharedPsiElementImplUtil.getReferences(this);
- }
-
- @Override
- public PsiReference getReference() {
- ASTNode identifier = getNode().findChildByType(ProjectViewTokenType.IDENTIFIER);
- PathFormat pathFormat = getLabelType();
- if (identifier != null && pathFormat != null) {
- return new ProjectViewLabelReference(this, pathFormat);
- }
- return null;
- }
-
- @Nullable
- public PathFormat getLabelType() {
- ASTNode parent = getNode().getTreeParent();
- ASTNode identifier = parent != null ? parent.getFirstChildNode() : null;
- if (identifier == null) {
- return null;
- }
- ItemType itemType = ProjectViewKeywords.ITEM_TYPES.get(identifier.getText());
- if (itemType == null) {
- return null;
- }
- switch (itemType) {
- case Label: return PathFormat.NonLocal;
- case FileSystemItem: return PathFormat.NonLocalWithoutInitialBackslashes;
- default: return null;
- }
- }
-
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/util/ProjectViewElementGenerator.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/util/ProjectViewElementGenerator.java
deleted file mode 100644
index ccf5996..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/psi/util/ProjectViewElementGenerator.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.psi.util;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiElement;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiSectionItem;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiFileFactory;
-import com.intellij.psi.impl.PsiFileFactoryImpl;
-import com.intellij.testFramework.LightVirtualFile;
-
-import javax.annotation.Nullable;
-
-/**
- * Creates dummy BuildElements, e.g. for renaming purposes.
- */
-public class ProjectViewElementGenerator {
-
- private static final String DUMMY_FILENAME = "dummy.bazelproject";
-
- private static PsiFile createDummyFile(Project project, String contents) {
- PsiFileFactory factory = PsiFileFactory.getInstance(project);
- LightVirtualFile virtualFile = new LightVirtualFile(DUMMY_FILENAME, ProjectViewFileType.INSTANCE, contents);
- PsiFile psiFile = ((PsiFileFactoryImpl) factory).trySetupPsiForFile(virtualFile, ProjectViewLanguage.INSTANCE, false, true);
- assert psiFile != null;
- return psiFile;
- }
-
- @Nullable
- public static ASTNode createReplacementItemNode(ProjectViewPsiSectionItem sectionItem, String newStringContents) {
- TextRange itemRange = sectionItem.getTextRange();
- ProjectViewPsiElement parent = (ProjectViewPsiElement) sectionItem.getParent();
- if (parent == null) {
- return sectionItem.getNode();
- }
- int startOffset = sectionItem.getStartOffsetInParent();
- String originalSectionText = parent.getText();
- String newSectionText = StringUtil.replaceSubstring(originalSectionText,
- new TextRange(startOffset, startOffset + itemRange.getLength()),
- newStringContents);
- PsiFile dummyFile = createDummyFile(sectionItem.getProject(), newSectionText);
- PsiElement leafElement = dummyFile.findElementAt(startOffset);
- return leafElement != null ? leafElement.getParent().getNode() : null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/references/ProjectViewLabelReference.java b/blaze-base/src/com/google/idea/blaze/base/lang/projectview/references/ProjectViewLabelReference.java
deleted file mode 100644
index 431f481..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/lang/projectview/references/ProjectViewLabelReference.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.references;
-
-import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.completion.LabelRuleLookupElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
-import com.google.idea.blaze.base.lang.buildfile.references.FileLookupData;
-import com.google.idea.blaze.base.lang.buildfile.references.FileLookupData.PathFormat;
-import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
-import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiSectionItem;
-import com.google.idea.blaze.base.lang.projectview.psi.util.ProjectViewElementGenerator;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.intellij.lang.ASTNode;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReferenceBase;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.IncorrectOperationException;
-
-import javax.annotation.Nullable;
-
-/**
- * A blaze label reference.
- */
-public class ProjectViewLabelReference extends PsiReferenceBase<ProjectViewPsiSectionItem> {
-
- private final PathFormat pathFormat;
-
- public ProjectViewLabelReference(ProjectViewPsiSectionItem element, PathFormat pathFormat) {
- super(element, new TextRange(0, element.getTextLength()));
- this.pathFormat = pathFormat;
- }
-
- @Nullable
- @Override
- public PsiElement resolve() {
- Label label = getLabel(myElement.getText());
- if (label == null) {
- return null;
- }
- return BuildReferenceManager.getInstance(myElement.getProject()).resolveLabel(label);
- }
-
- @Nullable
- private static Label getLabel(@Nullable String labelString) {
- if (labelString == null || !labelString.startsWith("//") || labelString.indexOf('*') != -1) {
- return null;
- }
- return LabelUtils.createLabelFromString(null, labelString);
- }
-
- @Override
- public Object[] getVariants() {
- String labelString = LabelUtils.trimToDummyIdentifier(myElement.getText());
- return ArrayUtil.mergeArrays(
- getRuleLookups(labelString),
- getFileLookups(labelString));
- }
-
- private BuildLookupElement[] getRuleLookups(String labelString) {
- if (!labelString.startsWith("//") || !labelString.contains(":")) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
- BuildFile referencedBuildFile = BuildReferenceManager.getInstance(myElement.getProject()).resolveBlazePackage(packagePrefix);
- if (referencedBuildFile == null) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- return LabelRuleLookupElement.collectAllRules(referencedBuildFile, labelString, packagePrefix, null, QuoteType.NoQuotes);
- }
-
- private BuildLookupElement[] getFileLookups(String labelString) {
- if (pathFormat == PathFormat.NonLocalWithoutInitialBackslashes) {
- labelString = StringUtil.trimStart(labelString, "-");
- }
- FileLookupData lookupData = FileLookupData.nonLocalFileLookup(labelString, null, QuoteType.NoQuotes, pathFormat);
- if (lookupData == null) {
- return BuildLookupElement.EMPTY_ARRAY;
- }
- return BuildReferenceManager.getInstance(myElement.getProject()).resolvePackageLookupElements(lookupData);
- }
-
- @Override
- public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
- return myElement;
- }
-
- @Override
- public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
- String currentString = myElement.getText();
- Label label = getLabel(currentString);
- if (label == null) {
- return myElement;
- }
- String ruleName = label.ruleName().toString();
- String newRuleName = newElementName;
-
- // handle subdirectories
- int lastSlashIndex = ruleName.lastIndexOf('/');
- if (lastSlashIndex != -1) {
- newRuleName = ruleName.substring(0, lastSlashIndex + 1) + newElementName;
- }
-
- String packageString = LabelUtils.getPackagePathComponent(currentString);
- if (packageString.isEmpty() && !currentString.contains(":")) {
- return handleRename(newRuleName);
- }
- return handleRename(packageString + ":" + newRuleName);
- }
-
- private PsiElement handleRename(String newStringContents) {
- ASTNode replacement = ProjectViewElementGenerator.createReplacementItemNode(myElement, newStringContents);
- if (replacement != null) {
- myElement.getNode().replaceAllChildrenToChildrenOf(replacement);
- }
- return myElement;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/metrics/Action.java b/blaze-base/src/com/google/idea/blaze/base/metrics/Action.java
deleted file mode 100644
index 7faa893..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/metrics/Action.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.metrics;
-
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * An item that can be logged. All actions contain a name that is used as a primary key. The name
- * should be immutable forever to keep the logs sane.
- * <p/>
- * The name used by each {@link Action} should be [a-zA-Z0-9]* to keep things robust since various
- * log back ends may have different rules about what may or may not be in a key.
- * <p/>
- * Do not use any of the following retired values for enums:
- * INDEX_TOTAL_TIME("index")
- * REBUILD_TOTAL_TIME("rtt")
- * SYNC_SAVE_FILES("ssf")
- * SYNC_COMPUTE_MODULE_DIFF("scmd")
- * RUN_TOTAL_TIME("ttrp")
- * DEBUG_TOTAL_TIME("ttsbp")
- * RUN_TOTAL_TIME_FOR_ANDROID_TEST("ttrpat")
- * DEBUG_TOTAL_TIME_FOR_ANDROID_TEST("ttsbpat")
- * IMPORT_TOTAL_TIME("tip")
- * IDE_BUILD_INFO_RESPONSE("ibi")
- * RULES_EXTRACTION("re")
- * BLAZE_MODULES_CREATION("mvc")
- * INTELLIJ_MODULE_CREATION("imc")
- * SYNC_RESET_PROJECT("srp")
- * <p/>
- */
-public enum Action {
-
- MAKE_PROJECT_TOTAL_TIME("mtt"),
- MAKE_MODULE_TOTAL_TIME("mmtt"),
-
- SYNC_TOTAL_TIME("stt"),
- SYNC_IMPORT_DATA_TIME("sidt"),
- BLAZE_BUILD_DURING_SYNC("bb"),
- BLAZE_BUILD("bld"),
-
- APK_BUILD_AND_INSTALL("apkbi"),
-
- BLAZE_COMMAND_USAGE("ttrpbc"),
-
- OPEN_IN_CODESEARCH("oics"),
- COPY_GOOGLE3_PATH("cg3p"),
- OPEN_CORRESPONDING_BUILD_FILE("ocbf"),
-
- CREATE_BLAZE_RULE("cbr"),
- CREATE_BLAZE_PACKAGE("cbp"),
-
- SYNC_SDK("ssdk"),
-
- C_RESOLVE_FILE("crf"),
- BLAZE_CLION_TEST_RUN("ctr"),
- BLAZE_CLION_TEST_DEBUG("ctd")
- ;
-
- @NotNull
- @NonNls
- final private String name;
-
- Action(@NotNull String name) {
- this.name = name;
- }
-
- @NotNull
- public String getName() {
- return name;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/metrics/LoggingService.java b/blaze-base/src/com/google/idea/blaze/base/metrics/LoggingService.java
deleted file mode 100644
index 01ecc7a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/metrics/LoggingService.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.metrics;
-
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Logging service that handles logging timing, hit, and other events to an external sink for
- * later analysis.
- */
-public interface LoggingService {
-
- ExtensionPointName<LoggingService> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.LoggingService");
-
- /**
- * Report a value for an event to the available logging services.
- * @param variable The variable to report to. Once a value is selected for a logical
- * measurement, the variable's name should never change, even if the colloquial name for the
- * variable changes.
- */
- static void reportEvent(Project project, Action variable) {
- reportEvent(project, variable, 0);
- }
-
- /**
- * Report a value for an event to the available logging services.
- * @param variable The variable to report to. Once a value is selected for a logical
- * measurement, the variable's name should never change, even if the colloquial name for the
- * variable changes.
- * @param value should be >= 0, set the value to 0 if the value is meaningless
- */
- static void reportEvent(Project project, Action variable, long value) {
- for (LoggingService service : EP_NAME.getExtensions()) {
- service.doReportEvent(project, variable, value);
- }
- }
-
- /**
- * Report a value for an event to the logging service
- * @param variable The variable to report to. Once a value is selected for a logical
- * measurement, the variable's name should never change, even if the colloquial name for the
- * variable changes.
- * @param value should be >= 0, set the value to 0 if the value is meaningless
- */
- void doReportEvent(@Nullable Project project, Action variable, long value);
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/BlazeProjectData.java b/blaze-base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
deleted file mode 100644
index 4b4e1a9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import java.io.Serializable;
-
-/**
- * The top-level object serialized to cache.
- */
-@Immutable
-public class BlazeProjectData implements Serializable {
- private static final long serialVersionUID = 18L;
-
- public final long syncTime;
- public final ImmutableMap<Label, RuleIdeInfo> ruleMap;
- public final BlazeRoots blazeRoots;
- @Nullable
- public final WorkingSet workingSet;
- public final WorkspacePathResolver workspacePathResolver;
- public final WorkspaceLanguageSettings workspaceLanguageSettings;
- public final SyncState syncState;
- public final ImmutableMultimap<Label, Label> reverseDependencies;
-
- public BlazeProjectData(
- long syncTime,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- WorkspaceLanguageSettings workspaceLangaugeSettings,
- SyncState syncState,
- ImmutableMultimap<Label, Label> reverseDependencies
- ) {
- this.syncTime = syncTime;
- this.ruleMap = ruleMap;
- this.blazeRoots = blazeRoots;
- this.workingSet = workingSet;
- this.workspacePathResolver = workspacePathResolver;
- this.workspaceLanguageSettings = workspaceLangaugeSettings;
- this.syncState = syncState;
- this.reverseDependencies = reverseDependencies;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/BlazeWorkspaceType.java b/blaze-base/src/com/google/idea/blaze/base/model/BlazeWorkspaceType.java
deleted file mode 100644
index 46380bf..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/BlazeWorkspaceType.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model;
-
-public enum BlazeWorkspaceType {
- BASE,
- JAVA,
- ANDROID
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/SyncState.java b/blaze-base/src/com/google/idea/blaze/base/model/SyncState.java
deleted file mode 100644
index d91ac1f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/SyncState.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model;
-
-import com.google.common.collect.ImmutableMap;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-import java.util.Map;
-
-/**
- * Used to save arbitrary state with the sync task.
- */
-public class SyncState implements Serializable {
- private static final long serialVersionUID = 1L;
- private final ImmutableMap<String, Serializable> syncStateMap;
-
- @SuppressWarnings("unchecked")
- @Nullable
- public <T extends Serializable> T get(Class<T> klass) {
- return (T) syncStateMap.get(klass.getName());
- }
-
- public static class Builder {
- ImmutableMap.Builder<Class, Serializable> syncStateMap = ImmutableMap.builder();
- public <K extends Serializable, V extends K> Builder put(Class<K> klass, V instance) {
- syncStateMap.put(klass, instance);
- return this;
- }
- public SyncState build() {
- return new SyncState(syncStateMap.build());
- }
- }
-
- SyncState(ImmutableMap<Class, Serializable> syncStateMap) {
- ImmutableMap.Builder<String, Serializable> extraProjectSyncStateMap = ImmutableMap.builder();
- for (Map.Entry<Class, Serializable> entry : syncStateMap.entrySet()) {
- extraProjectSyncStateMap.put(entry.getKey().getName(), entry.getValue());
- }
- this.syncStateMap = extraProjectSyncStateMap.build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java
deleted file mode 100644
index 1ae5775..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.common.base.Objects;
-import com.intellij.openapi.util.io.FileUtil;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.Serializable;
-
-/**
- * An absolute or relative path returned from Blaze. If it is a relative path, it is relative to the execution root.
- */
-public final class ExecutionRootPath implements Serializable {
- public static final long serialVersionUID = 3L;
-
- private final File path;
-
- public ExecutionRootPath(String path) {
- this.path = new File(path);
- }
-
- public ExecutionRootPath(File path) {
- this.path = path;
- }
-
- public File getAbsoluteOrRelativeFile() {
- return path;
- }
-
- public File getFileRootedAt(File absoluteRoot) {
- if (path.isAbsolute()) {
- return path;
- }
- return new File(absoluteRoot, path.getPath());
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ExecutionRootPath that = (ExecutionRootPath)o;
- return Objects.equal(path, that.path);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(path);
- }
-
- @Override
- public String toString() {
- return "ExecutionRootPath{" +
- "path='" + path + '\'' +
- '}';
- }
-
- /**
- * Returns the relative {@link ExecutionRootPath} if {@code root} is an ancestor of {@code path} otherwise returns null.
- */
- @Nullable
- public static ExecutionRootPath createAncestorRelativePath(File root, File path) {
- // We cannot find the relative path between an absolute and relative path. The underlying code will make the relative path absolute
- // by rooting it at the current working directory which is almost never what you want.
- if (root.isAbsolute() != path.isAbsolute()) {
- return null;
- }
- if (!isAncestor(root.getPath(), path.getPath(), false /* strict */)) {
- return null;
- }
- String relativePath = FileUtil.getRelativePath(root, path);
- if (relativePath == null) {
- return null;
- }
- return new ExecutionRootPath(new File(relativePath));
- }
-
- /**
- * @param possibleParent
- * @param possibleChild
- * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent} equals to {@code possibleChild}.
- */
- public static boolean isAncestor(ExecutionRootPath possibleParent, ExecutionRootPath possibleChild, boolean strict) {
- return isAncestor(possibleParent.getAbsoluteOrRelativeFile().getPath(), possibleChild.getAbsoluteOrRelativeFile().getPath(), strict);
- }
-
- /**
- * @param possibleParentPath
- * @param possibleChild
- * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent} equals to {@code possibleChild}.
- */
- public static boolean isAncestor(String possibleParentPath, ExecutionRootPath possibleChild, boolean strict) {
- return isAncestor(possibleParentPath, possibleChild.getAbsoluteOrRelativeFile().getPath(), strict);
- }
-
- /**
- * @param possibleParent
- * @param possibleChildPath
- * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent} equals to {@code possibleChild}.
- */
- public static boolean isAncestor(ExecutionRootPath possibleParent, String possibleChildPath, boolean strict) {
- return isAncestor(possibleParent.getAbsoluteOrRelativeFile().getPath(), possibleChildPath, strict);
- }
-
- /**
- * @param possibleParentPath
- * @param possibleChildPath
- * @param strict if {@code false} then this method returns {@code true} if {@code possibleParent} equals to {@code possibleChild}.
- */
- public static boolean isAncestor(String possibleParentPath, String possibleChildPath, boolean strict) {
- return FileUtil.isAncestor(possibleParentPath, possibleChildPath, strict);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/Kind.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/Kind.java
deleted file mode 100644
index 2272a1f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/Kind.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.common.collect.ImmutableMap;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Wrapper around a string for a blaze kind (android_library, android_test...)
- */
-public enum Kind {
-
- ANDROID_BINARY("android_binary", LanguageClass.ANDROID),
- ANDROID_LIBRARY("android_library", LanguageClass.ANDROID),
- ANDROID_TEST("android_test", LanguageClass.ANDROID),
- ANDROID_ROBOLECTRIC_TEST("android_robolectric_test", LanguageClass.ANDROID),
- JAVA_LIBRARY("java_library", LanguageClass.JAVA),
- JAVA_TEST("java_test", LanguageClass.JAVA),
- JAVA_BINARY("java_binary", LanguageClass.JAVA),
- JAVA_IMPORT("java_import", LanguageClass.JAVA),
- JAVA_TOOLCHAIN("java_toolchain", LanguageClass.JAVA),
- PROTO_LIBRARY("proto_library", LanguageClass.JAVA), // The LanguageClass might have to change if we support other languages
- JAVA_PLUGIN("java_plugin", LanguageClass.JAVA),
- ANDROID_RESOURCES("android_resources", LanguageClass.ANDROID),
- CC_LIBRARY("cc_library", LanguageClass.C),
- CC_BINARY("cc_binary", LanguageClass.C),
- CC_TEST("cc_test", LanguageClass.C),
- CC_INC_LIBRARY("cc_inc_library", LanguageClass.C),
- CC_TOOLCHAIN("cc_toolchain", LanguageClass.C),
- JAVA_WRAP_CC("java_wrap_cc", LanguageClass.JAVA),
- GWT_APPLICATION("gwt_application", LanguageClass.JAVA),
- GWT_HOST("gwt_host", LanguageClass.JAVA),
- GWT_MODULE("gwt_module", LanguageClass.JAVA),
- GWT_TEST("gwt_test", LanguageClass.JAVA),
- ;
-
- static final ImmutableMap<String, Kind> STRING_TO_KIND = makeStringToKindMap();
-
- private static ImmutableMap<String, Kind> makeStringToKindMap() {
- ImmutableMap.Builder<String, Kind> result = ImmutableMap.builder();
- for (Kind kind : Kind.values()) {
- result.put(kind.toString(), kind);
- }
- return result.build();
- }
-
- public static Kind fromString(String kindString) {
- return STRING_TO_KIND.get(kindString);
- }
-
- private final String kind;
- private final LanguageClass languageClass;
-
- Kind(String kind, LanguageClass languageClass) {
- this.kind = kind;
- this.languageClass = languageClass;
- }
-
- @Override
- public String toString() {
- return kind;
- }
-
- public LanguageClass getLanguageClass() {
- return languageClass;
- }
-
- public boolean isOneOf(Kind... kinds) {
- return isOneOf(Arrays.asList(kinds));
- }
-
- public boolean isOneOf(List<Kind> kinds) {
- for (Kind kind : kinds) {
- if (this.equals(kind)) {
- return true;
- }
- }
- return false;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/Label.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/Label.java
deleted file mode 100644
index c4bf28a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/Label.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.List;
-
-/**
- * Wrapper around a string for a blaze label (//package:rule).
- */
-@Immutable
-public final class Label extends TargetExpression {
- private static final Logger LOG = Logger.getInstance(Label.class);
-
- public static final Comparator<Label> COMPARATOR = (o1, o2) -> String.CASE_INSENSITIVE_ORDER.compare(o1.toString(), o2.toString());
-
- public static final long serialVersionUID = 2L;
-
- /**
- * Silently returns null if this is not a valid Label
- */
- @Nullable
- public static Label createIfValid(String label) {
- if (validate(label)) {
- return new Label(label);
- }
- return null;
- }
-
- public Label(String label) {
- super(label);
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (!validate(label, errors)) {
- BlazeValidationError.throwError(errors);
- }
- }
-
- public Label(
- WorkspacePath packageName,
- RuleName newRuleName) {
- this("//" + packageName.toString() + ":" + newRuleName.toString());
- }
-
- public static boolean validate(String label) {
- return validate(label, null);
- }
-
- public static boolean validate(String label, @Nullable Collection<BlazeValidationError> errors) {
- int colonIndex = label.indexOf(':');
- if (label.startsWith("//") && colonIndex >= 0) {
- String packageName = label.substring("//".length(), colonIndex);
- if (!validatePackagePath(packageName, errors)) {
- return false;
- }
- String ruleName = label.substring(colonIndex + 1);
- if (!RuleName.validate(ruleName, errors)) {
- return false;
- }
- return true;
- }
- if (label.startsWith("@") && colonIndex >= 0) {
- // a bazel-specific label pointing to a different repository
- int slashIndex = label.indexOf("//");
- if (slashIndex >= 0) {
- return validate(label.substring(slashIndex), errors);
- }
- }
- if (errors != null) {
- errors.add(new BlazeValidationError("Not a valid label, no target name found: " + label));
- }
- return false;
- }
-
- /**
- * Extract the rule name from a label. The rule name follows a colon at the end of the label.
- *
- * @return the rule name
- */
- public RuleName ruleName() {
- String labelStr = toString();
- int colonLocation = labelStr.lastIndexOf(':');
- int ruleNameStart = colonLocation + 1;
- String ruleNameStr = labelStr.substring(ruleNameStart);
- return RuleName.create(ruleNameStr);
- }
-
- /**
- * Return the workspace path for the package label for the given label. For example, if the
- * package is //j/c/g/a/apps/docs:release, it returns j/c/g/a/apps/docs.
- */
- public WorkspacePath blazePackage() {
- String labelStr = toString();
- int startIndex = labelStr.indexOf("//") + "//".length();
- int colonIndex = labelStr.lastIndexOf(':');
- LOG.assertTrue(colonIndex >= 0);
- return new WorkspacePath(labelStr.substring(startIndex, colonIndex));
- }
-
- public static boolean validatePackagePath(String path) {
- return validatePackagePath(path, null);
- }
-
- public static boolean validatePackagePath(String path, @Nullable Collection<BlazeValidationError> errors) {
- // Empty packages are legal but not recommended
- if (path.isEmpty()) {
- return true;
- }
-
- if (path.charAt(0) < 'a' || path.charAt(0) > 'z') {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid package name: " + path + "\n "
- + "Package names must start with a lowercase ASCII letter"
- ));
- return false;
- }
- if (path.contains("//")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid package name: " + path + "\n "
- + "package names may not contain \"//\" path separators."
- ));
- return false;
- }
- if (path.endsWith("/")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid package name: " + path + "\n "
- + "package names may not end with \"/\""
- ));
- return false;
- }
- return true;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java
deleted file mode 100644
index 86cedf7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-/**
- * Language classes.
- */
-public enum LanguageClass {
- GENERIC("generic"),
- C("c"),
- JAVA("java"),
- ANDROID("android"),
- JAVASCRIPT("javascript"),
- TYPESCRIPT("typescript"),
- DART("dart");
-
- private final String name;
- LanguageClass(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public static LanguageClass fromString(String name) {
- for (LanguageClass ruleClass : LanguageClass.values()) {
- if (ruleClass.name.equals(name)) {
- return ruleClass;
- }
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/RuleName.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/RuleName.java
deleted file mode 100644
index aed7e88..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/RuleName.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.List;
-import java.util.regex.Pattern;
-
-public final class RuleName {
-
- // This is a subset of the allowable target names in Blaze
- private static final String ALNUM_REGEX_STR = "[a-zA-Z0-9]*";
- private static final Pattern ALNUM_REGEX = Pattern.compile(ALNUM_REGEX_STR);
-
- // Rule names must be alpha-numeric or consist of the following allowed chars:
- // (note, rule names can also contain '/'; we handle that case separately)
- private static final ImmutableSet<Character> ALLOWED_META = ImmutableSet.of('+', '_', ',', '=', '-', '.', '@', '~');
-
- private final String name;
-
- private RuleName(String ruleName) {
- this.name = ruleName;
- }
-
- /**
- * Silently returns null if the string is not a valid rule name.
- */
- @Nullable
- public static RuleName createIfValid(String ruleName) {
- if (validate(ruleName, null)) {
- return new RuleName(ruleName);
- }
- return null;
- }
-
- public static RuleName create(String ruleName) {
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (!validate(ruleName, errors)) {
- BlazeValidationError.throwError(errors);
- }
- return new RuleName(ruleName);
- }
-
- /**
- * Validates a rule name using the same logic as Blaze
- */
- public static boolean validate(String ruleName) {
- return validate(ruleName, null);
- }
-
- /**
- * Validates a rule name using the same logic as Blaze
- */
- public static boolean validate(String ruleName, @Nullable Collection<BlazeValidationError> errors) {
- if (ruleName.isEmpty()) {
- BlazeValidationError.collect(errors, new BlazeValidationError("target names cannot be empty"));
- return false;
- }
- // Forbidden start chars:
- if (ruleName.charAt(0) == '/') {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not start with \"/\""
- ));
- return false;
- }
- else if (ruleName.charAt(0) == '.') {
- if (ruleName.startsWith("../") || ruleName.equals("..")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain up-level references \"..\""
- ));
- return false;
- }
- else if (ruleName.equals(".")) {
- return true;
- }
- else if (ruleName.startsWith("./")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain \".\" as a path segment"
- ));
- return false;
- }
- }
-
- for (int i = 0; i < ruleName.length(); ++i) {
- char c = ruleName.charAt(i);
- if (ALLOWED_META.contains(c)) {
- continue;
- }
- if (c == '/') {
- // Forbidden substrings: "/../", "/./", "//"
- if (ruleName.contains("/../")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain up-level references \"..\""
- ));
- return false;
- }
- else if (ruleName.contains("/./")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain \".\" as a path segment"
- ));
- return false;
- }
- else if (ruleName.contains("//")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain \"//\" path separators"
- ));
- return false;
- }
- continue;
- }
- boolean isAlnum = ALNUM_REGEX.matcher(String.valueOf(c)).matches();
- if (!isAlnum) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain " + c
- ));
- return false;
- }
- }
-
- // Forbidden end chars:
- if (ruleName.endsWith("/..")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not contain up-level references \"..\""
- ));
- return false;
- }
- else if (ruleName.endsWith("/.")) {
- return true;
- }
- else if (ruleName.endsWith("/")) {
- BlazeValidationError.collect(errors, new BlazeValidationError(
- "Invalid target name: " + ruleName + "\n" +
- "target names may not end with \"/\""
- ));
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- return name;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(name);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof RuleName) {
- RuleName that = (RuleName) obj;
- return Objects.equal(name, that.name);
- }
- return false;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java
deleted file mode 100644
index 6093869..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.common.base.Preconditions;
-
-import java.io.Serializable;
-
-/**
- * An interface for objects that represent targets you could pass to Blaze on the command line.
- * See {@link com.google.idea.blaze.base.model.primitives.Label},
- */
-public class TargetExpression implements Serializable, Comparable<TargetExpression> {
- public static final long serialVersionUID = 1L;
-
- private final String expression;
-
- /**
- * @return A Label instance if the expression is a valid label, or a TargetExpression
- * instance if it is not.
- */
- public static TargetExpression fromString(String expression) {
- return Label.validate(expression)
- ? new Label(expression)
- : new TargetExpression(expression);
- }
-
- TargetExpression(String expression) {
- // TODO(joshgiles): Validation/canonicalization for target expressions.
- // For reference, handled in Blaze/Bazel in TargetPattern.java.
- Preconditions.checkArgument(!expression.isEmpty(), "Target should be non-empty.");
- this.expression = expression;
- }
-
- @Override
- public String toString() {
- return expression;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof TargetExpression)) {
- return false;
- }
- TargetExpression that = (TargetExpression)o;
- return expression.equals(that.expression);
- }
-
- @Override
- public int hashCode() {
- return expression.hashCode();
- }
-
- /**
- * All targets in all packages below the given path
- */
- public static TargetExpression allFromPackageRecursive(WorkspacePath localPackage) {
- if (localPackage.relativePath().isEmpty()) {
- // localPackage is the workspace root
- return new TargetExpression("//...:all");
- }
- return new TargetExpression("//" + localPackage.relativePath() + "/...:all");
- }
-
- public static TargetExpression allFromPackageNonRecursive(WorkspacePath localPackage) {
- return new TargetExpression("//" + localPackage.relativePath() + ":all");
- }
-
- @Override
- public int compareTo(TargetExpression o) {
- return expression.compareTo(o.expression);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java
deleted file mode 100644
index 4a5c60a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * Represents a path relative to the workspace root. The path component separator is Blaze specific.
- * <p/>
- * A {@link WorkspacePath} is *not* necessarily a valid package name/path. The primary reason is
- * because it could represent a file and files don't have to follow the same conventions as package
- * names.
- */
-@Immutable
-public class WorkspacePath implements Serializable {
- public static final long serialVersionUID = 1L;
-
- /**
- * Silently returns null if this is not a valid workspace path.
- */
- @Nullable
- public static WorkspacePath createIfValid(String relativePath) {
- if (validate(relativePath)) {
- return new WorkspacePath(relativePath);
- }
- return null;
- }
-
- private static final char BLAZE_COMPONENT_SEPARATOR = '/';
-
- @NotNull
- private final String relativePath;
-
- /**
- * @param relativePath relative path that must use the Blaze specific separator char to separate
- * path components
- */
- public WorkspacePath(@NotNull String relativePath) {
- if (!validate(relativePath)) {
- throw new IllegalArgumentException("Invalid workspace path: " + relativePath);
- }
- this.relativePath = relativePath;
- }
-
- public WorkspacePath(@NotNull WorkspacePath parentPath, @NotNull String childPath) {
- this(parentPath.relativePath() + BLAZE_COMPONENT_SEPARATOR + childPath);
- }
-
- public static boolean validate(@NotNull String relativePath) {
- return validate(relativePath, null);
- }
-
- public static boolean validate(@NotNull String relativePath, @Nullable Collection<BlazeValidationError> errors) {
- if (relativePath.startsWith("/") ) {
- BlazeValidationError.collect(errors, new BlazeValidationError("Workspace path may not start with '/': " + relativePath));
- return false;
- }
-
- if (relativePath.endsWith("/") ) {
- BlazeValidationError.collect(errors, new BlazeValidationError("Workspace path may not end with '/': " + relativePath));
- return false;
- }
-
- if (relativePath.indexOf(':') >= 0) {
- BlazeValidationError.collect(errors, new BlazeValidationError("Workspace path may not contain ':': " + relativePath));
- return false;
- }
-
- return true;
- }
-
- public boolean isWorkspaceRoot() {
- return relativePath.isEmpty();
- }
-
- @Override
- public String toString() {
- return relativePath;
- }
-
- public String relativePath() {
- return relativePath;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || this.getClass() != o.getClass()) {
- return false;
- }
-
- WorkspacePath that = (WorkspacePath)o;
- return relativePath.equals(that.relativePath);
- }
-
- @Override
- public int hashCode() {
- return relativePath.hashCode();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java
deleted file mode 100644
index 917603a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.Serializable;
-
-/**
- * Represents a workspace root
- */
-public class WorkspaceRoot implements Serializable {
- public static final long serialVersionUID = 1L;
-
- private final File directory;
-
- public WorkspaceRoot(File directory) {
- this.directory = directory;
- }
-
- /**
- * Get the workspace root for a project
- *
- * @param blazeSettings settings for the project in question
- * @return the path to workspace root that is used for the project
- */
- public static WorkspaceRoot fromImportSettings(BlazeImportSettings blazeSettings) {
- return new WorkspaceRoot(new File(blazeSettings.getWorkspaceRoot()));
- }
-
- /**
- * Tries to load the import settings for the given project and get the workspace root directory.<br>
- * Unlike {@link #fromProject}, it will silently return null if this is not a blaze project.
- */
- @Nullable
- public static WorkspaceRoot fromProjectSafe(Project project) {
- if (Blaze.isBlazeProject(project)) {
- return fromProject(project);
- }
- return null;
- }
-
- /**
- * Tries to load the import settings for the given project and get the workspace root directory.
- */
- public static WorkspaceRoot fromProject(Project project) {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project)
- .getImportSettings();
- if (importSettings == null) {
- throw new IllegalStateException("null BlazeImportSettings.");
- }
- return fromImportSettings(importSettings);
- }
-
- public File fileForPath(WorkspacePath workspacePath) {
- return new File(directory, workspacePath.relativePath());
- }
-
- public File directory() {
- return directory;
- }
-
- public WorkspacePath workspacePathFor(VirtualFile file) {
- return workspacePathFor(file.getPath());
- }
-
- public boolean isInWorkspace(VirtualFile file) {
- return isInWorkspace(file.getPath());
- }
-
- public WorkspacePath workspacePathFor(File file) {
- return workspacePathFor(file.getPath());
- }
-
- public boolean isInWorkspace(File file) {
- return isInWorkspace(file.getPath());
- }
-
- private WorkspacePath workspacePathFor(String path) {
- if (!isInWorkspace(path)) {
- throw new IllegalArgumentException("File is not under this workspace");
- }
- if (directory.getPath().length() == path.length()) {
- return new WorkspacePath("");
- }
- return new WorkspacePath(path.substring(directory.getPath().length() + 1));
- }
-
- private boolean isInWorkspace(String path) {
- return FileUtil.isAncestor(directory.getPath(), path, false);
- }
-
- @Override
- public String toString() {
- return directory.toString();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- WorkspaceRoot that = (WorkspaceRoot)o;
- return directory.equals(that.directory);
- }
-
- @Override
- public int hashCode() {
- return directory.hashCode();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspaceType.java b/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspaceType.java
deleted file mode 100644
index fbd7eb1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/model/primitives/WorkspaceType.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-/**
- * Workspace types.
- *
- * <p>If the user doesn't specify a workspace, she gets the highest
- * supported workspace type by enum ordinal.
- */
-public enum WorkspaceType {
- INTELLIJ_PLUGIN("intellij_plugin", LanguageClass.JAVA),
- C("c", LanguageClass.C),
- JAVA("java", LanguageClass.JAVA),
- ANDROID_NDK("android_ndk", LanguageClass.ANDROID, LanguageClass.JAVA, LanguageClass.C),
- ANDROID("android", LanguageClass.ANDROID, LanguageClass.JAVA),
- JAVASCRIPT("javascript");
-
- private final String name;
- private final LanguageClass[] languages;
- WorkspaceType(String name, LanguageClass... languages) {
- this.name = name;
- this.languages = languages;
- }
-
- public String getName() {
- return name;
- }
-
- public LanguageClass[] getLanguages() {
- return languages;
- }
-
- public static WorkspaceType fromString(String name) {
- for (WorkspaceType ruleClass : WorkspaceType.values()) {
- if (ruleClass.name.equals(name)) {
- return ruleClass;
- }
- }
- return null;
- }
-
- @Override
- public String toString() {
- return name;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java b/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
deleted file mode 100644
index ebb3fc0..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.actionSystem.ActionManager;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.project.Project;
-
-/**
- * Wraps an action and makes it invisible for blaze-based projects.
- */
-public class BlazeActionRemover extends AnAction {
-
- public static void hideAction(String actionId) {
- AnAction oldAction = ActionManager.getInstance().getAction(actionId);
- if (oldAction != null) {
- replaceAction(actionId, new BlazeActionRemover(oldAction));
- }
- }
-
- private static void replaceAction(String actionId, AnAction newAction) {
- ActionManager actionManager = ActionManager.getInstance();
- AnAction oldAction = actionManager.getAction(actionId);
- if (oldAction != null) {
- newAction.getTemplatePresentation().setIcon(oldAction.getTemplatePresentation().getIcon());
- actionManager.unregisterAction(actionId);
- }
- actionManager.registerAction(actionId, newAction);
- }
-
- private final AnAction delegate;
-
- private BlazeActionRemover(AnAction delegate) {
- super(delegate.getTemplatePresentation().getTextWithMnemonic(),
- delegate.getTemplatePresentation().getDescription(),
- delegate.getTemplatePresentation().getIcon());
- this.delegate = delegate;
- }
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- delegate.actionPerformed(e);
- }
-
- @Override
- public void update(AnActionEvent e) {
- Presentation presentation = e.getPresentation();
- Project project = e.getProject();
- if (project != null && Blaze.isBlazeProject(project)) {
- presentation.setEnabledAndVisible(false);
- return;
- }
- delegate.update(e);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeBinaryFileType.java b/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeBinaryFileType.java
deleted file mode 100644
index d032499..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeBinaryFileType.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin;
-
-import com.intellij.openapi.fileTypes.UserBinaryFileType;
-
-/**
- * Marker type to mark something as binary.
- */
-public class BlazeBinaryFileType extends UserBinaryFileType {
- public static final BlazeBinaryFileType INSTANCE;
- static {
- INSTANCE = new BlazeBinaryFileType();
- INSTANCE.setName("Binary File");
- INSTANCE.setDescription("The blaze plugin has guessed this file type as binary for performance.");
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeFileTypeFactory.java b/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeFileTypeFactory.java
deleted file mode 100644
index 03d8771..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeFileTypeFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin;
-
-import com.intellij.ide.highlighter.ArchiveFileType;
-import com.intellij.openapi.fileTypes.FileTypeConsumer;
-import com.intellij.openapi.fileTypes.FileTypeFactory;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * @author chuckj
- */
-public class BlazeFileTypeFactory extends FileTypeFactory {
- @Override
- public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
- consumer.consume(ArchiveFileType.INSTANCE, "srcjar");
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazePluginId.java b/blaze-base/src/com/google/idea/blaze/base/plugin/BlazePluginId.java
deleted file mode 100644
index 4ef6f93..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazePluginId.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin;
-
-import com.intellij.openapi.components.ServiceManager;
-
-/**
- * Supplies the ID of the sync plugin.
- */
-public interface BlazePluginId {
-
- static BlazePluginId getInstance() {
- return ServiceManager.getService(BlazePluginId.class);
- }
-
- /**
- * @return the plugin ID (same as in the plugin.xml).
- */
- String getPluginId();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeSpecificInitializer.java b/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeSpecificInitializer.java
deleted file mode 100644
index 1d1e4f8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/BlazeSpecificInitializer.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileTypeFactory;
-import com.intellij.openapi.actionSystem.IdeActions;
-import com.intellij.openapi.components.ApplicationComponent;
-
-/**
- * Runs on startup.
- */
-public class BlazeSpecificInitializer extends ApplicationComponent.Adapter {
-
- @Override
- public void initComponent() {
- hideMakeActions();
- initializeBuildFileSupportStatus();
- }
-
- private static void initializeBuildFileSupportStatus() {
- BuildFileTypeFactory.updateBuildFileLanguageEnabled(BuildFileLanguage.buildFileSupportEnabled());
- }
-
- // The original actions will be visible only on plain IDEA projects.
- private static void hideMakeActions() {
- // 'Build' > 'Make Project' action
- BlazeActionRemover.hideAction("CompileDirty");
-
- // 'Build' > 'Make Modules' action
- BlazeActionRemover.hideAction(IdeActions.ACTION_MAKE_MODULE);
-
- // 'Build' > 'Rebuild' action
- BlazeActionRemover.hideAction(IdeActions.ACTION_COMPILE_PROJECT);
-
- // 'Build' > 'Compile Modules' action
- BlazeActionRemover.hideAction(IdeActions.ACTION_COMPILE);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/Version.java b/blaze-base/src/com/google/idea/blaze/base/plugin/Version.java
deleted file mode 100644
index 5806517..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/Version.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.intellij.ide.plugins.IdeaPluginDescriptor;
-import com.intellij.ide.plugins.PluginManager;
-import com.intellij.openapi.extensions.PluginId;
-
-/**
- * Blaze sync plugin ID and version information.
- */
-public class Version {
-
- public static class PluginInfo {
- public final String id;
- public final String version;
-
- @VisibleForTesting
- public static final PluginInfo UNKNOWN = new PluginInfo("UNKNOWN_PLUGIN", "UNKNOWN_VERSION");
-
- public PluginInfo(String id, String version) {
- this.id = id;
- this.version = version;
- }
- }
-
- public static PluginInfo getSyncPluginInfo() {
- BlazePluginId idService = BlazePluginId.getInstance();
- if (idService != null) {
- PluginId pluginId = PluginId.getId(idService.getPluginId());
- IdeaPluginDescriptor pluginInfo = PluginManager.getPlugin(pluginId);
- if (pluginInfo != null) {
- return new PluginInfo(pluginId.getIdString(), pluginInfo.getVersion());
- }
- }
- return PluginInfo.UNKNOWN;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/dependency/PluginDependencyHelper.java b/blaze-base/src/com/google/idea/blaze/base/plugin/dependency/PluginDependencyHelper.java
deleted file mode 100644
index 0e4bac1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/dependency/PluginDependencyHelper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin.dependency;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.plugin.BlazePluginId;
-import com.intellij.externalDependencies.DependencyOnPlugin;
-import com.intellij.externalDependencies.ExternalDependenciesManager;
-import com.intellij.externalDependencies.ProjectExternalDependency;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-public class PluginDependencyHelper {
-
- public static void addDependencyOnSyncPlugin(@NotNull Project blazeProject) {
- BlazePluginId idService = BlazePluginId.getInstance();
- if (idService != null) {
- addDependency(
- blazeProject,
- new DependencyOnPlugin(idService.getPluginId(), null, null, null)
- );
- }
- }
-
- /**
- * Adds dependency, or replaces existing dependency of same type.
- * Doesn't trigger any update checking
- */
- private static void addDependency(
- @NotNull Project project,
- @NotNull DependencyOnPlugin newDep) {
-
- ExternalDependenciesManager manager = ExternalDependenciesManager.getInstance(project);
- List<ProjectExternalDependency> deps = Lists.newArrayList(manager.getAllDependencies());
- boolean added = false;
- for (int i = 0; i < deps.size(); i++) {
- ProjectExternalDependency dep = deps.get(i);
- if (!(dep instanceof DependencyOnPlugin)) {
- continue;
- }
- DependencyOnPlugin pluginDep = (DependencyOnPlugin) dep;
- if (pluginDep.getPluginId().equals(newDep.getPluginId())) {
- added = true;
- deps.set(i, newDep);
- }
- }
- if (!added) {
- deps.add(newDep);
- }
- manager.setAllDependencies(deps);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/plugin/dependency/ProjectDependencyMigration.java b/blaze-base/src/com/google/idea/blaze/base/plugin/dependency/ProjectDependencyMigration.java
deleted file mode 100644
index eafdbf9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/plugin/dependency/ProjectDependencyMigration.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.plugin.dependency;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.components.ApplicationComponent;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.project.ProjectManagerAdapter;
-
-/**
- * Temporary migration code. Listens for blaze projects opening and closing,
- * and adds required plugin dependencies
- */
-public class ProjectDependencyMigration extends ApplicationComponent.Adapter {
-
- @Override
- public void initComponent() {
- ProjectManager projectManager = ProjectManager.getInstance();
- projectManager.addProjectManagerListener(new ProjectManagerAdapter() {
- @Override
- public void projectOpened(Project project) {
- if (Blaze.isBlazeProject(project)) {
- PluginDependencyHelper.addDependencyOnSyncPlugin(project);
- }
- }
- });
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java b/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
deleted file mode 100644
index fa7594c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.prefetch;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Interface to request prefetching of files
- */
-public interface PrefetchService {
- static PrefetchService getInstance() {
- return ServiceManager.getService(PrefetchService.class);
- }
-
- /**
- * Instructs all prefetchers to prefetch these files.
- *
- * @param files The files to prefetch
- * @param synchronous A hint whether the prefetch should be complete when the future completes.
- */
- ListenableFuture<?> prefetchFiles(List<File> files, boolean synchronous);
-
- /**
- * Instructs all prefetchers to prefetch any project files they're interested in.
- *
- * Should be asynchronous.
- */
- void prefetchProjectFiles(Project project);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java b/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java
deleted file mode 100644
index a335bb6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.prefetch;
-
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.intellij.openapi.project.Project;
-import com.intellij.util.concurrency.BoundedTaskExecutor;
-
-import java.io.File;
-import java.util.List;
-import java.util.concurrent.Executors;
-
-/**
- * Implementation for prefetcher.
- */
-public class PrefetchServiceImpl implements PrefetchService {
- private static final int THREAD_COUNT = 32;
- private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(
- new BoundedTaskExecutor(Executors.newFixedThreadPool(THREAD_COUNT), THREAD_COUNT));
-
- @Override
- public ListenableFuture<?> prefetchFiles(List<File> files, boolean synchronous) {
- List<ListenableFuture<?>> futures = Lists.newArrayList();
- for (Prefetcher prefetcher : Prefetcher.EP_NAME.getExtensions()) {
- futures.add(prefetcher.prefetchFiles(files, executor, synchronous));
- }
- return Futures.allAsList(futures);
- }
-
- @Override
- public void prefetchProjectFiles(Project project) {
- for (Prefetcher prefetcher : Prefetcher.EP_NAME.getExtensions()) {
- prefetcher.prefetchProjectFiles(project, executor);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceProjectComponent.java b/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceProjectComponent.java
deleted file mode 100644
index 66a404e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceProjectComponent.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.prefetch;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.ProjectTopics;
-import com.intellij.openapi.components.ProjectComponent;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModuleRootAdapter;
-import com.intellij.openapi.roots.ModuleRootEvent;
-import com.intellij.util.messages.MessageBusConnection;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Instructs prefetchers to prefetch all project files when they may have changed / be stale.
- */
-public class PrefetchServiceProjectComponent implements ProjectComponent {
- private final Project project;
-
- public PrefetchServiceProjectComponent(Project project) {
- this.project = project;
- MessageBusConnection connection = project.getMessageBus().connect(project);
- connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
- @Override
- public void rootsChanged(ModuleRootEvent event) {
- prefetch();
- }
- });
- }
-
- @Override
- public void projectOpened() {
- prefetch();
- }
-
- private void prefetch() {
- if (!Blaze.isBlazeProject(project)) {
- return;
- }
- PrefetchService.getInstance().prefetchProjectFiles(project);
- }
-
- @Override
- public void projectClosed() {
- }
-
- @Override
- public void initComponent() {
- }
-
- @Override
- public void disposeComponent() {
- }
-
- @NotNull
- @Override
- public String getComponentName() {
- return "PrefetchServiceProjectComponent";
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/prefetch/Prefetcher.java b/blaze-base/src/com/google/idea/blaze/base/prefetch/Prefetcher.java
deleted file mode 100644
index 274b2b5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/prefetch/Prefetcher.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.prefetch;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.project.Project;
-
-import java.io.File;
-
-/**
- * Prefetches files when a project is opened or roots change.
- */
-public interface Prefetcher {
- ExtensionPointName<Prefetcher> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.Prefetcher");
-
- /**
- * Prefetches the given list of files.
- *
- * It is the responsibility of the prefetcher to filter out any files it isn't interested in.
- *
- * @param synchronous A hint whether the prefetch should be complete when the returned future completes
- */
- ListenableFuture<?> prefetchFiles(Iterable<File> file,
- ListeningExecutorService executor,
- boolean synchrononous);
-
- /**
- * Prefetch any project files that this prefetcher is interested in.
- *
- * <p>The prefetch should be asynchronous.
- */
- void prefetchProjectFiles(Project project, ListeningExecutorService executor);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectView.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectView.java
deleted file mode 100644
index 7366b6b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectView.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.projectview.section.Section;
-import com.google.idea.blaze.base.projectview.section.SectionBuilder;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import java.io.Serializable;
-import java.util.Map;
-
-/**
- * Represents instructions for what should be included in a project.
- */
-public final class ProjectView implements Serializable {
- private static final long serialVersionUID = 2L;
-
- private static final Logger LOG = Logger.getInstance(ProjectView.class);
- private final ImmutableMap<SectionKey, Section> sections;
-
- private ProjectView(ImmutableMap<SectionKey, Section> sections) {
- this.sections = sections;
- }
-
- @SuppressWarnings("unchecked")
- @Nullable
- public <T, SectionType extends Section<T>> SectionType getSectionOfType(SectionKey<T, SectionType> key) {
- return (SectionType) sections.get(key);
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static Builder builder(ProjectView projectView) {
- return new Builder(projectView);
- }
-
- /**
- * Builder class.
- */
- public static class Builder {
- private final Map<SectionKey, Section> sections;
-
- Builder() {
- sections = Maps.newHashMap();
- }
-
- Builder(ProjectView projectView) {
- sections = Maps.newHashMap(projectView.sections);
- }
-
- public <T, SectionType extends Section<T>> Builder put(SectionBuilder<T, SectionType> builder) {
- sections.put(builder.getSectionKey(), builder.build());
- return this;
- }
-
- public <T, SectionType extends Section<T>> Builder put(SectionKey<T, SectionType> key, SectionType section) {
- sections.put(key, section);
- return this;
- }
-
- @SuppressWarnings("unchecked")
- @Nullable
- public <T, SectionType extends Section<T>> SectionType get(SectionKey<T, SectionType> key) {
- return (SectionType) sections.get(key);
- }
-
- public ProjectView build() {
- return new ProjectView(ImmutableMap.copyOf(sections));
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewEdit.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewEdit.java
deleted file mode 100644
index ea647f8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewEdit.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Represents a modification to one or more project view files.
- */
-public class ProjectViewEdit {
-
- private static final Logger LOG = Logger.getInstance(ProjectViewEdit.class);
- private final Project project;
- private final List<Modification> modifications;
-
- ProjectViewEdit(Project project, List<Modification> modifications) {
- this.project = project;
- this.modifications = modifications;
- }
-
- private static class Modification {
- ProjectView oldProjectView;
- ProjectView newProjectView;
- File projectViewFile;
- }
-
- /**
- * Creates a new edit that modifies all reachable project views in the project view set.
- */
- public static ProjectViewEdit editProjectViewSet(Project project, ProjectViewEditor editor) {
- ProjectViewSet oldProjectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- List<Modification> modifications = Lists.newArrayList();
- if (oldProjectViewSet != null) {
- for (ProjectViewSet.ProjectViewFile projectViewFile : oldProjectViewSet.getProjectViewFiles()) {
- ProjectView.Builder builder = ProjectView.builder(projectViewFile.projectView);
- if (editor.editProjectView(builder)) {
- Modification modification = new Modification();
- modification.newProjectView = builder.build();
- modification.oldProjectView = projectViewFile.projectView;
- modification.projectViewFile = projectViewFile.projectViewFile;
- modifications.add(modification);
- }
- }
- }
- return new ProjectViewEdit(project, modifications);
- }
-
- /**
- * Creates a new edit that modifies the local project view only.
- */
- public static ProjectViewEdit editLocalProjectView(Project project, ProjectViewEditor editor) {
- List<Modification> modifications = Lists.newArrayList();
- ProjectViewSet oldProjectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (oldProjectViewSet != null) {
- ProjectViewSet.ProjectViewFile projectViewFile = oldProjectViewSet.getTopLevelProjectViewFile();
- if (projectViewFile != null) {
- ProjectView.Builder builder = ProjectView.builder(projectViewFile.projectView);
- if (editor.editProjectView(builder)) {
- Modification modification = new Modification();
- modification.newProjectView = builder.build();
- modification.oldProjectView = projectViewFile.projectView;
- modification.projectViewFile = projectViewFile.projectViewFile;
- modifications.add(modification);
- }
- }
- }
- return new ProjectViewEdit(project, modifications);
- }
-
- public void apply() {
- apply(true);
- }
-
- public void undo() {
- apply(false);
- }
-
- private void apply(boolean isApply) {
- for (Modification modification : modifications) {
- ProjectView projectView = isApply ? modification.newProjectView : modification.oldProjectView;
- String projectViewText = ProjectViewParser.projectViewToString(projectView);
- try {
- ProjectViewStorageManager.getInstance().writeProjectView(projectViewText, modification.projectViewFile);
- }
- catch (IOException e) {
- LOG.error(e);
- Messages.showErrorDialog(
- project,
- "Could not write updated project view. Is the file write protected?",
- "Edit Failed");
- }
- }
- }
-
- public boolean hasModifications() {
- return !modifications.isEmpty();
- }
-
- public interface ProjectViewEditor {
- boolean editProjectView(ProjectView.Builder builder);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewManager.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewManager.java
deleted file mode 100644
index 7f24cdb..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewManager.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Class that manages access to a project's
- * {@link ProjectView}.
- */
-public abstract class ProjectViewManager {
-
- public static ProjectViewManager getInstance(Project project) {
- return ServiceManager.getService(project, ProjectViewManager.class);
- }
-
- /**
- * Returns the current project view collection. If there is an error, returns null.
- */
- @Nullable
- public abstract ProjectViewSet getProjectViewSet();
-
- /**
- * Reloads the project view, replacing the current one only if there are no errors.
- *
- * @return Success.
- */
- @Nullable
- public abstract ProjectViewSet reloadProjectView(BlazeContext context, WorkspacePathResolver workspacePathResolver);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
deleted file mode 100644
index c497b70..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.base.util.SerializationUtil;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Project view manager implementation.
- */
-/**
- * Stores mutable per-project user settings.
- */
-final class ProjectViewManagerImpl extends ProjectViewManager {
-
- private static final Logger LOG = Logger.getInstance(ProjectViewManagerImpl.class);
- private static final String CACHE_FILE_NAME = "project.view.dat";
-
- private final Project project;
- @Nullable private ProjectViewSet projectViewSet;
- private boolean projectViewSetLoaded = false;
-
- public ProjectViewManagerImpl(@NotNull Project project) {
- this.project = project;
- }
-
- @Nullable
- @Override
- public ProjectViewSet getProjectViewSet() {
- if (projectViewSet == null && !projectViewSetLoaded) {
- ProjectViewSet loadedProjectViewSet = null;
- try {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project).getImportSettings();
- if (importSettings == null) {
- return null;
- }
- File file = getCacheFile(project, importSettings);
-
- List<ClassLoader> classLoaders = Lists.newArrayList();
- classLoaders.add(getClass().getClassLoader());
- classLoaders.add(Thread.currentThread().getContextClassLoader());
- loadedProjectViewSet = (ProjectViewSet) SerializationUtil.loadFromDisk(file, classLoaders);
- } catch (IOException e) {
- LOG.info(e);
- }
- this.projectViewSet = loadedProjectViewSet;
- this.projectViewSetLoaded = true;
- }
- return projectViewSet;
- }
-
- @Override
- public ProjectViewSet reloadProjectView(BlazeContext context, WorkspacePathResolver workspacePathResolver) {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project).getImportSettings();
- assert importSettings != null;
- assert importSettings.getProjectViewFile() != null;
- File projectViewFile = new File(importSettings.getProjectViewFile());
- ProjectViewParser parser = new ProjectViewParser(context, workspacePathResolver);
- parser.parseProjectView(projectViewFile);
-
- boolean success = !context.hasErrors();
- if (success) {
- ProjectViewSet projectViewSet = parser.getResult();
- File file = getCacheFile(project, importSettings);
- try {
- SerializationUtil.saveToDisk(file, projectViewSet);
- }
- catch (IOException e) {
- LOG.error(e);
- }
- this.projectViewSet = projectViewSet;
- }
- return success ? projectViewSet : null;
- }
-
- private static File getCacheFile(Project project, BlazeImportSettings importSettings) {
- return new File(BlazeDataStorage.getProjectCacheDir(project, importSettings), CACHE_FILE_NAME);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
deleted file mode 100644
index adcfaa4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.Section;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * A collection of project views and their file names.
- */
-public final class ProjectViewSet implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private final ImmutableList<ProjectViewFile> projectViewFiles;
-
- public ProjectViewSet(ImmutableList<ProjectViewFile> projectViewFiles) {
- this.projectViewFiles = projectViewFiles;
- }
-
- public <T> List<T> listItems(SectionKey<T, ListSection<T>> key) {
- List<T> result = Lists.newArrayList();
- for (ListSection<T> section : getSections(key)) {
- result.addAll(section.items());
- }
- return result;
- }
-
- @Nullable
- public <T> T getSectionValue(SectionKey<T, ScalarSection<T>> key) {
- return getSectionValue(key, null);
- }
-
- public <T> T getSectionValue(SectionKey<T, ScalarSection<T>> key, T defaultValue) {
- Collection<ScalarSection<T>> sections = getSections(key);
- if (sections.isEmpty()) {
- return defaultValue;
- } else {
- return Iterables.getLast(sections).getValue();
- }
- }
-
- public <T, SectionType extends Section<T>> Collection<SectionType> getSections(SectionKey<T, SectionType> key) {
- List<SectionType> result = Lists.newArrayList();
- for (ProjectViewFile projectViewFile : projectViewFiles) {
- ProjectView projectView = projectViewFile.projectView;
- SectionType section = projectView.getSectionOfType(key);
- if (section != null) {
- result.add(section);
- }
- }
- return result;
- }
-
- public Collection<ProjectViewFile> getProjectViewFiles() {
- return projectViewFiles;
- }
-
- @Nullable
- public ProjectViewFile getTopLevelProjectViewFile() {
- return !projectViewFiles.isEmpty() ? projectViewFiles.get(projectViewFiles.size() - 1) : null;
- }
-
- /**
- * A project view/file pair
- */
- public static class ProjectViewFile implements Serializable {
- private static final long serialVersionUID = 1L;
- public final ProjectView projectView;
- @Nullable public final File projectViewFile;
-
- public ProjectViewFile(ProjectView projectView, @Nullable File projectViewFile) {
- this.projectView = projectView;
- this.projectViewFile = projectViewFile;
- }
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- ImmutableList.Builder<ProjectViewFile> projectViewFiles = ImmutableList.builder();
-
- public Builder add(ProjectView projectView) {
- return add(null, projectView);
- }
-
- public Builder add(@Nullable File projectViewFile, ProjectView projectView) {
- projectViewFiles.add(new ProjectViewFile(projectView, projectViewFile));
- return this;
- }
-
- public Builder addAll(Collection<ProjectViewFile> projectViewFiles) {
- this.projectViewFiles.addAll(projectViewFiles);
- return this;
- }
-
- public ProjectViewSet build() {
- return new ProjectViewSet(projectViewFiles.build());
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManager.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManager.java
deleted file mode 100644
index 567db81..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManager.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.components.ServiceManager;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Manages project view storage.
- *
- * For the most part, use ProjectViewManager instead. This is a lower-level API intended for use by
- * ProjectViewManager itself, and during the import process before a project exists.
- */
-public abstract class ProjectViewStorageManager {
-
- private static final String BLAZE_EXTENSION = "blazeproject";
- private static final String BAZEL_EXTENSION = "bazelproject";
- private static final String LEGACY_EXTENSION = "asproject";
-
- public static final ImmutableList<String> VALID_EXTENSIONS = ImmutableList.of(
- BLAZE_EXTENSION,
- BAZEL_EXTENSION,
- LEGACY_EXTENSION
- );
-
- public static boolean isProjectViewFile(@NotNull File file) {
- return isProjectViewFile(file.getName());
- }
-
- public static boolean isProjectViewFile(String fileName) {
- for (String ext : VALID_EXTENSIONS) {
- if (fileName.endsWith("." + ext)) {
- return true;
- }
- }
- return false;
- }
-
- public static String getProjectViewFileName(BuildSystem buildSystem) {
- switch (buildSystem) {
- case Blaze:
- return "." + BLAZE_EXTENSION;
- case Bazel:
- return "." + BAZEL_EXTENSION;
- default:
- throw new IllegalArgumentException("Unrecognized build system type: " + buildSystem);
- }
- }
-
- public static File getLocalProjectViewFileName(BuildSystem buildSystem, File projectDataDirectory) {
- return new File(projectDataDirectory, getProjectViewFileName(buildSystem));
- }
-
- public static ProjectViewStorageManager getInstance() {
- return ServiceManager.getService(ProjectViewStorageManager.class);
- }
-
- @Nullable
- public abstract String loadProjectView(File projectViewFile) throws IOException;
-
- public abstract void writeProjectView(String projectViewText, File projectViewFile) throws IOException;
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
deleted file mode 100644
index 9f4bed2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- * Project view storage implementation.
- */
-final class ProjectViewStorageManagerImpl extends ProjectViewStorageManager {
- private static final Logger LOG = Logger.getInstance(ProjectViewManagerImpl.class);
-
- @Nullable
- @Override
- public String loadProjectView(@NotNull File projectViewFile) throws IOException {
- FileInputStream fis = new FileInputStream(projectViewFile);
- byte[] data = new byte[(int)projectViewFile.length()];
- fis.read(data);
- fis.close();
- return new String(data, Charsets.UTF_8);
- }
-
- @Override
- public void writeProjectView(
- @NotNull String projectViewText,
- @NotNull File projectViewFile) throws IOException {
- FileWriter fileWriter = new FileWriter(projectViewFile);
- try {
- fileWriter.write(projectViewText);
- } finally {
- fileWriter.close();
- }
-
- LocalFileSystem.getInstance().refreshIoFiles(ImmutableList.of(projectViewFile));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java b/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
deleted file mode 100644
index 705d832..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.io.WorkspaceScanner;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.projectview.section.sections.ExcludedSourceSection;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.intellij.openapi.util.io.FileUtil;
-
-import java.util.List;
-
-/**
- * Verifies project views.
- */
-public class ProjectViewVerifier {
-
- public static class MissingDirectoryIssueData extends IssueOutput.IssueData {
- public final WorkspacePath workspacePath;
- public MissingDirectoryIssueData(WorkspacePath workspacePath) {
- this.workspacePath = workspacePath;
- }
- }
-
- /**
- * Verifies the project view. Any errors are output to the context as issues.
- */
- public static boolean verifyProjectView(
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings) {
- if (!verifyIncludedPackagesExistOnDisk(context, workspaceRoot, projectViewSet)) {
- return false;
- }
- if (!verifyDirectoriesAreNonOverlapping(context, projectViewSet)) {
- return false;
- }
- if (!verifyIncludedPackagesAreNotExcluded(context, projectViewSet)) {
- return false;
- }
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- if (!syncPlugin.validateProjectView(context, projectViewSet, workspaceLanguageSettings)) {
- return false;
- }
- }
- if (!projectViewSet.listItems(ExcludedSourceSection.KEY).isEmpty()) {
- IssueOutput
- .warn("excluded_sources is deprecated and has no effect.")
- .inFile(projectViewSet.getTopLevelProjectViewFile().projectViewFile)
- .submit(context);
- }
- return true;
- }
-
- private static boolean verifyDirectoriesAreNonOverlapping(
- BlazeContext context,
- ProjectViewSet projectViewSet) {
- boolean ok = true;
-
- List<WorkspacePath> includedDirectories = getIncludedDirectories(projectViewSet);
-
- for (WorkspacePath includedDirectory : includedDirectories) {
- for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
- ListSection<DirectoryEntry> directorySection = projectViewFile.projectView.getSectionOfType(DirectorySection.KEY);
- if (directorySection == null) {
- continue;
- }
-
- for (DirectoryEntry entry : directorySection.items()) {
- if (!entry.included) {
- continue;
- }
-
- if (isAncestor(includedDirectory.relativePath(), entry.directory.relativePath())) {
- IssueOutput
- .error(String.format("Overlapping directories: %s already included by %s",
- entry.directory.toString(),
- includedDirectory.toString()))
- .inFile(projectViewFile.projectViewFile)
- .submit(context);
- ok = false;
- }
- }
- }
- }
- return ok;
- }
-
- /**
- * Returns true if 'path' is a strict child of 'ancestorPath'.
- */
- private static boolean isAncestor(String ancestorPath, String path) {
- // FileUtil.isAncestor has a bug in its handling of equal, empty paths (it ignores the 'strict' flag in this case).
- if (ancestorPath.equals(path)) {
- return false;
- }
- return FileUtil.isAncestor(ancestorPath, path, true);
- }
-
- private static boolean verifyIncludedPackagesAreNotExcluded(
- BlazeContext context,
- ProjectViewSet projectViewSet) {
- boolean ok = true;
-
- List<WorkspacePath> includedDirectories = getIncludedDirectories(projectViewSet);
-
- for (WorkspacePath includedDirectory : includedDirectories) {
- for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
- ListSection<DirectoryEntry> directorySection = projectViewFile.projectView.getSectionOfType(DirectorySection.KEY);
- if (directorySection == null) {
- continue;
- }
-
- for (DirectoryEntry entry : directorySection.items()) {
- if (entry.included) {
- continue;
- }
-
- WorkspacePath excludedDirectory = entry.directory;
- if (FileUtil.isAncestor(
- excludedDirectory.relativePath(),
- includedDirectory.relativePath(),
- false)) {
- IssueOutput
- .error(String.format("%s is included, but that contradicts %s which was excluded",
- includedDirectory.toString(),
- excludedDirectory.toString()))
- .inFile(projectViewFile.projectViewFile)
- .submit(context);
- ok = false;
- }
- }
- }
- }
- return ok;
- }
-
- private static List<WorkspacePath> getIncludedDirectories(ProjectViewSet projectViewSet) {
- List<WorkspacePath> includedDirectories = Lists.newArrayList();
- for (DirectoryEntry entry : projectViewSet.listItems(DirectorySection.KEY)) {
- if (entry.included) {
- includedDirectories.add(entry.directory);
- }
- }
- return includedDirectories;
- }
-
- private static boolean verifyIncludedPackagesExistOnDisk(
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet) {
- boolean ok = true;
-
- WorkspaceScanner workspaceScanner = WorkspaceScanner.getInstance();
-
- for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
- ListSection<DirectoryEntry> directorySection = projectViewFile.projectView.getSectionOfType(DirectorySection.KEY);
- if (directorySection == null) {
- continue;
- }
- for (DirectoryEntry entry : directorySection.items()) {
- if (!entry.included) {
- continue;
- }
- WorkspacePath workspacePath = entry.directory;
- if (!workspaceScanner.exists(workspaceRoot, workspacePath)) {
- IssueOutput
- .error(String.format("Directory '%s' specified in import roots not found under workspace root '%s'",
- workspacePath, workspaceRoot))
- .inFile(projectViewFile.projectViewFile)
- .withData(new MissingDirectoryIssueData(workspacePath))
- .submit(context);
- ok = false;
- }
- }
- }
- return ok;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java b/blaze-base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java
deleted file mode 100644
index 8d20d8b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.parser;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Context for the project view parser.
- */
-public class ParseContext {
- private final BlazeContext context;
- private final WorkspacePathResolver workspacePathResolver;
- @Nullable private final File file;
- private final List<String> lines;
-
- @Nullable private Line currentLine;
- private int currentLineIndex;
-
- public static class Line {
- public final String text;
- public final int indent;
- public Line(String text, int indent) {
- this.text = text;
- this.indent = indent;
- }
- }
-
- public ParseContext(BlazeContext context, WorkspacePathResolver workspacePathResolver, @Nullable File file, String text) {
- this.context = context;
- this.workspacePathResolver = workspacePathResolver;
- this.file = file;
- this.lines = Lists.newArrayList(text.split("\n"));
- this.currentLine = null;
- this.currentLineIndex = -1;
- consume();
- }
-
- public Line current() {
- assert currentLine != null;
- return currentLine;
- }
-
- public void consume() {
- while (++currentLineIndex < lines.size()) {
- String line = lines.get(currentLineIndex);
- int indent = 0;
- while (indent < line.length() && line.charAt(indent) == ' ') {
- ++indent;
- }
- if (!indentationCorrect(indent)) {
- addError(String.format("Invalid indentation. Project view files are indented with %d spaces.", SectionParser.INDENT));
- continue;
- }
-
- line = line.trim();
- if (!shouldSkipLine(line)) {
- currentLine = new Line(line, indent);
- break;
- }
- }
- }
-
- private boolean indentationCorrect(int indent) {
- return indent == 0 || indent == 2;
- }
-
- boolean shouldSkipLine(String line) {
- return line.isEmpty() || line.startsWith("#");
- }
-
- public boolean atEnd() {
- return currentLineIndex >= lines.size();
- }
-
- public BlazeContext getContext() {
- return context;
- }
-
- public WorkspacePathResolver getWorkspacePathResolver() {
- return workspacePathResolver;
- }
-
- @Nullable
- public File getProjectViewFile() {
- return file;
- }
-
- public void addErrors(List<BlazeValidationError> errors) {
- for (BlazeValidationError error : errors) {
- addError(error.getError());
- }
- }
-
- public void addError(String error) {
- IssueOutput
- .error(error)
- .inFile(file)
- .onLine(currentLineIndex)
- .submit(context);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java b/blaze-base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java
deleted file mode 100644
index c9507a5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.parser;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.projectview.section.Section;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.projectview.section.sections.Sections;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Parses and writes project views.
- */
-public class ProjectViewParser {
-
- private final BlazeContext context;
- private final WorkspacePathResolver workspacePathResolver;
- private final boolean recursive;
-
- ImmutableList.Builder<ProjectViewSet.ProjectViewFile> projectViewFiles = ImmutableList.builder();
-
- public ProjectViewParser(BlazeContext context,
- WorkspacePathResolver workspacePathResolver) {
- this.context = context;
- this.workspacePathResolver = workspacePathResolver;
- this.recursive = true;
- }
-
- public void parseProjectView(File projectViewFile) {
- String projectViewText = null;
- try {
- projectViewText = ProjectViewStorageManager.getInstance().loadProjectView(projectViewFile);
- }
- catch (IOException e) {
- // Error handled below
- }
- if (projectViewText == null) {
- IssueOutput.error(String.format("Could not load project view file: '%s'", projectViewFile.getPath()))
- .submit(context);
- return;
- }
- parseProjectView(new ParseContext(context, workspacePathResolver, projectViewFile, projectViewText));
- }
-
- public void parseProjectView(String text) {
- parseProjectView(new ParseContext(context, workspacePathResolver, null, text));
- }
-
- private void parseProjectView(ParseContext parseContext) {
- Map<SectionKey, Section> sectionMap = Maps.newHashMap();
-
- while (!parseContext.atEnd()) {
- if (parseContext.current().indent != 0) {
- parseContext.addError(String.format("Invalid indentation on line: '%s'", parseContext.current().text));
- skipSection(parseContext);
- continue;
- }
- Section section = null;
- SectionParser producingParser = null;
- for (SectionParser sectionParser : Sections.getParsers()) {
- section = sectionParser.parse(this, parseContext);
- if (section != null) {
- producingParser = sectionParser;
- break;
- }
- }
- if (section != null) {
- SectionKey key = producingParser.getSectionKey();
- if (!sectionMap.containsKey(key)) {
- sectionMap.put(key, section);
- } else {
- BlazeContext context = parseContext.getContext();
- IssueOutput.error(String.format("Duplicate attribute: '%s'", producingParser.getName()))
- .inFile(parseContext.getProjectViewFile())
- .submit(context);
- }
- } else {
- parseContext.addError(String.format("Could not parse: '%s'", parseContext.current().text));
- parseContext.consume();
-
- // Skip past the entire section
- skipSection(parseContext);
- }
- }
-
- ProjectView.Builder builder = ProjectView.builder();
- for (Map.Entry<SectionKey, Section> entry : sectionMap.entrySet()) {
- builder.put(entry.getKey(), entry.getValue());
- }
-
- projectViewFiles.add(new ProjectViewSet.ProjectViewFile(builder.build(), parseContext.getProjectViewFile()));
- }
-
- /**
- * Skips all lines until the next unindented, non-empty line.
- */
- private static void skipSection(ParseContext parseContext) {
- while (!parseContext.atEnd() && parseContext.current().indent != 0) {
- parseContext.consume();
- }
- }
-
- public boolean isRecursive() {
- return recursive;
- }
-
- public ProjectViewSet getResult() {
- return new ProjectViewSet(projectViewFiles.build());
- }
-
- public static String projectViewToString(ProjectView projectView) {
- StringBuilder sb = new StringBuilder();
- int sectionCount = 0;
- for (SectionParser sectionParser : Sections.getParsers()) {
- SectionKey sectionKey = sectionParser.getSectionKey();
- Section section = projectView.getSectionOfType(sectionKey);
- if (section != null) {
- if (sectionCount > 0) {
- sb.append('\n');
- }
- sectionParser.print(sb, section);
- ++sectionCount;
- }
- }
- return sb.toString();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/Glob.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/Glob.java
deleted file mode 100644
index 29226cd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/Glob.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-import com.intellij.openapi.fileTypes.FileNameMatcher;
-import org.jetbrains.jps.model.fileTypes.FileNameMatcherFactory;
-
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * Glob matcher.
- */
-public class Glob implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private String pattern;
- transient private FileNameMatcher matcher;
-
- public Glob(String pattern) {
- this.pattern = pattern;
- }
-
- public static class GlobSet implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private final Collection<Glob> globs = Lists.newArrayList();
-
- public GlobSet(Collection<Glob> globs) {
- this.globs.addAll(globs);
- }
-
- public boolean isEmpty() {
- return globs.isEmpty();
- }
-
- public void add(Glob glob) {
- globs.add(glob);
- }
-
- public boolean matches(String string) {
- for (Glob glob : globs) {
- if (glob.matches(string)) {
- return true;
- }
- }
- return false;
- }
- }
-
- public boolean matches(String string) {
- if (matcher == null) {
- matcher = FileNameMatcherFactory.getInstance().createMatcher(pattern);
- }
- return matcher.accept(string);
- }
-
- @Override
- public String toString() {
- return pattern;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Glob glob = (Glob)o;
- return Objects.equal(pattern, glob.pattern);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(pattern);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/GlobSectionParser.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/GlobSectionParser.java
deleted file mode 100644
index 30e1a41..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/GlobSectionParser.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-
-import java.util.regex.PatternSyntaxException;
-
-/**
- * Parses glob sections.
- */
-public class GlobSectionParser extends ListSectionParser<Glob> {
-
- public GlobSectionParser(SectionKey<Glob, ListSection<Glob>> key) {
- super(key);
- }
-
- @Override
- protected final void parseItem(ProjectViewParser parser,
- ParseContext parseContext,
- ImmutableList.Builder<Glob> items) {
- String text = parseContext.current().text;
- try {
- Glob glob = new Glob(text);
- items.add(glob);
- }
- catch (PatternSyntaxException e) {
- parseContext.addError(e.getMessage());
- }
- }
-
- @Override
- protected final void printItem(Glob item, StringBuilder sb) {
- sb.append(item.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.FileSystemItem;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java
deleted file mode 100644
index a34fdcc..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * Section of labels
- */
-public final class LabelSectionParser extends ListSectionParser<Label> {
- public LabelSectionParser(SectionKey<Label, ListSection<Label>> key) {
- super(key);
- }
-
- @Override
- protected void parseItem(@NotNull ProjectViewParser parser,
- @NotNull ParseContext parseContext,
- @NotNull ImmutableList.Builder<Label> items) {
- String text = parseContext.current().text;
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (!Label.validate(text, errors)) {
- parseContext.addErrors(errors);
- return;
- }
- items.add(new Label(text));
- }
-
- @Override
- protected void printItem(@NotNull Label item, @NotNull StringBuilder sb) {
- sb.append(item.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Label;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ListSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/ListSection.java
deleted file mode 100644
index 4bf8eba..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ListSection.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.collect.ImmutableList;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-
-/**
- * List value. Eg.
- *
- * my_attribute:
- * value0
- * value1
- * value2
- * ...
- */
-public final class ListSection<T> extends Section<T> {
- private static final long serialVersionUID = 1L;
-
- private final ImmutableList<T> items;
-
- ListSection(ImmutableList<T> items) {
- this.items = items;
- }
-
- public Collection<T> items() {
- return items;
- }
-
- public static <T> Builder<T> builder(SectionKey<T, ListSection<T>> sectionKey) {
- return new Builder<T>(sectionKey, null);
- }
-
- public static <T> Builder<T> update(SectionKey<T, ListSection<T>> sectionKey, @Nullable ListSection<T> section) {
- return new Builder<T>(sectionKey, section);
- }
-
- public static class Builder<T> extends SectionBuilder<T, ListSection<T>> {
- private final ImmutableList.Builder<T> items = ImmutableList.builder();
-
- public Builder(SectionKey<T, ListSection<T>> sectionKey, @Nullable ListSection<T> section) {
- super(sectionKey);
- if (section != null) {
- items.addAll(section.items);
- }
- }
-
- public final Builder<T> add(T item) {
- items.add(item);
- return this;
- }
-
- @Override
- public final ListSection<T> build() {
- return new ListSection<T>(items.build());
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ListSectionParser.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/ListSectionParser.java
deleted file mode 100644
index 713bad2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ListSectionParser.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-
-import javax.annotation.Nullable;
-
-/**
- * List section parser base class.
- */
-public abstract class ListSectionParser<T> extends SectionParser {
- protected ListSectionParser(SectionKey<T, ? extends ListSection<T>> key) {
- super(key);
- }
-
- @Nullable
- @Override
- public final Section parse(ProjectViewParser parser, ParseContext parseContext) {
- if (parseContext.atEnd()) {
- return null;
- }
-
- String name = getName();
-
- if (!parseContext.current().text.equals(name + ':')) {
- return null;
- }
- parseContext.consume();
-
- ImmutableList.Builder<T> builder = ImmutableList.builder();
-
- while (!parseContext.atEnd() && parseContext.current().indent >= SectionParser.INDENT) {
- parseItem(parser, parseContext, builder);
- parseContext.consume();
- }
-
- ImmutableList<T> items = builder.build();
- if (items.isEmpty()) {
- parseContext.addError(String.format("Empty section: '%s'", name));
- }
-
- return new ListSection<T>(items);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public final void print(StringBuilder sb, Section section) {
- ListSection<T> listSection = (ListSection<T>)section;
-
- // Omit empty sections completely
- if (listSection.items().isEmpty()) {
- return;
- }
-
- sb.append(getName()).append(':').append('\n');
- for (T item : listSection.items()) {
- for (int i = 0; i < SectionParser.INDENT; ++i) {
- sb.append(' ');
- }
- printItem(item, sb);
- sb.append('\n');
- }
- }
-
- protected abstract void parseItem(ProjectViewParser parser,
- ParseContext parseContext,
- ImmutableList.Builder<T> items);
-
- protected abstract void printItem(T item, StringBuilder sb);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/MetricsProjectSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/MetricsProjectSection.java
deleted file mode 100644
index ea43916..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/MetricsProjectSection.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.base.CharMatcher;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-
-import javax.annotation.Nullable;
-
-public class MetricsProjectSection {
- public static final SectionKey<String, ScalarSection<String>> KEY =
- SectionKey.of("metrics_project");
- public static final SectionParser PARSER = new MetricsProjectSectionParser();
-
- private static class MetricsProjectSectionParser extends ScalarSectionParser<String> {
- public MetricsProjectSectionParser() {
- super(KEY, ':');
- }
-
- @Nullable
- @Override
- protected String parseItem(ProjectViewParser parser, ParseContext parseContext, String rest) {
- return CharMatcher.is('\"').trimFrom(rest);
- }
-
- @Override
- protected void printItem(StringBuilder sb, String value) {
- sb.append(value);
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Other;
- }
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ScalarSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/ScalarSection.java
deleted file mode 100644
index d43ba63..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ScalarSection.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-/**
- * Scalar value.
- */
-public final class ScalarSection<T> extends Section<T> {
- private static final long serialVersionUID = 1L;
-
- private final T value;
-
- public ScalarSection(T value) {
- this.value = value;
- }
-
- public T getValue() {
- return value;
- }
-
- public static <T> Builder<T> builder(SectionKey<T, ScalarSection<T>> sectionKey) {
- return new Builder<T>(sectionKey);
- }
-
- public static class Builder<T> extends SectionBuilder<T, ScalarSection<T>> {
- private T value;
-
- public Builder(SectionKey<T, ScalarSection<T>> sectionKey) {
- super(sectionKey);
- }
-
- public Builder<T> set(T value) {
- this.value = value;
- return this;
- }
-
- @Override
- public ScalarSection<T> build() {
- return new ScalarSection<T>(value);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ScalarSectionParser.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/ScalarSectionParser.java
deleted file mode 100644
index 7942372..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/ScalarSectionParser.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-
-import javax.annotation.Nullable;
-
-/**
- * Parses scalar values
- */
-public abstract class ScalarSectionParser<T> extends SectionParser {
-
- private final char divider;
-
- protected ScalarSectionParser(SectionKey<T, ? extends ScalarSection<T>> sectionKey,
- char divider) {
- super(sectionKey);
- this.divider = divider;
- }
-
- @Nullable
- @Override
- public final ScalarSection<T> parse(ProjectViewParser parser, ParseContext parseContext) {
- if (parseContext.atEnd()) {
- return null;
- }
-
- String name = getName();
- ParseContext.Line line = parseContext.current();
-
- if (!line.text.startsWith(name + divider)) {
- return null;
- }
- String rest = line.text.substring(name.length() + 1).trim();
- parseContext.consume();
- T item = parseItem(parser, parseContext, rest);
- return item != null ? new ScalarSection<T>(item) : null;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public final void print(StringBuilder sb, Section section) {
- sb.append(getName()).append(divider);
- if (divider != ' ') {
- sb.append(' ');
- }
- printItem(sb, ((ScalarSection<T>)section).getValue());
- sb.append('\n');
- }
-
- /**
- * Used by psi-parser for validation.
- */
- public char getDivider() {
- return divider;
- }
-
- @Nullable
- protected abstract T parseItem(ProjectViewParser parser, ParseContext parseContext, String rest);
-
- protected abstract void printItem(StringBuilder sb, T value);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/Section.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/Section.java
deleted file mode 100644
index 6fc63d2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/Section.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import java.io.Serializable;
-
-/**
- * A section is a part of an project view file. For instance:
- *
- * directories
- * java/com/a
- * java/com/b
- *
- * Is a directory section with two items.
- */
-public abstract class Section<T> implements Serializable {
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionBuilder.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionBuilder.java
deleted file mode 100644
index 74ee9f5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionBuilder.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-/**
- * Builder base class.
- */
-public abstract class SectionBuilder<T, SectionType extends Section<T>> {
- private final SectionKey<T, SectionType> sectionKey;
-
- protected SectionBuilder(SectionKey<T, SectionType> sectionKey) {
- this.sectionKey = sectionKey;
- }
-
- public abstract SectionType build();
-
- public final SectionKey<T, SectionType> getSectionKey() {
- return sectionKey;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionKey.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionKey.java
deleted file mode 100644
index 2c4084b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionKey.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.common.base.Objects;
-
-import java.io.Serializable;
-
-/**
- * Key to a section of type T.
- */
-public final class SectionKey<T, SectionType extends Section<T>> implements Serializable {
- private static final long serialVersionUID = 1L;
- private final String name;
-
- public SectionKey(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public static <T, SectionType extends Section<T>> SectionKey<T, SectionType> of(String name) {
- return new SectionKey<T, SectionType>(name);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- SectionKey<?, ?> that = (SectionKey<?, ?>)o;
- return Objects.equal(name, that.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(name);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java
deleted file mode 100644
index d01cad6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section;
-
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Parses a section.
- */
-public abstract class SectionParser {
-
- public static final int INDENT = 2;
-
- /**
- * The type of item(s) in this section
- */
- public enum ItemType {
- FileSystemItem, // files, directories, globs
- Label, // a blaze label
- Other, // anything else
- }
-
- private final SectionKey sectionKey;
-
- protected SectionParser(SectionKey sectionKey) {
- this.sectionKey = sectionKey;
- }
-
- public String getName() {
- return sectionKey.getName();
- }
-
- public SectionKey getSectionKey() {
- return sectionKey;
- }
-
- @Nullable
- public abstract Section parse(ProjectViewParser parser, ParseContext parseContext);
-
- public abstract void print(StringBuilder sb, Section section);
-
- public boolean isDeprecated() {
- return false;
- }
-
- /**
- * The type of item(s) in this section.
- */
- public abstract ItemType getItemType();
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/AdditionalLanguagesSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/AdditionalLanguagesSection.java
deleted file mode 100644
index 692d385..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/AdditionalLanguagesSection.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ListSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Allows users to set the rule classes they want to be imported
- */
-public class AdditionalLanguagesSection {
- public static final SectionKey<LanguageClass, ListSection<LanguageClass>> KEY = SectionKey.of("additional_languages");
- public static final SectionParser PARSER = new AdditionalLanguagesSectionParser();
-
- private static class AdditionalLanguagesSectionParser extends ListSectionParser<LanguageClass> {
- public AdditionalLanguagesSectionParser() {
- super(KEY);
- }
-
- @Override
- protected void parseItem(@NotNull ProjectViewParser parser,
- @NotNull ParseContext parseContext,
- @NotNull ImmutableList.Builder<LanguageClass> items) {
- String text = parseContext.current().text;
- LanguageClass language = LanguageClass.fromString(text);
- if (language == null) {
- parseContext.addError("Invalid language: " + text);
- return;
- }
- items.add(language);
- }
-
- @Override
- protected void printItem(@NotNull LanguageClass item, @NotNull StringBuilder sb) {
- sb.append(item.getName());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Other;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/BuildFlagsSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/BuildFlagsSection.java
deleted file mode 100644
index d48cc0c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/BuildFlagsSection.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ListSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Section for blaze_flags
- */
-public class BuildFlagsSection {
- public static final SectionKey<String, ListSection<String>> KEY = SectionKey.of("build_flags");
- public static final SectionParser PARSER = new BuildFlagsSectionParser();
-
- public static class BuildFlagsSectionParser extends ListSectionParser<String> {
- protected BuildFlagsSectionParser() {
- super(KEY);
- }
-
- @Override
- protected void parseItem(@NotNull ProjectViewParser parser,
- @NotNull ParseContext parseContext,
- @NotNull ImmutableList.Builder<String> items) {
- String text = parseContext.current().text;
- items.add(text);
- }
-
- @Override
- protected void printItem(@NotNull String item, @NotNull StringBuilder sb) {
- sb.append(item);
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Other;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/DirectoryEntry.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/DirectoryEntry.java
deleted file mode 100644
index 924c487..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/DirectoryEntry.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.base.Objects;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-
-import java.io.Serializable;
-
-/**
- * An entry in the directory section.
- */
-public class DirectoryEntry implements Serializable {
- private static final long serialVersionUID = 1L;
- public final WorkspacePath directory;
- public final boolean included;
-
- public DirectoryEntry(WorkspacePath directory, boolean included) {
- this.directory = directory;
- this.included = included;
- }
-
- public static DirectoryEntry include(WorkspacePath directory) {
- return new DirectoryEntry(directory, true);
- }
-
- public static DirectoryEntry exclude(WorkspacePath directory) {
- return new DirectoryEntry(directory, false);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- DirectoryEntry that = (DirectoryEntry)o;
- return Objects.equal(included, that.included)
- && Objects.equal(directory, that.directory);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(directory, included);
- }
-
- @Override
- public String toString() {
- return (included ? "" : "-") + directoryString();
- }
-
- private String directoryString() {
- if (directory.isWorkspaceRoot()) {
- return ".";
- }
- return directory.relativePath();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/DirectorySection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/DirectorySection.java
deleted file mode 100644
index b8e3329..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/DirectorySection.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ListSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import com.intellij.util.PathUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * "directories" section.
- */
-public class DirectorySection {
- public static final SectionKey<DirectoryEntry, ListSection<DirectoryEntry>> KEY = SectionKey.of("directories");
- public static final SectionParser PARSER = new DirectorySectionParser();
-
- private static class DirectorySectionParser extends ListSectionParser<DirectoryEntry> {
- public DirectorySectionParser() {
- super(KEY);
- }
-
- @Override
- protected void parseItem(@NotNull ProjectViewParser parser,
- @NotNull ParseContext parseContext,
- @NotNull ImmutableList.Builder<DirectoryEntry> items) {
- String text = parseContext.current().text;
- boolean excluded = text.startsWith("-");
- text = excluded ? text.substring(1) : text;
-
- text = PathUtil.getCanonicalPath(text);
-
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (WorkspacePath.validate(text, errors)) {
- items.add(new DirectoryEntry(new WorkspacePath(text), !excluded));
- } else {
- parseContext.addErrors(errors);
- }
- }
-
- @Override
- protected void printItem(@NotNull DirectoryEntry item, @NotNull StringBuilder sb) {
- sb.append(item.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.FileSystemItem;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludeTargetSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludeTargetSection.java
deleted file mode 100644
index 8376747..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludeTargetSection.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.projectview.section.LabelSectionParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-
-/**
- * Excludes a target.
- */
-public class ExcludeTargetSection {
- public static final SectionKey<Label, ListSection<Label>> KEY = SectionKey.of("exclude_target");
- public static final SectionParser PARSER = new LabelSectionParser(KEY);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludedSourceSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludedSourceSection.java
deleted file mode 100644
index da17d6b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ExcludedSourceSection.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.idea.blaze.base.projectview.section.*;
-
-/**
- * Section for excluding source files.
- */
-@Deprecated
-public class ExcludedSourceSection {
- public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("excluded_sources");
- public static final SectionParser PARSER = new GlobSectionParser(KEY) {
- @Override
- public boolean isDeprecated() {
- return true;
- }
- };
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ImportSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ImportSection.java
deleted file mode 100644
index 53a989d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ImportSection.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * "import" section.
- */
-public class ImportSection {
- public static final SectionKey<WorkspacePath, ScalarSection<WorkspacePath>> KEY = SectionKey.of("import");
- public static final SectionParser PARSER = new ImportSectionParser();
-
- private static class ImportSectionParser extends ScalarSectionParser<WorkspacePath> {
- public ImportSectionParser() {
- super(KEY, ' ');
- }
-
- @Override
- @Nullable
- protected WorkspacePath parseItem(@NotNull ProjectViewParser parser, @NotNull ParseContext parseContext, @NotNull String text) {
- List<BlazeValidationError> errors = Lists.newArrayList();
- if (WorkspacePath.validate(text, errors)) {
- WorkspacePath workspacePath = new WorkspacePath(text);
- if (parser.isRecursive()) {
- File projectViewFile = parseContext.getWorkspacePathResolver().resolveToFile(workspacePath);
- if (projectViewFile != null) {
- parser.parseProjectView(projectViewFile);
- } else {
- parseContext.addError("Could not resolve import: " + workspacePath);
- }
- }
- return workspacePath;
- }
- parseContext.addErrors(errors);
- return null;
- }
-
- @Override
- protected void printItem(@NotNull StringBuilder sb, @NotNull WorkspacePath section) {
- sb.append(section.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.FileSystemItem;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ImportTargetOutputSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ImportTargetOutputSection.java
deleted file mode 100644
index 13824e7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/ImportTargetOutputSection.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.projectview.section.LabelSectionParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-
-/**
- * Forces target output import of mentioned targets.
- */
-public class ImportTargetOutputSection {
- public static final SectionKey<Label, ListSection<Label>> KEY = SectionKey.of("import_target_output");
- public static final SectionParser PARSER = new LabelSectionParser(KEY);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/Sections.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/Sections.java
deleted file mode 100644
index 9d3784e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/Sections.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.section.MetricsProjectSection;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * List of available sections.
- */
-public class Sections {
- // Put these in the order that you want them to appear in the output
- private static final List<SectionParser> PARSERS = Lists.newArrayList(
- ImportSection.PARSER,
- DirectorySection.PARSER,
- TargetSection.PARSER,
- WorkspaceTypeSection.PARSER,
- AdditionalLanguagesSection.PARSER,
- TestSourceSection.PARSER,
- BuildFlagsSection.PARSER,
- ImportTargetOutputSection.PARSER,
- ExcludeTargetSection.PARSER,
- ExcludedSourceSection.PARSER,
- MetricsProjectSection.PARSER
- );
-
- public static List<SectionParser> getParsers() {
- List<SectionParser> parsers = Lists.newArrayList(PARSERS);
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- parsers.addAll(syncPlugin.getSections());
- }
- return parsers;
- }
-
- public static List<SectionParser> getUndeprecatedParsers() {
- return getParsers().stream()
- .filter(p -> !p.isDeprecated())
- .collect(Collectors.toList());
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/TargetSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/TargetSection.java
deleted file mode 100644
index 8a737fb..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/TargetSection.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ListSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * "targets" section.
- */
-public class TargetSection {
- public static final SectionKey<TargetExpression, ListSection<TargetExpression>> KEY = SectionKey.of("targets");
- public static final SectionParser PARSER = new TargetSectionParser();
-
- private static class TargetSectionParser extends ListSectionParser<TargetExpression> {
- public TargetSectionParser() {
- super(KEY);
- }
-
- @Override
- protected void parseItem(@NotNull ProjectViewParser parser,
- @NotNull ParseContext parseContext,
- @NotNull ImmutableList.Builder<TargetExpression> items) {
- String text = parseContext.current().text;
- items.add(TargetExpression.fromString(text));
- }
-
- @Override
- protected void printItem(@NotNull TargetExpression item, @NotNull StringBuilder sb) {
- sb.append(item.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Label;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/TestSourceSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/TestSourceSection.java
deleted file mode 100644
index 4cbc6bc..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/TestSourceSection.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.idea.blaze.base.projectview.section.*;
-
-/**
- * Section for configuring test sources.
- */
-public class TestSourceSection {
- public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("test_sources");
- public static final SectionParser PARSER = new GlobSectionParser(KEY);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/WorkspaceTypeSection.java b/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/WorkspaceTypeSection.java
deleted file mode 100644
index abab2ed..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/projectview/section/sections/WorkspaceTypeSection.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.section.sections;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-
-import javax.annotation.Nullable;
-import java.util.List;
-
-/**
- * The type of your workspace.
- */
-public class WorkspaceTypeSection {
- public static final SectionKey<WorkspaceType, ScalarSection<WorkspaceType>> KEY = SectionKey.of("workspace_type");
- public static final SectionParser PARSER = new WorkspaceTypeSectionParser();
-
- private static class WorkspaceTypeSectionParser extends ScalarSectionParser<WorkspaceType> {
- public WorkspaceTypeSectionParser() {
- super(KEY, ':');
- }
-
- @Override
- @Nullable
- protected WorkspaceType parseItem(ProjectViewParser parser, ParseContext parseContext, String text) {
- List<BlazeValidationError> errors = Lists.newArrayList();
- WorkspaceType workspaceType = WorkspaceType.fromString(text);
- if (workspaceType == null) {
- parseContext.addError("Invalid workspace type: " + text);
- }
- parseContext.addErrors(errors);
- return workspaceType;
- }
-
- @Override
- protected void printItem(StringBuilder sb, WorkspaceType item) {
- sb.append(item.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Other;
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/rulemaps/ReverseDependencyMap.java b/blaze-base/src/com/google/idea/blaze/base/rulemaps/ReverseDependencyMap.java
deleted file mode 100644
index 84e073b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/rulemaps/ReverseDependencyMap.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.rulemaps;
-
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Iterables;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-
-import java.util.Map;
-
-public class ReverseDependencyMap {
- public static ImmutableMultimap<Label, Label> createRdepsMap(Map<Label, RuleIdeInfo> ruleMap) {
- ImmutableMultimap.Builder<Label, Label> builder = ImmutableMultimap.builder();
- for (Map.Entry<Label, RuleIdeInfo> entry : ruleMap.entrySet()) {
- Label label = entry.getKey();
- RuleIdeInfo ruleIdeInfo = entry.getValue();
- for (Label dep : Iterables.concat(ruleIdeInfo.dependencies, ruleIdeInfo.runtimeDeps)) {
- if (ruleMap.containsKey(dep)) {
- builder.put(dep, label);
- }
- }
- }
- return builder.build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMap.java b/blaze-base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMap.java
deleted file mode 100644
index 2b10c82..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMap.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.rulemaps;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import java.io.File;
-
-/**
- * Maps source files to their respective targets
- */
-public interface SourceToRuleMap {
-
- static SourceToRuleMap getInstance(Project project) {
- return ServiceManager.getService(project, SourceToRuleMap.class);
- }
-
- ImmutableCollection<Label> getTargetsForSourceFile(File file);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMapImpl.java b/blaze-base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMapImpl.java
deleted file mode 100644
index c330077..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/rulemaps/SourceToRuleMapImpl.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.rulemaps;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.SyncListener;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Maps source files to their respective targets
- */
-public class SourceToRuleMapImpl implements SourceToRuleMap {
- private final Project project;
- private ImmutableMultimap<File, Label> sourceToTargetMap;
-
- public static SourceToRuleMapImpl getImpl(Project project) {
- return (SourceToRuleMapImpl) ServiceManager.getService(project, SourceToRuleMap.class);
- }
-
- public SourceToRuleMapImpl(Project project) {
- this.project = project;
- }
-
- @Override
- public ImmutableCollection<Label> getTargetsForSourceFile(File file) {
- ImmutableMultimap<File, Label> sourceToTargetMap = getSourceToTargetMap();
- return sourceToTargetMap != null ? sourceToTargetMap.get(file) : ImmutableList.of();
- }
-
- @Nullable
- private synchronized ImmutableMultimap<File, Label> getSourceToTargetMap() {
- if (this.sourceToTargetMap == null) {
- this.sourceToTargetMap = initSourceToTargetMap();
- }
- return this.sourceToTargetMap;
- }
-
- private synchronized void clearSourceToTargetMap() {
- this.sourceToTargetMap = null;
- }
-
- @Nullable
- private ImmutableMultimap<File, Label> initSourceToTargetMap() {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return null;
- }
- ImmutableMultimap.Builder<File, Label> sourceToTargetMap = ImmutableMultimap.builder();
- for (RuleIdeInfo rule : blazeProjectData.ruleMap.values()) {
- Label label = rule.label;
- for (ArtifactLocation sourceArtifact : rule.sources) {
- sourceToTargetMap.put(sourceArtifact.getFile(), label);
- }
- }
- return sourceToTargetMap.build();
- }
-
- static class ClearSourceToTargetMap extends SyncListener.Adapter {
- @Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- getImpl(project).clearSourceToTargetMap();
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/BlazeRuleConfigurationFactory.java b/blaze-base/src/com/google/idea/blaze/base/run/BlazeRuleConfigurationFactory.java
deleted file mode 100644
index 87ab7c7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/BlazeRuleConfigurationFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run;
-
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.RunnerAndConfigurationSettings;
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-/**
- * A factory creating run configurations based on Blaze rules.
- */
-public interface BlazeRuleConfigurationFactory {
- ExtensionPointName<BlazeRuleConfigurationFactory> EP_NAME =
- ExtensionPointName.create("com.google.idea.blaze.RuleConfigurationFactory");
-
- /**
- * Returns whether this factory can handle a rule.
- */
- boolean handlesRule(WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule);
-
- /** Constructs and initializes a configuration for the given rule. */
- RunnerAndConfigurationSettings createForRule(RunManager runManager, RuleIdeInfo rule);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java b/blaze-base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
deleted file mode 100644
index f9b6865..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run;
-
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Marker interface for all run configurations
- */
-public interface BlazeRunConfiguration {
- @Nullable
- TargetExpression getTarget();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java b/blaze-base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
deleted file mode 100755
index 4f81112..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run;
-
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.SyncListener;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.RunnerAndConfigurationSettings;
-import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.util.ui.UIUtil;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Creates run configurations for modules imported from
- * {@link com.android.builder.model.AndroidProject}s.
- */
-public class BlazeRunConfigurationSyncListener implements SyncListener {
- private static Logger log = Logger.getInstance(BlazeRunConfigurationSyncListener.class);
-
- @Override
- public void onSyncStart(Project project) {
- }
-
- @Override
- public void afterSync(Project project,
- boolean successful) {
- }
-
- @Override
- public void onSyncComplete(
- Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
-
- UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
- Set<Label> labelsWithConfigs = labelsWithConfigs(project);
- Set<TargetExpression> targetExpressions = Sets.newHashSet(projectViewSet.listItems(TargetSection.KEY));
- for (RuleIdeInfo rule : blazeProjectData.ruleMap.values()) {
- maybeAddRunConfiguration(project, blazeProjectData.workspaceLanguageSettings, targetExpressions, labelsWithConfigs, rule);
- }
- });
- }
-
- /** Collects a set of all the Blaze labels that have an associated run configuration. */
- private static Set<Label> labelsWithConfigs(Project project) {
- List<RunConfiguration> configurations =
- RunManager.getInstance(project).getAllConfigurationsList();
- Set<Label> labelsWithConfigs = Sets.newHashSet();
- for (RunConfiguration configuration : configurations) {
- if (configuration instanceof BlazeRunConfiguration) {
- BlazeRunConfiguration blazeRunConfiguration =
- (BlazeRunConfiguration) configuration;
- TargetExpression target = blazeRunConfiguration.getTarget();
- if (target instanceof Label) {
- labelsWithConfigs.add((Label)target);
- }
- }
- }
- return labelsWithConfigs;
- }
-
- /**
- * Adds a run configuration for an android_binary target if there is not already a configuration
- * for that target.
- */
- private static void maybeAddRunConfiguration(
- Project project,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- Set<TargetExpression> importTargets,
- Set<Label> labelsWithConfigs,
- RuleIdeInfo rule) {
- Label label = rule.label;
- // We only auto-generate configurations for rules listed in the project view.
- if (!importTargets.contains(label) ||
- labelsWithConfigs.contains(label)) {
- return;
- }
- labelsWithConfigs.add(label);
- final RunManager runManager = RunManager.getInstance(project);
-
- for (BlazeRuleConfigurationFactory configurationFactory : BlazeRuleConfigurationFactory.EP_NAME.getExtensions()) {
- if (configurationFactory.handlesRule(workspaceLanguageSettings, rule)) {
- final RunnerAndConfigurationSettings settings = configurationFactory.createForRule(runManager, rule);
- runManager.addConfiguration(settings, false /* isShared */);
- if (runManager.getSelectedConfiguration() == null) {
- // TODO(joshgiles): Better strategy for picking initially selected config.
- runManager.setSelectedConfiguration(settings);
- }
- break;
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/TestRuleFinder.java b/blaze-base/src/com/google/idea/blaze/base/run/TestRuleFinder.java
deleted file mode 100644
index 28e7da2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/TestRuleFinder.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run;
-
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-
-/**
- * Locates test rules for a given file.
- */
-public interface TestRuleFinder {
- static TestRuleFinder getInstance(Project project) {
- return ServiceManager.getService(project, TestRuleFinder.class);
- }
-
- Collection<Label> testTargetsForSourceFile(File sourceFile, @Nullable TestIdeInfo.TestSize testSize);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/processhandler/LineProcessingProcessAdapter.java b/blaze-base/src/com/google/idea/blaze/base/run/processhandler/LineProcessingProcessAdapter.java
deleted file mode 100644
index 261d38b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/processhandler/LineProcessingProcessAdapter.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run.processhandler;
-
-import com.google.common.base.Charsets;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.intellij.execution.process.ProcessAdapter;
-import com.intellij.execution.process.ProcessEvent;
-import com.intellij.openapi.util.Key;
-
-import java.io.IOException;
-
-public final class LineProcessingProcessAdapter extends ProcessAdapter {
- private final LineProcessingOutputStream myOutputStream;
-
- public LineProcessingProcessAdapter(LineProcessingOutputStream outputStream) {
- myOutputStream = outputStream;
- }
-
- @Override
- public void onTextAvailable(ProcessEvent event, Key outputType) {
- String text = event.getText();
- if (text != null) {
- try {
- myOutputStream.write(text.getBytes(Charsets.UTF_8));
- }
- catch (IOException e) {
- // Ignore -- cannot happen
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/processhandler/ScopedBlazeProcessHandler.java b/blaze-base/src/com/google/idea/blaze/base/run/processhandler/ScopedBlazeProcessHandler.java
deleted file mode 100644
index abf486e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/processhandler/ScopedBlazeProcessHandler.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run.processhandler;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.configurations.GeneralCommandLine;
-import com.intellij.execution.process.*;
-import com.intellij.openapi.util.Key;
-
-/**
- * Scoped process handler.
- *
- * A context is created during construction and is ended when the process is terminated.
- */
-public final class ScopedBlazeProcessHandler extends KillableColoredProcessHandler {
- /**
- * Methods to give the caller of {@link ScopedBlazeProcessHandler} hooks after the context is created.
- */
- public interface ScopedProcessHandlerDelegate {
- /**
- * This method is called when the process starts. Any context setup (like pushing scopes on the context) should be done here.
- */
- void onBlazeContextStart(BlazeContext context);
-
- /**
- * Get a list of process listeners to add to the process.
- */
- ImmutableList<ProcessListener> createProcessListeners(BlazeContext context);
-
- }
-
- private final ScopedProcessHandlerDelegate scopedProcessHandlerDelegate;
- private final BlazeContext context;
-
- /**
- * Construct a process handler and a context to be used for the life of the process.
- *
- * @param blazeCommand the blaze command to run
- * @param workspaceRoot workspace root
- * @param scopedProcessHandlerDelegate delegate methods that will be run with the process's context.
- * @throws ExecutionException
- */
- public ScopedBlazeProcessHandler(
- BlazeCommand blazeCommand,
- WorkspaceRoot workspaceRoot,
- ScopedProcessHandlerDelegate scopedProcessHandlerDelegate) throws ExecutionException {
- super(new GeneralCommandLine(blazeCommand.toList()).withWorkDirectory(workspaceRoot.directory().getPath()));
-
- this.scopedProcessHandlerDelegate = scopedProcessHandlerDelegate;
- this.context = new BlazeContext();
- // The context is released in the ScopedProcessHandlerListener.
- this.context.hold();
-
- for (ProcessListener processListener : scopedProcessHandlerDelegate.createProcessListeners(context)) {
- addProcessListener(processListener);
- }
- addProcessListener(new ScopedProcessHandlerListener());
- }
-
- @Override
- public void coloredTextAvailable(String text, Key attributes) {
- // Change blaze's stderr output to normal color, otherwise
- // test output looks red
- if (attributes == ProcessOutputTypes.STDERR) {
- attributes = ProcessOutputTypes.STDOUT;
- }
-
- super.coloredTextAvailable(text, attributes);
- }
-
- /**
- * Handle the {@link BlazeContext} held in a {@link ScopedBlazeProcessHandler}. This class will take care of calling methods when the
- * process starts and freeing the context when the process terminates.
- */
- private class ScopedProcessHandlerListener extends ProcessAdapter {
-
- @Override
- public void startNotified(ProcessEvent event) {
- scopedProcessHandlerDelegate.onBlazeContextStart(context);
- }
-
- @Override
- public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
- context.release();
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinder.java b/blaze-base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinder.java
deleted file mode 100644
index 89441f2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinder.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run.rulefinder;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Searches BlazeProjectData for matching rules.
- */
-public abstract class RuleFinder {
- public static RuleFinder getInstance() {
- return ServiceManager.getService(RuleFinder.class);
- }
-
- @Nullable
- public RuleIdeInfo ruleForTarget(Project project, final Label target) {
- return findRule(project, input -> input.label.equals(target));
- }
-
- public ImmutableList<RuleIdeInfo> rulesOfKinds(
- Project project, final Kind... kinds) {
- return rulesOfKinds(project, Arrays.asList(kinds));
- }
-
- public ImmutableList<RuleIdeInfo> rulesOfKinds(
- Project project, final List<Kind> kinds) {
- return ImmutableList.copyOf(findRules(project, input -> input.kindIsOneOf(kinds)));
- }
-
- @Nullable
- public RuleIdeInfo firstRuleOfKinds(Project project, Kind... kinds) {
- return Iterables.getFirst(rulesOfKinds(project, kinds), null);
- }
-
- @Nullable
- public RuleIdeInfo firstRuleOfKinds(Project project, List<Kind> kinds) {
- return Iterables.getFirst(rulesOfKinds(project, kinds), null);
- }
-
- @Nullable
- private RuleIdeInfo findRule(Project project, Predicate<RuleIdeInfo> predicate) {
- List<RuleIdeInfo> results = findRules(project, predicate);
- assert results.size() <= 1;
- return Iterables.getFirst(results, null);
- }
-
- @Nullable
- public RuleIdeInfo findFirstRule(Project project, Predicate<RuleIdeInfo> predicate) {
- return Iterables.getFirst(findRules(project, predicate), null);
- }
-
- public abstract List<RuleIdeInfo> findRules(Project project, Predicate<RuleIdeInfo> predicate);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinderImpl.java b/blaze-base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinderImpl.java
deleted file mode 100644
index b07943c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/rulefinder/RuleFinderImpl.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run.rulefinder;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * Implementation of RuleFinder.
- */
-class RuleFinderImpl extends RuleFinder {
- @Override
- public List<RuleIdeInfo> findRules(@NotNull Project project, @NotNull Predicate<RuleIdeInfo> predicate) {
- BlazeProjectData projectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (projectData == null) {
- return ImmutableList.of();
- }
-
- ImmutableList.Builder<RuleIdeInfo> resultList = ImmutableList.builder();
- for (RuleIdeInfo rule : projectData.ruleMap.values()) {
- if (predicate.apply(rule)) {
- resultList.add(rule);
- }
- }
- return resultList.build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/run/testmap/TestRuleFinderImpl.java b/blaze-base/src/com/google/idea/blaze/base/run/testmap/TestRuleFinderImpl.java
deleted file mode 100644
index 91e8f6d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/run/testmap/TestRuleFinderImpl.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run.testmap;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.*;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.run.TestRuleFinder;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.SyncListener;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-import java.util.Queue;
-import java.util.Set;
-
-/**
- * Used to locate tests from source files for things like right-clicks.
- *
- * It's essentially a map from source file -> reachable test rules.
- */
-public class TestRuleFinderImpl implements TestRuleFinder {
-
- // Safety experiment to allow us to turn this off. Deployed in ijwb 1.2.
- private static final BoolExperiment USE_TEST_SIZE = new BoolExperiment("use.test.sizes", true);
-
- private final Project project;
- @Nullable
- private TestMap testMap;
-
- static class TestMap {
- private final Project project;
- private final Multimap<File, Label> rootsMap;
- private final ImmutableMap<Label, RuleIdeInfo> ruleMap;
-
- TestMap(Project project, ImmutableMap<Label, RuleIdeInfo> ruleMap) {
- this.project = project;
- this.rootsMap = createRootsMap(ruleMap.values());
- this.ruleMap = ruleMap;
- }
-
- public Collection<Label> testTargetsForSourceFile(File sourceFile,
- @Nullable TestIdeInfo.TestSize testSize) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData != null) {
- if (!USE_TEST_SIZE.getValue()) {
- testSize = null;
- }
- // If testSize == null then do a pass preferring small
- // Some test runners will assume no size annotation == small and filter on that, others will not
- else if (testSize == null) {
- Collection<Label> smallResults = testTargetsForSourceFile(
- blazeProjectData.reverseDependencies,
- sourceFile,
- TestIdeInfo.DEFAULT_NON_ANNOTATED_TEST_SIZE);
-
- if (!smallResults.isEmpty()) {
- return smallResults;
- }
- }
-
- return testTargetsForSourceFile(blazeProjectData.reverseDependencies, sourceFile, testSize);
- }
- return ImmutableList.of();
- }
-
- @VisibleForTesting
- Collection<Label> testTargetsForSourceFile(ImmutableMultimap<Label, Label> rdepsMap,
- File sourceFile,
- @Nullable TestIdeInfo.TestSize testSize) {
- List<Label> result = Lists.newArrayList();
- Collection<Label> roots = rootsMap.get(sourceFile);
-
- Queue<Label> todo = Queues.newArrayDeque();
- for (Label label : roots) {
- todo.add(label);
- }
- Set<Label> seen = Sets.newHashSet();
- while (!todo.isEmpty()) {
- Label label = todo.remove();
- if (!seen.add(label)) {
- continue;
- }
-
- RuleIdeInfo rule = ruleMap.get(label);
- if (isTestRule(rule) && matchesTestSize(rule, testSize)) {
- result.add(label);
- }
- for (Label rdep : rdepsMap.get(label)) {
- todo.add(rdep);
- }
- }
- return result;
- }
-
- static Multimap<File, Label> createRootsMap(Collection<RuleIdeInfo> rules) {
- Multimap<File, Label> result = ArrayListMultimap.create();
- for (RuleIdeInfo ruleIdeInfo : rules) {
- for (ArtifactLocation source : ruleIdeInfo.sources) {
- result.put(source.getFile(), ruleIdeInfo.label);
- }
- }
- return result;
- }
-
- private static boolean isTestRule(@Nullable RuleIdeInfo rule) {
- return rule != null && rule.kind != null && rule.kind.isOneOf(
- Kind.ANDROID_ROBOLECTRIC_TEST,
- Kind.ANDROID_TEST,
- Kind.JAVA_TEST,
- Kind.GWT_TEST
- );
- }
- }
-
- private static boolean matchesTestSize(RuleIdeInfo rule, @Nullable TestIdeInfo.TestSize testSize) {
- if (testSize == null) {
- return true;
- }
- TestIdeInfo.TestSize ruleTestSize = TestIdeInfo.getTestSize(rule);
- if (ruleTestSize == null) {
- return true;
- }
- return ruleTestSize == testSize;
- }
-
- public TestRuleFinderImpl(Project project) {
- this.project = project;
- }
-
- @Override
- public Collection<Label> testTargetsForSourceFile(File sourceFile, @Nullable TestIdeInfo.TestSize testSize) {
- TestMap testMap = getTestMap();
- if (testMap == null) {
- return ImmutableList.of();
- }
- return testMap.testTargetsForSourceFile(sourceFile, testSize);
- }
-
- private synchronized TestMap getTestMap() {
- if (testMap == null) {
- testMap = initTestMap();
- }
- return testMap;
- }
-
- @Nullable
- private TestMap initTestMap() {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return null;
- }
- return new TestMap(project, blazeProjectData.ruleMap);
- }
-
- private synchronized void clearMapData() {
- this.testMap = null;
- }
-
- static class ClearTestMap extends SyncListener.Adapter {
- @Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- TestRuleFinder testRuleFinder = TestRuleFinder.getInstance(project);
- ((TestRuleFinderImpl) testRuleFinder).clearMapData();
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/BlazeContext.java b/blaze-base/src/com/google/idea/blaze/base/scope/BlazeContext.java
deleted file mode 100644
index 83f1d0f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/BlazeContext.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Lists;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
-/**
- * Scoped operation context.
- */
-public class BlazeContext {
- @Nullable
- private BlazeContext parentContext;
-
- @NotNull
- private final List<BlazeScope> scopes = Lists.newArrayList();
-
- @NotNull
- private final ArrayListMultimap<Class<? extends Output>, OutputSink<?>> outputSinks = ArrayListMultimap.create();
-
- boolean isEnding;
-
- boolean isCancelled;
-
- private int holdCount;
-
- private boolean hasErrors;
-
- private boolean propagatesErrors = true;
-
- public BlazeContext() {
- this(null);
- }
-
- public BlazeContext(@Nullable BlazeContext parentContext) {
- this.parentContext = parentContext;
- }
-
- public BlazeContext push(@NotNull BlazeScope scope) {
- scopes.add(scope);
- scope.onScopeBegin(this);
- return this;
- }
-
- /**
- * Ends the context scope.
- */
- public void endScope() {
- if (isEnding || holdCount > 0) {
- return;
- }
- isEnding = true;
- for (int i = scopes.size() - 1; i >= 0; i--) {
- scopes.get(i).onScopeEnd(this);
- }
-
- if (parentContext != null && hasErrors && propagatesErrors) {
- parentContext.setHasError();
- }
- }
-
- /**
- * Requests cancellation of the operation.
- * <p/>
- * <p>Each context holder must handle cancellation individually.
- */
- public void setCancelled() {
- if (isEnding || isCancelled) {
- return;
- }
-
- isCancelled = true;
-
- if (parentContext != null) {
- parentContext.setCancelled();
- }
- }
-
- public void hold() {
- ++holdCount;
- }
-
- public void release() {
- if (--holdCount == 0) {
- endScope();
- }
- }
-
- public boolean isEnding() {
- return isEnding;
- }
-
- public boolean isCancelled() {
- return isCancelled;
- }
-
- @Nullable
- public <T extends BlazeScope> T getScope(@NotNull Class<T> scopeClass) {
- return getScope(scopeClass, scopes.size());
- }
-
- @Nullable
- private <T extends BlazeScope> T getScope(@NotNull Class<T> scopeClass, int endIndex) {
- for (int i = endIndex - 1; i >= 0; i--) {
- if (scopes.get(i).getClass() == scopeClass) {
- return scopeClass.cast(scopes.get(i));
- }
- }
- if (parentContext != null) {
- return parentContext.getScope(scopeClass);
- }
- return null;
- }
-
- @Nullable
- public <T extends BlazeScope> T getParentScope(@NotNull T scope) {
- int index = scopes.indexOf(scope);
- if (index == -1) {
- throw new IllegalArgumentException("Scope does not belong to this context.");
- }
- @SuppressWarnings("unchecked")
- Class<T> scopeClass = (Class<T>)scope.getClass();
- return getScope(scopeClass, index);
- }
-
- /**
- * Find all instances of {@param scopeClass} that are on the stack starting with this context.
- * That includes this context and all parent contexts recursively.
- *
- * @param scopeClass type of scopes to locate
- * @return The ordered list of all scopes of type {@param scopeClass}, ordered from
- * {@param startingScope} to the root.
- */
- @NotNull
- public <T extends BlazeScope> List<T> getScopes(@NotNull Class<T> scopeClass) {
- List<T> scopesCollector = Lists.newArrayList();
- getScopes(scopesCollector, scopeClass, scopes.size());
- return scopesCollector;
- }
-
- /**
- * Find all instances of {@param scopeClass} that are above {@param startingScope} on the stack.
- * That includes this context and all parent contexts recursively. {@param startingScope} must be
- * in the this {@link BlazeContext}.
- *
- * @param scopeClass type of scopes to locate
- * @param startingScope scope to start our search from
- * @return If {@param startingScope} is in this context, the ordered list of all scopes of type
- * {@param scopeClass}, ordered from {@param startingScope} to the root. Otherwise, an empty
- * list.
- */
- @NotNull
- public <T extends BlazeScope> List<T> getScopes(
- @NotNull Class<T> scopeClass,
- @NotNull BlazeScope startingScope) {
- List<T> scopesCollector = Lists.newArrayList();
- int index = scopes.indexOf(startingScope);
- if (index == -1) {
- return scopesCollector;
- }
-
- // index + 1 so we include startingScope
- getScopes(scopesCollector, scopeClass, index + 1);
- return scopesCollector;
- }
-
- /**
- * Add matching scopes to {@param scopesCollector}. Search from {@param maxIndex} - 1 to 0.
- */
- @VisibleForTesting
- <T extends BlazeScope> void getScopes(
- @NotNull List<T> scopesCollector,
- @NotNull Class<T> scopeClass,
- int maxIndex) {
- for (int i = maxIndex - 1; i >= 0; --i) {
- BlazeScope scope = scopes.get(i);
- if (scope.getClass() == scopeClass) {
- scopesCollector.add((T)scope);
- }
- }
- if (parentContext != null) {
- parentContext.getScopes(
- scopesCollector,
- scopeClass,
- parentContext.scopes.size());
- }
- }
-
- public <T extends Output> BlazeContext addOutputSink(@NotNull Class<T> outputClass,
- @NotNull OutputSink<T> outputSink) {
- outputSinks.put(outputClass, outputSink);
- return this;
- }
-
- /**
- * Produces output by sending it to any registered sinks.
- */
- @SuppressWarnings("unchecked")
- public synchronized <T extends Output> void output(@NotNull T output) {
- Class<? extends Output> outputClass = output.getClass();
- List<OutputSink<?>> outputSinks = this.outputSinks.get(outputClass);
-
- boolean continuePropagation = true;
- for (int i = outputSinks.size() - 1; i >= 0; --i) {
- OutputSink<?> outputSink = outputSinks.get(i);
- OutputSink.Propagation propagation = ((OutputSink<T>)outputSink).onOutput(output);
- continuePropagation = propagation == OutputSink.Propagation.Continue;
- if (!continuePropagation) {
- break;
- }
- }
- if (continuePropagation && parentContext != null) {
- parentContext.output(output);
- }
- }
-
- /**
- * Sets the error state.
- * <p/>
- * <p>The error state will be propagated to any parents.
- */
- public void setHasError() {
- this.hasErrors = true;
- }
-
- /**
- * Returns true if there were errors
- */
- public boolean hasErrors() {
- return hasErrors;
- }
-
- public boolean isRoot() {
- return parentContext == null;
- }
-
- /**
- * Returns true if no errors and isn't cancelled.
- */
- public boolean shouldContinue() {
- return !hasErrors() && !isCancelled();
- }
-
- /**
- * Sets whether errors are propagated to the parent context.
- */
- public void setPropagatesErrors(boolean propagatesErrors) {
- this.propagatesErrors = propagatesErrors;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/BlazeScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/BlazeScope.java
deleted file mode 100644
index 56a48cd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/BlazeScope.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A scoped facet of a scoped operation.
- * <p/>
- * <p>Attaches to a blaze context and starts and ends with it.
- */
-public interface BlazeScope {
- /**
- * Called when the scope is added to the context.
- */
- void onScopeBegin(@NotNull BlazeContext context);
-
- /**
- * Called when the context scope is ending.
- */
- void onScopeEnd(@NotNull BlazeContext context);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/Output.java b/blaze-base/src/com/google/idea/blaze/base/scope/Output.java
deleted file mode 100644
index c5a7759..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/Output.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-/**
- * A base interface for contextual output operations.
- */
-public interface Output {
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/OutputSink.java b/blaze-base/src/com/google/idea/blaze/base/scope/OutputSink.java
deleted file mode 100644
index df8e98e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/OutputSink.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * An output sink registered with a context.
- * <p/>
- * <p>Register these via a ScopeExtension.
- */
-public interface OutputSink<T extends Output> {
- enum Propagation {
- Continue,
- Stop
- }
-
- /**
- * Called when an Output of the correct type goes through the scope.
- *
- * @return Whether to continue propagation of this input.
- */
- Propagation onOutput(@NotNull T output);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/Result.java b/blaze-base/src/com/google/idea/blaze/base/scope/Result.java
deleted file mode 100644
index 7285a11..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/Result.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-/**
- * Helper class to be used when you want to return a result or error in a scoped function.
- */
-public class Result<T> {
- public final T result;
- public final Throwable error;
-
- public Result(T result) {
- this.result = result;
- this.error = null;
- }
-
- public Result(Throwable error) {
- this.result = null;
- this.error = error;
- }
-
- public static <T> Result<T> of(T result) {
- return new Result<T>(result);
- }
-
- public static <T> Result<T> error(Throwable t) {
- return new Result<T>(t);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/Scope.java b/blaze-base/src/com/google/idea/blaze/base/scope/Scope.java
deleted file mode 100644
index 6ddd243..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/Scope.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Helper methods to run scoped functions and operations in a scoped context.
- */
-public final class Scope {
- private static final Logger LOG = Logger.getInstance(Scope.class);
-
- /**
- * Runs a scoped function in a new root scope.
- */
- public static <T> T root(
- @NotNull ScopedFunction<T> scopedFunction) {
- return push(null, scopedFunction);
- }
-
- /**
- * Runs a scoped function in a new nested scope.
- */
- public static <T> T push(
- @Nullable BlazeContext parentContext,
- @NotNull ScopedFunction<T> scopedFunction) {
- BlazeContext context = new BlazeContext(parentContext);
- try {
- return scopedFunction.execute(context);
- }
- catch (RuntimeException e) {
- context.setHasError();
- LOG.error(e);
- throw e;
- }
- finally {
- context.endScope();
- }
- }
-
- /**
- * Runs a scoped operation in a new root scope.
- */
- public static void root(
- @NotNull ScopedOperation scopedOperation) {
- push(null, scopedOperation);
- }
-
- /**
- * Runs a scoped operation in a new nested scope.
- */
- public static void push(
- @Nullable BlazeContext parentContext,
- @NotNull ScopedOperation scopedOperation) {
- BlazeContext context = new BlazeContext(parentContext);
- try {
- scopedOperation.execute(context);
- }
- catch (RuntimeException e) {
- context.setHasError();
- LOG.error(e);
- throw e;
- }
- finally {
- context.endScope();
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/ScopedFunction.java b/blaze-base/src/com/google/idea/blaze/base/scope/ScopedFunction.java
deleted file mode 100644
index 8a780cd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/ScopedFunction.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A scoped operation that can return a result to its caller.
- */
-public interface ScopedFunction<T> {
- T execute(@NotNull BlazeContext context);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/ScopedOperation.java b/blaze-base/src/com/google/idea/blaze/base/scope/ScopedOperation.java
deleted file mode 100644
index 29f3610..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/ScopedOperation.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A scoped operation.
- */
-public interface ScopedOperation {
- void execute(@NotNull BlazeContext context);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/ScopedTask.java b/blaze-base/src/com/google/idea/blaze/base/scope/ScopedTask.java
deleted file mode 100644
index 341cae4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/ScopedTask.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import com.google.idea.blaze.base.scope.scopes.ProgressIndicatorScope;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.Progressive;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Wrapper between an IntelliJ Task and a BlazeContext
- */
-public abstract class ScopedTask implements Progressive {
- @Nullable
- final BlazeContext parentContext;
-
- public ScopedTask() {
- this(null /* parentContext */);
- }
-
- public ScopedTask(@Nullable BlazeContext parentContext) {
- this.parentContext = parentContext;
- }
-
- @Override
- public void run(@NotNull final ProgressIndicator indicator) {
- Scope.push(parentContext, new ScopedOperation() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- context.push(new ProgressIndicatorScope(indicator));
- ScopedTask.this.execute(context);
- }
- });
- }
-
- protected abstract void execute(@NotNull BlazeContext context);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java b/blaze-base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java
deleted file mode 100644
index e3b28d7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.output;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Output;
-import com.intellij.pom.Navigatable;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-
-/**
- * An issue in a blaze operation.
- */
-public class IssueOutput implements Output {
-
- public static final int NO_LINE = -1;
- public static final int NO_COLUMN = -1;
-
- @Nullable private final File file;
- private final int line;
- private final int column;
- @NotNull private final Category category;
- @NotNull private final String message;
- @Nullable Navigatable navigatable;
- @Nullable IssueData issueData;
-
- public static class IssueData {}
-
- public enum Category {
- ERROR,
- WARNING,
- STATISTICS,
- INFORMATION
- }
-
- @NotNull
- public static Builder issue(@NotNull Category category, @NotNull String message) {
- return new Builder(category, message);
- }
-
- @NotNull
- public static Builder error(@NotNull String message) {
- return new Builder(Category.ERROR, message);
- }
-
- @NotNull
- public static Builder warn(@NotNull String message) {
- return new Builder(Category.WARNING, message);
- }
-
- public static class Builder {
- @NotNull private final Category category;
- @NotNull private final String message;
- @Nullable private File file;
- private int line = NO_LINE;
- private int column = NO_COLUMN;
- @Nullable Navigatable navigatable;
- @Nullable IssueData issueData;
-
- public Builder(@NotNull Category category, @NotNull String message) {
- this.category = category;
- this.message = message;
- }
-
- @NotNull
- public Builder inFile(@Nullable File file) {
- this.file = file;
- return this;
- }
-
- @NotNull
- public Builder onLine(int line) {
- this.line = line;
- return this;
- }
-
- @NotNull
- public Builder inColumn(int column) {
- this.column = column;
- return this;
- }
-
- @NotNull
- public Builder withData(@Nullable IssueData issueData) {
- this.issueData = issueData;
- return this;
- }
-
- @NotNull
- public Builder navigatable(@Nullable Navigatable navigatable) {
- this.navigatable = navigatable;
- return this;
- }
-
- public IssueOutput build() {
- return new IssueOutput(file, line, column, navigatable, category, message, issueData);
- }
-
- public void submit(@NotNull BlazeContext context) {
- context.output(build());
- if (category == Category.ERROR) {
- context.setHasError();
- }
- }
- }
-
- private IssueOutput(
- @Nullable File file,
- int line,
- int column,
- @Nullable Navigatable navigatable,
- @NotNull Category category,
- @NotNull String message,
- @Nullable IssueData issueData) {
- this.file = file;
- this.line = line;
- this.column = column;
- this.navigatable = navigatable;
- this.category = category;
- this.message = message;
- this.issueData = issueData;
- }
-
- @Nullable
- public File getFile() {
- return file;
- }
-
- public int getLine() {
- return line;
- }
-
- public int getColumn() {
- return column;
- }
-
- @Nullable
- public Navigatable getNavigatable() {
- return navigatable;
- }
-
- @NotNull
- public Category getCategory() {
- return category;
- }
-
- @NotNull
- public String getMessage() {
- return message;
- }
-
- @Override
- public String toString() {
- return message;
- }
-
- @Nullable
- public IssueData getIssueData() {
- return issueData;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/output/PerformanceWarning.java b/blaze-base/src/com/google/idea/blaze/base/scope/output/PerformanceWarning.java
deleted file mode 100644
index 1cdbf27..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/output/PerformanceWarning.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.output;
-
-import com.google.idea.blaze.base.scope.Output;
-
-/**
- * Output that is collected when running in performance collection mode.
- */
-public class PerformanceWarning implements Output {
- public final String text;
-
- public PerformanceWarning(String text) {
- this.text = text;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/output/PrintOutput.java b/blaze-base/src/com/google/idea/blaze/base/scope/output/PrintOutput.java
deleted file mode 100644
index dfe0203..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/output/PrintOutput.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.output;
-
-import com.google.idea.blaze.base.scope.Output;
-import com.intellij.execution.process.ProcessOutputTypes;
-import com.intellij.openapi.util.Key;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Output that can be printed to a log.
- */
-public class PrintOutput implements Output {
-
- @NotNull
- private final String text;
-
- @NotNull
- private final OutputType outputType;
-
- public enum OutputType {
- NORMAL,
- ERROR;
-
- public static OutputType fromProcessOutputKey(Key outputKey) {
- return outputKey == ProcessOutputTypes.STDERR ? ERROR : NORMAL;
- }
- }
-
- public PrintOutput(@NotNull String text, @NotNull OutputType outputType) {
- this.text = text;
- this.outputType = outputType;
- }
-
- public PrintOutput(@NotNull String text) {
- this(text, OutputType.NORMAL);
- }
-
- @NotNull
- public String getText() {
- return text;
- }
-
- @NotNull
- public OutputType getOutputType() {
- return outputType;
- }
-
- public static PrintOutput output(String text) {
- return new PrintOutput(text);
- }
-
- public static PrintOutput error(String text) {
- return new PrintOutput(text, OutputType.ERROR);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/output/StatusOutput.java b/blaze-base/src/com/google/idea/blaze/base/scope/output/StatusOutput.java
deleted file mode 100644
index 92ab9f3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/output/StatusOutput.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.output;
-
-import com.google.idea.blaze.base.scope.Output;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Status message output.
- */
-public class StatusOutput implements Output {
- @NotNull
- String status;
-
- public StatusOutput(@NotNull String status) {
- this.status = status;
- }
-
- @NotNull
- public String getStatus() {
- return status;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java
deleted file mode 100644
index 646afbc..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.idea.blaze.base.console.BlazeConsoleService;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.OutputSink;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput.OutputType;
-import com.google.idea.blaze.base.scope.output.StatusOutput;
-import com.intellij.execution.ui.ConsoleViewContentType;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Moves print output to the blaze console.
- */
-public class BlazeConsoleScope implements BlazeScope {
-
- public static class Builder {
- private Project project;
- private ProgressIndicator progressIndicator;
- private boolean suppressConsole = false;
-
- public Builder(@NotNull Project project) {
- this(project, null);
- }
-
- public Builder(@NotNull Project project,
- ProgressIndicator progressIndicator) {
- this.project = project;
- this.progressIndicator = progressIndicator;
- }
-
- public Builder setSuppressConsole(boolean suppressConsole) {
- this.suppressConsole = suppressConsole;
- return this;
- }
-
- public BlazeConsoleScope build() {
- return new BlazeConsoleScope(project, progressIndicator, suppressConsole);
- }
-
- }
-
- @NotNull
- private final Project project;
-
- @NotNull
- private final BlazeConsoleService blazeConsoleService;
-
- @Nullable
- private final ProgressIndicator progressIndicator;
-
- private final boolean showDialogOnChange;
- private boolean activated;
-
- private OutputSink<PrintOutput> printSink = (output) -> {
- @NotNull String text = output.getText();
- @NotNull ConsoleViewContentType contentType = output.getOutputType() == OutputType.NORMAL
- ? ConsoleViewContentType.NORMAL_OUTPUT
- : ConsoleViewContentType.ERROR_OUTPUT;
- print(text, contentType);
- return OutputSink.Propagation.Continue;
- };
-
- private OutputSink<StatusOutput> statusSink = (output) -> {
- @NotNull String text = output.getStatus();
- @NotNull ConsoleViewContentType contentType = ConsoleViewContentType.NORMAL_OUTPUT;
- print(text, contentType);
- return OutputSink.Propagation.Continue;
- };
-
- private BlazeConsoleScope(@NotNull Project project,
- @Nullable ProgressIndicator progressIndicator,
- boolean suppressConsole) {
- this.project = project;
- this.blazeConsoleService = BlazeConsoleService.getInstance(project);
- this.progressIndicator = progressIndicator;
- this.showDialogOnChange = !suppressConsole;
- }
-
- private void print(String text, ConsoleViewContentType contentType) {
- blazeConsoleService.print(text + "\n", contentType);
-
- if (showDialogOnChange && !activated) {
- activated = true;
- ApplicationManager.getApplication().invokeLater(() -> blazeConsoleService.activateConsoleWindow());
- }
- }
-
- @Override
- public void onScopeBegin(@NotNull final BlazeContext context) {
- context.addOutputSink(PrintOutput.class, printSink);
- context.addOutputSink(StatusOutput.class, statusSink);
- blazeConsoleService.clear();
- blazeConsoleService.setStopHandler(() -> {
- if (progressIndicator != null) {
- progressIndicator.cancel();
- }
- context.setCancelled();
- });
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- blazeConsoleService.setStopHandler(null);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/IssuesScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/IssuesScope.java
deleted file mode 100644
index 5241fff..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/IssuesScope.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.OutputSink;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.ui.BlazeProblemsView;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.openapi.wm.ToolWindowManager;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.UUID;
-
-/**
- * Shows the compiler output.
- */
-public class IssuesScope implements BlazeScope, OutputSink<IssueOutput> {
-
- private final Project project;
- private final UUID sessionId;
- private int issuesCount;
-
- public IssuesScope(@NotNull Project project) {
- this.project = project;
- this.sessionId = UUID.randomUUID();
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- context.addOutputSink(IssueOutput.class, this);
- BlazeProblemsView blazeProblemsView = BlazeProblemsView.getInstance(project);
- if (blazeProblemsView != null) {
- blazeProblemsView.clearOldMessages(sessionId);
- }
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- if (issuesCount > 0) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- focusProblemsView();
- }
- });
- }
- }
-
- private void focusProblemsView() {
- ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
- ToolWindow toolWindow = toolWindowManager.getToolWindow("Problems");
- if (toolWindow != null) {
- toolWindow.activate(null, false, false);
- }
- }
-
- @Override
- public Propagation onOutput(@NotNull IssueOutput output) {
- BlazeProblemsView blazeProblemsView = BlazeProblemsView.getInstance(project);
- if (blazeProblemsView != null) {
- blazeProblemsView.addMessage(output, sessionId);
- }
- ++issuesCount;
- return Propagation.Continue;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/LoggedTimingScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/LoggedTimingScope.java
deleted file mode 100644
index 64fca5a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/LoggedTimingScope.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.common.base.Stopwatch;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.metrics.LoggingService;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.intellij.openapi.project.Project;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * Timing scope where the results are sent to a logging service
- */
-public class LoggedTimingScope implements BlazeScope {
- // It is not guaranteed that the threading model will be sane during the entirety of this scope,
- // so we use wall clock time and not ThreadMXBean where we could get user/system time.
-
- Project project;
- private final Action action;
- private Stopwatch timer;
-
- /**
- * @param action The action we will be reporting a time for to the logging service
- */
- public LoggedTimingScope(Project project, Action action) {
- this.project = project;
- this.action = action;
- this.timer = Stopwatch.createUnstarted();
- }
-
- @Override
- public void onScopeBegin(BlazeContext context) {
- timer.start();
- }
-
- @Override
- public void onScopeEnd(BlazeContext context) {
- if (!context.isCancelled()) {
- long totalMS = timer.elapsed(TimeUnit.MILLISECONDS);
- LoggingService.reportEvent(project, action, totalMS);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/NotificationScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/NotificationScope.java
deleted file mode 100644
index 96d67c7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/NotificationScope.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput.OutputType;
-import com.intellij.openapi.project.Project;
-import com.intellij.ui.SystemNotifications;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Notifies the user with a system notification when the scope ends.
- */
-public class NotificationScope implements BlazeScope {
-
- private static final long NOTIFICATION_THRESHOLD_MS = 0;
-
- @NotNull
- private Project project;
-
- @NotNull
- private final String notificationName;
-
- @NotNull
- private final String notificationTitle;
-
- @NotNull
- private final String notificationText;
-
- @NotNull
- private final String notificationErrorText;
-
- private long startTime;
-
- public NotificationScope(
- @NotNull Project project,
- @NotNull String notificationName,
- @NotNull String notificationTitle,
- @NotNull String notificationText,
- @NotNull String notificationErrorText) {
- this.project = project;
- this.notificationName = notificationName;
- this.notificationTitle = notificationTitle;
- this.notificationText = notificationText;
- this.notificationErrorText = notificationErrorText;
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- startTime = System.currentTimeMillis();
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- if (project.isDisposed()) {
- return;
- }
- if (context.isCancelled()) {
- context.output(new PrintOutput(notificationName + " cancelled"));
- return;
- }
- long duration = System.currentTimeMillis() - startTime;
- if (duration < NOTIFICATION_THRESHOLD_MS) {
- return;
- }
-
- String notificationText = !context.hasErrors()
- ? this.notificationText
- : this.notificationErrorText;
-
- SystemNotifications.getInstance().notify(
- notificationName,
- notificationTitle,
- notificationText);
-
- if (context.hasErrors()) {
- context.output(new PrintOutput(notificationName + " failed", OutputType.ERROR));
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/PerformanceWarningScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/PerformanceWarningScope.java
deleted file mode 100644
index e36d310..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/PerformanceWarningScope.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.OutputSink;
-import com.google.idea.blaze.base.scope.output.PerformanceWarning;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-
-import java.util.List;
-
-/**
- * Shows performance warnings.
- */
-public class PerformanceWarningScope implements BlazeScope, OutputSink<PerformanceWarning> {
-
- private final List<PerformanceWarning> outputs = Lists.newArrayList();
-
- @Override
- public void onScopeBegin(BlazeContext context) {
- context.addOutputSink(PerformanceWarning.class, this);
- }
-
- @Override
- public void onScopeEnd(BlazeContext context) {
- if (outputs.isEmpty()) {
- return;
- }
- context.output(new PrintOutput("\n===== PERFORMANCE WARNINGS =====\n"));
- context.output(new PrintOutput("Your IDE isn't as fast as it could be."));
- context.output(new PrintOutput("You can turn these off via Blaze > Show Performance Warnings."));
- context.output(new PrintOutput(""));
- for (PerformanceWarning output : outputs) {
- context.output(new PrintOutput(output.text));
- }
- }
-
- @Override
- public Propagation onOutput(PerformanceWarning output) {
- outputs.add(output);
- return Propagation.Continue;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/ProgressIndicatorScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/ProgressIndicatorScope.java
deleted file mode 100644
index 3d1f96b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/ProgressIndicatorScope.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.OutputSink;
-import com.google.idea.blaze.base.scope.output.StatusOutput;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.util.AbstractProgressIndicatorExBase;
-import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Progress indicator scope.
- * <p/>
- * <p>Channels status outputs to the progress indicator text.
- * <p>Cancels the scope if the user presses cancel on the progress indicator.
- */
-public class ProgressIndicatorScope extends AbstractProgressIndicatorExBase
- implements BlazeScope, OutputSink<StatusOutput> {
-
- private final ProgressIndicator progressIndicator;
- private BlazeContext context;
-
- public ProgressIndicatorScope(@NotNull ProgressIndicator progressIndicator) {
- this.progressIndicator = progressIndicator;
-
- if (progressIndicator instanceof ProgressIndicatorEx) {
- ((ProgressIndicatorEx)progressIndicator).addStateDelegate(this);
- }
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- this.context = context;
- context.addOutputSink(StatusOutput.class, this);
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- }
-
- @Override
- public void cancel() {
- context.setCancelled();
- }
-
- @Override
- public Propagation onOutput(@NotNull StatusOutput output) {
- progressIndicator.setText(output.getStatus());
- return Propagation.Continue;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/ProjectCloseScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/ProjectCloseScope.java
deleted file mode 100644
index d4e8369..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/ProjectCloseScope.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.project.ProjectManagerListener;
-import com.intellij.openapi.ui.Messages;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Prevents the user from closing the project while the scope is open.
- */
-public class ProjectCloseScope implements ProjectManagerListener, BlazeScope {
-
- @NotNull
- private final Project project;
-
- private boolean isApplicationExitingOrProjectClosing;
-
- public ProjectCloseScope(@NotNull Project project) {
- this.project = project;
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- ProjectManager projectManager = ProjectManager.getInstance();
- projectManager.addProjectManagerListener(project, this);
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- ProjectManager projectManager = ProjectManager.getInstance();
- projectManager.removeProjectManagerListener(project, this);
- }
-
- @Override
- public void projectOpened(Project project) {
- }
-
- @Override
- public boolean canCloseProject(Project project) {
- if (!project.equals(this.project)) {
- return true;
- }
- if (shouldPromptUser()) {
- askUserToWait();
- return false;
- }
- return false;
- }
-
- @Override
- public void projectClosed(Project project) {
- }
-
- @Override
- public void projectClosing(Project project) {
- if (project.equals(this.project)) {
- isApplicationExitingOrProjectClosing = true;
- }
- }
-
- private boolean shouldPromptUser() {
- return !isApplicationExitingOrProjectClosing;
- }
-
- private void askUserToWait() {
- String buildSystem = Blaze.buildSystemName(project);
- Messages.showMessageDialog(project,
- String.format("Please wait until %s command execution finishes", buildSystem),
- buildSystem + " Running",
- null);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java b/blaze-base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java
deleted file mode 100644
index 49f0d24..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope.scopes;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
-/**
- * Prints timing information as output.
- */
-public class TimingScope implements BlazeScope {
-
- @NotNull
- private final String name;
-
- private long startTime;
-
- private double duration;
-
- @Nullable
- private TimingScope parentScope;
-
- @NotNull
- private List<TimingScope> children = Lists.newArrayList();
-
- public TimingScope(@NotNull String name) {
- this.name = name;
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- startTime = System.currentTimeMillis();
- parentScope = context.getParentScope(this);
-
- if (parentScope != null) {
- parentScope.children.add(this);
- }
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- if (context.isCancelled()) {
- return;
- }
-
- long elapsedTime = System.currentTimeMillis() - startTime;
- duration = (double)elapsedTime / 1000.0;
-
- if (parentScope == null) {
- outputReport(context);
- }
- }
-
- private void outputReport(@NotNull BlazeContext context) {
- context.output(new PrintOutput("\n==== TIMING REPORT ====\n"));
- outputReport(context, this, 0);
- }
-
- private static void outputReport(
- @NotNull BlazeContext context,
- @NotNull TimingScope timingScope,
- int depth) {
- String selfString = "";
-
- // Self time trivially 100% if no children
- if (timingScope.children.size() > 0) {
- // Calculate self time as <my duration> - <sum child duration>
- double selfTime = timingScope.duration;
- for (TimingScope child : timingScope.children) {
- selfTime -= child.duration;
- }
-
- selfString = selfTime > 0.1
- ? String.format(" (%s)", durationStr(selfTime))
- : "";
- }
-
- context.output(new PrintOutput(
- String.format("%s%s: %s%s",
- getIndentation(depth),
- timingScope.name,
- durationStr(timingScope.duration),
- selfString)
- ));
-
- for (TimingScope child : timingScope.children) {
- outputReport(context, child, depth + 1);
- }
- }
-
- private static String durationStr(double time) {
- return time >= 1.0
- ? String.format("%.1fs", time)
- : String.format("%dms", (int)(time * 1000));
- }
-
- private static String getIndentation(int depth) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < depth; ++i) {
- sb.append(" ");
- }
- return sb.toString();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/Blaze.java b/blaze-base/src/com/google/idea/blaze/base/settings/Blaze.java
deleted file mode 100644
index 2b85c24..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/Blaze.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings;
-
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.intellij.ide.DataManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * Blaze project utilities.
- */
-public class Blaze {
-
- public enum BuildSystem {
- Blaze,
- Bazel;
-
- /**
- * The build system name, capitalized.
- */
- public String getName() {
- return name();
- }
-
- /**
- * The build system name, capitalized.
- */
- public String getLowerCaseName() {
- return name().toLowerCase();
- }
- }
-
- private Blaze() {
- }
-
- public static boolean isBlazeProjectOpen() {
- for (Project project : ProjectManager.getInstance().getOpenProjects()) {
- if (isBlazeProject(project)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns whether this project was imported from blaze.
- */
- public static boolean isBlazeProject(Project project) {
- return BlazeImportSettingsManager.getInstance(project).getImportSettings() != null;
- }
-
- /**
- * Returns the build system associated with this project,
- * or falls back to the default blaze build system if the project is null or
- * not a blaze project.
- */
- public static BuildSystem getBuildSystem(@Nullable Project project) {
- BlazeImportSettings importSettings =
- project == null ? null: BlazeImportSettingsManager.getInstance(project).getImportSettings();
- if (importSettings == null) {
- return BuildSystemProvider.defaultBuildSystem().buildSystem();
- }
- return importSettings.getBuildSystem();
- }
-
- /**
- * The name of the build system associated with the given project,
- * or falls back to the default blaze build system if the project is null or
- * not a blaze project.
- */
- public static String buildSystemName(@Nullable Project project) {
- return getBuildSystem(project).getName();
- }
-
- /**
- * The name of the application-wide build system default. This should
- * only be used in situations where it doesn't make sense to use the build system
- * associated with the current project (e.g. the import project action).
- */
- public static String defaultBuildSystemName() {
- return BuildSystemProvider.defaultBuildSystem().buildSystem().getName();
- }
-
- /**
- * Tries to guess the current project, and uses that to determine the build system name.<br>
- * Should only be used in situations where the current project is not accessible.
- */
- public static String guessBuildSystemName() {
- Project project = guessCurrentProject();
- return buildSystemName(project);
- }
-
- private static Project guessCurrentProject() {
- Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
- if (openProjects.length == 1) {
- return openProjects[0];
- }
- if (SwingUtilities.isEventDispatchThread()) {
- return (Project) DataManager.getInstance().getDataContext().getData("project");
- }
- return null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java b/blaze-base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
deleted file mode 100644
index ac4db38..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings;
-
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.util.xmlb.annotations.Tag;
-
-import javax.annotation.Nullable;
-
-/**
- * Project settings that are set at import time.
- */
-@Tag("BlazeProjectSettings") // Legacy migration support
-public final class BlazeImportSettings {
-
- private String workspaceRoot = "";
-
- private String projectName = "";
-
- private String projectDataDirectory = "";
-
- private String locationHash = "";
-
- private String projectViewFile;
-
- private BuildSystem buildSystem = BuildSystem.Blaze; // default for backwards compatibility with existing projects.
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- BlazeImportSettings() {
- }
-
- public BlazeImportSettings(
- String workspaceRoot,
- String projectName,
- String projectDataDirectory,
- String locationHash,
- String projectViewFile,
- BuildSystem buildSystem) {
- this.workspaceRoot = workspaceRoot;
- this.projectName = projectName;
- this.projectDataDirectory = projectDataDirectory;
- this.locationHash = locationHash;
- this.projectViewFile = projectViewFile;
- this.buildSystem = buildSystem;
- }
-
- @SuppressWarnings("unused")
- public String getWorkspaceRoot() {
- return workspaceRoot;
- }
-
- @SuppressWarnings("unused")
- public String getProjectName() {
- return projectName;
- }
-
- @SuppressWarnings("unused")
- public String getProjectDataDirectory() {
- return projectDataDirectory;
- }
-
- /**
- * Hash used to give the project a unique directory in the system directory.
- */
- @SuppressWarnings("unused")
- public String getLocationHash() {
- return locationHash;
- }
-
- /**
- * The user's local project view file
- */
- @SuppressWarnings("unused")
- public String getProjectViewFile() {
- return projectViewFile;
- }
-
- /**
- * The build system used for the project.
- */
- @SuppressWarnings("unused")
- public BuildSystem getBuildSystem() {
- return buildSystem;
- }
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- public void setWorkspaceRoot(String workspaceRoot) {
- this.workspaceRoot = workspaceRoot;
- }
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- public void setProjectName(String projectName) {
- this.projectName = projectName;
- }
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- public void setProjectDataDirectory(String projectDataDirectory) {
- this.projectDataDirectory = projectDataDirectory;
- }
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- public void setLocationHash(String locationHash) {
- this.locationHash = locationHash;
- }
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- public void setProjectViewFile(@Nullable String projectViewFile) {
- this.projectViewFile = projectViewFile;
- }
-
- // Used by bean serialization -- legacy import support
- @SuppressWarnings("unused")
- public void setAsProjectFile(@Nullable String projectViewFile) {
- this.projectViewFile = projectViewFile;
- }
-
- // Used by bean serialization
- @SuppressWarnings("unused")
- public void setBuildSystem(BuildSystem buildSystem) {
- this.buildSystem = buildSystem;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java b/blaze-base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
deleted file mode 100644
index 3e40500..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings;
-
-import com.google.common.collect.Lists;
-import com.intellij.openapi.components.*;
-import com.intellij.openapi.project.Project;
-import com.intellij.util.xmlb.annotations.AbstractCollection;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Manages storage for the project's {@link BlazeImportSettings}.
- */
-@State(
- name = "BlazeSettings",
- storages = {@Storage(file = StoragePathMacros.PROJECT_FILE),
- @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/blaze.xml",
- scheme = StorageScheme.DIRECTORY_BASED)}
-)
-public class BlazeImportSettingsManager implements
- PersistentStateComponent<BlazeImportSettingsManager.State> {
-
- @Nullable
- private BlazeImportSettings importSettings;
-
- @NotNull
- private Project project;
-
- public BlazeImportSettingsManager(@NotNull Project project) {
- this.project = project;
- }
-
- @NotNull
- public static BlazeImportSettingsManager getInstance(@NotNull Project project) {
- return ServiceManager.getService(project, BlazeImportSettingsManager.class);
- }
-
- @SuppressWarnings("unchecked")
- @Nullable
- @Override
- public State getState() {
- State state = new State();
- List<BlazeImportSettings> value = Lists.newArrayList();
- if (importSettings != null) {
- value.add(importSettings);
- }
- state.setLinkedExternalProjectsSettings(value);
- return state;
- }
-
- @Override
- public void loadState(State state) {
- Collection<BlazeImportSettings> settings = state.getLinkedExternalProjectsSettings();
- if (settings != null && !settings.isEmpty()) {
- importSettings = settings.iterator().next();
- }
- else {
- importSettings = null;
- }
- }
-
- @Nullable
- public BlazeImportSettings getImportSettings() {
- return importSettings;
- }
-
- public void setImportSettings(@NotNull BlazeImportSettings importSettings) {
- this.importSettings = importSettings;
- }
-
- /**
- * State class for the Blaze settings.
- */
- static class State {
-
- private List<BlazeImportSettings> importSettings = Lists.newArrayList();
-
- @AbstractCollection(surroundWithTag = false, elementTypes = {BlazeImportSettings.class})
- public List<BlazeImportSettings> getLinkedExternalProjectsSettings() {
- return importSettings;
- }
-
- public void setLinkedExternalProjectsSettings(List<BlazeImportSettings> settings) {
- importSettings = settings;
- }
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/BlazeUserSettings.java b/blaze-base/src/com/google/idea/blaze/base/settings/BlazeUserSettings.java
deleted file mode 100644
index dc3b699..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/BlazeUserSettings.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings;
-
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileTypeFactory;
-import com.google.idea.blaze.base.sync.status.BlazeSyncStatus;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Storage;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.util.xmlb.XmlSerializerUtil;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-
-/**
- * Stores blaze view settings.
- */
-@State(
- name = "BlazeUserSettings",
- storages = @Storage(id = "other", value = "blaze.view.xml")
-)
-public class BlazeUserSettings implements PersistentStateComponent<BlazeUserSettings> {
-
- public boolean suppressConsoleForRunAction = false;
- private boolean resyncAutomatically = false;
- private boolean buildFileSupportEnabled = true;
- private boolean syncStatusPopupShown = false;
- private boolean expandSyncToWorkingSet = true;
- private boolean showPerformanceWarnings = false;
- private boolean attachSourcesByDefault = false;
- private boolean attachSourcesOnDemand = false;
- private boolean collapseProjectView = true;
- private String blazeBinaryPath = "/usr/bin/blaze";
- @Nullable private String bazelBinaryPath;
-
- @NotNull
- public static BlazeUserSettings getInstance() {
- return ServiceManager.getService(BlazeUserSettings.class);
- }
-
- @Override
- @NotNull
- public BlazeUserSettings getState() {
- return this;
- }
-
- @Override
- public void loadState(BlazeUserSettings state) {
- XmlSerializerUtil.copyBean(state, this);
- }
-
- /**
- * Also kicks off an incremental sync if we're now syncing automatically,
- * and the project is currently dirty.
- */
- public void setResyncAutomatically(boolean resyncAutomatically) {
- if (this.resyncAutomatically == resyncAutomatically) {
- return;
- }
- this.resyncAutomatically = resyncAutomatically;
- ProjectManager projectManager = ApplicationManager.getApplication().getComponent(ProjectManager.class);
- Project[] openProjects = projectManager.getOpenProjects();
- for (Project project : openProjects) {
- if (Blaze.isBlazeProject(project)) {
- BlazeSyncStatus.getInstance(project).queueAutomaticSyncIfDirty();
- }
- }
- }
-
- public boolean getResyncAutomatically() {
- return resyncAutomatically;
- }
-
- /**
- * Triggers an update to the list of registered file types.
- */
- public void setBuildFileSupportEnabled(boolean supportEnabled) {
- if (supportEnabled != buildFileSupportEnabled) {
- buildFileSupportEnabled = supportEnabled;
- BuildFileTypeFactory.updateBuildFileLanguageEnabled(BuildFileLanguage.BUILD_FILE_SUPPORT_ENABLED.getValue() && supportEnabled);
- }
- }
-
- public boolean getBuildFileSupportEnabled() {
- return buildFileSupportEnabled;
- }
-
- public boolean getSuppressConsoleForRunAction() {
- return suppressConsoleForRunAction;
- }
-
- public void setSuppressConsoleForRunAction(boolean suppressConsoleForRunAction) {
- this.suppressConsoleForRunAction = suppressConsoleForRunAction;
- }
-
- public boolean getSyncStatusPopupShown() {
- return syncStatusPopupShown;
- }
-
- public void setSyncStatusPopupShown(boolean syncStatusPopupShown) {
- this.syncStatusPopupShown = syncStatusPopupShown;
- }
-
- public boolean getExpandSyncToWorkingSet() {
- return expandSyncToWorkingSet;
- }
-
- public void setExpandSyncToWorkingSet(boolean expandSyncToWorkingSet) {
- this.expandSyncToWorkingSet = expandSyncToWorkingSet;
- }
-
- public boolean getShowPerformanceWarnings() {
- return showPerformanceWarnings;
- }
-
- public void setShowPerformanceWarnings(boolean showPerformanceWarnings) {
- this.showPerformanceWarnings = showPerformanceWarnings;
- }
-
- public String getBlazeBinaryPath() {
- return blazeBinaryPath;
- }
-
- public void setBlazeBinaryPath(String blazeBinaryPath) {
- this.blazeBinaryPath = blazeBinaryPath;
- }
-
- @Nullable
- public String getBazelBinaryPath() {
- return bazelBinaryPath;
- }
-
- public void setBazelBinaryPath(String bazelBinaryPath) {
- this.bazelBinaryPath = bazelBinaryPath;
- }
-
- public boolean getAttachSourcesByDefault() {
- return attachSourcesByDefault;
- }
-
- public void setAttachSourcesByDefault(boolean attachSourcesByDefault) {
- this.attachSourcesByDefault = attachSourcesByDefault;
- }
-
- public boolean getAttachSourcesOnDemand() {
- return attachSourcesOnDemand;
- }
-
- public void setAttachSourcesOnDemand(boolean attachSourcesOnDemand) {
- this.attachSourcesOnDemand = attachSourcesOnDemand;
- }
-
- public boolean getCollapseProjectView() {
- return collapseProjectView;
- }
-
- public void setCollapseProjectView(boolean collapseProjectView) {
- this.collapseProjectView = collapseProjectView;
- }
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/IsBlazeProjectCondition.java b/blaze-base/src/com/google/idea/blaze/base/settings/IsBlazeProjectCondition.java
deleted file mode 100644
index ebfc6a7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/IsBlazeProjectCondition.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Condition;
-
-/**
- * Condition for enabling features (e.g. Blaze and Crow consoles) only in Blaze projects.
- */
-public class IsBlazeProjectCondition implements Condition<Project> {
-
- @Override
- public boolean value(Project project) {
- return project != null && Blaze.isBlazeProject(project);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsConfigurable.java b/blaze-base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsConfigurable.java
deleted file mode 100644
index d63c2cf..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/ui/BlazeUserSettingsConfigurable.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings.ui;
-
-import com.google.common.base.Objects;
-import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl;
-import com.google.idea.blaze.base.ui.FileSelectorWithStoredHistory;
-import com.intellij.openapi.options.BaseConfigurable;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SearchableConfigurable;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.uiDesigner.core.GridConstraints;
-import com.intellij.uiDesigner.core.GridLayoutManager;
-import com.intellij.uiDesigner.core.Spacer;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-
-/**
- * Blaze console view settings
- */
-public class BlazeUserSettingsConfigurable extends BaseConfigurable implements SearchableConfigurable {
-
- private static final String BLAZE_BINARY_PATH_KEY = "blaze.binary.path";
- public static final String BAZEL_BINARY_PATH_KEY = "bazel.binary.path";
-
- private final BuildSystem buildSystem;
-
- private JPanel myMainPanel;
- private JCheckBox suppressConsoleForRunAction;
- private JCheckBox resyncAutomatically;
- private JCheckBox buildFileSupportEnabled;
- private JCheckBox attachSourcesByDefault;
- private JCheckBox attachSourcesOnDemand;
- private JCheckBox collapseProjectView;
- private FileSelectorWithStoredHistory blazeBinaryPathField;
- private FileSelectorWithStoredHistory bazelBinaryPathField;
-
- public BlazeUserSettingsConfigurable(Project project) {
- this.buildSystem = Blaze.getBuildSystem(project);
- setupUI();
- }
-
- @Override
- public String getDisplayName() {
- return buildSystem.getName() + " View Settings";
- }
-
- @Nullable
- @Override
- public String getHelpTopic() {
- return null;
- }
-
- @Override
- public void apply() throws ConfigurationException {
- BlazeUserSettings settings = BlazeUserSettings.getInstance();
- settings.setSuppressConsoleForRunAction(suppressConsoleForRunAction.isSelected());
- settings.setResyncAutomatically(resyncAutomatically.isSelected());
- settings.setBuildFileSupportEnabled(buildFileSupportEnabled.isSelected());
- settings.setAttachSourcesByDefault(attachSourcesByDefault.isSelected());
- settings.setAttachSourcesOnDemand(attachSourcesOnDemand.isSelected());
- settings.setCollapseProjectView(collapseProjectView.isSelected());
- if (blazeBinaryPathField.getText() != null) {
- settings.setBlazeBinaryPath(blazeBinaryPathField.getText());
- }
- if (bazelBinaryPathField.getText() != null) {
- settings.setBazelBinaryPath(bazelBinaryPathField.getText());
- }
- }
-
- @Override
- public void reset() {
- BlazeUserSettings settings = BlazeUserSettings.getInstance();
- suppressConsoleForRunAction.setSelected(settings.getSuppressConsoleForRunAction());
- resyncAutomatically.setSelected(settings.getResyncAutomatically());
- buildFileSupportEnabled.setSelected(settings.getBuildFileSupportEnabled());
- attachSourcesByDefault.setSelected(settings.getAttachSourcesByDefault());
- attachSourcesOnDemand.setSelected(settings.getAttachSourcesOnDemand());
- collapseProjectView.setSelected(settings.getCollapseProjectView());
- blazeBinaryPathField.setTextWithHistory(settings.getBlazeBinaryPath());
- bazelBinaryPathField.setTextWithHistory(settings.getBazelBinaryPath());
- }
-
- @Nullable
- @Override
- public JComponent createComponent() {
- resyncAutomatically.setVisible(BlazeSyncStatusImpl.AUTOMATIC_INCREMENTAL_SYNC.getValue());
- buildFileSupportEnabled.setVisible(BuildFileLanguage.BUILD_FILE_SUPPORT_ENABLED.getValue());
- return myMainPanel;
- }
-
- @Override
- public boolean isModified() {
- BlazeUserSettings settings = BlazeUserSettings.getInstance();
- return !Objects.equal(suppressConsoleForRunAction.isSelected(), settings.getSuppressConsoleForRunAction()) ||
- !Objects.equal(resyncAutomatically.isSelected(), settings.getResyncAutomatically()) ||
- !Objects.equal(buildFileSupportEnabled.isSelected(), settings.getBuildFileSupportEnabled()) ||
- !Objects.equal(attachSourcesByDefault.isSelected(), settings.getAttachSourcesByDefault()) ||
- !Objects.equal(attachSourcesOnDemand.isSelected(), settings.getAttachSourcesOnDemand()) ||
- !Objects.equal(collapseProjectView.isSelected(), settings.getCollapseProjectView()) ||
- !Objects.equal(blazeBinaryPathField.getText(), settings.getBlazeBinaryPath()) ||
- !Objects.equal(bazelBinaryPathField.getText(), settings.getBazelBinaryPath());
- }
-
- @Override
- public void disposeUIResources() {
- }
-
- @Override
- public String getId() {
- return "blaze.view.settings";
- }
-
- @Nullable
- @Override
- public Runnable enableSearch(String option) {
- return null;
- }
-
-
- /**
- * Initially generated by IntelliJ from a .form file.
- */
- private void setupUI() {
- myMainPanel = new JPanel();
- myMainPanel.setLayout(new GridLayoutManager(8, 2, new Insets(0, 0, 0, 0), -1, -1));
- suppressConsoleForRunAction = new JCheckBox();
- suppressConsoleForRunAction.setText(String.format("Suppress %s console for Run/Debug actions", buildSystem));
- suppressConsoleForRunAction.setVerticalAlignment(0);
- myMainPanel.add(suppressConsoleForRunAction,
- new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- resyncAutomatically = new JCheckBox();
- resyncAutomatically.setSelected(false);
- resyncAutomatically.setText("Automatically re-sync project when BUILD files change");
- myMainPanel.add(resyncAutomatically, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- buildFileSupportEnabled = new JCheckBox();
- buildFileSupportEnabled.setSelected(true);
- buildFileSupportEnabled.setText("BUILD file language support enabled");
- myMainPanel.add(buildFileSupportEnabled, new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- attachSourcesByDefault = new JCheckBox();
- attachSourcesByDefault.setSelected(false);
- attachSourcesByDefault.setText("Automatically attach sources on project sync (WARNING: increases index time by 100%+)");
- myMainPanel.add(attachSourcesByDefault, new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- attachSourcesByDefault.addActionListener((event) -> {
- BlazeUserSettings settings = BlazeUserSettings.getInstance();
- if (attachSourcesByDefault.isSelected() && !settings.getAttachSourcesByDefault()) {
- int result = Messages.showOkCancelDialog(
- "You are turning on source jars by default. This setting increases indexing time by "
- + ">100%, can cost ~1GB RAM, and will increase project reopen time significantly. "
- + "Are you sure you want to proceed?",
- "Turn On Sources By Default?",
- null
- );
- if (result != Messages.OK) {
- attachSourcesByDefault.setSelected(false);
- }
- }
- });
-
- attachSourcesOnDemand = new JCheckBox();
- attachSourcesOnDemand.setSelected(false);
- attachSourcesOnDemand.setText("Automatically attach sources when you open decompiled source");
- myMainPanel.add(attachSourcesOnDemand, new GridConstraints(4, 0, 1, 2, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- collapseProjectView = new JCheckBox();
- collapseProjectView.setSelected(false);
- collapseProjectView.setText("Collapse project view directory roots");
- myMainPanel.add(collapseProjectView, new GridConstraints(5, 0, 1, 2, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
-
- blazeBinaryPathField = FileSelectorWithStoredHistory.create(BLAZE_BINARY_PATH_KEY, "Specify the blaze binary path");
- bazelBinaryPathField = FileSelectorWithStoredHistory.create(BAZEL_BINARY_PATH_KEY, "Specify the bazel binary path");
-
- JLabel pathLabel;
- JComponent pathPanel;
- if (buildSystem == BuildSystem.Blaze) {
- pathPanel = blazeBinaryPathField;
- pathLabel = new JLabel("Blaze binary location");
- } else {
- pathPanel = bazelBinaryPathField;
- pathLabel = new JLabel("Bazel binary location");
- }
- pathLabel.setLabelFor(pathPanel);
- myMainPanel.add(pathLabel, new GridConstraints(6, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE,
- GridConstraints.SIZEPOLICY_FIXED,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
- myMainPanel.add(pathPanel, new GridConstraints(6, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
- GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
- GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
-
- myMainPanel.add(new Spacer(), new GridConstraints(7, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1,
- GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/ui/EditProjectViewAction.java b/blaze-base/src/com/google/idea/blaze/base/settings/ui/EditProjectViewAction.java
deleted file mode 100644
index 73259f2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/ui/EditProjectViewAction.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings.ui;
-
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.OpenFileDescriptor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import java.io.File;
-
-/**
- * Opens all the user's project views.
- */
-public class EditProjectViewAction extends BlazeAction {
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- if (project == null) {
- return;
- }
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- return;
- }
- for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
- File file = projectViewFile.projectViewFile;
- if (file != null) {
- VirtualFile virtualFile = VfsUtil.findFileByIoFile(file, true);
- if (virtualFile != null) {
- OpenFileDescriptor descriptor = new OpenFileDescriptor(project, virtualFile);
- FileEditorManager.getInstance(project).openTextEditor(descriptor, true);
- }
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java b/blaze-base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java
deleted file mode 100644
index f29c7db..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings.ui;
-
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.DataProvider;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-
-/**
- * A normal JPanel which implements DataProvider, providing the specified IntelliJ Project.<p>
- * This is used by IntelliJ's action system to determine the relevant project associated with
- * a UI component.
- */
-public class JPanelProvidingProject extends JPanel implements DataProvider {
-
- private final Project project;
-
- public JPanelProvidingProject(Project project, LayoutManager layoutManager) {
- super(layoutManager);
- this.project = project;
- }
-
- @Nullable
- @Override
- public Object getData(String dataId) {
- return CommonDataKeys.PROJECT.is(dataId) ? project : null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java b/blaze-base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java
deleted file mode 100644
index 4b78ff9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.settings.ui;
-
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewFileType;
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.scope.OutputSink;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.ide.DataManager;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.Result;
-import com.intellij.openapi.application.WriteAction;
-import com.intellij.openapi.command.undo.UndoUtil;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.EditorFactory;
-import com.intellij.openapi.editor.EditorSettings;
-import com.intellij.openapi.editor.colors.EditorColors;
-import com.intellij.openapi.editor.ex.EditorEx;
-import com.intellij.openapi.editor.impl.DocumentImpl;
-import com.intellij.openapi.editor.impl.EditorFactoryImpl;
-import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-import com.intellij.openapi.project.impl.ProjectImpl;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.psi.PsiManager;
-import com.intellij.psi.impl.PsiManagerEx;
-import com.intellij.psi.impl.file.impl.FileManager;
-import com.intellij.testFramework.LightVirtualFile;
-import com.intellij.ui.components.JBLabel;
-import org.jetbrains.annotations.NotNull;
-import org.picocontainer.MutablePicoContainer;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-import java.util.List;
-
-/**
- * UI for changing the ProjectView.
- */
-public class ProjectViewUi {
-
- private static final String USE_SHARED_PROJECT_VIEW = "Use shared project view file";
-
- private final Disposable parentDisposable;
- private EditorEx projectViewEditor;
- private JCheckBox useShared;
-
- private WorkspaceRoot workspaceRoot;
- private boolean useSharedProjectView;
- private boolean allowEditShared;
- private String sharedProjectViewText;
- private boolean settingsInitialized;
-
- public ProjectViewUi(Disposable parentDisposable) {
- this.parentDisposable = parentDisposable;
- }
-
- /**
- * To support the custom language features, we need a ProjectImpl, and it's not desirable to create one from scratch.<br>
- * @return the current, non-default project, if one exists, else the default project.
- */
- public static Project getProject() {
- Project project = (Project) DataManager.getInstance().getDataContext().getData("project");
- if (project != null && project instanceof ProjectImpl) {
- return project;
- }
- return ProjectManager.getInstance().getDefaultProject();
- }
-
- public static Dimension getMinimumSize() {
- return new Dimension(1000, 550);
- }
-
- private static EditorEx createEditor(String tooltip) {
- Project project = getProject();
- LightVirtualFile virtualFile = new LightVirtualFile("mockProjectViewFile", ProjectViewLanguage.INSTANCE, "");
- final Document document = ((EditorFactoryImpl) EditorFactory.getInstance()).createDocument(true);
- ((DocumentImpl) document).setAcceptSlashR(true);
- FileDocumentManagerImpl.registerDocument(document, virtualFile);
-
- FileManager fileManager = ((PsiManagerEx) PsiManager.getInstance(project)).getFileManager();
- fileManager.setViewProvider(virtualFile, fileManager.createFileViewProvider(virtualFile, true));
-
- if (project.isDefault()) {
- // Undo-redo doesn't work with the default project. Explicitly turn it off to avoid error dialogs.
- UndoUtil.disableUndoFor(document);
- }
-
- EditorEx editor = (EditorEx) EditorFactory.getInstance().createEditor(document, project, ProjectViewFileType.INSTANCE, false);
- final EditorSettings settings = editor.getSettings();
- settings.setLineNumbersShown(false);
- settings.setLineMarkerAreaShown(false);
- settings.setFoldingOutlineShown(false);
- settings.setRightMarginShown(false);
- settings.setAdditionalPageAtBottom(false);
- editor.getComponent().setMinimumSize(getMinimumSize());
- editor.getComponent().setPreferredSize(getMinimumSize());
- editor.getComponent().setToolTipText(tooltip);
- editor.getComponent().setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
- editor.getComponent().setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
- return editor;
- }
-
- public void fillUi(JPanel canvas, int indentLevel) {
- String tooltip = "Enter a project view descriptor file. See 'go/intellij/docs/project-views.md' for more information.";
-
- projectViewEditor = createEditor(tooltip);
- projectViewEditor.getColorsScheme().setColor(EditorColors.READONLY_BACKGROUND_COLOR, UIManager.getColor("Label.background"));
- Disposer.register(parentDisposable, () -> EditorFactory.getInstance().releaseEditor(projectViewEditor));
-
- JBLabel labelsLabel = new JBLabel("Project View");
- labelsLabel.setToolTipText(tooltip);
- canvas.add(labelsLabel, UiUtil.getFillLineConstraints(indentLevel));
-
- canvas.add(projectViewEditor.getComponent(), UiUtil.getFillLineConstraints(indentLevel));
-
- useShared = new JCheckBox(USE_SHARED_PROJECT_VIEW);
- useShared.addActionListener(e -> {
- useSharedProjectView = useShared.isSelected();
- if (useSharedProjectView) {
- setProjectViewText(sharedProjectViewText);
- }
- updateTextAreasEnabled();
- });
- canvas.add(useShared, UiUtil.getFillLineConstraints(indentLevel));
- }
-
- public void init(
- WorkspaceRoot workspaceRoot,
- String projectViewText,
- @Nullable String sharedProjectViewText,
- @Nullable File sharedProjectViewFile,
- boolean useSharedProjectView,
- boolean allowEditShared
- ) {
- this.workspaceRoot = workspaceRoot;
- this.useSharedProjectView = useSharedProjectView;
- this.allowEditShared = allowEditShared;
- this.sharedProjectViewText = sharedProjectViewText;
-
- assert !(useSharedProjectView && sharedProjectViewText == null);
-
- if (sharedProjectViewFile != null) {
- WorkspacePath workspacePath = workspaceRoot.workspacePathFor(sharedProjectViewFile);
- useShared.setText(USE_SHARED_PROJECT_VIEW + ": " + workspacePath.relativePath());
- }
-
- useShared.setSelected(useSharedProjectView);
-
- if (sharedProjectViewText == null) {
- useShared.setEnabled(false);
- }
-
- setDummyWorkspacePathResolverProvider(workspaceRoot);
- setProjectViewText(projectViewText);
- settingsInitialized = true;
- }
-
- private void setDummyWorkspacePathResolverProvider(WorkspaceRoot workspaceRoot) {
- MutablePicoContainer container = (MutablePicoContainer) getProject().getPicoContainer();
- Class<WorkspacePathResolverProvider> key = WorkspacePathResolverProvider.class;
- Object oldProvider = container.getComponentInstance(key);
- container.unregisterComponent(key.getName());
- container.registerComponentInstance(key.getName(),
- (WorkspacePathResolverProvider) () -> new WorkspacePathResolverImpl(workspaceRoot));
- if (!settingsInitialized) {
- Disposer.register(parentDisposable, () -> {
- container.unregisterComponent(key.getName());
- if (oldProvider != null) {
- container.registerComponentInstance(key.getName(), oldProvider);
- }
- });
- }
- }
-
- private void setProjectViewText(String projectViewText) {
- new WriteAction() {
- @Override
- protected void run(@NotNull Result result) throws Throwable {
- projectViewEditor.getDocument().setReadOnly(false);
- projectViewEditor.getDocument().setText(projectViewText);
- }
- }.execute();
- updateTextAreasEnabled();
- }
-
- private void updateTextAreasEnabled() {
- boolean editEnabled = allowEditShared || !useSharedProjectView;
- projectViewEditor.setViewer(!editEnabled);
- projectViewEditor.getDocument().setReadOnly(!editEnabled);
- projectViewEditor.reinitSettings();
- }
-
- public ProjectViewSet parseProjectView(final List<IssueOutput> issues) {
- final String projectViewText = projectViewEditor.getDocument().getText();
- final OutputSink<IssueOutput> issueCollector = output -> {
- issues.add(output);
- return OutputSink.Propagation.Continue;
- };
- return Scope.root(context -> {
- context.addOutputSink(IssueOutput.class, issueCollector);
- ProjectViewParser projectViewParser = new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot));
- projectViewParser.parseProjectView(projectViewText);
- return projectViewParser.getResult();
- });
- }
-
- public boolean getUseSharedProjectView() {
- return this.useSharedProjectView;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncManager.java b/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncManager.java
deleted file mode 100644
index c99f9db..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.startup.StartupManager;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Manages syncing and its listeners.
- */
-public class BlazeSyncManager {
-
- @NotNull
- private final Project project;
-
- public BlazeSyncManager(@NotNull Project project) {
- this.project = project;
- }
-
- public static BlazeSyncManager getInstance(@NotNull Project project) {
- return ServiceManager.getService(project, BlazeSyncManager.class);
- }
-
- /**
- * Requests a project sync with Blaze.
- */
- public void requestProjectSync(@NotNull final BlazeSyncParams syncParams) {
- StartupManager.getInstance(project).runWhenProjectIsInitialized(new Runnable() {
- @Override
- public void run() {
- final BlazeImportSettings importSettings =
- BlazeImportSettingsManager.getInstance(project).getImportSettings();
- if (importSettings == null) {
- throw new IllegalStateException(String.format("Attempt to sync non-%s project.", Blaze.buildSystemName(project)));
- }
-
- final BlazeSyncTask syncTask = new BlazeSyncTask(
- project,
- importSettings,
- syncParams
- );
-
- BlazeExecutor.submitTask(project, syncTask);
- }
- });
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncParams.java b/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncParams.java
deleted file mode 100644
index 9137fd5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncParams.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-
-import javax.annotation.concurrent.Immutable;
-import java.util.Collection;
-
-/**
- * Parameters that control the sync.
- */
-@Immutable
-public final class BlazeSyncParams {
-
- public enum SyncMode {
- RESTORE_EPHEMERAL_STATE,
- INCREMENTAL,
- FULL
- }
-
- public static final class Builder {
- private String title;
- private SyncMode syncMode;
- private boolean backgroundSync = false;
- private boolean doBuild = true;
- private ImmutableList.Builder<TargetExpression> targetExpressions = ImmutableList.builder();
-
- public Builder(String title,
- SyncMode syncMode) {
- this.title = title;
- this.syncMode = syncMode;
- }
-
- public Builder setDoBuild(boolean doBuild) {
- this.doBuild = doBuild;
- return this;
- }
-
- public Builder setBackgroundSync(boolean backgroundSync) {
- this.backgroundSync = backgroundSync;
- return this;
- }
-
- public Builder addTargetExpression(TargetExpression targetExpression) {
- this.targetExpressions.add(targetExpression);
- return this;
- }
-
- public Builder addTargetExpressions(Collection<TargetExpression> targets) {
- this.targetExpressions.addAll(targets);
- return this;
- }
-
- public BlazeSyncParams build() {
- return new BlazeSyncParams(title, syncMode, backgroundSync, doBuild, targetExpressions.build());
- }
- }
-
- public final String title;
- public final SyncMode syncMode;
- public final boolean backgroundSync;
- public final boolean doBuild;
- public final ImmutableList<TargetExpression> targetExpressions;
-
- private BlazeSyncParams(
- String title,
- SyncMode syncMode,
- boolean backgroundSync,
- boolean doBuild,
- ImmutableList<TargetExpression> targetExpressions) {
- this.title = title;
- this.syncMode = syncMode;
- this.backgroundSync = backgroundSync;
- this.doBuild = doBuild;
- this.targetExpressions = targetExpressions;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java b/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
deleted file mode 100644
index 2f65e17..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleType;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.ModifiableRootModel;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * Can plug into the blaze sync system.
- */
-public interface BlazeSyncPlugin {
- ExtensionPointName<BlazeSyncPlugin> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.SyncPlugin");
-
- /**
- * May be used by the plugin to create/edit modules.
- *
- * Using this ensures that the blaze plugin is aware of the modules,
- * won't garbage collect them, and that all module modifications
- * happen in a single transaction.
- */
- interface ModuleEditor {
- /**
- * Creates a new module and registers it with the module editor.
- */
- Module createModule(String moduleName, ModuleType moduleType);
-
- /**
- * Edits a module. It will be committed when commit is called.
- *
- * <p>The module will be returned in a cleared state. You should
- * not call this method multiple times.
- */
- ModifiableRootModel editModule(Module module);
-
- /**
- * Registers a module. This prevents garbage collection of
- * the module upon commit.
- *
- * @return True if the module exists and was registered.
- */
- boolean registerModule(String moduleName);
-
- /**
- * Finds a module by name. This doesn't register the module.
- */
- @Nullable
- Module findModule(String moduleName);
-
- /**
- * Commits the module editor without garbage collection.
- */
- void commit();
- }
-
- /**
- * @return The default workspace type recommended by this plugin.
- */
- @Nullable
- WorkspaceType getDefaultWorkspaceType();
-
- /**
- * @return The module type for the workspace given the workspace type.
- */
- @Nullable
- ModuleType getWorkspaceModuleType(WorkspaceType workspaceType);
-
- /**
- * @return The set of supported languages under this workspace type.
- */
- Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType);
-
- void updateSyncState(
- Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState
- );
-
- /**
- * Updates the sdk.
- */
- void updateSdk(Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData);
-
- /**
- * Modify the project content entries. There will be one content entry
- * per project directory from the project view set.
- */
- void updateContentEntries(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- Collection<ContentEntry> contentEntries);
-
- void updateProjectStructure(
- Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel
- );
-
- /**
- * Validates the project.
- */
- boolean validate(Project project,
- BlazeContext context,
- BlazeProjectData blazeProjectData);
-
- /**
- * Validates the project view.
- * @return True for success, false for fatal error.
- */
- boolean validateProjectView(
- BlazeContext context,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings
- );
-
- /**
- * Returns any custom sections that this plugin supports.
- */
- Collection<SectionParser> getSections();
-
- /**
- * Returns whether this plugin requires resolving ide artifacts to function.
- */
- boolean requiresResolveIdeArtifacts();
-
- /**
- * Whether this plugin requires an Android SDK to function.
- */
- boolean requiresAndroidSdk(WorkspaceLanguageSettings workspaceLanguageSettings);
-
- /**
- * Returns any source file extensions that are a good candidate for the {@link com.google.idea.blaze.base.prefetch.Prefetcher}.
- */
- Set<String> prefetchSrcFileExtensions();
-
- class Adapter implements BlazeSyncPlugin {
-
- @Nullable
- @Override
- public WorkspaceType getDefaultWorkspaceType() {
- return null;
- }
-
- @Nullable
- @Override
- public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
- return null;
- }
-
- @Override
- public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- return ImmutableSet.of();
- }
-
- @Override
- public void updateSyncState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
- }
-
- @Override
- public void updateSdk(Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- }
-
- @Override
- public void updateContentEntries(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- Collection<ContentEntry> contentEntries) {
- }
-
- @Override
- public void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel) {
- }
-
- @Override
- public boolean validate(Project project,
- BlazeContext context,
- BlazeProjectData blazeProjectData) {
- return true;
- }
-
- @Override
- public boolean validateProjectView(BlazeContext context,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings) {
- return true;
- }
-
- @Override
- public Collection<SectionParser> getSections() {
- return ImmutableList.of();
- }
-
- @Override
- public boolean requiresResolveIdeArtifacts() {
- return false;
- }
-
- @Override
- public boolean requiresAndroidSdk(WorkspaceLanguageSettings workspaceLanguageSettings) {
- return false;
- }
-
- @Override
- public Set<String> prefetchSrcFileExtensions() {
- return ImmutableSet.of();
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncStartupActivity.java b/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncStartupActivity.java
deleted file mode 100644
index 726a5ae..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncStartupActivity.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.actions.IncrementalSyncProjectAction;
-import com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.startup.StartupActivity;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Syncs the project upon startup.
- */
-public class BlazeSyncStartupActivity implements StartupActivity {
-
- @Override
- public void runActivity(@NotNull final Project project) {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project)
- .getImportSettings();
-
- if (importSettings != null) {
- BlazeSyncManager.getInstance(project).requestProjectSync(getSyncParams());
- }
- }
-
- private static BlazeSyncParams getSyncParams() {
- if (BlazeSyncStatusImpl.AUTOMATIC_INCREMENTAL_SYNC.getValue()) {
- return IncrementalSyncProjectAction.startupSyncParams;
- }
- return new BlazeSyncParams.Builder(
- "Sync Project",
- BlazeSyncParams.SyncMode.RESTORE_EPHEMERAL_STATE)
- .build();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java b/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
deleted file mode 100755
index 788906c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.idea.blaze.base.async.AsyncUtil;
-import com.google.idea.blaze.base.async.FutureUtil;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.experiments.ExperimentScope;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.ProjectViewVerifier;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.rulemaps.ReverseDependencyMap;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.output.StatusOutput;
-import com.google.idea.blaze.base.scope.scopes.*;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin.ModuleEditor;
-import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManagerImpl;
-import com.google.idea.blaze.base.sync.projectstructure.ContentEntryEditor;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleDataStorage;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorImpl;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
-import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.*;
-import com.google.idea.blaze.base.util.SaveUtil;
-import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleType;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.Progressive;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.StandardFileSystems;
-import com.intellij.openapi.vfs.VirtualFileManager;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-
-/**
- * Syncs the project with blaze.
- */
-final class BlazeSyncTask implements Progressive {
-
- private final static Logger LOG = Logger.getInstance(BlazeSyncTask.class);
-
- private final Project project;
- private final BlazeImportSettings importSettings;
- private final WorkspaceRoot workspaceRoot;
- private final BlazeSyncParams syncParams;
- private final boolean expandSyncToWorkingSet;
- private final boolean showPerformanceWarnings;
- private long syncStartTime;
-
- BlazeSyncTask(
- Project project,
- BlazeImportSettings importSettings,
- final BlazeSyncParams syncParams) {
- this.project = project;
- this.importSettings = importSettings;
- this.workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
- this.syncParams = syncParams;
- this.expandSyncToWorkingSet = BlazeUserSettings.getInstance().getExpandSyncToWorkingSet()
- && ExpandWorkingSetTargetsExperiment.ENABLE_EXPAND_WORKING_SET_TARGETS.getValue();
- this.showPerformanceWarnings = BlazeUserSettings.getInstance().getShowPerformanceWarnings();
- }
-
-
- @Override
- public void run(final ProgressIndicator indicator) {
- Scope.root((BlazeContext context) -> {
- context.push(new ExperimentScope());
- if (showPerformanceWarnings) {
- context.push(new PerformanceWarningScope());
- }
- context
- .push(new ProgressIndicatorScope(indicator))
- .push(new TimingScope("Sync"))
- .push(new LoggedTimingScope(project, Action.SYNC_TOTAL_TIME))
- ;
-
- if (!syncParams.backgroundSync) {
- context
- .push(new BlazeConsoleScope.Builder(project, indicator).build())
- .push(new IssuesScope(project))
- .push(new NotificationScope(
- project,
- "Sync",
- "Sync project",
- "Sync successful",
- "Sync failed"
- ))
- ;
- }
-
- context.output(new StatusOutput("Syncing project..."));
- syncProject(context);
- });
- }
-
- /**
- * Returns true if sync successfully completed
- */
- @VisibleForTesting
- boolean syncProject(BlazeContext context) {
- boolean success = false;
- try {
- SaveUtil.saveAllFiles();
- onSyncStart(project);
- success = doSyncProject(context);
- } catch (AssertionError|Exception e) {
- LOG.error(e);
- IssueOutput.error("Internal error: " + e.getMessage()).submit(context);
- } finally {
- afterSync(project, success);
- }
- return success;
- }
-
- /**
- * @return true if sync successfully completed
- */
- private boolean doSyncProject(final BlazeContext context) {
- this.syncStartTime = System.currentTimeMillis();
-
- if (importSettings.getProjectViewFile() == null) {
- IssueOutput.error(
- "This project looks like it's been opened from an old version of ASwB. "
- + "That is unfortunately not supported. Please reimport your project."
- ).submit(context);
- return false;
- }
-
- @Nullable BlazeProjectData oldBlazeProjectData = null;
- if (syncParams.syncMode != SyncMode.FULL) {
- oldBlazeProjectData = BlazeProjectDataManagerImpl.getImpl(project).loadProjectRoot(context, importSettings);
- }
-
- BlazeVcsHandler vcsHandler = null;
- for (BlazeVcsHandler candidate : BlazeVcsHandler.EP_NAME.getExtensions()) {
- if (candidate.handlesProject(project, workspaceRoot)) {
- vcsHandler = candidate;
- break;
- }
- }
- if (vcsHandler == null) {
- IssueOutput.error("Could not find a VCS handler").submit(context);
- return false;
- }
-
- ListeningExecutorService executor = BlazeExecutor.getInstance().getExecutor();
- ListenableFuture<BlazeRoots> blazeRootsFuture = BlazeRoots.compute(project, workspaceRoot, context);
- ListenableFuture<WorkingSet> workingSetFuture = vcsHandler.getWorkingSet(project, workspaceRoot, executor);
-
- BlazeRoots blazeRoots = FutureUtil.waitForFuture(context, blazeRootsFuture)
- .timed(Blaze.buildSystemName(project) + "Roots")
- .withProgressMessage(String.format("Running %s info...", Blaze.buildSystemName(project)))
- .onError(String.format("Could not get %s roots", Blaze.buildSystemName(project)))
- .run()
- .result();
- if (blazeRoots == null) {
- return false;
- }
-
- WorkspacePathResolverAndProjectView workspacePathResolverAndProjectView = computeWorkspacePathResolverAndProjectView(
- context,
- blazeRoots,
- vcsHandler,
- executor
- );
- if (workspacePathResolverAndProjectView == null) {
- return false;
- }
- WorkspacePathResolver workspacePathResolver = workspacePathResolverAndProjectView.workspacePathResolver;
- ProjectViewSet projectViewSet = workspacePathResolverAndProjectView.projectViewSet;
-
- WorkspaceLanguageSettings workspaceLanguageSettings = LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
- if (workspaceLanguageSettings == null) {
- return false;
- }
-
- if (!ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings)) {
- return false;
- }
-
- final BlazeProjectData newBlazeProjectData;
-
- WorkingSet workingSet = FutureUtil.waitForFuture(context, workingSetFuture)
- .timed("WorkingSet")
- .withProgressMessage("Computing VCS working set...")
- .onError("Could not compute working set")
- .run()
- .result();
- if (!context.shouldContinue()) {
- return false;
- }
-
- if (workingSet != null) {
- printWorkingSet(context, workingSet);
- }
-
- boolean ideResolveErrors = false;
- if (syncParams.syncMode != SyncMode.RESTORE_EPHEMERAL_STATE || oldBlazeProjectData == null) {
- SyncState.Builder syncStateBuilder = new SyncState.Builder();
- SyncState previousSyncState = oldBlazeProjectData != null ? oldBlazeProjectData.syncState : null;
- List<TargetExpression> allTargets = projectViewSet.listItems(TargetSection.KEY);
- if (expandSyncToWorkingSet && workingSet != null) {
- allTargets.addAll(getWorkingSetTargets(workingSet));
- }
-
- boolean syncPluginRequiresBuild = false;
- boolean requiresAndroidSdk = false;
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- syncPluginRequiresBuild |= syncPlugin.requiresResolveIdeArtifacts();
- requiresAndroidSdk |= syncPlugin.requiresAndroidSdk(workspaceLanguageSettings);
- }
-
- final BlazeIdeInterface.IdeResult ideQueryResult = getIdeQueryResult(
- project,
- context,
- projectViewSet,
- allTargets,
- workspaceLanguageSettings,
- new ArtifactLocationDecoder(blazeRoots, workspacePathResolver),
- syncStateBuilder,
- previousSyncState,
- requiresAndroidSdk
- );
- if (ideQueryResult == null) {
- if (workingSet != null && !workingSet.isEmpty() && expandSyncToWorkingSet && !context.isCancelled()) {
- String msg = String.format("If you have broken targets in your VCS working set, uncheck '%s > Expand Sync to Working Set'" +
- " and try again.", Blaze.buildSystemName(project));
- context.output(new PrintOutput(msg, PrintOutput.OutputType.ERROR));
- }
- return false;
- }
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ideQueryResult.ruleMap;
-
- ListenableFuture<ImmutableMultimap<Label, Label>> reverseDependenciesFuture =
- BlazeExecutor.getInstance().submit(() -> ReverseDependencyMap.createRdepsMap(ruleMap));
-
- boolean doBuild = syncPluginRequiresBuild || (syncParams.doBuild || oldBlazeProjectData == null);
- if (doBuild) {
- List<TargetExpression> targetExpressions = Lists.newArrayList(syncParams.targetExpressions);
- if (targetExpressions.isEmpty()) {
- targetExpressions.addAll(allTargets);
- }
- ideResolveErrors = !resolveIdeArtifacts(project, context, workspaceRoot, projectViewSet, targetExpressions);
- LocalFileSystem.getInstance().refresh(true);
- if (context.isCancelled()) {
- return false;
- }
- }
-
- Scope.push(context, (childContext) -> {
- childContext.push(new TimingScope("UpdateSyncState"));
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- syncPlugin.updateSyncState(
- project,
- childContext,
- workspaceRoot,
- projectViewSet,
- workspaceLanguageSettings,
- blazeRoots,
- workingSet,
- workspacePathResolver,
- ruleMap,
- ideQueryResult.androidPlatformDirectory,
- syncStateBuilder,
- previousSyncState);
- }
- });
-
- ImmutableMultimap<Label, Label> reverseDependencies = FutureUtil.waitForFuture(context, reverseDependenciesFuture)
- .timed("ReverseDependencies")
- .onError("Failed to compute reverse dependency map")
- .run()
- .result();
- if (reverseDependencies == null) {
- return false;
- }
-
- newBlazeProjectData = new BlazeProjectData(
- syncStartTime,
- ruleMap,
- blazeRoots,
- workingSet,
- workspacePathResolver,
- workspaceLanguageSettings,
- syncStateBuilder.build(),
- reverseDependencies
- );
- } else {
- // Restore project based on old blaze project data
- newBlazeProjectData = oldBlazeProjectData;
- }
-
- boolean success = updateProject(project, context, projectViewSet, oldBlazeProjectData, newBlazeProjectData);
- if (!success) {
- return false;
- }
-
- if (ideResolveErrors) {
- context.output(new PrintOutput(
- "Sync was successful, but there were compilation errors. The project may not fully resolve until fixed.",
- PrintOutput.OutputType.ERROR
- ));
- }
-
- onSyncComplete(project, context, projectViewSet, newBlazeProjectData);
- return true;
- }
-
- static class WorkspacePathResolverAndProjectView {
- final WorkspacePathResolver workspacePathResolver;
- final ProjectViewSet projectViewSet;
- public WorkspacePathResolverAndProjectView(WorkspacePathResolver workspacePathResolver,
- ProjectViewSet projectViewSet) {
- this.workspacePathResolver = workspacePathResolver;
- this.projectViewSet = projectViewSet;
- }
- }
- private WorkspacePathResolverAndProjectView computeWorkspacePathResolverAndProjectView(BlazeContext context,
- BlazeRoots blazeRoots,
- BlazeVcsHandler vcsHandler,
- ListeningExecutorService executor) {
- for (int i = 0; i < 3; ++i) {
- WorkspacePathResolver vcsWorkspacePathResolver = null;
- BlazeVcsHandler.BlazeVcsSyncHandler vcsSyncHandler = vcsHandler.createSyncHandler(project, workspaceRoot);
- if (vcsSyncHandler != null) {
- boolean ok = Scope.push(context, (childContext) -> {
- childContext.push(new TimingScope("UpdateVcs"));
- return vcsSyncHandler.update(context, blazeRoots, executor);
- });
- if (!ok) {
- return null;
- }
- vcsWorkspacePathResolver = vcsSyncHandler.getWorkspacePathResolver();
- }
-
- WorkspacePathResolver workspacePathResolver = vcsWorkspacePathResolver != null
- ? vcsWorkspacePathResolver
- : new WorkspacePathResolverImpl(workspaceRoot, blazeRoots);
-
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).reloadProjectView(context, workspacePathResolver);
- if (projectViewSet == null) {
- return null;
- }
-
- if (vcsSyncHandler != null) {
- BlazeVcsHandler.BlazeVcsSyncHandler.ValidationResult validationResult =
- vcsSyncHandler.validateProjectView(context, projectViewSet);
- switch (validationResult) {
- case OK:
- // Fall-through and return
- break;
- case Error:
- return null;
- case RestartSync:
- continue;
- default:
- // Cannot happen
- return null;
- }
- }
-
- return new WorkspacePathResolverAndProjectView(workspacePathResolver, projectViewSet);
- }
- return null;
- }
-
- private void printWorkingSet(BlazeContext context, WorkingSet workingSet) {
- List<String> messages = Lists.newArrayList();
- messages.addAll(workingSet.addedFiles.stream().map(file -> file.relativePath() + " (added)").collect(Collectors.toList()));
- messages.addAll(workingSet.modifiedFiles.stream().map(file -> file.relativePath() + " (modified)").collect(Collectors.toList()));
- Collections.sort(messages);
-
- if (messages.isEmpty()) {
- context.output(new PrintOutput("Your working set is empty"));
- return;
- }
- int maxFiles = 20;
- for (String message : Iterables.limit(messages, maxFiles)) {
- context.output(new PrintOutput(" " + message));
- }
- if (messages.size() > maxFiles) {
- context.output(new PrintOutput(String.format(" (and %d more)", messages.size() - maxFiles)));
- }
- }
-
- private Collection<? extends TargetExpression> getWorkingSetTargets(WorkingSet workingSet) {
- List<TargetExpression> result = Lists.newArrayList();
- for (WorkspacePath workspacePath : Iterables.concat(workingSet.addedFiles, workingSet.modifiedFiles)) {
- File buildFile = workspaceRoot.fileForPath(workspacePath);
- if (buildFile.getName().equals("BUILD")) {
- result.add(TargetExpression.allFromPackageNonRecursive(workspaceRoot.workspacePathFor(buildFile.getParentFile())));
- }
- }
- return result;
- }
-
-
- private boolean updateProject(Project project,
- BlazeContext parentContext,
- ProjectViewSet projectViewSet,
- @Nullable BlazeProjectData oldBlazeProjectData,
- BlazeProjectData newBlazeProjectData) {
- return Scope.push(parentContext, context -> {
- context
- .push(new LoggedTimingScope(project, Action.SYNC_IMPORT_DATA_TIME))
- .push(new TimingScope("UpdateProjectStructure"));
- context.output(new StatusOutput("Committing project structure..."));
-
- return updateProject(
- context,
- importSettings,
- projectViewSet,
- oldBlazeProjectData,
- newBlazeProjectData
- );
- });
- }
-
- @Nullable
- private BlazeIdeInterface.IdeResult getIdeQueryResult(
- Project project,
- BlazeContext parentContext,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder artifactLocationDecoder,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState,
- boolean requiresAndroidSdk) {
-
- return Scope.push(parentContext, context -> {
- context.push(new TimingScope("IdeQuery"));
-
- BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
- return blazeIdeInterface.updateBlazeIdeState(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- targets,
- workspaceLanguageSettings,
- artifactLocationDecoder,
- syncStateBuilder,
- previousSyncState,
- requiresAndroidSdk
- );
- });
- }
-
- private static boolean resolveIdeArtifacts(
- Project project,
- BlazeContext parentContext,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targetExpressions) {
- return Scope.push(parentContext, context -> {
- context
- .push(new LoggedTimingScope(project, Action.BLAZE_BUILD_DURING_SYNC))
- .push(new TimingScope("BlazeBuild"))
- ;
- context.output(new StatusOutput("Building project dependencies..."));
-
- // We don't want errors propagated for the build step - compilation errors shouldn't be interpreted
- // as "Sync failed"
- context.setPropagatesErrors(false);
-
- if (!targetExpressions.isEmpty()) {
- BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
- blazeIdeInterface.resolveIdeArtifacts(project, context, workspaceRoot, projectViewSet, targetExpressions);
- }
-
- return !context.hasErrors();
- });
- }
-
- private boolean updateProject(
- BlazeContext context,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- @Nullable BlazeProjectData oldBlazeProjectData,
- BlazeProjectData newBlazeProjectData) {
-
- try {
- AsyncUtil.executeProjectChangeAction(() -> ProjectRootManagerEx.getInstanceEx(project).mergeRootsChangesDuring(() -> {
- updateSdk(
- context,
- projectViewSet,
- newBlazeProjectData
- );
- updateProjectStructure(
- context,
- importSettings,
- projectViewSet,
- oldBlazeProjectData,
- newBlazeProjectData
- );
- }));
- } catch (Throwable t) {
- IssueOutput.error("Internal error. Please issue a bug at go/aswbbug. Error: " + t)
- .submit(context);
- LOG.error(t);
- return false;
- }
-
- BlazeProjectDataManagerImpl.getImpl(project).saveProject(importSettings, newBlazeProjectData);
- return true;
- }
-
- private void updateSdk(BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData newBlazeProjectData) {
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- syncPlugin.updateSdk(project, context, projectViewSet, newBlazeProjectData);
- }
- }
-
- private void updateProjectStructure(
- BlazeContext context,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- @Nullable BlazeProjectData oldBlazeProjectData,
- BlazeProjectData newBlazeProjectData) {
-
- ModuleEditorImpl moduleEditor = ModuleEditorProvider.getInstance().getModuleEditor(project, importSettings);
-
- ModuleType workspaceModuleType = null;
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- workspaceModuleType = syncPlugin.getWorkspaceModuleType(newBlazeProjectData.workspaceLanguageSettings.getWorkspaceType());
- if (workspaceModuleType != null) {
- break;
- }
- }
- if (workspaceModuleType == null) {
- workspaceModuleType = ModuleType.EMPTY;
- IssueOutput.warn("Could not set module type for workspace module.").submit(context);
- }
-
- Module workspaceModule = moduleEditor.createModule(ModuleDataStorage.WORKSPACE_MODULE_NAME, workspaceModuleType);
- ModifiableRootModel workspaceModifiableModel = moduleEditor.editModule(workspaceModule);
-
- ContentEntryEditor.createContentEntries(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- newBlazeProjectData,
- workspaceModifiableModel
- );
-
- for (BlazeSyncPlugin blazeSyncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- blazeSyncPlugin.updateProjectStructure(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- newBlazeProjectData,
- oldBlazeProjectData,
- moduleEditor,
- workspaceModule,
- workspaceModifiableModel);
- }
-
- createProjectDataDirectoryModule(moduleEditor, new File(importSettings.getProjectDataDirectory()), workspaceModuleType);
-
- moduleEditor.commitWithGc(context);
- }
-
- /**
- * Creates a module that includes the user's data directory.
- *
- * This is useful to be able to edit the project view without IntelliJ complaining it's outside the project.
- */
- private void createProjectDataDirectoryModule(ModuleEditor moduleEditor,
- File projectDataDirectory,
- ModuleType moduleType) {
- Module module = moduleEditor.createModule(ModuleDataStorage.PROJECT_DATA_DIR_MODULE_NAME, moduleType);
- ModifiableRootModel modifiableModel = moduleEditor.editModule(module);
- ContentEntry rootContentEntry = modifiableModel.addContentEntry(pathToUrl(projectDataDirectory));
- rootContentEntry.addExcludeFolder(pathToUrl(new File(projectDataDirectory, ".idea")));
- rootContentEntry.addExcludeFolder(pathToUrl(new File(projectDataDirectory, ModuleDataStorage.DATA_SUBDIRECTORY)));
- }
-
- private static String pathToUrl(File path) {
- String filePath = FileUtil.toSystemIndependentName(path.getPath());
- return VirtualFileManager.constructUrl(StandardFileSystems.FILE_PROTOCOL, filePath);
- }
-
- private static void onSyncStart(Project project) {
- final SyncListener[] syncListeners = SyncListener.EP_NAME.getExtensions();
- for (SyncListener syncListener : syncListeners) {
- syncListener.onSyncStart(project);
- }
- }
-
- private static void afterSync(Project project,
- boolean successful) {
- final SyncListener[] syncListeners = SyncListener.EP_NAME.getExtensions();
- for (SyncListener syncListener : syncListeners) {
- syncListener.afterSync(project, successful);
- }
- }
-
- private void onSyncComplete(Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- validate(project, context, blazeProjectData);
-
- final SyncListener[] syncListeners = SyncListener.EP_NAME.getExtensions();
- for (SyncListener syncListener : syncListeners) {
- syncListener.onSyncComplete(
- project,
- importSettings,
- projectViewSet,
- blazeProjectData
- );
- }
- }
-
- private static void validate(
- Project project,
- BlazeContext context,
- BlazeProjectData blazeProjectData) {
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- syncPlugin.validate(project, context, blazeProjectData);
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/ExpandWorkingSetTargetsExperiment.java b/blaze-base/src/com/google/idea/blaze/base/sync/ExpandWorkingSetTargetsExperiment.java
deleted file mode 100644
index 29e189e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/ExpandWorkingSetTargetsExperiment.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-
-/**
- * Experiment holder for the working set experiment.
- */
-public class ExpandWorkingSetTargetsExperiment {
- public static final BoolExperiment ENABLE_EXPAND_WORKING_SET_TARGETS = new BoolExperiment("enable.expand.working.set.targets", true);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/SyncListener.java b/blaze-base/src/com/google/idea/blaze/base/sync/SyncListener.java
deleted file mode 100644
index 4e7fd71..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/SyncListener.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.project.Project;
-
-/**
- * Extension interface for listening to syncs.
- */
-public interface SyncListener {
- ExtensionPointName<SyncListener> EP_NAME = ExtensionPointName
- .create("com.google.idea.blaze.SyncListener");
-
- /**
- * Called after open documents have been saved, prior to starting the blaze sync.
- */
- void onSyncStart(Project project);
-
- /**
- * Called on successful completion of a sync
- */
- void onSyncComplete(
- Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData);
-
- /**
- * Guaranteed to be called once per sync,
- * regardless of whether it successfully completed
- */
- void afterSync(Project project,
- boolean successful);
-
- /**
- * Convenience adapter class.
- */
- abstract class Adapter implements SyncListener {
-
- @Override
- public void onSyncStart(Project project) {
- }
-
- @Override
- public void onSyncComplete(Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- }
-
- @Override
- public void afterSync(Project project, boolean successful) {
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/actions/ExpandSyncToWorkingSetAction.java b/blaze-base/src/com/google/idea/blaze/base/sync/actions/ExpandSyncToWorkingSetAction.java
deleted file mode 100644
index 5b577a9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/actions/ExpandSyncToWorkingSetAction.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.actions;
-
-import com.google.idea.blaze.base.actions.BlazeToggleAction;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.ExpandWorkingSetTargetsExperiment;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Manages a tick box of whether to expand the sync targets to the working set.
- */
-public class ExpandSyncToWorkingSetAction extends BlazeToggleAction {
- @Override
- public boolean isSelected(AnActionEvent e) {
- return BlazeUserSettings.getInstance().getExpandSyncToWorkingSet();
- }
-
- @Override
- public void setSelected(AnActionEvent e, boolean state) {
- BlazeUserSettings.getInstance().setExpandSyncToWorkingSet(state);
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent e) {
- super.doUpdate(e);
-
- boolean enabled = ExpandWorkingSetTargetsExperiment.ENABLE_EXPAND_WORKING_SET_TARGETS.getValue();
- e.getPresentation().setVisible(enabled);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/actions/FullSyncProjectAction.java b/blaze-base/src/com/google/idea/blaze/base/sync/actions/FullSyncProjectAction.java
deleted file mode 100644
index 853181b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/actions/FullSyncProjectAction.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.actions;
-
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.sync.BlazeSyncManager;
-import com.google.idea.blaze.base.sync.BlazeSyncParams;
-import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.project.Project;
-
-/**
- * Re-imports (syncs) an Android-Blaze project, without showing the "Import Project" wizard.
- */
-public class FullSyncProjectAction extends BlazeAction {
-
- public FullSyncProjectAction() {
- super("Non-Incrementally Sync Project with BUILD Files");
- }
-
- @Override
- public void actionPerformed(final AnActionEvent e) {
- Project project = e.getProject();
- if (project != null) {
- Presentation presentation = e.getPresentation();
- presentation.setEnabled(false);
- try {
- BlazeSyncParams syncParams = new BlazeSyncParams.Builder(
- "Full Sync",
- SyncMode.FULL
- ).build();
- BlazeSyncManager.getInstance(project).requestProjectSync(syncParams);
- }
- finally {
- presentation.setEnabled(true);
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/actions/IncrementalSyncProjectAction.java b/blaze-base/src/com/google/idea/blaze/base/sync/actions/IncrementalSyncProjectAction.java
deleted file mode 100644
index c82265f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/actions/IncrementalSyncProjectAction.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.actions;
-
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.BlazeSyncManager;
-import com.google.idea.blaze.base.sync.BlazeSyncParams;
-import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
-import com.google.idea.blaze.base.sync.status.BlazeSyncStatus;
-import com.google.idea.blaze.base.sync.status.BlazeSyncStatusImpl;
-import com.intellij.notification.*;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.project.Project;
-import icons.BlazeIcons;
-
-import javax.swing.*;
-
-
-/**
- * Re-imports (syncs) an Android-Blaze project, without showing the "Import Project" wizard.
- */
-public class IncrementalSyncProjectAction extends BlazeAction {
-
- public static final String ACTION_ID = "Blaze.IncrementalSyncProject";
-
- public static final BlazeSyncParams manualSyncParams =
- new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL).build();
-
- public static final BlazeSyncParams autoSyncParams =
- new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
- .setBackgroundSync(true)
- .setDoBuild(false)
- .build();
-
- public static final BlazeSyncParams startupSyncParams =
- new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
- .setDoBuild(false)
- .build();
-
- public IncrementalSyncProjectAction() {
- super("Sync Project with BUILD Files");
- }
-
- @Override
- public void actionPerformed(final AnActionEvent e) {
- Project project = e.getProject();
- if (project != null) {
- BlazeSyncManager.getInstance(project).requestProjectSync(manualSyncParams);
- updateIcon(e);
- }
- }
-
- @Override
- protected void doUpdate(AnActionEvent e) {
- super.doUpdate(e);
- updateIcon(e);
- }
-
- private static void updateIcon(AnActionEvent e) {
- Project project = e.getProject();
- Presentation presentation = e.getPresentation();
- if (project == null) {
- presentation.setIcon(BlazeIcons.Blaze);
- presentation.setEnabled(true);
- return;
- }
- BlazeSyncStatusImpl statusHelper = BlazeSyncStatusImpl.getImpl(project);
- BlazeSyncStatus.SyncStatus status = statusHelper.getStatus();
- presentation.setIcon(getIcon(status));
- presentation.setEnabled(!statusHelper.syncInProgress.get());
-
- if (status == BlazeSyncStatus.SyncStatus.DIRTY && !BlazeUserSettings.getInstance().getSyncStatusPopupShown()) {
- BlazeUserSettings.getInstance().setSyncStatusPopupShown(true);
- showPopupNotification(project);
- }
- }
-
- private static Icon getIcon(BlazeSyncStatus.SyncStatus status) {
- switch (status) {
- case FAILED: return BlazeIcons.BlazeFailed;
- case DIRTY: return BlazeIcons.BlazeDirty;
- case CLEAN: return BlazeIcons.BlazeClean;
- default: return BlazeIcons.Blaze;
- }
- }
-
- private static final NotificationGroup NOTIFICATION_GROUP =
- new NotificationGroup("Changes since last blaze sync", NotificationDisplayType.BALLOON, true);
-
- private static void showPopupNotification(Project project) {
- String msg = "Some relevant files (e.g. BUILD files, .blazeproject file) have changed " +
- "since the last sync. Please press the 'Sync' button in the toolbar to " +
- "re-sync your IntelliJ project.";
- Notification notification = new Notification(
- NOTIFICATION_GROUP.getDisplayId(),
- String.format("Changes since last %s sync", Blaze.buildSystemName(project)),
- msg,
- NotificationType.INFORMATION);
- notification.setImportant(true);
- Notifications.Bus.notify(notification, project);
- }
-
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/actions/PartialSyncAction.java b/blaze-base/src/com/google/idea/blaze/base/sync/actions/PartialSyncAction.java
deleted file mode 100644
index 43eeab6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/actions/PartialSyncAction.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.actions;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.BlazeSyncManager;
-import com.google.idea.blaze.base.sync.BlazeSyncParams;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-
-/**
- * Allows a partial sync of the project depending on what's been selected.
- */
-public class PartialSyncAction extends BlazeAction {
- @Override
- public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- if (project != null) {
- List<TargetExpression> targetExpressions = Lists.newArrayList();
- getTargets(e, targetExpressions);
-
- BlazeSyncParams syncParams = new BlazeSyncParams.Builder("Partial Sync", BlazeSyncParams.SyncMode.INCREMENTAL)
- .setDoBuild(true)
- .setBackgroundSync(false)
- .addTargetExpressions(targetExpressions)
- .build();
-
- BlazeSyncManager.getInstance(project).requestProjectSync(syncParams);
- }
- }
-
- @Override
- protected void doUpdate(AnActionEvent e) {
- super.doUpdate(e);
- List<TargetExpression> targets = Lists.newArrayList();
- String objectName = getTargets(e, targets);
-
- boolean enabled = objectName != null && !targets.isEmpty();
- Presentation presentation = e.getPresentation();
- presentation.setEnabled(enabled);
-
-
- if (enabled) {
- presentation.setText(String.format(
- "Partially Sync %s with %s", objectName, buildSystemName(e.getProject())
- ));
- } else {
- presentation.setText(String.format("Partial %s Sync", buildSystemName(e.getProject())));
- }
- }
-
- private static String buildSystemName(@Nullable Project project) {
- return Blaze.buildSystemName(project);
- }
-
- @Nullable
- private String getTargets(AnActionEvent e, List<TargetExpression> targets) {
- Project project = e.getProject();
- VirtualFile virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE);
- if (project == null || virtualFile == null || !virtualFile.isInLocalFileSystem()) {
- return null;
- }
-
- String objectName = null;
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
-
- if (virtualFile.isDirectory()) {
- if (workspaceRoot.isInWorkspace(virtualFile)) {
- targets.add(TargetExpression.allFromPackageRecursive(workspaceRoot.workspacePathFor(virtualFile)));
- }
- objectName = "Package";
- } else {
- targets.addAll(SourceToRuleMap.getInstance(project).getTargetsForSourceFile(new File(virtualFile.getPath())));
-
- // If empty, try to build parent package
- if (targets.isEmpty()) {
- VirtualFile parent = virtualFile.getParent();
- if (parent.isDirectory()) {
- if (workspaceRoot.isInWorkspace(parent)) {
- targets.add(TargetExpression.allFromPackageNonRecursive(workspaceRoot.workspacePathFor(parent)));
- }
- }
- }
- objectName = "File";
- }
-
- return objectName;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/actions/ShowPerformanceWarningsToggleAction.java b/blaze-base/src/com/google/idea/blaze/base/sync/actions/ShowPerformanceWarningsToggleAction.java
deleted file mode 100644
index b5306ad..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/actions/ShowPerformanceWarningsToggleAction.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.actions;
-
-import com.google.idea.blaze.base.actions.BlazeToggleAction;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-
-/**
- * Manages a tick box of whether to show performance warnings.
- */
-public class ShowPerformanceWarningsToggleAction extends BlazeToggleAction {
- @Override
- public boolean isSelected(AnActionEvent e) {
- return BlazeUserSettings.getInstance().getShowPerformanceWarnings();
- }
-
- @Override
- public void setSelected(AnActionEvent e, boolean state) {
- BlazeUserSettings.getInstance().setShowPerformanceWarnings(state);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/AspectStrategy.java b/blaze-base/src/com/google/idea/blaze/base/sync/aspects/AspectStrategy.java
deleted file mode 100644
index 0d8e3e4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/AspectStrategy.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
-import com.google.repackaged.protobuf.TextFormat;
-
-import java.io.*;
-
-/**
- * Indirection for our various ways of calling the aspect.
- */
-public interface AspectStrategy {
-
- String getName();
-
- void modifyIdeInfoCommand(BlazeCommand.Builder blazeCommandBuilder);
-
- void modifyIdeResolveCommand(BlazeCommand.Builder blazeCommandBuilder);
-
- String getAspectOutputFileExtension();
-
- AndroidStudioIdeInfo.RuleIdeInfo readAspectFile(File file) throws IOException;
-
- AspectStrategy NATIVE_ASPECT = new AspectStrategy() {
- @Override
- public String getName() {
- return "NativeAspect";
- }
-
- @Override
- public void modifyIdeInfoCommand(BlazeCommand.Builder blazeCommandBuilder) {
- blazeCommandBuilder
- .addBlazeFlags("--aspects=AndroidStudioInfoAspect")
- .addBlazeFlags("--output_groups=ide-info");
- }
-
- @Override
- public void modifyIdeResolveCommand(BlazeCommand.Builder blazeCommandBuilder) {
- blazeCommandBuilder
- .addBlazeFlags("--aspects=AndroidStudioInfoAspect")
- .addBlazeFlags("--output_groups=ide-resolve");
- }
-
- @Override
- public String getAspectOutputFileExtension() {
- return ".aswb-build";
- }
-
- @Override
- public AndroidStudioIdeInfo.RuleIdeInfo readAspectFile(File file) throws IOException {
- try (InputStream inputStream = new FileInputStream(file)) {
- return AndroidStudioIdeInfo.RuleIdeInfo.parseFrom(inputStream);
- }
- }
- };
-
- AspectStrategy SKYLARK_ASPECT = new AspectStrategy() {
- @Override
- public String getName() {
- return "SkylarkAspect";
- }
-
- private void addAspectFlag(BlazeCommand.Builder blazeCommandBuilder) {
- blazeCommandBuilder.addBlazeFlags(
- "--aspects=//third_party/bazel/src/test/java/com/google/devtools/build/lib/ideinfo/intellij_info.bzl%intellij_info_aspect"
- );
- }
-
- @Override
- public void modifyIdeInfoCommand(BlazeCommand.Builder blazeCommandBuilder) {
- addAspectFlag(blazeCommandBuilder);
- blazeCommandBuilder.addBlazeFlags("--output_groups=ide-info-text");
- }
-
- @Override
- public void modifyIdeResolveCommand(BlazeCommand.Builder blazeCommandBuilder) {
- addAspectFlag(blazeCommandBuilder);
- blazeCommandBuilder.addBlazeFlags("--output_groups=ide-resolve");
- }
-
- @Override
- public String getAspectOutputFileExtension() {
- return ".intellij-build.txt";
- }
-
- @Override
- public AndroidStudioIdeInfo.RuleIdeInfo readAspectFile(File file) throws IOException {
- try (InputStream inputStream = new FileInputStream(file)) {
- AndroidStudioIdeInfo.RuleIdeInfo.Builder builder = AndroidStudioIdeInfo.RuleIdeInfo.newBuilder();
- TextFormat.Parser parser = TextFormat.Parser.newBuilder()
- .setAllowUnknownFields(true)
- .build();
- parser.merge(new InputStreamReader(inputStream), builder);
- return builder.build();
- }
- }
- };
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java b/blaze-base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java
deleted file mode 100644
index d988982..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-
-/**
- * Indirection between ide_build_info and aspect style IDE info.
- */
-public abstract class BlazeIdeInterface {
-
- public static BlazeIdeInterface getInstance() {
- return ServiceManager.getService(BlazeIdeInterface.class);
- }
-
- public static class IdeResult {
- public final ImmutableMap<Label, RuleIdeInfo> ruleMap;
- @Deprecated
- @Nullable
- public final File androidPlatformDirectory;
- public IdeResult(
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Nullable File androidPlatformDirectory) {
-
- this.ruleMap = ruleMap;
- this.androidPlatformDirectory = androidPlatformDirectory;
- }
- }
-
- @Nullable
- public abstract IdeResult updateBlazeIdeState(
- Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder artifactLocationDecoder,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState,
- boolean requiresAndroidSdk);
-
- public abstract void resolveIdeArtifacts(
- Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java
deleted file mode 100644
index 367a1ed..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.async.FutureUtil;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.command.ExperimentalShowArtifactsLineProcessor;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.prefetch.PrefetchService;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Result;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.ScopedFunction;
-import com.google.idea.blaze.base.scope.output.PerformanceWarning;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.sync.filediff.FileDiffService;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Implementation of BlazeIdeInterface based on aspects.
- */
-public class BlazeIdeInterfaceAspectsImpl extends BlazeIdeInterface {
-
- private static final Logger LOG = Logger.getInstance(BlazeIdeInterfaceAspectsImpl.class);
- private static final Label ANDROID_SDK_TARGET = new Label("//third_party/java/android/android_sdk_linux:android");
- private static final FileDiffService fileDiffService = new FileDiffService();
- private static final BoolExperiment USE_SKYLARK_ASPECT = new BoolExperiment("use.skylark.aspect", false);
-
- static class State implements Serializable {
- private static final long serialVersionUID = 10L;
- ImmutableMap<Label, RuleIdeInfo> ruleMap;
- File androidPlatformDirectory;
- FileDiffService.State fileState = null;
- Map<File, Label> fileToLabel = Maps.newHashMap();
- WorkspaceLanguageSettings workspaceLanguageSettings;
- String aspectStrategyName;
- }
-
- @Nullable
- @Override
- public IdeResult updateBlazeIdeState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder artifactLocationDecoder,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState,
- boolean requiresAndroidSdk) {
- State prevState = previousSyncState != null ? previousSyncState.get(State.class) : null;
-
- // If the language filter has changed, redo everything from scratch
- if (prevState != null && !prevState.workspaceLanguageSettings.equals(workspaceLanguageSettings)) {
- prevState = null;
- }
-
- // If the aspect strategy has changed, redo everything from scratch
- final AspectStrategy aspectStrategy = getAspectStrategy();
- if (prevState != null && !Objects.equal(prevState.aspectStrategyName, aspectStrategy.getName())) {
- prevState = null;
- }
-
- List<File> fileList = getIdeInfo(project, context, workspaceRoot, projectViewSet, targets, aspectStrategy, requiresAndroidSdk);
- if (!context.shouldContinue()) {
- return null;
- }
-
- List<File> updatedFiles = Lists.newArrayList();
- List<File> removedFiles = Lists.newArrayList();
- FileDiffService.State fileState = fileDiffService.updateFiles(
- prevState != null ? prevState.fileState : null,
- fileList,
- updatedFiles,
- removedFiles
- );
- if (fileState == null) {
- return null;
- }
-
- context.output(new PrintOutput(String.format(
- "Total rules: %d, new/changed: %d, removed: %d",
- fileList.size(),
- updatedFiles.size(),
- removedFiles.size()
- )));
-
- ListenableFuture<?> prefetchFuture = PrefetchService.getInstance().prefetchFiles(updatedFiles, true);
- if (!FutureUtil.waitForFuture(context, prefetchFuture)
- .timed("FetchAspectOutput")
- .run()
- .success()) {
- return null;
- }
-
- State state = updateState(
- context,
- prevState,
- fileState,
- workspaceLanguageSettings,
- artifactLocationDecoder,
- aspectStrategy,
- updatedFiles,
- removedFiles
- );
- if (state == null) {
- return null;
- }
- if (state.androidPlatformDirectory == null && requiresAndroidSdk) {
- LOG.error("Android platform directory not found.");
- return null;
- }
- syncStateBuilder.put(State.class, state);
- return new IdeResult(state.ruleMap, state.androidPlatformDirectory);
- }
-
- private static List<File> getIdeInfo(Project project,
- BlazeContext parentContext,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets,
- AspectStrategy aspectStrategy,
- boolean addAndroidSdkTarget) {
- return Scope.push(parentContext, context -> {
- context.push(new TimingScope("ExecuteBlazeCommand"));
-
- List<File> result = Lists.newArrayList();
-
- BuildSystem buildSystem = Blaze.getBuildSystem(project);
- BlazeCommand.Builder blazeCommandBuilder = BlazeCommand.builder(buildSystem, BlazeCommandName.BUILD);
- if (addAndroidSdkTarget) {
- blazeCommandBuilder.addTargets(ANDROID_SDK_TARGET);
- }
- blazeCommandBuilder
- .addTargets(targets)
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS)
- .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet));
-
- aspectStrategy.modifyIdeInfoCommand(blazeCommandBuilder);
-
- int retVal = ExternalTask.builder(workspaceRoot, blazeCommandBuilder.build())
- .context(context)
- .stderr(LineProcessingOutputStream.of(
- new ExperimentalShowArtifactsLineProcessor(result, aspectStrategy.getAspectOutputFileExtension()),
- new IssueOutputLineProcessor(project, context, workspaceRoot)
- ))
- .build()
- .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
-
- if (retVal != 0) {
- context.setHasError();
- }
-
- return result;
- });
- }
-
- private static class RuleIdeInfoOrSdkInfo {
- public File file;
- public RuleIdeInfo ruleIdeInfo;
- public File androidPlatformDirectory;
- }
-
- @Nullable
- static State updateState(BlazeContext parentContext,
- @Nullable State prevState,
- FileDiffService.State fileState,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder artifactLocationDecoder,
- AspectStrategy aspectStrategy,
- List<File> newFiles,
- List<File> removedFiles) {
- Result<State> result = Scope.push(parentContext, (ScopedFunction<Result<State>>)context -> {
- context.push(new TimingScope("UpdateRuleMap"));
-
- State state = new State();
- state.fileState = fileState;
- state.workspaceLanguageSettings = workspaceLanguageSettings;
- state.aspectStrategyName = aspectStrategy.getName();
-
- Map<Label, RuleIdeInfo> ruleMap = Maps.newHashMap();
- Map<Label, RuleIdeInfo> updatedRules = Maps.newHashMap();
- if (prevState != null) {
- ruleMap.putAll(prevState.ruleMap);
- state.androidPlatformDirectory = prevState.androidPlatformDirectory;
- state.fileToLabel.putAll(prevState.fileToLabel);
- }
-
- // Update removed
- for (File removedFile : removedFiles) {
- Label label = state.fileToLabel.remove(removedFile);
- if (label != null) {
- ruleMap.remove(label);
- }
- }
-
- AtomicLong totalSizeLoaded = new AtomicLong(0);
-
- // Read protos from any new files
- List<ListenableFuture<RuleIdeInfoOrSdkInfo>> futures = Lists.newArrayList();
- for (File file : newFiles) {
- futures.add(submit(() -> {
- RuleIdeInfoOrSdkInfo ruleIdeInfoOrSdkInfo = new RuleIdeInfoOrSdkInfo();
- ruleIdeInfoOrSdkInfo.file = file;
-
- totalSizeLoaded.addAndGet(file.length());
-
- AndroidStudioIdeInfo.RuleIdeInfo ruleProto = aspectStrategy.readAspectFile(file);
- if (ruleProto.getLabel().equals(ANDROID_SDK_TARGET.toString())) {
- ruleIdeInfoOrSdkInfo.androidPlatformDirectory = getAndroidPlatformDirectoryFromAndroidTarget(
- ruleProto,
- artifactLocationDecoder
- );
- }
- else {
- ruleIdeInfoOrSdkInfo.ruleIdeInfo = IdeInfoFromProtobuf.makeRuleIdeInfo(
- workspaceLanguageSettings,
- artifactLocationDecoder,
- ruleProto
- );
- }
- return ruleIdeInfoOrSdkInfo;
- }
- ));
- }
-
- // Update state with result from proto files
- int duplicateRuleLabels = 0;
- try {
- for (RuleIdeInfoOrSdkInfo ruleIdeInfoOrSdkInfo : Futures.allAsList(futures).get()) {
- if (ruleIdeInfoOrSdkInfo.androidPlatformDirectory != null) {
- state.androidPlatformDirectory = ruleIdeInfoOrSdkInfo.androidPlatformDirectory;
- } else if (ruleIdeInfoOrSdkInfo.ruleIdeInfo != null) {
- File file = ruleIdeInfoOrSdkInfo.file;
- Label label = ruleIdeInfoOrSdkInfo.ruleIdeInfo.label;
-
- RuleIdeInfo previousRule = updatedRules.putIfAbsent(label, ruleIdeInfoOrSdkInfo.ruleIdeInfo);
- if (previousRule == null) {
- state.fileToLabel.put(file, label);
- } else {
- duplicateRuleLabels++;
- }
- }
- }
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return Result.error(null);
- }
- catch (ExecutionException e) {
- return Result.error(e);
- }
- ruleMap.putAll(updatedRules);
-
- context.output(new PrintOutput(String.format(
- "Loaded %d aspect files, total size %dkB", newFiles.size(), totalSizeLoaded.get() / 1024
- )));
- if (duplicateRuleLabels > 0) {
- context.output(new PerformanceWarning(String.format(
- "There were %d duplicate rules. You may be including multiple configurations in your build. "
- + "Your IDE sync is slowed down by ~%d%%.",
- duplicateRuleLabels,
- (100 * duplicateRuleLabels / ruleMap.size())
- )));
- }
-
- state.ruleMap = ImmutableMap.copyOf(ruleMap);
- return Result.of(state);
- });
-
- if (result.error != null) {
- LOG.error(result.error);
- return null;
- }
- return result.result;
- }
-
- @Nullable
- private static File getAndroidPlatformDirectoryFromAndroidTarget(AndroidStudioIdeInfo.RuleIdeInfo ruleProto,
- ArtifactLocationDecoder artifactLocationDecoder) {
- if (!ruleProto.hasJavaRuleIdeInfo()) {
- return null;
- }
- AndroidStudioIdeInfo.JavaRuleIdeInfo javaRuleIdeInfo = ruleProto.getJavaRuleIdeInfo();
- if (javaRuleIdeInfo.getJarsCount() == 0) {
- return null;
- }
- AndroidStudioIdeInfo.LibraryArtifact libraryArtifact = javaRuleIdeInfo.getJars(0);
- AndroidStudioIdeInfo.ArtifactLocation artifactLocation = libraryArtifact.getJar();
- if (artifactLocation == null) {
- return null;
- }
- File androidJar = artifactLocationDecoder.decode(artifactLocation).getFile();
- return androidJar.getParentFile();
- }
-
- private static <T> ListenableFuture<T> submit(Callable<T> callable) {
- return BlazeExecutor.getInstance().submit(callable);
- }
-
- @Override
- public void resolveIdeArtifacts(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets) {
- AspectStrategy aspectStrategy = getAspectStrategy();
-
- BlazeCommand.Builder blazeCommandBuilder = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD)
- .addTargets(targets)
- .addBlazeFlags()
- .addBlazeFlags(BlazeFlags.KEEP_GOING)
- .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet));
-
- aspectStrategy.modifyIdeResolveCommand(blazeCommandBuilder);
-
- BlazeCommand blazeCommand = blazeCommandBuilder.build();
-
- int retVal = ExternalTask.builder(workspaceRoot, blazeCommand)
- .context(context)
- .stderr(LineProcessingOutputStream.of(new IssueOutputLineProcessor(project, context, workspaceRoot)))
- .build()
- .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
-
- if (retVal != 0) {
- context.setHasError();
- }
- }
-
- private AspectStrategy getAspectStrategy() {
- return USE_SKYLARK_ASPECT.getValue() ? AspectStrategy.SKYLARK_ASPECT : AspectStrategy.NATIVE_ASPECT;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java b/blaze-base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java
deleted file mode 100644
index e723505..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.ideinfo.*;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
-import com.google.repackaged.protobuf.ProtocolStringList;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Conversion functions from new aspect-style Bazel IDE info to ASWB internal classes.
- */
-public class IdeInfoFromProtobuf {
-
- @Nullable
- public static RuleIdeInfo makeRuleIdeInfo(WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.RuleIdeInfo message) {
- Kind kind = getKind(message);
- if (kind == null) {
- return null;
- }
- if (!workspaceLanguageSettings.isLanguageActive(kind.getLanguageClass())) {
- return null;
- }
-
- Label label = new Label(message.getLabel());
- ArtifactLocation buildFile = getBuildFile(decoder, message);
-
- Collection<Label> dependencies = makeLabelListFromProtobuf(message.getDependenciesList());
- Collection<Label> runtimeDeps = makeLabelListFromProtobuf(message.getRuntimeDepsList());
- Collection<String> tags = ImmutableList.copyOf(message.getTagsList());
-
- Collection<ArtifactLocation> sources = Lists.newArrayList();
- CRuleIdeInfo cRuleIdeInfo = null;
- if (message.hasCRuleIdeInfo()) {
- cRuleIdeInfo = makeCRuleIdeInfo(decoder, message.getCRuleIdeInfo());
- sources.addAll(cRuleIdeInfo.sources);
- }
- CToolchainIdeInfo cToolchainIdeInfo = null;
- if (message.hasCToolchainIdeInfo()) {
- cToolchainIdeInfo = makeCToolchainIdeInfo(message.getCToolchainIdeInfo());
- }
- JavaRuleIdeInfo javaRuleIdeInfo = null;
- if (message.hasJavaRuleIdeInfo()) {
- javaRuleIdeInfo = makeJavaRuleIdeInfo(decoder, message.getJavaRuleIdeInfo());
- Collection<ArtifactLocation> javaSources = makeArtifactLocationList(decoder, message.getJavaRuleIdeInfo().getSourcesList());
- sources.addAll(javaSources);
- }
- AndroidRuleIdeInfo androidRuleIdeInfo = null;
- if (message.hasAndroidRuleIdeInfo()) {
- androidRuleIdeInfo = makeAndroidRuleIdeInfo(decoder, message.getAndroidRuleIdeInfo());
- }
- TestIdeInfo testIdeInfo = null;
- if (message.hasTestInfo()) {
- testIdeInfo = makeTestIdeInfo(message.getTestInfo());
- }
- ProtoLibraryLegacyInfo protoLibraryLegacyInfo = null;
- if (message.hasProtoLibraryLegacyJavaIdeInfo()) {
- protoLibraryLegacyInfo = makeProtoLibraryLegacyInfo(decoder, message.getProtoLibraryLegacyJavaIdeInfo());
- }
- JavaToolchainIdeInfo javaToolchainIdeInfo = null;
- if (message.hasJavaToolchainIdeInfo()) {
- javaToolchainIdeInfo = makeJavaToolchainIdeInfo(message.getJavaToolchainIdeInfo());
- }
-
- return new RuleIdeInfo(
- label,
- kind,
- buildFile,
- dependencies,
- runtimeDeps,
- tags,
- sources,
- cRuleIdeInfo,
- cToolchainIdeInfo,
- javaRuleIdeInfo,
- androidRuleIdeInfo,
- testIdeInfo,
- protoLibraryLegacyInfo,
- javaToolchainIdeInfo
- );
- }
-
- @Nullable
- private static ArtifactLocation getBuildFile(ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.RuleIdeInfo message) {
- if (message.hasBuildFileArtifactLocation()) {
- return makeArtifactLocation(decoder, message.getBuildFileArtifactLocation());
- }
- return null;
- }
-
- private static CRuleIdeInfo makeCRuleIdeInfo(
- ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.CRuleIdeInfo cRuleIdeInfo
- ) {
- List<ArtifactLocation> sources = makeArtifactLocationList(decoder, cRuleIdeInfo.getSourceList());
- List<ExecutionRootPath> transitiveIncludeDirectories = makeExecutionRootPathList(cRuleIdeInfo.getTransitiveIncludeDirectoryList());
- List<ExecutionRootPath> transitiveQuoteIncludeDirectories =
- makeExecutionRootPathList(cRuleIdeInfo.getTransitiveQuoteIncludeDirectoryList());
- List<ExecutionRootPath> transitiveSystemIncludeDirectories =
- makeExecutionRootPathList(cRuleIdeInfo.getTransitiveSystemIncludeDirectoryList());
-
- CRuleIdeInfo.Builder builder = CRuleIdeInfo.builder()
- .addSources(sources)
- .addTransitiveIncludeDirectories(transitiveIncludeDirectories)
- .addTransitiveQuoteIncludeDirectories(transitiveQuoteIncludeDirectories)
- .addTransitiveDefines(cRuleIdeInfo.getTransitiveDefineList())
- .addTransitiveSystemIncludeDirectories(transitiveSystemIncludeDirectories)
- ;
-
- return builder.build();
- }
-
- private static List<ExecutionRootPath> makeExecutionRootPathList(Iterable<String> relativePaths) {
- List<ExecutionRootPath> workspacePaths = Lists.newArrayList();
- for (String relativePath : relativePaths) {
- workspacePaths.add(new ExecutionRootPath(relativePath));
- }
- return workspacePaths;
- }
-
- private static CToolchainIdeInfo makeCToolchainIdeInfo(AndroidStudioIdeInfo.CToolchainIdeInfo cToolchainIdeInfo) {
- Collection<ExecutionRootPath> builtInIncludeDirectories = makeExecutionRootPathList(cToolchainIdeInfo.getBuiltInIncludeDirectoryList());
- ExecutionRootPath cppExecutable = new ExecutionRootPath(cToolchainIdeInfo.getCppExecutable());
- ExecutionRootPath preprocessorExecutable = new ExecutionRootPath(cToolchainIdeInfo.getPreprocessorExecutable());
-
- UnfilteredCompilerOptions unfilteredCompilerOptions =
- new UnfilteredCompilerOptions(cToolchainIdeInfo.getUnfilteredCompilerOptionList());
-
- CToolchainIdeInfo.Builder builder = CToolchainIdeInfo.builder()
- .addBaseCompilerOptions(cToolchainIdeInfo.getBaseCompilerOptionList())
- .addCCompilerOptions(cToolchainIdeInfo.getCOptionList())
- .addCppCompilerOptions(cToolchainIdeInfo.getCppOptionList())
- .addLinkOptions(cToolchainIdeInfo.getLinkOptionList())
- .addBuiltInIncludeDirectories(builtInIncludeDirectories)
- .setCppExecutable(cppExecutable)
- .setPreprocessorExecutable(preprocessorExecutable)
- .setTargetName(cToolchainIdeInfo.getTargetName())
- .addUnfilteredCompilerOptions(unfilteredCompilerOptions.getToolchainFlags())
- .addUnfilteredToolchainSystemIncludes(unfilteredCompilerOptions.getToolchainSysIncludes())
- ;
-
- return builder.build();
- }
-
- private static JavaRuleIdeInfo makeJavaRuleIdeInfo(ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.JavaRuleIdeInfo javaRuleIdeInfo) {
- return new JavaRuleIdeInfo(
- makeLibraryArtifactList(decoder, javaRuleIdeInfo.getJarsList()),
- makeLibraryArtifactList(decoder, javaRuleIdeInfo.getGeneratedJarsList()),
- javaRuleIdeInfo.hasPackageManifest() ? makeArtifactLocation(decoder, javaRuleIdeInfo.getPackageManifest()) : null,
- javaRuleIdeInfo.hasJdeps() ? makeArtifactLocation(decoder, javaRuleIdeInfo.getJdeps()) : null
- );
- }
-
- private static AndroidRuleIdeInfo makeAndroidRuleIdeInfo(ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.AndroidRuleIdeInfo androidRuleIdeInfo) {
- return new AndroidRuleIdeInfo(
- makeArtifactLocationList(decoder, androidRuleIdeInfo.getResourcesList()),
- androidRuleIdeInfo.getJavaPackage(),
- androidRuleIdeInfo.getGenerateResourceClass(),
- androidRuleIdeInfo.hasManifest() ? makeArtifactLocation(decoder, androidRuleIdeInfo.getManifest()) : null,
- androidRuleIdeInfo.hasIdlJar() ? makeLibraryArtifact(decoder, androidRuleIdeInfo.getIdlJar()) : null,
- androidRuleIdeInfo.hasResourceJar() ? makeLibraryArtifact(decoder, androidRuleIdeInfo.getResourceJar()) : null,
- androidRuleIdeInfo.getHasIdlSources(),
- !Strings.isNullOrEmpty(androidRuleIdeInfo.getLegacyResources()) ? new Label(androidRuleIdeInfo.getLegacyResources()) : null
- );
- }
-
- private static TestIdeInfo makeTestIdeInfo(AndroidStudioIdeInfo.TestInfo testInfo) {
- String size = testInfo.getSize();
- TestIdeInfo.TestSize testSize = TestIdeInfo.DEFAULT_RULE_TEST_SIZE;
- if (!Strings.isNullOrEmpty(size)) {
- switch (size) {
- case "small":
- testSize = TestIdeInfo.TestSize.SMALL;
- break;
- case "medium":
- testSize = TestIdeInfo.TestSize.MEDIUM;
- break;
- case "large":
- testSize = TestIdeInfo.TestSize.LARGE;
- break;
- case "enormous":
- testSize = TestIdeInfo.TestSize.ENORMOUS;
- break;
- default:
- break;
- }
- }
- return new TestIdeInfo(testSize);
- }
-
- private static ProtoLibraryLegacyInfo makeProtoLibraryLegacyInfo(ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.ProtoLibraryLegacyJavaIdeInfo protoLibraryLegacyJavaIdeInfo) {
- final ProtoLibraryLegacyInfo.ApiFlavor apiFlavor;
- if (protoLibraryLegacyJavaIdeInfo.getApiVersion() == 1) {
- apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1;
- } else {
- switch (protoLibraryLegacyJavaIdeInfo.getApiFlavor()) {
- case MUTABLE:
- apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.MUTABLE;
- break;
- case IMMUTABLE:
- apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE;
- break;
- case BOTH:
- apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.BOTH;
- break;
- default:
- apiFlavor = ProtoLibraryLegacyInfo.ApiFlavor.NONE;
- break;
- }
- }
- return new ProtoLibraryLegacyInfo(
- apiFlavor,
- makeLibraryArtifactList(decoder, protoLibraryLegacyJavaIdeInfo.getJars1List()),
- makeLibraryArtifactList(decoder, protoLibraryLegacyJavaIdeInfo.getJarsMutableList()),
- makeLibraryArtifactList(decoder, protoLibraryLegacyJavaIdeInfo.getJarsImmutableList())
- );
- }
-
- private static JavaToolchainIdeInfo makeJavaToolchainIdeInfo(AndroidStudioIdeInfo.JavaToolchainIdeInfo javaToolchainIdeInfo) {
- return new JavaToolchainIdeInfo(javaToolchainIdeInfo.getSourceVersion(), javaToolchainIdeInfo.getTargetVersion());
- }
-
- private static Collection<LibraryArtifact> makeLibraryArtifactList(
- ArtifactLocationDecoder decoder,
- List<AndroidStudioIdeInfo.LibraryArtifact> jarsList) {
- ImmutableList.Builder<LibraryArtifact> builder = ImmutableList.builder();
- for (AndroidStudioIdeInfo.LibraryArtifact libraryArtifact : jarsList) {
- LibraryArtifact lib = makeLibraryArtifact(decoder, libraryArtifact);
- if (lib != null) {
- builder.add(lib);
- }
- }
- return builder.build();
- }
-
- @Nullable
- private static LibraryArtifact makeLibraryArtifact(ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.LibraryArtifact libraryArtifact) {
- ArtifactLocation runtimeJar = libraryArtifact.hasJar()
- ? makeArtifactLocation(decoder, libraryArtifact.getJar()) : null;
- ArtifactLocation iJar = libraryArtifact.hasInterfaceJar()
- ? makeArtifactLocation(decoder, libraryArtifact.getInterfaceJar()) : runtimeJar;
- ArtifactLocation sourceJar = libraryArtifact.hasSourceJar()
- ? makeArtifactLocation(decoder, libraryArtifact.getSourceJar()) : null;
- if (iJar == null) {
- // Failed to find ArtifactLocation file -- presumably because it was removed from file system since blaze build
- return null;
- }
- return new LibraryArtifact(
- iJar,
- runtimeJar,
- sourceJar
- );
- }
-
- private static List<ArtifactLocation> makeArtifactLocationList(
- ArtifactLocationDecoder decoder,
- List<AndroidStudioIdeInfo.ArtifactLocation> sourcesList) {
- ImmutableList.Builder<ArtifactLocation> builder = ImmutableList.builder();
- for (AndroidStudioIdeInfo.ArtifactLocation pbArtifactLocation : sourcesList) {
- ArtifactLocation loc = makeArtifactLocation(decoder, pbArtifactLocation);
- if (loc != null) {
- builder.add(loc);
- }
- }
- return builder.build();
- }
-
- @Nullable
- private static ArtifactLocation makeArtifactLocation(ArtifactLocationDecoder decoder,
- AndroidStudioIdeInfo.ArtifactLocation pbArtifactLocation) {
- if (pbArtifactLocation == null) {
- return null;
- }
- return decoder.decode(pbArtifactLocation);
- }
-
- private static Collection<Label> makeLabelListFromProtobuf(ProtocolStringList dependenciesList) {
- ImmutableList.Builder<Label> dependenciesBuilder = ImmutableList.builder();
- for (String dependencyLabel : dependenciesList) {
- dependenciesBuilder.add(new Label(dependencyLabel));
- }
- return dependenciesBuilder.build();
- }
-
- @Nullable
- private static Kind getKind(AndroidStudioIdeInfo.RuleIdeInfo rule) {
- String kindString = rule.getKindString();
- if (!Strings.isNullOrEmpty(kindString)) {
- return Kind.fromString(kindString);
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java b/blaze-base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java
deleted file mode 100644
index 4345b6f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-
-import java.util.List;
-
-/**
- * unfilteredCompilerOptions is a grab bag of options passed to the compiler. Do minimal parsing to extract what we need.
- */
-final class UnfilteredCompilerOptions {
- private enum NextOption {ISYSTEM, FLAG}
-
- private final List<ExecutionRootPath> toolchainSysIncludes;
- private final List<String> toolchainFlags;
-
- public UnfilteredCompilerOptions(Iterable<String> unfilteredOptions) {
- List<String> toolchainSystemIncludePaths = Lists.newArrayList();
- toolchainFlags = Lists.newArrayList();
- splitUnfilteredCompilerOptions(unfilteredOptions, toolchainSystemIncludePaths, toolchainFlags);
-
- toolchainSysIncludes = Lists.newArrayList();
- for (String systemInclude : toolchainSystemIncludePaths) {
- toolchainSysIncludes.add(new ExecutionRootPath(systemInclude));
- }
- }
-
- public List<String> getToolchainFlags() {
- return toolchainFlags;
- }
-
- public List<ExecutionRootPath> getToolchainSysIncludes() {
- return toolchainSysIncludes;
- }
-
- @VisibleForTesting
- static void splitUnfilteredCompilerOptions(
- Iterable<String> unfilteredOptions,
- List<String> toolchainSysIncludes,
- List<String> toolchainFlags
- ) {
- NextOption nextOption = NextOption.FLAG;
- for (String unfilteredOption : unfilteredOptions) {
- // We are looking for either the flag pair "-isystem /path/to/dir" or the flag "-isystem/path/to/dir"
- //
- // blaze emits isystem flags in both formats. The latter isn't ideal but apparently it is accepted by GCC and will be emitted by
- // blaze under certain circumstances.
- if (nextOption == NextOption.ISYSTEM) {
- toolchainSysIncludes.add(unfilteredOption);
- nextOption = NextOption.FLAG;
- }
- else {
- if (unfilteredOption.equals("-isystem")) {
- nextOption = NextOption.ISYSTEM;
- }
- else if (unfilteredOption.startsWith("-isystem")) {
- String iSystemIncludePath = unfilteredOption.substring("-isystem".length());
- toolchainSysIncludes.add(iSystemIncludePath);
- }
- else {
- toolchainFlags.add(unfilteredOption);
- nextOption = NextOption.FLAG;
- }
- }
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeDataStorage.java b/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeDataStorage.java
deleted file mode 100644
index edb49ea..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeDataStorage.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.data;
-
-import com.google.common.base.Strings;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-
-/**
- * Defines where we store our blaze project data.
- */
-public class BlazeDataStorage {
- public static final String CACHE_FILE_NAME = "cache.dat";
-
- @NotNull
- public static File getProjectCacheDir(
- @NotNull Project project,
- @NotNull BlazeImportSettings importSettings) {
- String locationHash = importSettings.getLocationHash();
-
- // Legacy support: The location hash used to be just the project hash
- if (Strings.isNullOrEmpty(locationHash)) {
- locationHash = project.getLocationHash();
- }
-
- return new File(getProjectConfigurationDir(), locationHash);
- }
-
- private static File getProjectConfigurationDir() {
- return new File(PathManager.getSystemPath(), "blaze/projects").getAbsoluteFile();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManager.java b/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManager.java
deleted file mode 100644
index fa0f881..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManager.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.data;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Stores a cache of blaze project data.
- */
-public interface BlazeProjectDataManager {
- static BlazeProjectDataManager getInstance(Project project) {
- return ServiceManager.getService(project, BlazeProjectDataManager.class);
- }
-
- @Nullable
- BlazeProjectData getBlazeProjectData();
-
- BlazeSyncPlugin.ModuleEditor editModules();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java
deleted file mode 100644
index c10640a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.data;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.StatusOutput;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
-import com.google.idea.blaze.base.util.SerializationUtil;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Stores a cache of blaze project data and issues any side effects when that data is updated.
- */
-public class BlazeProjectDataManagerImpl implements BlazeProjectDataManager {
-
- private static final Logger LOG = Logger.getInstance(BlazeProjectDataManagerImpl.class.getName());
-
- private final Project project;
-
- @Nullable
- private volatile BlazeProjectData blazeProjectData;
-
- private final Object saveLock = new Object();
-
- public static BlazeProjectDataManagerImpl getImpl(Project project) {
- return (BlazeProjectDataManagerImpl) BlazeProjectDataManager.getInstance(project);
- }
-
- public BlazeProjectDataManagerImpl(Project project) {
- this.project = project;
- }
-
- @Nullable
- public BlazeProjectData loadProjectRoot(
- BlazeContext context,
- BlazeImportSettings importSettings) {
- BlazeProjectData projectData = blazeProjectData;
- if (projectData != null) {
- return projectData;
- }
- synchronized (this) {
- projectData = blazeProjectData;
- return projectData != null ? projectData : loadProject(context, importSettings);
- }
- }
-
- @Override
- @Nullable
- public BlazeProjectData getBlazeProjectData() {
- return blazeProjectData;
- }
-
- @Override
- public BlazeSyncPlugin.ModuleEditor editModules() {
- return ModuleEditorProvider.getInstance().getModuleEditor(
- project,
- BlazeImportSettingsManager.getInstance(project).getImportSettings()
- );
- }
-
- @Nullable
- private synchronized BlazeProjectData loadProject(
- BlazeContext context,
- BlazeImportSettings importSettings) {
- BlazeProjectData blazeProjectData = null;
- try {
- File file = getCacheFile(project, importSettings);
-
- List<ClassLoader> classLoaders = Lists.newArrayList();
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- classLoaders.add(syncPlugin.getClass().getClassLoader());
- }
- classLoaders.add(getClass().getClassLoader());
- classLoaders.add(Thread.currentThread().getContextClassLoader());
-
- blazeProjectData = (BlazeProjectData)SerializationUtil.loadFromDisk(file, classLoaders);
- }
- catch (IOException e) {
- String buildSystemName = importSettings.getBuildSystem().getLowerCaseName();
- context.output(new StatusOutput(String.format("Stale %s project cache, sync will be needed", buildSystemName)));
- LOG.info(e);
- }
-
- this.blazeProjectData = blazeProjectData;
- return blazeProjectData;
- }
-
- public void saveProject(
- final BlazeImportSettings importSettings,
- final BlazeProjectData blazeProjectData) {
- this.blazeProjectData = blazeProjectData;
-
- // Can only run one save operation per project at a time
- synchronized (saveLock) {
- BlazeExecutor.submitTask(project, "Saving sync data...", (ProgressIndicator indicator) -> {
- try {
- File file = getCacheFile(project, importSettings);
- SerializationUtil.saveToDisk(file, blazeProjectData);
- }
- catch (IOException e) {
- LOG.error("Could not save cache data file to disk. Please resync project. Error: " + e.getMessage());
- }
- });
- }
- }
-
- private static File getCacheFile(Project project, BlazeImportSettings importSettings) {
- return new File(BlazeDataStorage.getProjectCacheDir(project, importSettings), BlazeDataStorage.CACHE_FILE_NAME);
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/filediff/FileDiffService.java b/blaze-base/src/com/google/idea/blaze/base/sync/filediff/FileDiffService.java
deleted file mode 100644
index 9cb4854..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/filediff/FileDiffService.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.filediff;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-/**
- * Provides a diffing service for a collection of files.
- */
-public class FileDiffService {
- private static Logger LOG = Logger.getInstance(FileDiffService.class);
-
- public static class State implements Serializable {
- private static final long serialVersionUID = 2L;
- Map<File, FileEntry> fileEntryMap;
- }
-
- static class FileEntry implements Serializable {
- private static final long serialVersionUID = 2L;
-
- public File file;
- public long timestamp;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- FileEntry fileEntry = (FileEntry)o;
- return Objects.equal(timestamp, fileEntry.timestamp) &&
- Objects.equal(file, fileEntry.file);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(file, timestamp);
- }
- }
-
- @Nullable
- public State updateFiles(@Nullable State oldState,
- @NotNull Iterable<File> files,
- @NotNull List<File> updatedFiles,
- @NotNull List<File> removedFiles) {
- Map<File, FileEntry> oldFiles = oldState != null
- ? oldState.fileEntryMap
- : ImmutableMap.of();
-
- List<FileEntry> fileEntryList = null;
- try {
- fileEntryList = updateTimeStamps(files);
- } catch (Exception e) {
- LOG.error(e);
- return null;
- }
-
- // Find changed/new
- for (FileEntry newFile : fileEntryList) {
- FileEntry oldFile = oldFiles.get(newFile.file);
- final boolean isNew = oldFile == null || newFile.timestamp != oldFile.timestamp;
- if (isNew) {
- updatedFiles.add(newFile.file);
- }
- }
-
- // Find removed
- Set<File> newFiles = Sets.newHashSet();
- for (File file : files) {
- newFiles.add(file);
- }
- for (File file : oldFiles.keySet()) {
- if (!newFiles.contains(file)) {
- removedFiles.add(file);
- }
- }
- ImmutableMap.Builder<File, FileEntry> fileMap = ImmutableMap.builder();
- for (FileEntry fileEntry : fileEntryList) {
- fileMap.put(fileEntry.file, fileEntry);
- }
- State newState = new State();
- newState.fileEntryMap = fileMap.build();
- return newState;
- }
-
- private static List<FileEntry> updateTimeStamps(@NotNull Iterable<File> fileList) throws Exception {
- final FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
- List<ListenableFuture<FileEntry>> futures = Lists.newArrayList();
- for (File file : fileList) {
- futures.add(submit(() -> {
- FileEntry fileEntry = new FileEntry();
- fileEntry.file = file;
- fileEntry.timestamp = fileAttributeProvider.getFileModifiedTime(fileEntry.file);
- return fileEntry;
- }
- ));
- }
- return Futures.allAsList(futures).get();
- }
-
- private static <T> ListenableFuture<T> submit(Callable<T> callable) {
- return BlazeExecutor.getInstance().submit(callable);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java
deleted file mode 100644
index 5fe25e7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectstructure;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.projectview.ImportRoots;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.io.FileUtilRt;
-import com.intellij.openapi.vfs.VfsUtilCore;
-import com.intellij.util.io.URLUtil;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-
-public class ContentEntryEditor {
-
- public static void createContentEntries(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- ModifiableRootModel modifiableRootModel) {
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
- .add(projectViewSet)
- .build();
- Collection<WorkspacePath> rootDirectories = importRoots.rootDirectories();
- Collection<WorkspacePath> excludeDirectories = importRoots.excludeDirectories();
- Multimap<WorkspacePath, WorkspacePath> excludesByRootDirectory = sortExcludesByRootDirectory(rootDirectories, excludeDirectories);
-
-
- List<ContentEntry> contentEntries = Lists.newArrayList();
- for (WorkspacePath rootDirectory : rootDirectories) {
- File root = workspaceRoot.fileForPath(rootDirectory);
- ContentEntry contentEntry = modifiableRootModel.addContentEntry(pathToUrl(root.getPath()));
- contentEntries.add(contentEntry);
-
- for (WorkspacePath exclude : excludesByRootDirectory.get(rootDirectory)) {
- File excludeFolder = workspaceRoot.fileForPath(exclude);
- contentEntry.addExcludeFolder(pathToIdeaUrl(excludeFolder));
- }
- }
-
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- syncPlugin.updateContentEntries(
- project,
- context,
- workspaceRoot,
- projectViewSet,
- blazeProjectData,
- contentEntries
- );
- }
- }
-
- private static Multimap<WorkspacePath, WorkspacePath> sortExcludesByRootDirectory(
- Collection<WorkspacePath> rootDirectories,
- Collection<WorkspacePath> excludedDirectories) {
-
- Multimap<WorkspacePath, WorkspacePath> result = ArrayListMultimap.create();
- for (WorkspacePath exclude : excludedDirectories) {
- WorkspacePath foundWorkspacePath = rootDirectories
- .stream()
- .filter(rootDirectory -> isUnderRootDirectory(rootDirectory, exclude.relativePath()))
- .findFirst()
- .orElse(null);
- if (foundWorkspacePath != null) {
- result.put(foundWorkspacePath, exclude);
- }
- }
- return result;
- }
-
- private static boolean isUnderRootDirectory(WorkspacePath rootDirectory, String relativePath) {
- if (rootDirectory.isWorkspaceRoot()) {
- return true;
- }
- String rootDirectoryString = rootDirectory.toString();
- return relativePath.startsWith(rootDirectoryString)
- && (relativePath.length() == rootDirectoryString.length()
- || (relativePath.charAt(rootDirectoryString.length()) == '/'));
- }
-
- @NotNull
- private static String pathToUrl(@NotNull String filePath) {
- filePath = FileUtil.toSystemIndependentName(filePath);
- if (filePath.endsWith(".srcjar") || filePath.endsWith(".jar")) {
- return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR +
- filePath + URLUtil.JAR_SEPARATOR;
- }
- else if (filePath.contains("src.jar!")) {
- return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR +
- filePath;
- }
- else {
- return VfsUtilCore.pathToUrl(filePath);
- }
- }
-
- @NotNull
- private static String pathToIdeaUrl(@NotNull File path) {
- return pathToUrl(toSystemIndependentName(path.getPath()));
- }
- @NotNull
- private static String toSystemIndependentName(@NonNls @NotNull String aFileName) {
- return FileUtilRt.toSystemIndependentName(aFileName);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleDataStorage.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleDataStorage.java
deleted file mode 100644
index 9371728..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleDataStorage.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectstructure;
-
-/**
- * Constants about where we store module data.
- */
-public class ModuleDataStorage {
- public static final String MODULE_DATA_SUBDIRECTORY = "modules";
- public static final String DATA_SUBDIRECTORY = ".blaze";
- public static final String WORKSPACE_MODULE_NAME = ".workspace";
- public static final String PROJECT_DATA_DIR_MODULE_NAME = ".project-data-dir";
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorImpl.java
deleted file mode 100644
index 2ae1167..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorImpl.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectstructure;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.intellij.ide.highlighter.ModuleFileType;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.ModifiableModuleModel;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
-import com.intellij.openapi.module.ModuleType;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.CompilerModuleExtension;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Module editor implementation.
- */
-public class ModuleEditorImpl implements BlazeSyncPlugin.ModuleEditor {
- private static final Logger LOG = Logger.getInstance(ModuleEditorImpl.class.getName());
- private static final String EXTERNAL_SYSTEM_ID_KEY = "external.system.id";
- private static final String EXTERNAL_SYSTEM_ID_VALUE = "Blaze";
-
- private final Project project;
- private final ModifiableModuleModel moduleModel;
- private final File imlDirectory;
- private final Set<String> moduleNames = Sets.newHashSet();
- @VisibleForTesting
- public Collection<ModifiableRootModel> modifiableModels = Lists.newArrayList();
-
- public ModuleEditorImpl(Project project, BlazeImportSettings importSettings) {
- this.project = project;
- this.moduleModel = ModuleManager.getInstance(project).getModifiableModel();
-
- this.imlDirectory = getImlDirectory(importSettings);
- if (!FileAttributeProvider.getInstance().exists(imlDirectory)) {
- if (!imlDirectory.mkdirs()) {
- LOG.error("Could not make directory: " + imlDirectory.getPath());
- }
- }
- }
-
- @Override
- public boolean registerModule(String moduleName) {
- boolean hasModule = moduleModel.findModuleByName(moduleName) != null;
- if (hasModule) {
- moduleNames.add(moduleName);
- }
- return hasModule;
- }
-
- @Override
- public Module createModule(String moduleName, ModuleType moduleType) {
- Module module = moduleModel.findModuleByName(moduleName);
- if (module == null) {
- File imlFile = new File(imlDirectory, moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION);
- removeImlFile(imlFile);
- module = moduleModel.newModule(imlFile.getPath(), moduleType.getId());
- module.setOption(EXTERNAL_SYSTEM_ID_KEY, EXTERNAL_SYSTEM_ID_VALUE);
- }
- module.setOption(Module.ELEMENT_TYPE, moduleType.getId());
- moduleNames.add(moduleName);
- return module;
- }
-
- @Override
- public ModifiableRootModel editModule(Module module) {
- ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel();
- modifiableModels.add(modifiableModel);
-
- modifiableModel.clear();
- modifiableModel.inheritSdk();
- CompilerModuleExtension compilerSettings = modifiableModel.getModuleExtension(CompilerModuleExtension.class);
- if (compilerSettings != null) {
- compilerSettings.inheritCompilerOutputPath(false);
- }
-
- return modifiableModel;
- }
-
- @Override
- @Nullable
- public Module findModule(String moduleName) {
- return moduleModel.findModuleByName(moduleName);
- }
-
- public void commitWithGc(BlazeContext context) {
- List<Module> orphanModules = Lists.newArrayList();
- for (Module module : ModuleManager.getInstance(project).getModules()) {
- if (!moduleNames.contains(module.getName())) {
- orphanModules.add(module);
- }
- }
- if (orphanModules.size() > 0) {
- context.output(new PrintOutput(
- String.format("Removing %d dead modules", orphanModules.size()))
- );
- for (Module module : orphanModules) {
- if (module.isDisposed()) {
- continue;
- }
- moduleModel.disposeModule(module);
- File imlFile = new File(module.getModuleFilePath());
- removeImlFile(imlFile);
- }
- }
-
- context.output(new PrintOutput(
- String.format("Workspace has %s modules", modifiableModels.size())
- ));
-
- commit();
- }
-
- @Override
- public void commit() {
- ModifiableModelCommitter.multiCommit(modifiableModels, moduleModel);
- }
-
- private File getImlDirectory(BlazeImportSettings importSettings) {
- return new File(
- new File(importSettings.getProjectDataDirectory(), ModuleDataStorage.DATA_SUBDIRECTORY),
- ModuleDataStorage.MODULE_DATA_SUBDIRECTORY
- );
- }
-
- // Delete using the virtual file to ensure that IntelliJ properly updates its index. Otherwise, it is possible for IntelliJ to read the
- // old IML file from its index and behave unpredictably (like failing to save the new IML files to disk).
- private static void removeImlFile(final File imlFile) {
- final VirtualFile imlVirtualFile = VfsUtil.findFileByIoFile(imlFile, true);
- if (imlVirtualFile != null && imlVirtualFile.exists()) {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- try {
- imlVirtualFile.delete(this);
- }
- catch (IOException e) {
- LOG.warn(String.format("Could not delete file: %s, will try to continue anyway.", imlVirtualFile.getPath()), e);
- }
- }
- });
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProvider.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProvider.java
deleted file mode 100644
index 3c00fe4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProvider.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectstructure;
-
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-/**
- * Provides a ModuleEditor. This indirection is required to avoid committing modules
- * during integration tests of the sync process, as this is not allowed by LightPlatformTestCase.
- */
-public interface ModuleEditorProvider {
-
- static ModuleEditorProvider getInstance() {
- return ServiceManager.getService(ModuleEditorProvider.class);
- }
-
- ModuleEditorImpl getModuleEditor(Project project, BlazeImportSettings importSettings);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProviderImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProviderImpl.java
deleted file mode 100644
index dfc5fe7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleEditorProviderImpl.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectstructure;
-
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.intellij.openapi.project.Project;
-
-/**
- * Provides a ModuleEditor. This indirection is required to avoid committing modules
- * during integration tests of the sync process, as this is not allowed by LightPlatformTestCase.
- */
-public class ModuleEditorProviderImpl implements ModuleEditorProvider {
-
- @Override
- public ModuleEditorImpl getModuleEditor(Project project, BlazeImportSettings importSettings) {
- return new ModuleEditorImpl(project, importSettings);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java
deleted file mode 100644
index 4e7ef66..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectview;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * The roots to import. Derived from project view.
- */
-public final class ImportRoots {
- public static class Builder {
- private final ImmutableCollection.Builder<WorkspacePath> rootDirectoriesBuilder = ImmutableList.builder();
- private final ImmutableSet.Builder<WorkspacePath> excludeDirectoriesBuilder = ImmutableSet.builder();
-
- private final WorkspaceRoot workspaceRoot;
- private final BuildSystem buildSystem;
-
- private Builder(WorkspaceRoot workspaceRoot, BuildSystem buildSystem) {
- this.workspaceRoot = workspaceRoot;
- this.buildSystem = buildSystem;
- }
-
- public Builder add(ProjectViewSet projectViewSet) {
- for (DirectoryEntry entry : projectViewSet.listItems(DirectorySection.KEY)) {
- add(entry);
- }
- return this;
- }
-
- @VisibleForTesting
- public Builder add(DirectoryEntry entry) {
- if (entry.included) {
- rootDirectoriesBuilder.add(entry.directory);
- } else {
- excludeDirectoriesBuilder.add(entry.directory);
- }
- return this;
- }
-
- public ImportRoots build() {
- ImmutableCollection<WorkspacePath> rootDirectories = rootDirectoriesBuilder.build();
- // for bazel projects, if we're including the workspace root, we force-exclude the bazel artifact directories
- // (e.g. bazel-bin, bazel-genfiles).
- if (buildSystem == BuildSystem.Bazel && hasWorkspaceRoot(rootDirectories)) {
- excludeBuildSystemArtifacts();
- }
- return new ImportRoots(rootDirectories, excludeDirectoriesBuilder.build());
- }
-
- private void excludeBuildSystemArtifacts() {
- for (String dir : BuildSystemProvider.getBuildSystemProvider(buildSystem).buildArtifactDirectories(workspaceRoot)) {
- excludeDirectoriesBuilder.add(new WorkspacePath(dir));
- }
- }
-
- private static boolean hasWorkspaceRoot(ImmutableCollection<WorkspacePath> rootDirectories) {
- return rootDirectories.stream().anyMatch(WorkspacePath::isWorkspaceRoot);
- }
-
- }
-
- private final ImmutableCollection<WorkspacePath> rootDirectories;
- private final ImmutableSet<WorkspacePath> excludeDirectories;
-
- public static Builder builder(WorkspaceRoot workspaceRoot, BuildSystem buildSystem) {
- return new Builder(workspaceRoot, buildSystem);
- }
-
- private ImportRoots(
- ImmutableCollection<WorkspacePath> rootDirectories,
- ImmutableSet<WorkspacePath> excludeDirectories) {
- this.rootDirectories = rootDirectories;
- this.excludeDirectories = excludeDirectories;
- }
-
- public Collection<WorkspacePath> rootDirectories() {
- return rootDirectories;
- }
-
- public Set<WorkspacePath> excludeDirectories() {
- return excludeDirectories;
- }
-
- /**
- * Returns true if this rule should be imported as source.
- */
- public boolean importAsSource(Label label) {
- return containsLabel(label);
- }
-
- private boolean containsLabel(Label label) {
- boolean included = false;
- boolean excluded = false;
- for (WorkspacePath workspacePath : rootDirectories()) {
- included = included || matchesLabel(workspacePath, label);
- }
- for (WorkspacePath workspacePath : excludeDirectories()) {
- excluded = excluded || matchesLabel(workspacePath, label);
- }
- return included && !excluded;
- }
-
- private static boolean matchesLabel(WorkspacePath workspacePath, Label label) {
- if (workspacePath.isWorkspaceRoot()) {
- return true;
- }
- String moduleLabelStr = label.toString();
- int packagePrefixLength = "//".length();
- int nextCharIndex = workspacePath.relativePath().length() + packagePrefixLength;
- if (moduleLabelStr.startsWith(workspacePath.relativePath(), packagePrefixLength)
- && moduleLabelStr.length() >= nextCharIndex) {
- char c = moduleLabelStr.charAt(nextCharIndex);
- return c == '/' || c == ':';
- }
- return false;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java
deleted file mode 100644
index e3a8d97..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectview;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection;
-import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.intellij.openapi.diagnostic.Logger;
-
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * Reads the user's language preferences from the project view.
- */
-public class LanguageSupport {
-
- private static final Logger LOG = Logger.getInstance(LanguageSupport.class);
-
- public static WorkspaceLanguageSettings createWorkspaceLanguageSettings(BlazeContext context, ProjectViewSet projectViewSet) {
- WorkspaceType workspaceType = projectViewSet.getSectionValue(WorkspaceTypeSection.KEY);
- if (workspaceType == null) {
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- WorkspaceType pluginWorkspaceType = syncPlugin.getDefaultWorkspaceType();
- if (pluginWorkspaceType != null) {
- if (workspaceType == null || workspaceType.ordinal() < pluginWorkspaceType.ordinal()) {
- workspaceType = pluginWorkspaceType;
- }
- }
- }
- }
-
- if (workspaceType == null) {
- LOG.error("Could not find workspace type."); // Should never happen
- return null;
- }
-
- Set<LanguageClass> activeLanguages = Sets.newHashSet();
- for (LanguageClass languageClass : workspaceType.getLanguages()) {
- activeLanguages.add(languageClass);
- }
- activeLanguages.addAll(projectViewSet.listItems(AdditionalLanguagesSection.KEY));
-
- Set<LanguageClass> supportedLanguages = Sets.newHashSet();
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- supportedLanguages.addAll(syncPlugin.getSupportedLanguagesInWorkspace(workspaceType));
- }
-
- for (LanguageClass languageClass : activeLanguages) {
- if (!supportedLanguages.contains(languageClass)) {
- IssueOutput
- .error(String.format(
- "Language '%s' is not supported for this plugin with workspace type: '%s'",
- languageClass.getName(), workspaceType.getName()))
- .submit(context);
- return null;
- }
- }
-
- return new WorkspaceLanguageSettings(workspaceType, activeLanguages);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/ProjectViewRuleImportFilter.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectview/ProjectViewRuleImportFilter.java
deleted file mode 100644
index 1585de9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/ProjectViewRuleImportFilter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectview;
-
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.Tags;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.sections.ExcludeTargetSection;
-import com.google.idea.blaze.base.projectview.section.sections.ImportTargetOutputSection;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.project.Project;
-
-import java.util.Set;
-
-/**
- * Filters rules into source/library depending on the project view.
- */
-public class ProjectViewRuleImportFilter {
- private final ImportRoots importRoots;
- private final Set<Label> importTargetOutputs;
- private final Set<Label> excludedTargets;
-
- public ProjectViewRuleImportFilter(Project project, WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
- this.importRoots = ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project)).add(projectViewSet).build();
- this.importTargetOutputs = Sets.newHashSet(projectViewSet.listItems(ImportTargetOutputSection.KEY));
- this.excludedTargets = Sets.newHashSet(projectViewSet.listItems(ExcludeTargetSection.KEY));
- }
-
- public boolean isSourceRule(RuleIdeInfo rule) {
- return importRoots.importAsSource(rule.label) && !importTargetOutput(rule);
- }
-
- private boolean importTargetOutput(RuleIdeInfo rule) {
- return rule.tags.contains(Tags.RULE_TAG_IMPORT_TARGET_OUTPUT)
- || rule.tags.contains(Tags.RULE_TAG_IMPORT_AS_LIBRARY_LEGACY)
- || importTargetOutputs.contains(rule.label);
- }
-
- public boolean excludeTarget(RuleIdeInfo rule) {
- return excludedTargets.contains(rule.label) || rule.tags.contains(Tags.RULE_TAG_PROVIDED_BY_SDK);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/SourceTestConfig.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectview/SourceTestConfig.java
deleted file mode 100644
index 04ab82c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/SourceTestConfig.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectview;
-
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.Glob;
-import com.google.idea.blaze.base.projectview.section.sections.TestSourceSection;
-
-/**
- * Affects the way sources are imported.
- */
-public class SourceTestConfig {
- private final Glob.GlobSet testSources;
-
- public SourceTestConfig(ProjectViewSet projectViewSet) {
- this.testSources = new Glob.GlobSet(projectViewSet.listItems(TestSourceSection.KEY));
- }
-
- /**
- * Returns true if this artifact is a test artifact.
- */
- public boolean isTestSource(String relativePath) {
- return testSources.matches(relativePath);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java b/blaze-base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java
deleted file mode 100644
index 3c9e5f2..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.projectview;
-
-import com.google.common.base.Objects;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.Serializable;
-import java.util.Set;
-
-/**
- * Contains the user's language preferences from the project view.
- */
-@Immutable
-public class WorkspaceLanguageSettings implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private final WorkspaceType workspaceType;
- private final Set<LanguageClass> activeLanguages;
-
- public WorkspaceLanguageSettings(WorkspaceType workspaceType,
- Set<LanguageClass> activeLanguages) {
- this.workspaceType = workspaceType;
- this.activeLanguages = activeLanguages;
- }
-
- public WorkspaceType getWorkspaceType() {
- return workspaceType;
- }
-
- public boolean isWorkspaceType(WorkspaceType workspaceType) {
- return this.workspaceType == workspaceType;
- }
-
- public boolean isWorkspaceType(WorkspaceType... workspaceTypes) {
- for (WorkspaceType workspaceType : workspaceTypes) {
- if (this.workspaceType == workspaceType) {
- return true;
- }
- }
- return false;
- }
-
- public boolean isLanguageActive(LanguageClass languageClass) {
- return activeLanguages.contains(languageClass);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- WorkspaceLanguageSettings that = (WorkspaceLanguageSettings)o;
- return workspaceType == that.workspaceType
- && Objects.equal(activeLanguages, that.activeLanguages);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(workspaceType, activeLanguages);
- }
-
- @Override
- public String toString() {
- return "WorkspaceLanguageSettings {" + "\n"
- + " workspaceType: " + workspaceType + "\n"
- + " activeLanguages: " + activeLanguages + "\n"
- + '}';
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/sdk/DefaultSdkProvider.java b/blaze-base/src/com/google/idea/blaze/base/sync/sdk/DefaultSdkProvider.java
deleted file mode 100644
index e444984..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/sdk/DefaultSdkProvider.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.sdk;
-
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * May download or otherwise provide default sdk locations for languages.
- */
-public interface DefaultSdkProvider {
- ExtensionPointName<DefaultSdkProvider> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.DefaultSdkProvider");
-
- @Nullable
- File provideSdkForLanguage(LanguageClass language);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatus.java b/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatus.java
deleted file mode 100644
index 1bc7381..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatus.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.status;
-
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-/**
- * Interface to tell blaze it might need to resync.
- */
-public interface BlazeSyncStatus {
-
- enum SyncStatus {
- FAILED,
- DIRTY,
- CLEAN,
- }
-
- SyncStatus getStatus();
-
- static BlazeSyncStatus getInstance(Project project) {
- return ServiceManager.getService(project, BlazeSyncStatus.class);
- }
-
- void setDirty();
-
- void queueAutomaticSyncIfDirty();
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java
deleted file mode 100644
index dba518e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.status;
-
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.BlazeSyncManager;
-import com.google.idea.blaze.base.sync.actions.IncrementalSyncProjectAction;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.fileEditor.*;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.*;
-import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Per-project listener for changes to BUILD files, and other changes requiring an incremental sync.
- */
-public class BlazeSyncStatusImpl implements BlazeSyncStatus {
-
- public static final BoolExperiment AUTOMATIC_INCREMENTAL_SYNC =
- new BoolExperiment("automatic.incremental.sync", true);
-
- public static BlazeSyncStatusImpl getImpl(@NotNull Project project) {
- return (BlazeSyncStatusImpl) BlazeSyncStatus.getInstance(project);
- }
-
- private static Logger log = Logger.getInstance(BlazeSyncStatusImpl.class);
-
- private final Project project;
-
- public final AtomicBoolean syncInProgress = new AtomicBoolean(false);
- private final AtomicBoolean syncPending = new AtomicBoolean(false);
-
- /**
- * has a BUILD file changed since the last sync started
- */
- private volatile boolean dirty = false;
-
- private volatile boolean failedSync = false;
-
- public BlazeSyncStatusImpl(Project project) {
- this.project = project;
- // listen for changes to the VFS
- VirtualFileManager.getInstance().addVirtualFileListener(new FileListener(), project);
-
- // trigger VFS updates whenever navigating away from an unsaved BUILD file
- project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER,
- new FileFocusListener());
- }
-
- private static boolean automaticSyncEnabled() {
- return AUTOMATIC_INCREMENTAL_SYNC.getValue()
- && BlazeUserSettings.getInstance().getResyncAutomatically();
- }
-
- @Override
- public SyncStatus getStatus() {
- if (failedSync) {
- return SyncStatus.FAILED;
- }
- return dirty ? SyncStatus.DIRTY : SyncStatus.CLEAN;
- }
-
- public void syncStarted() {
- syncPending.set(false);
- syncInProgress.set(true);
- }
-
- public void syncEnded(boolean successful) {
- syncInProgress.set(false);
- failedSync = !successful;
- if (successful && !syncPending.get()) {
- dirty = false;
- }
- }
-
- @Override
- public void setDirty() {
- dirty = true;
- queueIncrementalSync();
- }
-
- @Override
- public void queueAutomaticSyncIfDirty() {
- if (dirty) {
- queueIncrementalSync();
- }
- }
-
- private void queueIncrementalSync() {
- if (automaticSyncEnabled() && syncPending.compareAndSet(false, true)) {
- log.info("Automatic sync started");
- BlazeSyncManager.getInstance(project).requestProjectSync(IncrementalSyncProjectAction.autoSyncParams);
- }
- }
-
- /**
- * Listens for changes to files which impact the sync process
- * (BUILD files and project view files)
- */
- private class FileListener extends VirtualFileAdapter {
- @Override
- public void fileCreated(@NotNull VirtualFileEvent event) {
- processEvent(event);
- }
-
- @Override
- public void fileDeleted(@NotNull VirtualFileEvent event){
- processEvent(event);
- // we (sometimes) only get one event when a directory is deleted, so check the children too.
- checkChildren(event.getFile());
- }
-
- @Override
- public void fileMoved(@NotNull VirtualFileMoveEvent event){
- processEvent(event);
- }
-
- @Override
- public void contentsChanged(@NotNull VirtualFileEvent event){
- processEvent(event);
- }
-
- private void processEvent(@NotNull VirtualFileEvent event) {
- if (isSyncSensitiveFile(event.getFile())) {
- setDirty();
- }
- }
-
- private void checkChildren(VirtualFile file) {
- if (!(file instanceof NewVirtualFile)) {
- return;
- }
- Collection<VirtualFile> children = ((NewVirtualFile) file).getCachedChildren();
- for (VirtualFile child : children) {
- if (isSyncSensitiveFile(child)) {
- setDirty();
- return;
- }
- }
- }
- }
-
- /**
- * Listens for changes to files which impact the sync process
- * (BUILD files and project view files)
- */
- private static class FileFocusListener extends FileEditorManagerAdapter {
- @Override
- public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- processEvent(file);
- }
-
- @Override
- public void selectionChanged(@NotNull FileEditorManagerEvent event) {
- processEvent(event.getOldFile());
- }
-
- private void processEvent(@Nullable VirtualFile file) {
- if (isSyncSensitiveFile(file)) {
- FileDocumentManager manager = FileDocumentManager.getInstance();
- Document doc = manager.getCachedDocument(file);
- if (doc != null) {
- manager.saveDocument(doc);
- }
- }
- }
- }
-
- private static boolean isSyncSensitiveFile(@Nullable VirtualFile file) {
- return file != null && (isBuildFile(file) || ProjectViewStorageManager.isProjectViewFile(file.getPath()));
- }
-
-
- private static boolean isBuildFile(VirtualFile file) {
- return file.getName().equals("BUILD");
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusListener.java b/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusListener.java
deleted file mode 100644
index 382e022..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusListener.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.status;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.SyncListener;
-import com.intellij.openapi.project.Project;
-
-/**
- * Application-wide listener for blaze syncs. Notifies per-project status listener when
- * they start and finish.
- */
-public class BlazeSyncStatusListener implements SyncListener {
-
- @Override
- public void onSyncStart(Project project) {
- BlazeSyncStatusImpl.getImpl(project).syncStarted();
- }
-
- @Override
- public void afterSync(Project project,
- boolean successful) {
- BlazeSyncStatusImpl.getImpl(project).syncEnded(successful);
- }
-
- @Override
- public void onSyncComplete(
- Project project,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoder.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoder.java
deleted file mode 100644
index 19223da..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoder.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Decodes android_studio_ide_info.proto ArtifactLocation file paths
- */
-public class ArtifactLocationDecoder {
-
- private final BlazeRoots blazeRoots;
- private final WorkspacePathResolver pathResolver;
-
- public ArtifactLocationDecoder(BlazeRoots blazeRoots, WorkspacePathResolver pathResolver) {
- this.blazeRoots = blazeRoots;
- this.pathResolver = pathResolver;
- }
-
- /**
- * Decodes the ArtifactLocation proto, locates the absolute artifact file path.
- * Returns null if the file can't be found (presumably because it was removed
- * since the blaze build)
- */
- @Nullable
- public ArtifactLocation decode(AndroidStudioIdeInfo.ArtifactLocation loc) {
- return decode(loc.getRootPath(),
- loc.getRootExecutionPathFragment(),
- loc.getRelativePath(),
- loc.getIsSource());
- }
-
- /**
- * Decodes the ArtifactLocation proto, locates the absolute artifact file path.
- * Returns null if the file can't be found (presumably because it was removed
- * since the blaze build)
- */
- @Nullable
- public ArtifactLocation decode(PackageManifestOuterClass.ArtifactLocation loc) {
- return decode(loc.getRootPath(),
- loc.getRootExecutionPathFragment(),
- loc.getRelativePath(),
- loc.getIsSource());
- }
-
- @Nullable
- private ArtifactLocation decode(
- String rootPath,
- String rootExecutionPathFragment,
- String relativePath,
- boolean isSource) {
- File root;
- if (isSource) {
- root = pathResolver.findPackageRoot(relativePath);
- } else {
- if (rootExecutionPathFragment.isEmpty()) {
- // old format -- derive execution path fragment from the root path.
- // it's a backwards way of doing it -- but we want to test the new code,
- // and this will soon be removed
- rootExecutionPathFragment = deriveRootExecutionPathFragmentFromRoot(rootPath);
- }
- root = new File(blazeRoots.executionRoot, rootExecutionPathFragment);
- }
- if (root == null) {
- return null;
- }
- return ArtifactLocation.builder()
- .setRootPath(root.toString())
- .setRootExecutionPathFragment(rootExecutionPathFragment)
- .setRelativePath(relativePath)
- .setIsSource(isSource)
- .build();
- }
-
- @Deprecated
- private String deriveRootExecutionPathFragmentFromRoot(String rootPath) {
- String execRoot = blazeRoots.executionRoot.toString();
- if (rootPath.startsWith(execRoot)) {
- return rootPath.substring(execRoot.length());
- }
- return "";
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java
deleted file mode 100644
index 65b6145..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.command.info.BlazeInfo;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.List;
-
-/**
- * The data output by BlazeInfo.
- */
-public class BlazeRoots implements Serializable {
- public static final long serialVersionUID = 3L;
- private static final Logger LOG = Logger.getInstance(BlazeRoots.class);
-
- public static ListenableFuture<BlazeRoots> compute(Project project, WorkspaceRoot workspaceRoot, BlazeContext context) {
- BuildSystem buildSystem = Blaze.getBuildSystem(project);
- ListenableFuture<ImmutableMap<String, String>> blazeInfoDataFuture =
- BlazeInfo.getInstance().runBlazeInfo(context, buildSystem, workspaceRoot, ImmutableList.of());
- return Futures.transform(
- blazeInfoDataFuture,
- new Function<ImmutableMap<String, String>, BlazeRoots>() {
- @Nullable
- @Override
- public BlazeRoots apply(@Nullable ImmutableMap<String, String> blazeInfoData) {
- // This method is supposed to throw if the input is null but the input is not allowed to be null.
- if (blazeInfoData == null) {
- throw new NullPointerException("blazeInfoData is not allowed to be null");
- }
- return build(
- workspaceRoot,
- getOrThrow(buildSystem, blazeInfoData, BlazeInfo.EXECUTION_ROOT_KEY),
- getOrThrow(buildSystem, blazeInfoData, BlazeInfo.PACKAGE_PATH_KEY),
- getOrThrow(buildSystem, blazeInfoData, BlazeInfo.blazeBinKey(buildSystem)),
- getOrThrow(buildSystem, blazeInfoData, BlazeInfo.blazeGenfilesKey(buildSystem))
- );
- }
- }
- );
- }
-
- private static String getOrThrow(BuildSystem buildSystem, ImmutableMap<String, String> map, String key) {
- String value = map.get(key);
- if (value == null) {
- throw new RuntimeException(String.format("Could not locate %s in %s info", key, buildSystem.getLowerCaseName()));
- }
- return value;
- }
-
- private static BlazeRoots build(
- WorkspaceRoot workspaceRoot,
- String execRootString,
- String packagePathString,
- String blazeBinRoot,
- String blazeGenfilesRoot
- ) {
- List<File> packagePaths = parsePackagePaths(workspaceRoot.toString(), packagePathString.trim());
- File executionRoot = new File(execRootString.trim());
- ExecutionRootPath blazeBinExecutionRootPath = ExecutionRootPath.createAncestorRelativePath(
- executionRoot,
- new File(blazeBinRoot)
- );
- ExecutionRootPath blazeGenfilesExecutionRootPath = ExecutionRootPath.createAncestorRelativePath(
- executionRoot,
- new File(blazeGenfilesRoot)
- );
- LOG.assertTrue(blazeBinExecutionRootPath != null);
- LOG.assertTrue(blazeGenfilesExecutionRootPath != null);
- return new BlazeRoots(executionRoot, packagePaths, blazeBinExecutionRootPath, blazeGenfilesExecutionRootPath);
- }
-
- private static List<File> parsePackagePaths(String workspaceRoot,
- String packagePathString) {
- String[] paths = packagePathString.split(":");
- List<File> packagePaths = Lists.newArrayListWithCapacity(paths.length);
- FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
- for (String path : paths) {
- File packagePath = new File(path.replace("%workspace%", workspaceRoot));
- if (fileAttributeProvider.exists(packagePath)) {
- packagePaths.add(packagePath);
- }
- }
- return packagePaths;
- }
-
- public final File executionRoot;
- public final List<File> packagePaths;
- public final ExecutionRootPath blazeBinExecutionRootPath;
- public final ExecutionRootPath blazeGenfilesExecutionRootPath;
-
- @VisibleForTesting
- public BlazeRoots(
- File executionRoot,
- List<File> packagePaths,
- ExecutionRootPath blazeBinExecutionRootPath,
- ExecutionRootPath blazeGenfilesExecutionRootPath
- ) {
- this.executionRoot = executionRoot;
- this.packagePaths = packagePaths;
- this.blazeBinExecutionRootPath = blazeBinExecutionRootPath;
- this.blazeGenfilesExecutionRootPath = blazeGenfilesExecutionRootPath;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkingSet.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkingSet.java
deleted file mode 100644
index 39b5373..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkingSet.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-
-import java.io.Serializable;
-
-/**
- * Computes the working set of files of directories from source control.
- */
-public class WorkingSet implements Serializable {
- private static final long serialVersionUID = 2L;
-
- public final ImmutableList<WorkspacePath> addedFiles;
- public final ImmutableList<WorkspacePath> modifiedFiles;
- public final ImmutableList<WorkspacePath> deletedFiles;
-
- public WorkingSet(ImmutableList<WorkspacePath> addedFiles,
- ImmutableList<WorkspacePath> modifiedFiles,
- ImmutableList<WorkspacePath> deletedFiles) {
- this.addedFiles = addedFiles;
- this.modifiedFiles = modifiedFiles;
- this.deletedFiles = deletedFiles;
- }
-
- public boolean isEmpty() {
- return addedFiles.isEmpty() && modifiedFiles.isEmpty() && deletedFiles.isEmpty();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java
deleted file mode 100644
index acc5ea1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.Serializable;
-
-/**
- * Uses workspace root, blaze roots and git5 tracked directory information to
- * convert workspace-relative paths to absolute files with a minimum of file system calls (typically none).
- */
-public interface WorkspacePathResolver extends Serializable {
- /**
- * Resolves a workspace path to an absolute file.
- */
- @Nullable
- default File resolveToFile(WorkspacePath workspacepath) {
- return resolveToFile(workspacepath.relativePath());
- }
-
- /**
- * Resolves a workspace relative path to an absolute file.
- */
- @Nullable
- default File resolveToFile(String workspaceRelativePath) {
- File packageRoot = findPackageRoot(workspaceRelativePath);
- return packageRoot != null ? new File(packageRoot, workspaceRelativePath) : null;
- }
-
- /**
- * This method should be used for directories. In the case that the directory is tracked, it returns the directory under the workspace
- * root. If the directory is partially tracked (a sub directory is tracked), then the directory in the workspace and the directory under
- * READONLY are returned in that order in a list. If the directory is untracked, the path is examined to see if this method should return
- * a file under the execution root or a file under READONLY.
- */
- ImmutableList<File> resolveToIncludeDirectories(ExecutionRootPath executionRootPath);
-
- /**
- * Finds the package root directory that a workspace relative path is in.
- */
- @Nullable
- File findPackageRoot(String relativePath);
-
- WorkspaceRoot getWorkspaceRoot();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java
deleted file mode 100644
index 119b3aa..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-
-/**
- * Uses the package path locations to resolve a workspace path.
- */
-public class WorkspacePathResolverImpl implements WorkspacePathResolver {
- private static final long serialVersionUID = 2L;
-
- private final WorkspaceRoot workspaceRoot;
- private final List<File> packagePaths;
-
- public WorkspacePathResolverImpl(WorkspaceRoot workspaceRoot, BlazeRoots blazeRoots) {
- this(workspaceRoot, blazeRoots.packagePaths);
- }
-
- public WorkspacePathResolverImpl(WorkspaceRoot workspaceRoot) {
- this(workspaceRoot, ImmutableList.of(workspaceRoot.directory()));
- }
-
- public WorkspacePathResolverImpl(WorkspaceRoot workspaceRoot, List<File> packagePaths) {
- this.workspaceRoot = workspaceRoot;
- this.packagePaths = packagePaths;
- }
-
- @Override
- public ImmutableList<File> resolveToIncludeDirectories(ExecutionRootPath executionRootPath) {
- File trackedLocation = executionRootPath.getFileRootedAt(workspaceRoot.directory());
- return ImmutableList.of(trackedLocation);
- }
-
- @Override
- @Nullable
- public File findPackageRoot(String relativePath) {
- if (packagePaths.size() == 1) {
- return packagePaths.get(0);
- }
- // fall back to manually checking each one
- FileAttributeProvider existenceChecker = FileAttributeProvider.getInstance();
- for (File pkg : packagePaths) {
- if (existenceChecker.exists(new File(pkg, relativePath))) {
- return pkg;
- }
- }
- return null;
- }
-
- @Override
- public WorkspaceRoot getWorkspaceRoot() {
- return workspaceRoot;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProvider.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProvider.java
deleted file mode 100644
index 1d9d08f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides a WorkspacePathResolver.
- */
-public interface WorkspacePathResolverProvider {
-
- static WorkspacePathResolverProvider getInstance(Project project) {
- return ServiceManager.getService(project, WorkspacePathResolverProvider.class);
- }
-
- /**
- * Returns a WorkspacePathResolver for this project, or null if it's not a blaze/bazel project.
- */
- @Nullable
- WorkspacePathResolver getPathResolver();
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProviderImpl.java b/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProviderImpl.java
deleted file mode 100644
index 6563ed8..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverProviderImpl.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides a WorkspacePathResolver.
- */
-public class WorkspacePathResolverProviderImpl implements WorkspacePathResolverProvider {
-
- private final Project project;
-
- public WorkspacePathResolverProviderImpl(Project project) {
- this.project = project;
- }
-
- @Nullable
- @Override
- public WorkspacePathResolver getPathResolver() {
- BlazeProjectData projectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- return projectData != null ? projectData.workspacePathResolver : null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/trace/Trace.java b/blaze-base/src/com/google/idea/blaze/base/trace/Trace.java
deleted file mode 100644
index 07e4b0b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trace/Trace.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trace;
-
-import com.google.idea.blaze.base.trickle.*;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Helper methods for tracing.
- */
-public class Trace {
- public static <R> Function0<R> trace(@NotNull BlazeContext context, @NotNull String name, @NotNull Function0<R> func) {
- return () -> {
- try (TraceContext traceContext = new TraceContext(context, name)) {
- return func.run();
- }
- };
- }
-
- public static <A, R> Function1<A, R> trace(@NotNull BlazeContext context, @NotNull String name, @NotNull Function1<A, R> func) {
- return (a) -> {
- try (TraceContext traceContext = new TraceContext(context, name)) {
- return func.run(a);
- }
- };
- }
-
- public static <A, B, R> Function2<A, B, R> trace(@NotNull BlazeContext context, @NotNull String name, @NotNull Function2<A, B, R> func) {
- return (a, b) -> {
- try (TraceContext traceContext = new TraceContext(context, name)) {
- return func.run(a, b);
- }
- };
- }
-
- public static <A, B, C, R> Function3<A, B, C, R> trace(@NotNull BlazeContext context, @NotNull String name, @NotNull Function3<A, B, C, R> func) {
- return (a, b, c) -> {
- try (TraceContext traceContext = new TraceContext(context, name)) {
- return func.run(a, b, c);
- }
- };
- }
-
- public static <A, B, C, D, R> Function4<A, B, C, D, R> trace(@NotNull BlazeContext context, @NotNull String name, @NotNull Function4<A, B, C, D, R> func) {
- return (a, b, c, d) -> {
- try (TraceContext traceContext = new TraceContext(context, name)) {
- return func.run(a, b, c, d);
- }
- };
- }
-
- public static <A, B, C, D, E, R> Function5<A, B, C, D, E, R> trace(@NotNull BlazeContext context, @NotNull String name, @NotNull Function5<A, B, C, D, E, R> func) {
- return (a, b, c, d, e) -> {
- try (TraceContext traceContext = new TraceContext(context, name)) {
- return func.run(a, b, c, d, e);
- }
- };
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/trace/TraceContext.java b/blaze-base/src/com/google/idea/blaze/base/trace/TraceContext.java
deleted file mode 100644
index 473f871..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trace/TraceContext.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trace;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Trace context utility class that can be used with try-with-resource.
- */
-public class TraceContext implements AutoCloseable {
- @NotNull BlazeContext context;
- @NotNull String name;
-
- public TraceContext(@NotNull BlazeContext context, @NotNull String name) {
- this.context = context;
- this.name = name;
- context.output(new TraceEvent(name, TraceEvent.Type.Begin));
- }
-
- @Override
- public void close() {
- context.output(new TraceEvent(name, TraceEvent.Type.End));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/trace/TraceEvent.java b/blaze-base/src/com/google/idea/blaze/base/trace/TraceEvent.java
deleted file mode 100644
index 08e3395..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trace/TraceEvent.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trace;
-
-import com.google.idea.blaze.base.scope.Output;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Trace event.
- */
-public class TraceEvent implements Output {
- public final String name;
- public final Type type;
- public final long nanoTime;
- public long threadId;
-
- public enum Type {
- Begin,
- End,
- }
-
- public TraceEvent(@NotNull String name, @NotNull Type type) {
- this.name = name;
- this.type = type;
- this.nanoTime = System.nanoTime();
- this.threadId = Thread.currentThread().getId();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/trace/TraceScope.java b/blaze-base/src/com/google/idea/blaze/base/trace/TraceScope.java
deleted file mode 100644
index 488f3dd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trace/TraceScope.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trace;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.BlazeScope;
-import com.google.idea.blaze.base.scope.OutputSink;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Tracks trace events and writes trace to ~/blaze-trace.json at end of scope.
- *
- * The results can be imported into Chrome using chrome://tracing.
- */
-public class TraceScope implements BlazeScope, OutputSink<TraceEvent> {
- private static final Logger LOG = Logger.getInstance(TraceScope.class);
- private final List<TraceEvent> traceEvents = Collections.synchronizedList(Lists.newArrayList());
- private long traceStartNanos;
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- traceStartNanos = System.nanoTime();
- context.addOutputSink(TraceEvent.class, this);
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- Collections.sort(traceEvents, (a, b) -> Long.compare(a.nanoTime, b.nanoTime));
-
- String home = System.getProperty("user.home");
- File file = new File(home, "blaze-trace.json");
- try (PrintWriter printWriter = new PrintWriter(file)) {
- printWriter.println("[");
-
- for (int i = 0; i < traceEvents.size(); ++i) {
- TraceEvent traceEvent = traceEvents.get(i);
- long startTimeNanos = traceEvent.nanoTime - traceStartNanos;
- long startTimeMicros = startTimeNanos / 1000;
- printWriter.print(String.format(
- "{\"name\": \"%s\", \"ts\": %d, \"ph\": \"%s\", \"pid\": %d}",
- traceEvent.name,
- startTimeMicros,
- traceEvent.type == TraceEvent.Type.Begin ? "B" : "E",
- traceEvent.threadId
- ));
-
- // No trailing commas in JSON :(
- if (i != traceEvents.size() - 1) {
- printWriter.append(',');
- }
- printWriter.append('\n');
- }
-
- printWriter.println("]");
- }
- catch (FileNotFoundException e) {
- LOG.error(e);
- }
-
- context.output(new PrintOutput("Wrote trace output to: " + file));
- }
-
- @Override
- public Propagation onOutput(@NotNull TraceEvent output) {
- traceEvents.add(output);
- return Propagation.Continue;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryNode.java b/blaze-base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryNode.java
deleted file mode 100644
index 5d94e82..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryNode.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.treeview;
-
-import com.intellij.ide.projectView.PresentationData;
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.ui.SimpleTextAttributes;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A PsiDirectoryNode that doesn't render module names or source roots.
- */
-public class BlazePsiDirectoryNode extends PsiDirectoryNode {
- public BlazePsiDirectoryNode(@NotNull PsiDirectoryNode original) {
- this(original.getProject(), original.getValue(), original.getSettings());
- }
-
- public BlazePsiDirectoryNode(Project project, PsiDirectory directory, ViewSettings settings) {
- super(project, directory, settings);
- }
-
- @Override
- protected boolean shouldShowModuleName() {
- return false;
- }
-
- @Override
- protected boolean shouldShowSourcesRoot() {
- return false;
- }
-
- @Override
- protected void updateImpl(PresentationData data) {
- super.updateImpl(data);
- PsiDirectory psiDirectory = getValue();
- assert psiDirectory != null;
- String text = psiDirectory.getName();
-
- data.setPresentableText(text);
- data.clearText();
- data.addText(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
- data.setLocationString("");
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNode.java b/blaze-base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNode.java
deleted file mode 100644
index 4a71968..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/treeview/BlazePsiDirectoryRootNode.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.treeview;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.ide.projectView.PresentationData;
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.ui.SimpleTextAttributes;
-
-/**
- * A PsiDirectoryNode that represents a directory root, rendering the
- * whole directory name from the workspace root.
- */
-public class BlazePsiDirectoryRootNode extends BlazePsiDirectoryNode {
- public BlazePsiDirectoryRootNode(Project project, PsiDirectory directory, ViewSettings settings) {
- super(project, directory, settings);
- }
-
- @Override
- protected void updateImpl(PresentationData data) {
- super.updateImpl(data);
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(getProject());
- PsiDirectory psiDirectory = getValue();
- assert psiDirectory != null;
- WorkspacePath workspacePath = workspaceRoot.workspacePathFor(psiDirectory.getVirtualFile());
- String text = workspacePath.relativePath();
-
- data.setPresentableText(text);
- data.clearText();
- data.addText(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
- data.setLocationString("");
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java b/blaze-base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
deleted file mode 100644
index 85f8aad..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.treeview;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.ide.projectView.ProjectViewSettings;
-import com.intellij.ide.projectView.TreeStructureProvider;
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.ide.projectView.impl.nodes.ExternalLibrariesNode;
-import com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode;
-import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
-import com.intellij.ide.util.treeView.AbstractTreeNode;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiManager;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Modifies the project view:
- *
- * - Replaces the root with a single workspace root
- * - Removes rendering of module names and source roots
- */
-public class BlazeTreeStructureProvider implements TreeStructureProvider, DumbAware {
- @NotNull
- @Override
- public Collection<AbstractTreeNode> modify(@NotNull AbstractTreeNode parent,
- @NotNull Collection<AbstractTreeNode> children,
- ViewSettings settings) {
- Project project = parent.getProject();
- if (project == null || !Blaze.isBlazeProject(project)) {
- return children;
- }
-
- if (parent instanceof ProjectViewProjectNode) {
- WorkspaceRootNode rootNode = createRootNode(project, settings);
- if (rootNode == null) {
- return children;
- }
-
- Collection<AbstractTreeNode> result = Lists.newArrayList();
- result.add(rootNode);
- for (AbstractTreeNode treeNode : children) {
- if (treeNode instanceof ExternalLibrariesNode) {
- result.add(treeNode);
- }
- }
- return result;
- }
- else {
- List<AbstractTreeNode> result = Lists.newArrayList();
- for (AbstractTreeNode treeNode : children) {
- if (treeNode.getClass().equals(PsiDirectoryNode.class)) {
- result.add(new BlazePsiDirectoryNode((PsiDirectoryNode)treeNode));
- } else {
- result.add(treeNode);
- }
- }
- return result;
- }
- }
-
- @Nullable
- private WorkspaceRootNode createRootNode(@NotNull Project project, @NotNull ViewSettings settings) {
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project)
- .getImportSettings();
- if (importSettings != null) {
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
- File fdir = workspaceRoot.directory();
- VirtualFile vdir = LocalFileSystem.getInstance().findFileByIoFile(fdir);
- if (vdir != null) {
- final PsiManager psiManager = PsiManager.getInstance(project);
- PsiDirectory directory = psiManager.findDirectory(vdir);
- return new WorkspaceRootNode(project, workspaceRoot, directory, wrapViewSettings(settings));
- }
- }
- return null;
- }
-
- @Nullable
- @Override
- public Object getData(Collection<AbstractTreeNode> selected, String dataName) {
- return null;
- }
-
- private ViewSettings wrapViewSettings(@NotNull final ViewSettings original) {
- return new ProjectViewSettings() {
- @Override
- public boolean isShowMembers() {
- return original.isShowMembers();
- }
-
- @Override
- public boolean isStructureView() {
- return original.isStructureView();
- }
-
- @Override
- public boolean isShowModules() {
- return original.isShowModules();
- }
-
- @Override
- public boolean isFlattenPackages() {
- return false;
- }
-
- @Override
- public boolean isAbbreviatePackageNames() {
- return original.isAbbreviatePackageNames();
- }
-
- @Override
- public boolean isHideEmptyMiddlePackages() {
- return false;
- }
-
- @Override
- public boolean isShowLibraryContents() {
- return original.isShowLibraryContents();
- }
-
- @Override
- public boolean isShowExcludedFiles() {
- return true;
- }
- };
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/treeview/WorkspaceRootNode.java b/blaze-base/src/com/google/idea/blaze/base/treeview/WorkspaceRootNode.java
deleted file mode 100644
index e8ee00f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/treeview/WorkspaceRootNode.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.treeview;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.projectview.ImportRoots;
-import com.intellij.ide.projectView.PresentationData;
-import com.intellij.ide.projectView.ViewSettings;
-import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
-import com.intellij.ide.util.treeView.AbstractTreeNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiManager;
-import com.intellij.ui.SimpleTextAttributes;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Workspace root node.
- * <p/>
- * <p>Customizes rendering of the workspace root node to cut out
- * the full absolute path of the workspace directory.
- */
-public class WorkspaceRootNode extends PsiDirectoryNode {
-
- private static final BoolExperiment COLLAPSE_PROJECT_VIEW = new BoolExperiment("collapse.project.view", true);
-
- private final WorkspaceRoot workspaceRoot;
-
- public WorkspaceRootNode(Project project,
- WorkspaceRoot workspaceRoot,
- PsiDirectory value,
- ViewSettings viewSettings) {
- super(project, value, viewSettings);
- this.workspaceRoot = workspaceRoot;
- }
-
- @Override
- public Collection<AbstractTreeNode> getChildrenImpl() {
- if (!COLLAPSE_PROJECT_VIEW.getValue()) {
- return super.getChildrenImpl();
- }
- if (!BlazeUserSettings.getInstance().getCollapseProjectView()) {
- return super.getChildrenImpl();
- }
- Project project = getProject();
- if (project == null) {
- return super.getChildrenImpl();
- }
- List<AbstractTreeNode> children = Lists.newArrayList();
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- return super.getChildrenImpl();
- }
-
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project)).add(projectViewSet).build();
- if (importRoots.rootDirectories().stream().anyMatch(WorkspacePath::isWorkspaceRoot)) {
- return super.getChildrenImpl();
- }
- for (WorkspacePath workspacePath : importRoots.rootDirectories()) {
- VirtualFile virtualFile = VfsUtil.findFileByIoFile(workspaceRoot.fileForPath(workspacePath), false);
- if (virtualFile == null) {
- continue;
- }
- PsiDirectory psiDirectory = PsiManager.getInstance(project).findDirectory(virtualFile);
- if (psiDirectory == null) {
- continue;
- }
- children.add(new BlazePsiDirectoryRootNode(project, psiDirectory, getSettings()));
- }
- if (children.isEmpty()) {
- return super.getChildrenImpl();
- }
- return children;
- }
-
- @Override
- protected void updateImpl(PresentationData data) {
- super.updateImpl(data);
- PsiDirectory psiDirectory = getValue();
- assert psiDirectory != null;
- String text = psiDirectory.getName();
-
- data.setPresentableText(text);
- data.clearText();
- data.addText(text, SimpleTextAttributes.REGULAR_ATTRIBUTES);
- data.setLocationString("");
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Function0.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Function0.java
deleted file mode 100644
index a45bc3d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Function0.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-/**
- * Function of 0 parameters.
- */
-public interface Function0<R> {
- R run();
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Function1.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Function1.java
deleted file mode 100644
index 67893fd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Function1.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Function of 1 parameters.
- */
-public interface Function1<A, R> {
- R run(@NotNull A a);
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Function2.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Function2.java
deleted file mode 100644
index bc704a1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Function2.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Function of 2 parameters.
- */
-public interface Function2<A, B, R> {
- R run(@NotNull A a, @NotNull B b);
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Function3.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Function3.java
deleted file mode 100644
index faaecd6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Function3.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Function of 3 parameters.
- */
-public interface Function3<A, B, C, R> {
- R run(@NotNull A a, @NotNull B b, @NotNull C c);
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Function4.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Function4.java
deleted file mode 100644
index e75b134..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Function4.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Function of 4 parameters.
- */
-public interface Function4<A, B, C, D, R> {
- R run(@NotNull A a, @NotNull B b, @NotNull C c, @NotNull D d);
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Function5.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Function5.java
deleted file mode 100644
index 1573832..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Function5.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Function of 5 parameters.
- */
-public interface Function5<A, B, C, D, E, R> {
- R run(@NotNull A a, @NotNull B b, @NotNull C c, @NotNull D d, @NotNull E e);
-}
-
diff --git a/blaze-base/src/com/google/idea/blaze/base/trickle/Tricklex.java b/blaze-base/src/com/google/idea/blaze/base/trickle/Tricklex.java
deleted file mode 100644
index df7dbf9..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/trickle/Tricklex.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.trickle;
-
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.spotify.trickle.*;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Ties Trickle to an executor to cut down on boilerplate.
- */
-public class Tricklex {
- public static <R> ConfigurableGraph<R> call(@NotNull Function0<R> func) {
- return Trickle.call(func0(func));
- }
-
- public static <A, R> Trickle.NeedsParameters1<A, R> call(@NotNull Function1<A, R> func) {
- return Trickle.call(func1(func));
- }
-
- public static <A, B, R> Trickle.NeedsParameters2<A, B, R> call(@NotNull Function2<A, B, R> func) {
- return Trickle.call(func2(func));
- }
-
- public static <A, B, C, R> Trickle.NeedsParameters3<A, B, C, R> call(@NotNull Function3<A, B, C, R> func) {
- return Trickle.call(func3(func));
- }
-
- public static <A, B, C, D, R> Trickle.NeedsParameters4<A, B, C, D, R> call(@NotNull Function4<A, B, C, D, R> func) {
- return Trickle.call(func4(func));
- }
-
- public static <A, B, C, D, E, R> Trickle.NeedsParameters5<A, B, C, D, E, R> call(@NotNull Function5<A, B, C, D, E, R> func) {
- return Trickle.call(func5(func));
- }
-
- private static <R> Func0<R> func0(@NotNull final Function0<R> func) {
- return () -> BlazeExecutor.getInstance().submit(func::run);
- }
-
- private static <A, R> Func1<A, R> func1(@NotNull final Function1<A, R> func) {
- return a -> BlazeExecutor.getInstance().submit(() -> func.run(a));
- }
-
- private static <A, B, R> Func2<A, B, R> func2(@NotNull final Function2<A, B, R> func) {
- return (a, b) -> BlazeExecutor.getInstance().submit(() -> func.run(a, b));
- }
-
- private static <A, B, C, R> Func3<A, B, C, R> func3(@NotNull final Function3<A, B, C, R> func) {
- return (a, b, c) -> BlazeExecutor.getInstance().submit(() -> func.run(a, b, c));
- }
-
- private static <A, B, C, D, R> Func4<A, B, C, D, R> func4(@NotNull final Function4<A, B, C, D, R> func) {
- return (a, b, c, d) -> BlazeExecutor.getInstance().submit(() -> func.run(a, b, c, d));
- }
-
- private static <A, B, C, D, E, R> Func5<A, B, C, D, E, R> func5(@NotNull final Function5<A, B, C, D, E, R> func) {
- return (a, b, c, d, e) -> BlazeExecutor.getInstance().submit(() -> func.run(a, b, c, d, e));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/BlazeProblemsView.java b/blaze-base/src/com/google/idea/blaze/base/ui/BlazeProblemsView.java
deleted file mode 100644
index 0c65b61..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/BlazeProblemsView.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.util.UUID;
-
-public interface BlazeProblemsView {
- @Nullable
- static BlazeProblemsView getInstance(Project project) {
- return ServiceManager.getService(project, BlazeProblemsView.class);
- }
-
- void clearOldMessages(UUID sessionId);
- void addMessage(IssueOutput issue, UUID sessionId);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java b/blaze-base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
deleted file mode 100644
index bde6a7c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.annotation.concurrent.Immutable;
-import java.util.Collection;
-
-@Immutable
-public final class BlazeValidationError {
-
- @NotNull
- private final String error;
-
- public BlazeValidationError(@NotNull String validationFailure) {
- this.error = validationFailure;
- }
-
- @NotNull
- public String getError() {
- return error;
- }
-
- public static void collect(@Nullable Collection<BlazeValidationError> errors, @NotNull BlazeValidationError error) {
- if (errors != null) {
- errors.add(error);
- }
- }
-
- public static void throwError(@NotNull Collection<BlazeValidationError> errors) throws IllegalArgumentException {
- BlazeValidationError error = !errors.isEmpty() ? errors.iterator().next() : null;
- String errorMessage = error != null ? error.getError() : "Unknown validation error";
- throw new IllegalArgumentException(errorMessage);
- }
-
- /**
- * Shows an error dialog.
- *
- * @return true if there are no errors
- */
- public static boolean verify(@NotNull Project project, @NotNull String title, @NotNull Collection<BlazeValidationError> errors) {
- if (!errors.isEmpty()) {
- BlazeValidationError error = errors.iterator().next();
- Messages.showErrorDialog(project, error.getError(), title);
- return false;
- }
- return true;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java b/blaze-base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
deleted file mode 100644
index 8965526..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Pair of (success, validation error)
- */
-public class BlazeValidationResult {
- public final boolean success;
- @Nullable public final BlazeValidationError error;
-
- private static final BlazeValidationResult SUCCESS = new BlazeValidationResult(true, null);
-
- private BlazeValidationResult(boolean success, @Nullable BlazeValidationError error) {
- this.success = success;
- this.error = error;
- }
-
- public static BlazeValidationResult success() {
- return SUCCESS;
- }
-
- public static BlazeValidationResult failure(BlazeValidationError error) {
- return new BlazeValidationResult(false, error);
- }
-
- public static BlazeValidationResult failure(String error) {
- return failure(new BlazeValidationError(error));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/ComboWrapper.java b/blaze-base/src/com/google/idea/blaze/base/ui/ComboWrapper.java
deleted file mode 100644
index 363660b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/ComboWrapper.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import com.intellij.openapi.ui.ComboBox;
-import com.intellij.ui.ListCellRendererWrapper;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.event.ActionListener;
-import java.util.Collection;
-
-/**
- * A simple wrapper for IDEA's {@link ComboBox} class adding type safety for the methods we commonly
- * use.
- */
-public final class ComboWrapper<T> {
- @NotNull
- private final ComboBox combo;
-
- public static <T> ComboWrapper<T> create() {
- return new ComboWrapper<T>();
- }
-
- private ComboWrapper() {
- combo = new ComboBox();
- }
-
- public void setItems(@NotNull Collection<T> values) {
- combo.setModel(new DefaultComboBoxModel(values.toArray()));
- }
-
- public void setSelectedItem(T value) {
- combo.setSelectedItem(value);
- }
-
- public T getSelectedItem() {
- return (T)combo.getSelectedItem();
- }
-
- public void addActionListener(@NotNull ActionListener listener) {
- combo.addActionListener(listener);
- }
-
- public void setRenderer(ListCellRendererWrapper<T> renderer) {
- combo.setRenderer(renderer);
- }
-
- @NotNull
- public ComboBox getCombo() {
- return combo;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/FileSelectorWithStoredHistory.java b/blaze-base/src/com/google/idea/blaze/base/ui/FileSelectorWithStoredHistory.java
deleted file mode 100644
index 5a1ac95..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/FileSelectorWithStoredHistory.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import com.intellij.ide.util.BrowseFilesListener;
-import com.intellij.openapi.ui.ComponentWithBrowseButton;
-import com.intellij.openapi.ui.TextComponentAccessor;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.ui.TextFieldWithStoredHistory;
-
-import javax.annotation.Nullable;
-
-/**
- * A file selector panel with text field, browse button and stored history.
- */
-public class FileSelectorWithStoredHistory extends ComponentWithBrowseButton<TextFieldWithStoredHistory> {
-
- public static FileSelectorWithStoredHistory create(String historyKey, String title) {
- TextFieldWithStoredHistory textField = new TextFieldWithStoredHistory(historyKey);
- return new FileSelectorWithStoredHistory(textField, title);
- }
-
- private FileSelectorWithStoredHistory(TextFieldWithStoredHistory textField, String title) {
- super(textField, null);
-
- addBrowseFolderListener(
- title,
- "",
- null,
- BrowseFilesListener.SINGLE_FILE_DESCRIPTOR,
- TextComponentAccessor.TEXT_FIELD_WITH_STORED_HISTORY_WHOLE_TEXT);
- }
-
- /**
- * Set the text without altering the history.
- */
- public void setText(@Nullable String text) {
- if (text == null) {
- getChildComponent().reset();
- } else {
- getChildComponent().setText(text);
- }
- }
-
- public void setTextWithHistory(@Nullable String text) {
- setText(text);
- if (text != null) {
- getChildComponent().addCurrentTextToHistory();
- }
- }
-
- @Nullable
- public String getText() {
- String text = getChildComponent().getText();
- return StringUtil.nullize(text);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/IntegerTextField.java b/blaze-base/src/com/google/idea/blaze/base/ui/IntegerTextField.java
deleted file mode 100644
index 76f5245..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/IntegerTextField.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import javax.swing.*;
-import java.text.FieldPosition;
-import java.text.NumberFormat;
-import java.text.ParseException;
-import java.text.ParsePosition;
-
-/**
- * Naive extension of JTextField, accepting integers or null.
- */
-public class IntegerTextField extends JFormattedTextField {
-
- private static final NumberFormat integerFormatter = new NullableNumberFormat(NumberFormat.getIntegerInstance());
-
- private static class NullableNumberFormat extends NumberFormat {
-
- private final NumberFormat base;
-
- private NullableNumberFormat(NumberFormat base) {
- this.base = base;
- }
-
- @Override
- public Object parseObject(String source) throws ParseException {
- if (source == null || source.trim().isEmpty()) {
- return null;
- }
- return super.parseObject(source);
- }
-
- @Override
- public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
- return base.format(number, toAppendTo, pos);
- }
-
- @Override
- public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
- return base.format(number, toAppendTo, pos);
- }
-
- @Override
- public Number parse(String source, ParsePosition parsePosition) {
- return base.parse(source, parsePosition);
- }
- }
-
- private int minValue = Integer.MIN_VALUE;
- private int maxValue = Integer.MAX_VALUE;
-
- public IntegerTextField() {
- super(integerFormatter);
- }
-
- @Override
- public void setValue(Object value) {
- if (value == null) {
- super.setValue(value);
- return;
- }
- Integer integer;
- try {
- integer = Integer.parseInt(getFormatter().valueToString(value));
-
- } catch (ParseException | NumberFormatException e) {
- return; // retain existing value if invalid
- }
- super.setValue(integer < minValue ? minValue : integer > maxValue ? maxValue : integer);
- }
-
- public IntegerTextField setMinValue(int minValue) {
- this.minValue = minValue;
- return this;
- }
-
- public IntegerTextField setMaxValue(int maxValue) {
- this.maxValue = maxValue;
- return this;
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/src/com/google/idea/blaze/base/ui/UiUtil.java b/blaze-base/src/com/google/idea/blaze/base/ui/UiUtil.java
deleted file mode 100644
index 05530bd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/ui/UiUtil.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ui;
-
-import com.google.common.collect.Lists;
-import com.intellij.util.ui.GridBag;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-
-/**
- * A collection of UI utility methods.
- */
-public final class UiUtil {
-
- public static final int INSETS = 7;
-
- private UiUtil() {
- }
-
- public static Box createBox(@NotNull Component... components) {
- return createBox(Lists.newArrayList(components));
- }
-
- /**
- * Puts all the given components in order in a box, aligned left.
- */
- public static Box createBox(@NotNull Iterable<Component> components) {
- Box box = Box.createVerticalBox();
- box.setAlignmentX(0);
- for (Component component : components) {
- if (component instanceof JComponent) {
- ((JComponent)component).setAlignmentX(0);
- }
- box.add(component);
- }
- return box;
- }
-
- @NotNull
- public static GridBag getLabelConstraints(int indentLevel) {
- Insets insets = new Insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS);
- return new GridBag().anchor(GridBagConstraints.WEST).weightx(0).insets(insets);
- }
-
- @NotNull
- public static GridBag getFillLineConstraints(int indentLevel) {
- Insets insets = new Insets(INSETS, INSETS + INSETS * indentLevel, 0, INSETS);
- return new GridBag().weightx(1).coverLine().fillCellHorizontally().anchor(GridBagConstraints.WEST).insets(insets);
- }
-
- public static void fillBottom(@NotNull JComponent component) {
- component.add(Box.createVerticalGlue(), new GridBag().weightx(1).weighty(1).fillCell().coverLine());
- }
-
- public static void setEnabledRecursive(Component component, boolean enabled) {
- component.setEnabled(enabled);
- if (component instanceof Container) {
- for (Component child : ((Container) component).getComponents()) {
- setEnabledRecursive(child, enabled);
- }
- }
- }
-
- public static void setPreferredWidth(JComponent component, int width) {
- int height = component.getPreferredSize().height;
- component.setPreferredSize(new Dimension(width, height));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/util/BlazeHelperBinaryUtil.java b/blaze-base/src/com/google/idea/blaze/base/util/BlazeHelperBinaryUtil.java
deleted file mode 100644
index f9028bd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/util/BlazeHelperBinaryUtil.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.util;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.io.URLUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
-import java.util.HashMap;
-import java.util.Map;
-
-public final class BlazeHelperBinaryUtil {
-
- private static final Logger LOG = Logger.getInstance(BlazeHelperBinaryUtil.class);
-
- private static final File tempDirectory = com.google.common.io.Files.createTempDir();
- private static final Map<String, File> cachedFiles = new HashMap<>();
-
- @Nullable
- public static synchronized File getBlazeHelperBinary(@NotNull String binaryName) {
- File file = cachedFiles.get(binaryName);
- if (file != null) {
- return file;
- }
- file = new File(tempDirectory, binaryName);
- File directory = file.getParentFile();
-
- if (!directory.mkdirs()) {
- LOG.error("Could not create temporary dir: " + directory);
- return null;
- }
-
- URL url = BlazeHelperBinaryUtil.class.getResource(binaryName);
- if (url == null) {
- LOG.error(String.format("Blaze binary '%s' was not found", binaryName));
- return null;
- }
- try (InputStream inputStream = URLUtil.openResourceStream(url)) {
- Files.copy(inputStream, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
- file.setExecutable(true);
- cachedFiles.put(binaryName, file);
- return file;
- } catch (IOException e) {
- LOG.error(String.format("Error loading blaze binary '%s'", binaryName));
- return null;
- }
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java b/blaze-base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
deleted file mode 100644
index 5ca01c7..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.util;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Calculates package prefix from workspace paths.
- */
-public final class PackagePrefixCalculator {
-
- public static String packagePrefixOf(@NotNull WorkspacePath workspacePath) {
- int skipIndex = 0;
-
- skipIndex = skipIndex == 0 ? skip(workspacePath, "java/") : skipIndex;
- skipIndex = skipIndex == 0 ? skip(workspacePath, "javatests/") : skipIndex;
-
- return workspacePath.relativePath().substring(skipIndex).replace('/', '.');
- }
-
- private static int skip(@NotNull WorkspacePath workspacePath, @NotNull String skipString) {
- if (workspacePath.relativePath().startsWith(skipString)) {
- return skipString.length();
- }
- return 0;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/util/SaveUtil.java b/blaze-base/src/com/google/idea/blaze/base/util/SaveUtil.java
deleted file mode 100644
index b036308..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/util/SaveUtil.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.util;
-
-import com.intellij.openapi.fileEditor.FileDocumentManager;
-import com.intellij.util.ui.UIUtil;
-
-/**
- * Utility for saving all files.
- */
-public class SaveUtil {
- public static void saveAllFiles() {
- UIUtil.invokeAndWaitIfNeeded(new Runnable() {
- @Override
- public void run() {
- FileDocumentManager.getInstance().saveAllDocuments();
- }
- });
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/util/SerializationUtil.java b/blaze-base/src/com/google/idea/blaze/base/util/SerializationUtil.java
deleted file mode 100644
index 4e64cfe..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/util/SerializationUtil.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.util;
-
-import com.google.common.io.Closeables;
-import com.intellij.CommonBundle;
-import com.intellij.openapi.diagnostic.Logger;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.*;
-
-/**
- * Utils for serialization.
- */
-public class SerializationUtil {
- private static final Logger LOG = Logger.getInstance(SerializationUtil.class.getName());
-
- public static void saveToDisk(@NotNull File file, @NotNull Serializable serializable) throws IOException {
- ensureExists(file.getParentFile());
- FileOutputStream fos = null;
- try {
- fos = new FileOutputStream(file);
- ObjectOutputStream oos = new ObjectOutputStream(fos);
- try {
- oos.writeObject(serializable);
- }
- finally {
- Closeables.close(oos, false);
- }
- }
- finally {
- Closeables.close(fos, false);
- }
- }
-
- @Nullable
- public static Object loadFromDisk(
- @NotNull File file,
- @NotNull final Iterable<ClassLoader> classLoaders) throws IOException {
- try {
- FileInputStream fin = null;
- try {
- if (!file.exists()) {
- return null;
- }
- fin = new FileInputStream(file);
- ObjectInputStream ois = new ObjectInputStream(fin) {
- @Override
- protected Class<?> resolveClass(ObjectStreamClass desc)
- throws IOException, ClassNotFoundException {
- String name = desc.getName();
- for (ClassLoader loader : classLoaders) {
- try {
- return Class.forName(name, false, loader);
- }
- catch (ClassNotFoundException e) {
- // Ignore - will throw eventually in super
- }
- }
- return super.resolveClass(desc);
- }
- };
- try {
- return (Object) ois.readObject();
- }
- finally {
- Closeables.close(ois, false);
- }
- }
- finally {
- Closeables.close(fin, false);
- }
- }
- catch (ClassNotFoundException e) {
- throw new IOException(e);
- }
- catch (ClassCastException e) {
- throw new IOException(e);
- }
- }
-
- private static void ensureExists(@NotNull File dir) throws IOException {
- if (!dir.exists() && !dir.mkdirs()) {
- throw new IOException(
- CommonBundle.message("exception.directory.can.not.create", dir.getPath()));
- }
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeDefaultVcsRootPolicy.java b/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeDefaultVcsRootPolicy.java
deleted file mode 100644
index 527321c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeDefaultVcsRootPolicy.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.impl.DefaultVcsRootPolicy;
-import com.intellij.openapi.vcs.impl.projectlevelman.NewMappings;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VfsUtilCore;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Converts project-level mappings to actual VCS roots.
- */
-public class BlazeDefaultVcsRootPolicy extends DefaultVcsRootPolicy {
-
- @NotNull
- private final Project project;
-
- public BlazeDefaultVcsRootPolicy(@NotNull Project project) {
- this.project = project;
- }
-
- @Override
- public void addDefaultVcsRoots(
- NewMappings mappingList,
- @NotNull String vcsName,
- List<VirtualFile> result) {
- result.addAll(getVcsRoots());
- }
-
- @NotNull
- @Override
- public Collection<VirtualFile> getDirtyRoots() {
- return getVcsRoots();
- }
-
- private List<VirtualFile> getVcsRoots() {
- List<VirtualFile> result = Lists.newArrayList();
- BlazeImportSettings importSettings = BlazeImportSettingsManager.getInstance(project)
- .getImportSettings();
- if (importSettings == null) {
- return result;
- }
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- return result;
- }
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
-
- for (DirectoryEntry entry : projectViewSet.listItems(DirectorySection.KEY)) {
- if (!entry.included) {
- continue;
- }
- File packageDir = workspaceRoot.fileForPath(entry.directory);
-
- VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(packageDir);
- if (virtualFile != null) {
- result.add(virtualFile);
- }
- }
- return result;
- }
-
- @Override
- public boolean matchesDefaultMapping(final VirtualFile file, final Object matchContext) {
- for (VirtualFile directory : getVcsRoots()) {
- if (VfsUtilCore.isAncestor(directory, file, false)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- @Nullable
- public Object getMatchContext(final VirtualFile file) {
- return null;
- }
-
- @Override
- @Nullable
- public VirtualFile getVcsRootFor(final VirtualFile file) {
- for (VirtualFile directory : getVcsRoots()) {
- if (VfsUtilCore.isAncestor(directory, file, false)) {
- return directory;
- }
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeVcsHandler.java b/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeVcsHandler.java
deleted file mode 100644
index 973ce16..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeVcsHandler.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides a diff against the version control system.
- */
-public interface BlazeVcsHandler {
- ExtensionPointName<BlazeVcsHandler> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.VcsHandler");
-
- /**
- * Optionally returns a client name if the supplied workspace root corresponds to this VCS type.
- */
- @Nullable
- String getClientName(WorkspaceRoot workspaceRoot);
-
- /**
- * Returns whether this vcs handler can manage this project
- */
- boolean handlesProject(Project project, WorkspaceRoot workspaceRoot);
-
- /**
- * Returns the working set of modified files compared to some "upstream".
- */
- ListenableFuture<WorkingSet> getWorkingSet(Project project,
- WorkspaceRoot workspaceRoot,
- ListeningExecutorService executor);
-
- /**
- * Optionally creates a sync handler to perform vcs-specific computation during sync.
- */
- @Nullable
- BlazeVcsSyncHandler createSyncHandler(Project project, WorkspaceRoot workspaceRoot);
-
- interface BlazeVcsSyncHandler {
- enum ValidationResult {
- OK,
- Error,
- RestartSync, /** The sync process needs restarting **/
- }
-
- /**
- * Updates the vcs state of the project.
- *
- * @return True for OK, false to abort the sync process.
- */
- boolean update(BlazeContext context, BlazeRoots blazeRoots, ListeningExecutorService executor);
-
- /**
- * Returns a custom workspace path resolver for this vcs.
- */
- @Nullable
- WorkspacePathResolver getWorkspacePathResolver();
-
- /**
- * Validates the project view. Can cause sync to fail or restart.
- */
- ValidationResult validateProjectView(BlazeContext context, ProjectViewSet projectViewSet);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeVcsHelper.java b/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeVcsHelper.java
deleted file mode 100644
index 809f88a..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/BlazeVcsHelper.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs;
-
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-
-import javax.annotation.Nullable;
-
-/**
- * Utility methods for VCS-specific functionality.
- */
-public class BlazeVcsHelper {
-
- @Nullable
- public static String getClientName(WorkspaceRoot workspaceRoot) {
- for (BlazeVcsHandler candidate : BlazeVcsHandler.EP_NAME.getExtensions()) {
- String name = candidate.getClientName(workspaceRoot);
- if (name != null) {
- return name;
- }
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/FallbackBlazeVcsHandler.java b/blaze-base/src/com/google/idea/blaze/base/vcs/FallbackBlazeVcsHandler.java
deleted file mode 100644
index 5a9ea64..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/FallbackBlazeVcsHandler.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-/**
- * Used for bazel projects, when no other vcs handler can be found. Fallback to returning a null working set.
- */
-public class FallbackBlazeVcsHandler implements BlazeVcsHandler {
- @Nullable
- @Override
- public String getClientName(WorkspaceRoot workspaceRoot) {
- return null;
- }
-
- @Override
- public boolean handlesProject(Project project, WorkspaceRoot workspaceRoot) {
- return Blaze.getBuildSystem(project) == BuildSystem.Bazel;
- }
-
- @Override
- public ListenableFuture<WorkingSet> getWorkingSet(Project project, WorkspaceRoot workspaceRoot, ListeningExecutorService executor) {
- return Futures.immediateFuture(null);
- }
-
- @Nullable
- @Override
- public BlazeVcsSyncHandler createSyncHandler(Project project, WorkspaceRoot workspaceRoot) {
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/VcsWorkspacePathResolver.java b/blaze-base/src/com/google/idea/blaze/base/vcs/VcsWorkspacePathResolver.java
deleted file mode 100644
index b6cf25b..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/VcsWorkspacePathResolver.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs;
-
-import javax.annotation.Nullable;
-import java.io.File;
-
-/**
- * Created by tomlu on 5/13/16.
- */
-public interface VcsWorkspacePathResolver {
-
- @Nullable
- File findPackageRoot(String relativePath);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitBlazeVcsHandler.java b/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitBlazeVcsHandler.java
deleted file mode 100644
index 322e91f..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitBlazeVcsHandler.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs.git;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
-
-import javax.annotation.Nullable;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-
-/**
- * Vcs diff provider for git
- */
-public class GitBlazeVcsHandler implements BlazeVcsHandler {
-
- private static final Logger LOG = Logger.getInstance(GitBlazeVcsHandler.class);
-
- @Nullable
- @Override
- public String getClientName(WorkspaceRoot workspaceRoot) {
- return null;
- }
-
- @Override
- public boolean handlesProject(Project project, WorkspaceRoot workspaceRoot) {
- return Blaze.getBuildSystem(project) == BuildSystem.Bazel
- && isGitRepository(workspaceRoot)
- && tracksRemote(workspaceRoot);
- }
-
- @Override
- public ListenableFuture<WorkingSet> getWorkingSet(Project project,
- WorkspaceRoot workspaceRoot,
- ListeningExecutorService executor) {
- return executor.submit(() -> {
- String upstreamSha = getUpstreamSha(workspaceRoot, false);
- if (upstreamSha == null) {
- return null;
- }
- return GitDiffProvider.calculateDiff(workspaceRoot, upstreamSha);
- });
- }
-
- @Nullable
- @Override
- public BlazeVcsSyncHandler createSyncHandler(Project project,
- WorkspaceRoot workspaceRoot) {
- return null;
- }
-
- private static boolean isGitRepository(WorkspaceRoot workspaceRoot) {
- // TODO: What if the git repo root is a parent directory of the workspace root?
- // Just call 'git rev-parse --is-inside-work-tree' or similar instead?
- File gitDir = new File(workspaceRoot.directory(), ".git");
- return FileAttributeProvider.getInstance().isDirectory(gitDir);
- }
-
- /**
- * If we're not on a git branch which tracks a remote, we have no way of determining a WorkingSet.
- */
- private static boolean tracksRemote(WorkspaceRoot workspaceRoot) {
- return getUpstreamSha(workspaceRoot, true) != null;
- }
-
- /**
- * Returns the git commit SHA corresponding to the most recent commit
- * in the current branch which matches a commit in the currently-tracked remote branch.
- */
- @Nullable
- public static String getUpstreamSha(WorkspaceRoot workspaceRoot, boolean suppressErrors) {
- return getConsoleOutput(workspaceRoot, ImmutableList.of("git", "rev-parse", "@{u}"), suppressErrors);
- }
-
- /**
- * @return the console output, in string form, or null if there was a non-zero exit code.
- */
- @Nullable
- private static String getConsoleOutput(WorkspaceRoot workspaceRoot, ImmutableList<String> command, boolean suppressErrors) {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
-
- int retVal = ExternalTask.builder(workspaceRoot, command)
- .stdout(stdout)
- .stderr(stderr)
- .build()
- .run();
- if (retVal != 0) {
- if (!suppressErrors) {
- LOG.error(stderr);
- }
- return null;
- }
- return StringUtil.trimEnd(stdout.toString(), "\n");
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitDiffProvider.java b/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitDiffProvider.java
deleted file mode 100644
index 1981ae5..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitDiffProvider.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs.git;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.text.StringUtil;
-
-import javax.annotation.Nullable;
-import java.io.ByteArrayOutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Vcs diff provider for git.
- */
-public class GitDiffProvider {
-
- private static final Logger LOG = Logger.getInstance(GitDiffProvider.class);
-
- /**
- * Finds all changes between HEAD and the git commit specified by
- * the provided SHA.<br>
- * Returns null if an error occurred.
- */
- @Nullable
- public static WorkingSet calculateDiff(
- WorkspaceRoot workspaceRoot,
- String upstreamSha) {
-
- String gitRoot = getConsoleOutput(workspaceRoot, "git", "rev-parse", "--show-toplevel");
- if (gitRoot == null) {
- return null;
- }
- GitStatusLineProcessor processor = new GitStatusLineProcessor(workspaceRoot, gitRoot);
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
-
- // Do a git diff to find all modified files we know about
- int retVal = ExternalTask.builder(workspaceRoot, ImmutableList.of("git", "diff", "--name-status", "--no-renames", upstreamSha))
- .stdout(LineProcessingOutputStream.of(processor))
- .stderr(stderr)
- .build()
- .run();
- if (retVal != 0) {
- LOG.error(stderr);
- return null;
- }
-
- // Finally list all untracked files, as they're not caught by the git diff step above
- String untrackedFilesOutput = getConsoleOutput(workspaceRoot, "git", "ls-files", "--others", "--exclude-standard");
- if (untrackedFilesOutput == null) {
- return null;
- }
-
- List<WorkspacePath> untrackedFiles = Arrays.asList(untrackedFilesOutput.split("\n"))
- .stream()
- .filter(s -> !Strings.isNullOrEmpty(s))
- .filter(WorkspacePath::validate)
- .map(WorkspacePath::new)
- .collect(Collectors.toList());
-
- return new WorkingSet(
- ImmutableList.<WorkspacePath>builder().addAll(processor.addedFiles).addAll(untrackedFiles).build(),
- ImmutableList.copyOf(processor.modifiedFiles),
- ImmutableList.copyOf(processor.deletedFiles)
- );
- }
-
- /**
- * @return the console output, in string form, or null if there was a non-zero exit code.
- */
- @Nullable
- private static String getConsoleOutput(WorkspaceRoot workspaceRoot, String... commands) {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- ByteArrayOutputStream stderr = new ByteArrayOutputStream();
-
- int retVal = ExternalTask.builder(workspaceRoot, ImmutableList.copyOf(commands))
- .stdout(stdout)
- .stderr(stderr)
- .build()
- .run();
- if (retVal != 0) {
- LOG.error(stderr);
- return null;
- }
- return StringUtil.trimEnd(stdout.toString(), "\n");
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessor.java b/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessor.java
deleted file mode 100644
index aaf225e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessor.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs.git;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.openapi.util.text.StringUtil;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class GitStatusLineProcessor implements LineProcessingOutputStream.LineProcessor {
-
- private static final Pattern REGEX = Pattern.compile("^(A|M|D)\\s*(.*?)$");
-
- private final WorkspaceRoot workspaceRoot;
- private final String gitRoot;
-
- public final List<WorkspacePath> addedFiles = Lists.newArrayList();
- public final List<WorkspacePath> modifiedFiles = Lists.newArrayList();
- public final List<WorkspacePath> deletedFiles = Lists.newArrayList();
-
- public GitStatusLineProcessor(WorkspaceRoot workspaceRoot, String gitRoot) {
- this.workspaceRoot = workspaceRoot;
- this.gitRoot = gitRoot;
- }
-
- @Override
- public boolean processLine(String line) {
- Matcher matcher = REGEX.matcher(line);
- if (matcher.find()) {
- String type = matcher.group(1);
- String file = matcher.group(2);
- file = StringUtil.trimEnd(file, '/');
-
- WorkspacePath workspacePath = getWorkspacePath(file);
- if (workspacePath == null) {
- return true;
- }
- switch (type) {
- case "A":
- addedFiles.add(workspacePath);
- break;
- case "M":
- modifiedFiles.add(workspacePath);
- break;
- case "D":
- deletedFiles.add(workspacePath);
- break;
- }
- }
- return true;
- }
-
- @Nullable
- private WorkspacePath getWorkspacePath(String gitPath) {
- File absoluteFile = new File(gitRoot, gitPath);
- if (workspaceRoot.isInWorkspace(absoluteFile)) {
- return workspaceRoot.workspacePathFor(absoluteFile);
- }
- return null;
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeImportFileChooser.java b/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeImportFileChooser.java
deleted file mode 100644
index f9ef3f3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeImportFileChooser.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard;
-
-import com.intellij.ide.util.PropertiesComponent;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDialog;
-import com.intellij.openapi.fileChooser.FileChooserFactory;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NonNls;
-
-import javax.annotation.Nullable;
-
-public final class BlazeImportFileChooser {
- private static final String WIZARD_TITLE = "Import Blaze Project";
- private static final String WIZARD_DESCRIPTION = "Select a workspace, a .blazeproject file, or a BUILD file to import";
- @NonNls
- private static final String LAST_IMPORTED_LOCATION = "last.imported.location";
-
-
- private static final class BlazeFileChooser extends FileChooserDescriptor {
- BlazeFileChooser() {
- super(true, true, false, false, false, false);
- }
-
- @Override
- public boolean isFileSelectable(VirtualFile file) {
- // Default implementation doesn't filter directories, we want to make sure only workspace roots are selectable
- return super.isFileSelectable(file) && ImportSource.canImport(file);
- }
- }
-
- private static FileChooserDescriptor createFileChooserDescriptor() {
- return new BlazeFileChooser()
- .withShowHiddenFiles(true) // Show root project view file
- .withHideIgnored(false)
- .withTitle(WIZARD_TITLE)
- .withDescription(WIZARD_DESCRIPTION)
- .withFileFilter(ImportSource::canImport);
- }
-
- @Nullable
- public static VirtualFile getFileToImport() {
- FileChooserDescriptor descriptor = createFileChooserDescriptor();
- FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
- VirtualFile toSelect = null;
- String lastLocation = PropertiesComponent.getInstance().getValue(LAST_IMPORTED_LOCATION);
- if (lastLocation != null) {
- toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(lastLocation);
- }
- VirtualFile[] files = chooser.choose(null, toSelect);
- if (files.length == 0) {
- return null;
- }
- VirtualFile file = files[0];
- PropertiesComponent.getInstance().setValue(LAST_IMPORTED_LOCATION, file.getPath());
- return file;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeNewProjectBuilder.java b/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeNewProjectBuilder.java
deleted file mode 100644
index 3559ffd..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeNewProjectBuilder.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard;
-
-import com.google.idea.blaze.base.plugin.dependency.PluginDependencyHelper;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-
-public final class BlazeNewProjectBuilder {
- private static final Logger LOG = Logger.getInstance(BlazeNewProjectBuilder.class);
-
- public static List<Module> commit(final Project project, BlazeImportSettings importSettings, ProjectView projectView) {
- String projectDataDirectory = importSettings.getProjectDataDirectory();
-
- if (!StringUtil.isEmpty(projectDataDirectory)) {
- File projectDataDir = new File(projectDataDirectory);
- if (!projectDataDir.exists()) {
- if (!projectDataDir.mkdirs()) {
- LOG.error("Unable to create the project directory: " + projectDataDirectory);
- }
- }
- }
-
- BlazeImportSettingsManager.getInstance(project).setImportSettings(importSettings);
-
- try {
- String projectViewFile = importSettings.getProjectViewFile();
- LOG.assertTrue(projectViewFile != null);
- ProjectViewStorageManager.getInstance().writeProjectView(
- ProjectViewParser.projectViewToString(projectView),
- new File(projectViewFile)
- );
- } catch (IOException e) {
- LOG.error(e);
- }
-
- PluginDependencyHelper.addDependencyOnSyncPlugin(project);
-
- // Initial sync of the project happens in BlazeSyncStartupActivity
-
- return Collections.emptyList();
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeProjectSettingsControl.java b/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeProjectSettingsControl.java
deleted file mode 100644
index 9ebc727..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard/BlazeProjectSettingsControl.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.projectview.section.sections.ImportSection;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.ui.JPanelProvidingProject;
-import com.google.idea.blaze.base.settings.ui.ProjectViewUi;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.google.idea.blaze.base.vcs.BlazeVcsHelper;
-import com.intellij.ide.RecentProjectsManager;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.ApplicationNamesInfo;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.ui.TextComponentAccessor;
-import com.intellij.openapi.ui.TextFieldWithBrowseButton;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.util.SystemProperties;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-/**
- * The UI control to collect project settings when importing a Blaze project.
- */
-public final class BlazeProjectSettingsControl {
-
- private static final FileChooserDescriptor STUDIO_PROJECT_FOLDER_DESCRIPTOR =
- new FileChooserDescriptor(false, true, false, false, false, false);
- private static final Logger LOG = Logger.getInstance(BlazeProjectSettingsControl.class);
-
- private WorkspaceRoot workspaceRoot;
- @Nullable private File sharedProjectViewFile;
- @Nullable private String vcsClientName;
-
- private TextFieldWithBrowseButton projectDataDirField;
- private JTextField projectNameField;
- private ProjectViewUi projectViewUi;
-
- public BlazeProjectSettingsControl(Disposable parentDisposable) {
- this.projectViewUi = new ProjectViewUi(parentDisposable);
- }
-
- public JPanel createComponent(File fileToImport) {
- JPanel component = new JPanelProvidingProject(ProjectViewUi.getProject(), new GridBagLayout());
- fillUi(component, 0);
- init(fileToImport);
- UiUtil.fillBottom(component);
- return component;
- }
-
- private void fillUi(@NotNull JPanel canvas, int indentLevel) {
- JLabel projectDataDirLabel = new JBLabel("Project data directory:");
-
- Dimension minSize = ProjectViewUi.getMinimumSize();
- // Add 120 pixels so we have room for our extra fields
- minSize.setSize(minSize.width, minSize.height + 120);
- canvas.setMinimumSize(minSize);
- canvas.setPreferredSize(minSize);
-
- projectDataDirField = new TextFieldWithBrowseButton();
- projectDataDirField
- .addBrowseFolderListener("", "Blaze Android Studio project data directory", null,
- STUDIO_PROJECT_FOLDER_DESCRIPTOR,
- TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT, false);
- final String dataDirToolTipText =
- "Directory in which to store the project's metadata. Choose a directory outside of"
- + " the Piper/CitC client directories or Git5 directory.";
- projectDataDirField.setToolTipText(dataDirToolTipText);
- projectDataDirLabel.setToolTipText(dataDirToolTipText);
-
- canvas.add(projectDataDirLabel, UiUtil.getLabelConstraints(indentLevel));
- canvas.add(projectDataDirField, UiUtil.getFillLineConstraints(0));
-
- JLabel projectNameLabel = new JLabel("Project name:");
- projectNameField = new JTextField();
- final String projectNameToolTipText =
- "Project display name.";
- projectNameField.setToolTipText(projectNameToolTipText);
- projectNameLabel.setToolTipText(projectNameToolTipText);
- canvas.add(projectNameLabel, UiUtil.getLabelConstraints(indentLevel));
- canvas.add(projectNameField, UiUtil.getFillLineConstraints(0));
-
- projectViewUi.fillUi(canvas, indentLevel);
- }
-
- private void init(File fileToImport) {
- workspaceRoot = BuildSystemProvider.getWorkspaceRootProvider(BuildSystem.Blaze).findWorkspaceRoot(fileToImport);
- if (workspaceRoot == null) {
- throw new IllegalArgumentException("Invalid workspace root: " + fileToImport);
- }
- vcsClientName = BlazeVcsHelper.getClientName(workspaceRoot);
-
- File importDirectory = null;
- if (ProjectViewStorageManager.isProjectViewFile(fileToImport.getPath())) {
- importDirectory = fileToImport.getParentFile();
- sharedProjectViewFile = new File(fileToImport.getPath());
- }
- else if (ImportSource.isBuildFile(fileToImport)) {
- importDirectory = fileToImport.getParentFile();
- for (String extension : ProjectViewStorageManager.VALID_EXTENSIONS) {
- File defaultProjectViewFile = new File(fileToImport.getParentFile(), "." + extension);
- if (defaultProjectViewFile.exists()) {
- sharedProjectViewFile = defaultProjectViewFile;
- break;
- }
- }
- }
-
- String defaultProjectName = importDirectory != null
- ? importDirectory.getName()
- : workspaceRoot.directory().getParentFile().getName();
- projectNameField.setText(defaultProjectName);
-
- String defaultDataDir = getDefaultProjectDataDirectory(defaultProjectName, vcsClientName);
- projectDataDirField.setText(defaultDataDir);
-
- String projectViewText = "";
- if (sharedProjectViewFile != null) {
- try {
- projectViewText = ProjectViewStorageManager.getInstance().loadProjectView(sharedProjectViewFile);
- if (projectViewText == null) {
- LOG.error("Could not load project view: " + sharedProjectViewFile);
- projectViewText = "";
- }
- }
- catch (IOException e) {
- LOG.error(e);
- }
- }
- if (projectViewText.isEmpty() && importDirectory != null) {
- projectViewText = guessProjectViewFromLocation(workspaceRoot, importDirectory);
- }
-
- projectViewUi.init(
- workspaceRoot,
- projectViewText,
- sharedProjectViewFile != null ? projectViewText : null,
- sharedProjectViewFile,
- sharedProjectViewFile != null,
- false /* allowEditShared - not allowed during import */
- );
- }
-
-
- @NotNull
- private static String getDefaultProjectDataDirectory(@NotNull String projectName, @Nullable String vcsClientName) {
- File defaultDataDirectory = new File(getDefaultProjectsDirectory());
- if (vcsClientName != null) {
- // Ensure that each client gets its own data directory.
- projectName = vcsClientName + "-" + projectName;
- }
- File desiredLocation = new File(defaultDataDirectory, projectName);
- return newUniquePath(desiredLocation);
- }
-
- @NotNull
- private static String getDefaultProjectsDirectory() {
- final String lastProjectLocation = RecentProjectsManager.getInstance().getLastProjectCreationLocation();
- if (lastProjectLocation != null) {
- return lastProjectLocation.replace('/', File.separatorChar);
- }
- final String userHome = SystemProperties.getUserHome();
- String productName = ApplicationNamesInfo.getInstance().getLowercaseProductName();
- return userHome.replace('/', File.separatorChar) + File.separator + productName.replace(" ", "") + "Projects";
- }
-
- @NotNull
- private static String guessProjectViewFromLocation(
- @NotNull WorkspaceRoot workspaceRoot,
- @NotNull File importDirectory) {
-
- WorkspacePath mainModuleGoogle3RelativePath = workspaceRoot.workspacePathFor(importDirectory);
- WorkspacePath testModuleGoogle3RelativePath = guessTestRelativePath(
- workspaceRoot,
- mainModuleGoogle3RelativePath);
-
- ListSection.Builder<DirectoryEntry> directorySectionBuilder = ListSection.builder(DirectorySection.KEY);
- directorySectionBuilder.add(DirectoryEntry.include(mainModuleGoogle3RelativePath));
- if (testModuleGoogle3RelativePath != null) {
- directorySectionBuilder.add(DirectoryEntry.include(testModuleGoogle3RelativePath));
- }
-
- ListSection.Builder<TargetExpression> targetSectionBuilder = ListSection.builder(TargetSection.KEY);
- targetSectionBuilder.add(TargetExpression.fromString("//" + mainModuleGoogle3RelativePath + "/...:all"));
- if (testModuleGoogle3RelativePath != null) {
- targetSectionBuilder.add(TargetExpression.fromString("//" + testModuleGoogle3RelativePath + "/...:all"));
- }
-
- return ProjectViewParser.projectViewToString(
- ProjectView.builder()
- .put(directorySectionBuilder)
- .put(targetSectionBuilder)
- .build()
- );
- }
-
- @Nullable
- private static WorkspacePath guessTestRelativePath(
- @NotNull WorkspaceRoot workspaceRoot,
- @NotNull WorkspacePath projectWorkspacePath) {
- String projectRelativePath = projectWorkspacePath.relativePath();
- String testBuildFileRelativePath = null;
- if (projectRelativePath.startsWith("java/")) {
- testBuildFileRelativePath = projectRelativePath.replaceFirst("java/", "javatests/");
- }
- else if (projectRelativePath.contains("/java/")) {
- testBuildFileRelativePath = projectRelativePath.replaceFirst("/java/", "/javatests/");
- }
- if (testBuildFileRelativePath != null) {
- File testBuildFile = workspaceRoot.fileForPath(new WorkspacePath(testBuildFileRelativePath));
- if (testBuildFile.exists()) {
- return new WorkspacePath(testBuildFileRelativePath);
- }
- }
- return null;
- }
-
- /**
- * Returns a unique file path by appending numbers until a non-collision is found.
- */
- private static String newUniquePath(File location) {
- if (!location.exists()) {
- return location.getAbsolutePath();
- }
-
- String name = location.getName();
- File directory = location.getParentFile();
- int tries = 0;
- while (true) {
- String candidateName = String.format("%s-%02d", name, tries);
- File candidateFile = new File(directory, candidateName);
- if (!candidateFile.exists()) {
- return candidateFile.getAbsolutePath();
- }
- tries++;
- }
- }
-
- @Nullable
- private BlazeValidationError validateProjectDataDirectory(@NotNull File projectDataDirPath) {
- if (workspaceRoot.isInWorkspace(projectDataDirPath)) {
- return new BlazeValidationError(
- "Project data directory should be placed outside of the client directory"
- );
- }
- return null;
- }
-
- @NotNull
- public BlazeValidationResult validate() {
- // Validate project settings fields
- String projectName = projectNameField.getText().trim();
- if (StringUtil.isEmpty(projectName)) {
- return BlazeValidationResult.failure(new BlazeValidationError("Project name is not specified"));
- }
- String projectDataDirPath = projectDataDirField.getText().trim();
- if (StringUtil.isEmpty(projectDataDirPath)) {
- return BlazeValidationResult.failure(new BlazeValidationError("Project data directory is not specified"));
- }
- File projectDataDir = new File(projectDataDirPath);
- if (!projectDataDir.isAbsolute()) {
- return BlazeValidationResult.failure(new BlazeValidationError("Project data directory is not valid"));
- }
- BlazeValidationError projectDataDirectoryValidation = validateProjectDataDirectory(projectDataDir);
- if (projectDataDirectoryValidation != null) {
- return BlazeValidationResult.failure(projectDataDirectoryValidation);
- }
-
- List<IssueOutput> issues = Lists.newArrayList();
-
- ProjectViewSet projectViewSet = projectViewUi.parseProjectView(issues);
- BlazeValidationError projectViewParseError = validationErrorFromIssueList(issues);
- if (projectViewParseError != null) {
- return BlazeValidationResult.failure(projectViewParseError);
- }
-
- return BlazeValidationResult.success();
- }
-
- public ImportResults getResults() {
- String projectName = projectNameField.getText().trim();
- String projectDataDirectory = projectDataDirField.getText().trim();
-
- // Create unique location hash
- final String locationHash = createLocationHash(projectName);
-
- // Only support blaze in the old import wizard. TODO: remove this wizard prior to public bazel release.
- BuildSystem fixedBuildSystem = BuildSystem.Blaze;
-
- File sharedProjectViewFile = this.sharedProjectViewFile;
- File localProjectViewFile = ProjectViewStorageManager.getLocalProjectViewFileName(fixedBuildSystem, new File(projectDataDirectory));
-
- BlazeImportSettings importSettings = new BlazeImportSettings(
- workspaceRoot.directory().getPath(),
- projectName,
- projectDataDirectory,
- locationHash,
- localProjectViewFile.getPath(),
- fixedBuildSystem
- );
-
- boolean useSharedProjectView = projectViewUi.getUseSharedProjectView();
-
- // If we're using a shared project view, synthesize a local one that imports the shared one
- final ProjectView projectView;
- if (useSharedProjectView && sharedProjectViewFile != null) {
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
- projectView = ProjectView.builder()
- .put(ScalarSection.builder(ImportSection.KEY)
- .set(workspaceRoot.workspacePathFor(sharedProjectViewFile)))
- .build();
- } else {
- ProjectViewSet parseResult = projectViewUi.parseProjectView(Lists.<IssueOutput>newArrayList());
- ProjectViewSet.ProjectViewFile projectViewFile = parseResult.getTopLevelProjectViewFile();
- assert projectViewFile != null;
- projectView = projectViewFile.projectView;
- }
-
- return new ImportResults(
- importSettings,
- projectView,
- calculateProjectName(projectName, vcsClientName),
- projectDataDirectory
- );
- }
-
- @NotNull
- private static String createLocationHash(@NotNull String projectName) {
- String uuid = UUID.randomUUID().toString();
- uuid = uuid.substring(0, Math.min(uuid.length(), 8));
- return projectName.replaceAll("[^a-zA-Z0-9]", "") + "-" + uuid;
- }
-
- private static String calculateProjectName(
- @NotNull String projectName,
- @Nullable String vcsClientName) {
- if (vcsClientName != null) {
- projectName = String.format("%s (%s)", projectName, vcsClientName);
- }
- return projectName;
- }
-
- @Nullable
- private static BlazeValidationError validationErrorFromIssueList(List<IssueOutput> issues) {
- List<IssueOutput> errors = issues
- .stream()
- .filter(issue -> issue.getCategory() == IssueOutput.Category.ERROR)
- .collect(Collectors.toList());
-
- if (!errors.isEmpty()) {
- StringBuilder errorMessage = new StringBuilder();
- errorMessage.append("The following issues were found:\n\n");
- for (IssueOutput issue : errors) {
- errorMessage.append(issue.getMessage());
- errorMessage.append('\n');
- }
- return new BlazeValidationError(errorMessage.toString());
- }
- return null;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard/ImportResults.java b/blaze-base/src/com/google/idea/blaze/base/wizard/ImportResults.java
deleted file mode 100644
index 2d99054..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard/ImportResults.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard;
-
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-
-import javax.annotation.concurrent.Immutable;
-
-@Immutable
-public final class ImportResults {
-
- public final BlazeImportSettings importSettings;
- public final ProjectView projectView;
- public final String projectName;
- public final String projectDataDirectory;
-
- public ImportResults(
- BlazeImportSettings importSettings,
- ProjectView projectView,
- String projectName,
- String projectDataDirectory
- ) {
- this.importSettings = importSettings;
- this.projectView = projectView;
- this.projectName = projectName;
- this.projectDataDirectory = projectDataDirectory;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard/ImportSource.java b/blaze-base/src/com/google/idea/blaze/base/wizard/ImportSource.java
deleted file mode 100644
index 986ddef..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard/ImportSource.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard;
-
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.google.idea.blaze.base.bazel.WorkspaceRootProvider;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-
-/**
- * Some convenience methods regarding your import source.
- */
-public class ImportSource {
- static boolean isBuildFile(@NotNull File file) {
- return file.getName().equals("BUILD");
- }
-
- static boolean canImport(@NotNull File file) {
- WorkspaceRootProvider helper = BuildSystemProvider.getWorkspaceRootProvider(BuildSystem.Blaze);
- if (helper.isWorkspaceRoot(file)) {
- return true;
- }
- if (ProjectViewStorageManager.isProjectViewFile(file.getName()) || isBuildFile(file)) {
- if (helper.isInWorkspace(file)) {
- return true;
- }
- }
- return false;
- }
-
- public static boolean canImport(@NotNull VirtualFile file) {
- return canImport(new File(file.getPath()));
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BazelWizardOptionProvider.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BazelWizardOptionProvider.java
deleted file mode 100644
index e0c4ba4..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BazelWizardOptionProvider.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.common.collect.ImmutableList;
-
-import java.util.Collection;
-
-/**
- * Provides bazel options for the wizard.
- */
-public class BazelWizardOptionProvider implements BlazeWizardOptionProvider {
-
- @Override
- public Collection<BlazeSelectWorkspaceOption> getSelectWorkspaceOptions(BlazeNewProjectBuilder builder) {
- return ImmutableList.of(
- new UseExistingBazelWorkspaceOption(builder)
- );
- }
-
- @Override
- public Collection<BlazeSelectProjectViewOption> getSelectProjectViewOptions(BlazeNewProjectBuilder builder) {
- return ImmutableList.of(
- new CreateFromScratchProjectViewOption(),
- new ImportFromWorkspaceProjectViewOption(builder),
- new GenerateFromBuildFileSelectProjectViewOption(builder),
- new CopyExternalProjectViewOption(builder)
- );
- }
-
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
deleted file mode 100644
index 2738b20..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.plugin.dependency.PluginDependencyHelper;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.UUID;
-
-/**
- * Contains the state to build a new project throughout the new project wizard process.
- */
-public final class BlazeNewProjectBuilder {
- private static final Logger LOG = Logger.getInstance(BlazeNewProjectBuilder.class);
-
- // Stored in user settings as the last imported workspace
- private static final String LAST_IMPORTED_BLAZE_WORKSPACE = "blaze-wizard.last-imported-workspace";
- private static final String LAST_IMPORTED_BAZEL_WORKSPACE = "blaze-wizard.last-imported-bazel-workspace";
-
- public static String lastImportedWorkspaceKey(BuildSystem buildSystem) {
- switch (buildSystem) {
- case Blaze: return LAST_IMPORTED_BLAZE_WORKSPACE;
- case Bazel: return LAST_IMPORTED_BAZEL_WORKSPACE;
- default: throw new RuntimeException("Unrecognized build system type: " + buildSystem);
- }
- }
-
- private final BlazeWizardUserSettings userSettings;
- private BlazeSelectWorkspaceOption workspaceOption;
- private BlazeSelectProjectViewOption projectViewOption;
- private File projectViewFile;
- private ProjectView projectView;
- private ProjectViewSet projectViewSet;
- private String projectName;
- private String projectDataDirectory;
- private WorkspaceRoot workspaceRoot;
- private BuildSystem buildSystem;
-
- public BlazeNewProjectBuilder() {
- this.userSettings = BlazeWizardUserSettingsStorage.getInstance().copyUserSettings();
- }
-
- public BlazeWizardUserSettings getUserSettings() {
- return userSettings;
- }
-
- public BlazeSelectWorkspaceOption getWorkspaceOption() {
- return workspaceOption;
- }
-
- public BlazeSelectProjectViewOption getProjectViewOption() {
- return projectViewOption;
- }
-
- public String getProjectName() {
- return projectName;
- }
-
- public ProjectView getProjectView() {
- return projectView;
- }
-
- public ProjectViewSet getProjectViewSet() {
- return projectViewSet;
- }
-
- public String getProjectDataDirectory() {
- return projectDataDirectory;
- }
-
- public BuildSystem getBuildSystem() {
- return buildSystem;
- }
-
- public String getBuildSystemName() {
- if (buildSystem != null) {
- return buildSystem.getName();
- }
- return Blaze.defaultBuildSystemName();
- }
-
- public BlazeNewProjectBuilder setWorkspaceOption(BlazeSelectWorkspaceOption workspaceOption) {
- this.workspaceOption = workspaceOption;
- this.buildSystem = workspaceOption.getBuildSystemForWorkspace();
- return this;
- }
-
- public BlazeNewProjectBuilder setProjectViewOption(BlazeSelectProjectViewOption projectViewOption) {
- this.projectViewOption = projectViewOption;
- return this;
- }
-
- public BlazeNewProjectBuilder setProjectView(ProjectView projectView) {
- this.projectView = projectView;
- return this;
- }
-
- public BlazeNewProjectBuilder setProjectViewFile(File projectViewFile) {
- this.projectViewFile = projectViewFile;
- return this;
- }
-
- public BlazeNewProjectBuilder setProjectViewSet(ProjectViewSet projectViewSet) {
- this.projectViewSet = projectViewSet;
- return this;
- }
-
- public BlazeNewProjectBuilder setProjectName(String projectName) {
- this.projectName = projectName;
- return this;
- }
-
- public BlazeNewProjectBuilder setProjectDataDirectory(String projectDataDirectory) {
- this.projectDataDirectory = projectDataDirectory;
- return this;
- }
-
- /**
- * Commits the project. May report errors.
- */
- public void commit() throws BlazeProjectCommitException {
- this.workspaceRoot = workspaceOption.commit();
- projectViewOption.commit();
-
- String workspaceKey = lastImportedWorkspaceKey(workspaceOption.getBuildSystemForWorkspace());
- userSettings.put(workspaceKey, workspaceRoot.toString());
-
- if (!StringUtil.isEmpty(projectDataDirectory)) {
- File projectDataDir = new File(projectDataDirectory);
- if (!projectDataDir.exists()) {
- if (!projectDataDir.mkdirs()) {
- throw new BlazeProjectCommitException("Unable to create the project directory: " + projectDataDirectory);
- }
- }
- }
-
- try {
- LOG.assertTrue(projectViewFile != null);
- ProjectViewStorageManager.getInstance().writeProjectView(
- ProjectViewParser.projectViewToString(projectView),
- projectViewFile
- );
- } catch (IOException e) {
- throw new BlazeProjectCommitException("Could not create project view file", e);
- }
- }
-
- /**
- * Commits the project data. This method mustn't fail, because the project
- * has already been created.
- */
- public void commitToProject(Project project) {
- BlazeWizardUserSettingsStorage.getInstance().commit(userSettings);
-
- BlazeImportSettings importSettings = new BlazeImportSettings(
- workspaceRoot.directory().getPath(),
- projectName,
- projectDataDirectory,
- createLocationHash(projectName),
- projectViewFile.getPath(),
- buildSystem
- );
-
- BlazeImportSettingsManager.getInstance(project).setImportSettings(importSettings);
- PluginDependencyHelper.addDependencyOnSyncPlugin(project);
- // Initial sync of the project happens in BlazeSyncStartupActivity
- }
-
- private static String createLocationHash(String projectName) {
- String uuid = UUID.randomUUID().toString();
- uuid = uuid.substring(0, Math.min(uuid.length(), 8));
- return projectName.replaceAll("[^a-zA-Z0-9]", "") + "-" + uuid;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeProjectCommitException.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeProjectCommitException.java
deleted file mode 100644
index f52e94d..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeProjectCommitException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-/**
- * Throws during the commit stage of the new project wizard.
- */
-public class BlazeProjectCommitException extends Exception {
- public BlazeProjectCommitException(String message) {
- super(message);
- }
-
- public BlazeProjectCommitException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public BlazeProjectCommitException(Throwable cause) {
- super(cause);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
deleted file mode 100644
index f5e24ce..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-
-import javax.annotation.Nullable;
-
-/**
- * Provides an option on the "Select .blazeproject" screen
- */
-public interface BlazeSelectProjectViewOption extends BlazeWizardOption {
- @Nullable
- WorkspacePath getSharedProjectView();
-
- @Nullable
- String getInitialProjectViewText();
-
- void commit();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java
deleted file mode 100644
index 3a2a941..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-
-/**
- * Provides an option on the "Select workspace" screen
- */
-public interface BlazeSelectWorkspaceOption extends BlazeWizardOption {
- /**
- * @return a location to use when browsing for workspace paths.
- */
- WorkspaceRoot getTemporaryWorkspaceRoot();
-
- /**
- * @return the name of the workspace. Used to generate default project names.
- */
- String getWorkspaceName();
-
- BuildSystem getBuildSystemForWorkspace();
-
- WorkspaceRoot commit() throws BlazeProjectCommitException;
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOption.java
deleted file mode 100644
index 110804e..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOption.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-/**
- * Base class for the workspace and project view options.
- */
-public interface BlazeWizardOption {
- int HEADER_LABEL_WIDTH = 80;
- int MAX_INPUT_FIELD_WIDTH = 600;
-
- /**
- * @return A stable option name, used to remember which option was selected.
- */
- String getOptionName();
-
- /**
- * @return the option text, eg "Create workspace from scratch"
- */
- String getOptionText();
-
- /**
- * @return a ui component to be added below the corresponding radio button
- */
- @Nullable
- JComponent getUiComponent();
-
- BlazeValidationResult validate();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOptionProvider.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOptionProvider.java
deleted file mode 100644
index b928774..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardOptionProvider.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-import java.util.Collection;
-
-/**
- * Provides options during the import process.
- */
-public interface BlazeWizardOptionProvider {
- ExtensionPointName<BlazeWizardOptionProvider> EP_NAME =
- ExtensionPointName.create("com.google.idea.blaze.BlazeWizardOptionProvider");
-
- Collection<BlazeSelectWorkspaceOption> getSelectWorkspaceOptions(BlazeNewProjectBuilder builder);
-
- Collection<BlazeSelectProjectViewOption> getSelectProjectViewOptions(BlazeNewProjectBuilder builder);
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettings.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettings.java
deleted file mode 100644
index bafe536..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettings.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.Maps;
-import com.intellij.util.xmlb.annotations.MapAnnotation;
-import com.intellij.util.xmlb.annotations.Tag;
-
-import java.util.Map;
-
-/**
- * A bundle of settings that are stored between invocations of the wizard.
- *
- * <p>It's the user's responsibility to appropriately namespace the keys.
- */
-public class BlazeWizardUserSettings {
- Map<String, String> values = Maps.newHashMap();
-
- public BlazeWizardUserSettings() {
- }
-
- public BlazeWizardUserSettings(BlazeWizardUserSettings state) {
- values.putAll(state.getValues());
- }
-
- public String get(String key, String defaultValue) {
- return values.getOrDefault(key, defaultValue);
- }
-
- public void put(String key, String value) {
- values.put(key, value);
- }
-
- @SuppressWarnings("unused")
- @Tag("settings")
- @MapAnnotation(surroundWithTag = false)
- public Map<String, String> getValues() {
- return values;
- }
-
- @SuppressWarnings("unused")
- public void setValues(Map<String, String> values) {
- this.values = values;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- BlazeWizardUserSettings that = (BlazeWizardUserSettings)o;
- return Objects.equal(values, that.values);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(values);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
deleted file mode 100644
index 9492476..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Storage;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Stores wizard user settings between runs.
- */
-@State(
- name = "BlazeWizardUserSettings",
- storages = @Storage(value = "blaze.wizard.settings.xml")
-)
-public class BlazeWizardUserSettingsStorage implements PersistentStateComponent<BlazeWizardUserSettings> {
- private BlazeWizardUserSettings state = new BlazeWizardUserSettings();
-
- static BlazeWizardUserSettingsStorage getInstance() {
- return ServiceManager.getService(BlazeWizardUserSettingsStorage.class);
- }
-
- @Nullable
- @Override
- public BlazeWizardUserSettings getState() {
- return state;
- }
-
- @Override
- public void loadState(BlazeWizardUserSettings state) {
- this.state = state;
- }
-
- BlazeWizardUserSettings copyUserSettings() {
- return new BlazeWizardUserSettings(state);
- }
-
- void commit(BlazeWizardUserSettings userSettings) {
- this.state = userSettings;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/CopyExternalProjectViewOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/CopyExternalProjectViewOption.java
deleted file mode 100644
index 8d05996..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/CopyExternalProjectViewOption.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDialog;
-import com.intellij.openapi.fileChooser.FileChooserFactory;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.components.panels.HorizontalLayout;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-class CopyExternalProjectViewOption implements BlazeSelectProjectViewOption {
- private static final String LAST_WORKSPACE_PATH = "copy-external.last-project-view-path";
-
- final BlazeWizardUserSettings userSettings;
- final JComponent component;
- final JTextField projectViewPathField;
-
- CopyExternalProjectViewOption(BlazeNewProjectBuilder builder) {
- this.userSettings = builder.getUserSettings();
-
- String defaultWorkspacePath = userSettings.get(LAST_WORKSPACE_PATH, "");
-
- JPanel panel = new JPanel(new HorizontalLayout(10));
- JLabel label = new JLabel("Project view:");
- UiUtil.setPreferredWidth(label, HEADER_LABEL_WIDTH);
- panel.add(label);
- this.projectViewPathField = new JTextField();
- projectViewPathField.setText(defaultWorkspacePath);
- UiUtil.setPreferredWidth(projectViewPathField, MAX_INPUT_FIELD_WIDTH);
- panel.add(projectViewPathField);
- JButton button = new JButton("...");
- button.addActionListener(action -> chooseWorkspacePath());
- int buttonSize = projectViewPathField.getPreferredSize().height;
- button.setPreferredSize(new Dimension(buttonSize, buttonSize));
- panel.add(button);
- this.component = panel;
- }
-
- @Override
- public String getOptionName() {
- return "copy-external";
- }
-
- @Override
- public String getOptionText() {
- return "Copy external";
- }
-
- @Override
- public JComponent getUiComponent() {
- return component;
- }
-
- @Override
- public BlazeValidationResult validate() {
- if (getProjectViewPath().isEmpty()) {
- return BlazeValidationResult.failure("Path to project view file cannot be empty.");
- }
- File file = new File(getProjectViewPath());
- if (!file.exists()) {
- return BlazeValidationResult.failure("Project view file does not exist.");
- }
- return BlazeValidationResult.success();
- }
-
- @Nullable
- @Override
- public WorkspacePath getSharedProjectView() {
- return null;
- }
-
- @Nullable
- @Override
- public String getInitialProjectViewText() {
- try {
- byte[] bytes = Files.readAllBytes(Paths.get(getProjectViewPath()));
- return new String(bytes, StandardCharsets.UTF_8);
- }
- catch (IOException e) {
- return null;
- }
- }
-
- @Override
- public void commit() {
- userSettings.put(LAST_WORKSPACE_PATH, getProjectViewPath());
- }
-
- private String getProjectViewPath() {
- return projectViewPathField.getText().trim();
- }
-
- private void chooseWorkspacePath() {
- FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, false, false)
- .withShowHiddenFiles(true) // Show root project view file
- .withHideIgnored(false)
- .withTitle("Select Project View File")
- .withDescription("Select a project view file to import.")
- .withFileFilter(virtualFile -> ProjectViewStorageManager.isProjectViewFile(new File(virtualFile.getPath())));
- FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
-
- File startingLocation = null;
- String projectViewPath = getProjectViewPath();
- if (!projectViewPath.isEmpty()) {
- File fileLocation = new File(projectViewPath);
- if (fileLocation.exists()) {
- startingLocation = fileLocation;
- }
- }
- final VirtualFile[] files;
- if (startingLocation != null) {
- VirtualFile toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(startingLocation.getPath());
- files = chooser.choose(null, toSelect);
- } else {
- files = chooser.choose(null);
- }
- if (files.length == 0) {
- return;
- }
- VirtualFile file = files[0];
- projectViewPathField.setText(file.getPath());
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/CreateFromScratchProjectViewOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/CreateFromScratchProjectViewOption.java
deleted file mode 100644
index 89cbb32..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/CreateFromScratchProjectViewOption.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-
-class CreateFromScratchProjectViewOption implements BlazeSelectProjectViewOption {
- @Override
- public String getOptionName() {
- return "create-from-scratch";
- }
-
- @Override
- public String getOptionText() {
- return "Create from scratch";
- }
-
- @Override
- public JComponent getUiComponent() {
- return null;
- }
-
- @Nullable
- @Override
- public WorkspacePath getSharedProjectView() {
- return null;
- }
-
- @Nullable
- @Override
- public String getInitialProjectViewText() {
- return "";
- }
-
- @Override
- public void commit() {
- }
-
- @Override
- public BlazeValidationResult validate() {
- return BlazeValidationResult.success();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
deleted file mode 100644
index 1c2c41c..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDialog;
-import com.intellij.openapi.fileChooser.FileChooserFactory;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.components.panels.HorizontalLayout;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-
-class GenerateFromBuildFileSelectProjectViewOption implements BlazeSelectProjectViewOption {
- private static final String LAST_WORKSPACE_PATH = "generate-from-build-file.last-workspace-path";
- private final BlazeNewProjectBuilder builder;
- private final BlazeWizardUserSettings userSettings;
- private final JTextField buildFilePathField;
- private final JPanel component;
-
- public GenerateFromBuildFileSelectProjectViewOption(
- BlazeNewProjectBuilder builder) {
- this.builder = builder;
- this.userSettings = builder.getUserSettings();
-
- String defaultWorkspacePath = userSettings.get(LAST_WORKSPACE_PATH, "");
-
- JPanel panel = new JPanel(new HorizontalLayout(10));
- JLabel pathLabel = new JLabel("BUILD file:");
- UiUtil.setPreferredWidth(pathLabel, HEADER_LABEL_WIDTH);
- panel.add(pathLabel);
- this.buildFilePathField = new JTextField();
- buildFilePathField.setText(defaultWorkspacePath);
- UiUtil.setPreferredWidth(buildFilePathField, MAX_INPUT_FIELD_WIDTH);
- panel.add(buildFilePathField);
- JButton button = new JButton("...");
- button.addActionListener(action -> chooseWorkspacePath());
-
- int buttonSize = buildFilePathField.getPreferredSize().height;
- button.setPreferredSize(new Dimension(buttonSize, buttonSize));
- panel.add(button);
- this.component = panel;
- }
-
- @Override
- public String getOptionName() {
- return "generate-from-build-file";
- }
-
- @Override
- public String getOptionText() {
- return "Generate from BUILD file";
- }
-
- @Override
- public JComponent getUiComponent() {
- return component;
- }
-
- @Override
- public BlazeValidationResult validate() {
- if (getBuildFilePath().isEmpty()) {
- return BlazeValidationResult.failure("BUILD file field cannot be empty.");
- }
- WorkspaceRoot workspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
- File file = workspaceRoot.fileForPath(new WorkspacePath(getBuildFilePath()));
- if (!file.exists()) {
- return BlazeValidationResult.failure("BUILD file does not exist.");
- }
-
- return BlazeValidationResult.success();
- }
-
- @Nullable
- @Override
- public WorkspacePath getSharedProjectView() {
- return null;
- }
-
- @Nullable
- @Override
- public String getInitialProjectViewText() {
- WorkspaceRoot workspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
- WorkspacePath workspacePath = new WorkspacePath(getBuildFilePath());
- return guessProjectViewFromLocation(workspaceRoot,
- workspaceRoot.workspacePathFor(workspaceRoot.fileForPath(workspacePath).getParentFile()));
- }
-
- @Override
- public void commit() {
- userSettings.put(LAST_WORKSPACE_PATH, getBuildFilePath());
- }
-
- private static String guessProjectViewFromLocation(WorkspaceRoot workspaceRoot, WorkspacePath workspacePath) {
-
- WorkspacePath mainModuleWorkspaceRelativePath = workspacePath;
- WorkspacePath testModuleWorkspaceRelativePath = guessTestRelativePath(
- workspaceRoot,
- mainModuleWorkspaceRelativePath);
-
- ListSection.Builder<DirectoryEntry> directorySectionBuilder = ListSection.builder(DirectorySection.KEY);
- directorySectionBuilder.add(DirectoryEntry.include(mainModuleWorkspaceRelativePath));
- if (testModuleWorkspaceRelativePath != null) {
- directorySectionBuilder.add(DirectoryEntry.include(testModuleWorkspaceRelativePath));
- }
-
- ListSection.Builder<TargetExpression> targetSectionBuilder = ListSection.builder(TargetSection.KEY);
- targetSectionBuilder.add(TargetExpression.allFromPackageRecursive(mainModuleWorkspaceRelativePath));
- if (testModuleWorkspaceRelativePath != null) {
- targetSectionBuilder.add(TargetExpression.allFromPackageRecursive(testModuleWorkspaceRelativePath));
- }
-
- return ProjectViewParser.projectViewToString(
- ProjectView.builder()
- .put(directorySectionBuilder)
- .put(targetSectionBuilder)
- .build()
- );
- }
-
- @Nullable
- private static WorkspacePath guessTestRelativePath(
- WorkspaceRoot workspaceRoot,
- WorkspacePath projectWorkspacePath) {
- String projectRelativePath = projectWorkspacePath.relativePath();
- String testBuildFileRelativePath = null;
- if (projectRelativePath.startsWith("java/")) {
- testBuildFileRelativePath = projectRelativePath.replaceFirst("java/", "javatests/");
- }
- else if (projectRelativePath.contains("/java/")) {
- testBuildFileRelativePath = projectRelativePath.replaceFirst("/java/", "/javatests/");
- }
- if (testBuildFileRelativePath != null) {
- File testBuildFile = workspaceRoot.fileForPath(new WorkspacePath(testBuildFileRelativePath));
- if (testBuildFile.exists()) {
- return new WorkspacePath(testBuildFileRelativePath);
- }
- }
- return null;
- }
-
- private String getBuildFilePath() {
- return buildFilePathField.getText().trim();
- }
-
- private void chooseWorkspacePath() {
- FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, false, false)
- .withShowHiddenFiles(true) // Show root project view file
- .withHideIgnored(false)
- .withTitle("Select BUILD File")
- .withDescription("Select a BUILD file to synthesize a project view from.")
- .withFileFilter(virtualFile -> virtualFile.getName().equals("BUILD"));
- FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
-
- WorkspaceRoot workspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
-
- File startingLocation = workspaceRoot.directory();
- String buildFilePath = getBuildFilePath();
- if (!buildFilePath.isEmpty()) {
- File fileLocation = workspaceRoot.fileForPath(new WorkspacePath(buildFilePath));
- if (fileLocation.exists()) {
- startingLocation = fileLocation;
- }
- }
- VirtualFile toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(startingLocation.getPath());
- VirtualFile[] files = chooser.choose(null, toSelect);
- if (files.length == 0) {
- return;
- }
- VirtualFile file = files[0];
- String newWorkspacePath = FileUtil.getRelativePath(workspaceRoot.directory(), new File(file.getPath()));
- buildFilePathField.setText(newWorkspacePath);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
deleted file mode 100644
index 3fa8388..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDialog;
-import com.intellij.openapi.fileChooser.FileChooserFactory;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.components.panels.HorizontalLayout;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-
-class ImportFromWorkspaceProjectViewOption implements BlazeSelectProjectViewOption {
- private static final String LAST_WORKSPACE_PATH = "import-from-workspace.last-workspace-path";
-
- final BlazeNewProjectBuilder builder;
- final BlazeWizardUserSettings userSettings;
- final JComponent component;
- final JTextField projectViewPathField;
-
- ImportFromWorkspaceProjectViewOption(BlazeNewProjectBuilder builder) {
- this.builder = builder;
- this.userSettings = builder.getUserSettings();
-
- String defaultWorkspacePath = userSettings.get(LAST_WORKSPACE_PATH, "");
-
- JPanel panel = new JPanel(new HorizontalLayout(10));
- JLabel projectViewLabel = new JLabel("Project view:");
- UiUtil.setPreferredWidth(projectViewLabel, HEADER_LABEL_WIDTH);
- panel.add(projectViewLabel);
- this.projectViewPathField = new JTextField();
- projectViewPathField.setText(defaultWorkspacePath);
- UiUtil.setPreferredWidth(projectViewPathField, MAX_INPUT_FIELD_WIDTH);
- panel.add(projectViewPathField);
- JButton button = new JButton("...");
- button.addActionListener(action -> chooseWorkspacePath());
- int buttonSize = projectViewPathField.getPreferredSize().height;
- button.setPreferredSize(new Dimension(buttonSize, buttonSize));
- panel.add(button);
- this.component = panel;
- }
-
- @Override
- public String getOptionName() {
- return "import-from-workspace";
- }
-
- @Override
- public String getOptionText() {
- return "Import from workspace";
- }
-
- @Override
- public JComponent getUiComponent() {
- return component;
- }
-
- @Override
- public BlazeValidationResult validate() {
- if (getProjectViewPath().isEmpty()) {
- return BlazeValidationResult.failure("Workspace path to project view file cannot be empty.");
- }
- WorkspaceRoot workspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
- File file = workspaceRoot.fileForPath(getSharedProjectView());
- if (!file.exists()) {
- return BlazeValidationResult.failure("Project view file does not exist.");
- }
-
- return BlazeValidationResult.success();
- }
-
- @Nullable
- @Override
- public WorkspacePath getSharedProjectView() {
- return new WorkspacePath(getProjectViewPath());
- }
-
- @Nullable
- @Override
- public String getInitialProjectViewText() {
- return null;
- }
-
- @Override
- public void commit() {
- userSettings.put(LAST_WORKSPACE_PATH, getProjectViewPath());
- }
-
- private String getProjectViewPath() {
- return projectViewPathField.getText().trim();
- }
-
- private void chooseWorkspacePath() {
- FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, false, false)
- .withShowHiddenFiles(true) // Show root project view file
- .withHideIgnored(false)
- .withTitle("Select Project View File")
- .withDescription("Select a project view file to import.")
- .withFileFilter(virtualFile -> ProjectViewStorageManager.isProjectViewFile(new File(virtualFile.getPath())));
- FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
-
- WorkspaceRoot workspaceRoot = builder.getWorkspaceOption().getTemporaryWorkspaceRoot();
-
- File startingLocation = workspaceRoot.directory();
- String projectViewPath = getProjectViewPath();
- if (!projectViewPath.isEmpty()) {
- File fileLocation = workspaceRoot.fileForPath(new WorkspacePath(projectViewPath));
- if (fileLocation.exists()) {
- startingLocation = fileLocation;
- }
- }
- VirtualFile toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(startingLocation.getPath());
- VirtualFile[] files = chooser.choose(null, toSelect);
- if (files.length == 0) {
- return;
- }
- VirtualFile file = files[0];
-
- if (!FileUtil.isAncestor(workspaceRoot.directory().getPath(), file.getPath(), true)) {
- Messages.showErrorDialog(
- String.format(
- "You must choose a project view file under %s. To use an external project view, please use the 'Copy external' option.",
- workspaceRoot.directory().getPath()
- ),
- "Cannot Use Project View File"
- );
- return;
- }
-
- String newWorkspacePath = FileUtil.getRelativePath(workspaceRoot.directory(), new File(file.getPath()));
- projectViewPathField.setText(newWorkspacePath);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
deleted file mode 100644
index a19feb3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import icons.BlazeIcons;
-
-import javax.swing.*;
-import java.io.File;
-
-class UseExistingBazelWorkspaceOption extends UseExistingWorkspaceOption {
-
- UseExistingBazelWorkspaceOption(BlazeNewProjectBuilder builder) {
- super(builder, BuildSystem.Bazel);
- }
-
- @Override
- protected boolean isWorkspaceRoot(VirtualFile file) {
- return BuildSystemProvider.getWorkspaceRootProvider(BuildSystem.Bazel).isWorkspaceRoot(new File(file.getPath()));
- }
-
- @Override
- public String getOptionName() {
- return "use-existing-bazel-workspace";
- }
- @Override
- public String getOptionText() {
- return "Use existing bazel workspace";
- }
-
- @Override
- protected String getWorkspaceName(File workspaceRoot) {
- return workspaceRoot.getName();
- }
-
- @Override
- protected String fileChooserDescription() {
- return "Select the directory of the workspace you want to use.";
- }
-
- @Override
- protected Icon getBuildSystemIcon() {
- return BlazeIcons.BazelLeaf;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/UseExistingWorkspaceOption.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/UseExistingWorkspaceOption.java
deleted file mode 100644
index 79875aa..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/UseExistingWorkspaceOption.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2;
-
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.icons.AllIcons;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDialog;
-import com.intellij.openapi.fileChooser.FileChooserFactory;
-import com.intellij.openapi.util.IconLoader;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.components.panels.HorizontalLayout;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-
-public abstract class UseExistingWorkspaceOption implements BlazeSelectWorkspaceOption {
-
- private final BlazeWizardUserSettings userSettings;
- private final JComponent component;
- private final JTextField directoryField;
- private final BuildSystem buildSystem;
-
- protected UseExistingWorkspaceOption(BlazeNewProjectBuilder builder, BuildSystem buildSystem) {
- this.userSettings = builder.getUserSettings();
- this.buildSystem = buildSystem;
-
- String defaultDirectory = userSettings.get(BlazeNewProjectBuilder.lastImportedWorkspaceKey(buildSystem), "");
-
- JPanel panel = new JPanel(new HorizontalLayout(10));
- panel.add(getIconComponent());
- JLabel workspaceRootLabel = new JLabel("Workspace:");
- UiUtil.setPreferredWidth(workspaceRootLabel, HEADER_LABEL_WIDTH);
- panel.add(workspaceRootLabel);
- this.directoryField = new JTextField();
- directoryField.setText(defaultDirectory);
- UiUtil.setPreferredWidth(directoryField, MAX_INPUT_FIELD_WIDTH);
- panel.add(directoryField);
- JButton button = new JButton("...");
- button.addActionListener(action -> chooseDirectory());
- int buttonSize = directoryField.getPreferredSize().height;
- button.setPreferredSize(new Dimension(buttonSize, buttonSize));
- panel.add(button);
- this.component = panel;
- }
-
- protected abstract boolean isWorkspaceRoot(VirtualFile file);
-
- protected abstract String fileChooserDescription();
-
- protected abstract Icon getBuildSystemIcon();
-
- protected abstract String getWorkspaceName(File workspaceRoot);
-
- @Override
- public BuildSystem getBuildSystemForWorkspace() {
- return buildSystem;
- }
-
- @Override
- public JComponent getUiComponent() {
- return component;
- }
-
- @Override
- public WorkspaceRoot commit() throws BlazeProjectCommitException {
- return new WorkspaceRoot(new File(getDirectory()));
- }
-
- @Nullable
- @Override
- public WorkspaceRoot getTemporaryWorkspaceRoot() {
- return new WorkspaceRoot(new File(getDirectory()));
- }
-
- @Override
- public String getWorkspaceName() {
- File workspaceRoot = new File(getDirectory());
- return getWorkspaceName(workspaceRoot);
- }
-
- @Override
- public BlazeValidationResult validate() {
- if (getDirectory().isEmpty()) {
- return BlazeValidationResult.failure("Please select a workspace");
- }
-
- File workspaceRoot = new File(getDirectory());
- if (!workspaceRoot.exists()) {
- return BlazeValidationResult.failure("Workspace does not exist");
- }
- return BlazeValidationResult.success();
- }
-
- private String getDirectory() {
- return directoryField.getText().trim();
- }
-
- private void chooseDirectory() {
- FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false)
- {
- @Override
- public boolean isFileSelectable(VirtualFile file) {
- // Default implementation doesn't filter directories, we want to make sure only workspace roots are selectable
- return super.isFileSelectable(file) && isWorkspaceRoot(file);
- }
-
- @Override
- public Icon getIcon(VirtualFile file) {
- if (buildSystem == BuildSystem.Bazel) {
- // isWorkspaceRoot requires file system calls -- it's too expensive
- return super.getIcon(file);
- }
- if (isWorkspaceRoot(file)) {
- return AllIcons.Nodes.SourceFolder;
- }
- return super.getIcon(file);
- }
- }
- .withHideIgnored(false)
- .withTitle("Select Workspace Root")
- .withDescription(fileChooserDescription())
- .withFileFilter(this::isWorkspaceRoot);
- FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, null, null);
-
- final VirtualFile[] files;
- File existingLocation = new File(getDirectory());
- if (existingLocation.exists()) {
- VirtualFile toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(existingLocation.getPath());
- files = chooser.choose(null, toSelect);
- } else {
- files = chooser.choose(null);
- }
- if (files.length == 0) {
- return;
- }
- VirtualFile file = files[0];
- directoryField.setText(file.getPath());
- }
-
- private Component getIconComponent() {
- JLabel iconPanel = new JLabel(IconLoader.getIconSnapshot(getBuildSystemIcon())) {
- @Override
- public boolean isEnabled() {
- return true;
- }
- };
- UiUtil.setPreferredWidth(iconPanel, 16);
- return iconPanel;
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java
deleted file mode 100644
index a4d41d3..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2.ui;
-
-import com.google.common.collect.Lists;
-import com.google.common.hash.HashCode;
-import com.google.common.hash.Hashing;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.sections.ImportSection;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.settings.ui.JPanelProvidingProject;
-import com.google.idea.blaze.base.settings.ui.ProjectViewUi;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.BlazeSelectProjectViewOption;
-import com.google.idea.blaze.base.wizard2.BlazeSelectWorkspaceOption;
-import com.intellij.ide.RecentProjectsManager;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.ApplicationNamesInfo;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.ui.TextComponentAccessor;
-import com.intellij.openapi.ui.TextFieldWithBrowseButton;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.ui.components.JBLabel;
-import com.intellij.util.SystemProperties;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * The UI control to collect project settings when importing a Blaze project.
- */
-public final class BlazeEditProjectViewControl {
-
- private static final FileChooserDescriptor PROJECT_FOLDER_DESCRIPTOR =
- new FileChooserDescriptor(false, true, false, false, false, false);
- private static final Logger LOG = Logger.getInstance(BlazeEditProjectViewControl.class);
-
- private final JPanel component;
- private final String buildSystemName;
- private final ProjectViewUi projectViewUi;
-
- private TextFieldWithBrowseButton projectDataDirField;
- private JTextField projectNameField;
- private HashCode paramsHash;
-
- public BlazeEditProjectViewControl(BlazeNewProjectBuilder builder, Disposable parentDisposable) {
- this.projectViewUi = new ProjectViewUi(parentDisposable);
- JPanel component = new JPanelProvidingProject(ProjectViewUi.getProject(), new GridBagLayout());
- fillUi(component, 0, parentDisposable);
- update(builder);
- UiUtil.fillBottom(component);
- this.component = component;
- this.buildSystemName = builder.getBuildSystemName();
- }
-
- public Component getUiComponent() {
- return component;
- }
-
- private void fillUi(JPanel canvas, int indentLevel, Disposable parentDisposable) {
- JLabel projectDataDirLabel = new JBLabel("Project data directory:");
-
- Dimension minSize = ProjectViewUi.getMinimumSize();
- // Add 120 pixels so we have room for our extra fields
- minSize.setSize(minSize.width, minSize.height + 120);
- canvas.setMinimumSize(minSize);
- canvas.setPreferredSize(minSize);
-
- projectDataDirField = new TextFieldWithBrowseButton();
- projectDataDirField.addBrowseFolderListener("", buildSystemName + " project data directory", null,
- PROJECT_FOLDER_DESCRIPTOR,
- TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT, false);
- final String dataDirToolTipText =
- "Directory in which to store the project's metadata. Choose a directory outside of your workspace.";
- projectDataDirField.setToolTipText(dataDirToolTipText);
- projectDataDirLabel.setToolTipText(dataDirToolTipText);
-
- canvas.add(projectDataDirLabel, UiUtil.getLabelConstraints(indentLevel));
- canvas.add(projectDataDirField, UiUtil.getFillLineConstraints(0));
-
- JLabel projectNameLabel = new JLabel("Project name:");
- projectNameField = new JTextField();
- final String projectNameToolTipText =
- "Project display name.";
- projectNameField.setToolTipText(projectNameToolTipText);
- projectNameLabel.setToolTipText(projectNameToolTipText);
- canvas.add(projectNameLabel, UiUtil.getLabelConstraints(indentLevel));
- canvas.add(projectNameField, UiUtil.getFillLineConstraints(0));
-
- projectViewUi.fillUi(canvas, indentLevel);
- }
-
- public void update(BlazeNewProjectBuilder builder) {
- BlazeSelectWorkspaceOption workspaceOption = builder.getWorkspaceOption();
- BlazeSelectProjectViewOption projectViewOption = builder.getProjectViewOption();
- String workspaceName = workspaceOption.getWorkspaceName();
- WorkspaceRoot workspaceRoot = workspaceOption.getTemporaryWorkspaceRoot();
- WorkspacePath workspacePath = projectViewOption.getSharedProjectView();
- String initialProjectViewText = projectViewOption.getInitialProjectViewText();
-
- HashCode hashCode = Hashing.md5().newHasher()
- .putUnencodedChars(workspaceName)
- .putUnencodedChars(workspaceRoot.toString())
- .putUnencodedChars(workspacePath != null ? workspacePath.toString() : "")
- .putUnencodedChars(initialProjectViewText != null ? initialProjectViewText : "")
- .hash();
-
- // If any params have changed, reinit the control
- if (!hashCode.equals(paramsHash)) {
- this.paramsHash = hashCode;
- init(workspaceName, workspaceRoot, workspacePath, initialProjectViewText);
- }
- }
-
- private void init(String workspaceName,
- WorkspaceRoot workspaceRoot,
- @Nullable WorkspacePath sharedProjectView,
- @Nullable String initialProjectViewText) {
-
- projectNameField.setText(workspaceName);
- String defaultDataDir = getDefaultProjectDataDirectory(workspaceName);
- projectDataDirField.setText(defaultDataDir);
-
- String projectViewText = "";
- File sharedProjectViewFile = null;
-
- if (sharedProjectView != null) {
- sharedProjectViewFile = workspaceRoot.fileForPath(sharedProjectView);
-
- try {
- projectViewText = ProjectViewStorageManager.getInstance().loadProjectView(sharedProjectViewFile);
- if (projectViewText == null) {
- LOG.error("Could not load project view: " + sharedProjectViewFile);
- projectViewText = "";
- }
- }
- catch (IOException e) {
- LOG.error(e);
- }
- } else {
- projectViewText = initialProjectViewText;
- LOG.assertTrue(projectViewText != null);
- }
-
- projectViewUi.init(
- workspaceRoot,
- projectViewText,
- sharedProjectViewFile != null ? projectViewText : null,
- sharedProjectViewFile,
- sharedProjectViewFile != null,
- false /* allowEditShared - not allowed during import */
- );
- }
-
- private static String getDefaultProjectDataDirectory(String projectName) {
- File defaultDataDirectory = new File(getDefaultProjectsDirectory());
- File desiredLocation = new File(defaultDataDirectory, projectName);
- return newUniquePath(desiredLocation);
- }
-
- private static String getDefaultProjectsDirectory() {
- final String lastProjectLocation = RecentProjectsManager.getInstance().getLastProjectCreationLocation();
- if (lastProjectLocation != null) {
- return lastProjectLocation.replace('/', File.separatorChar);
- }
- final String userHome = SystemProperties.getUserHome();
- String productName = ApplicationNamesInfo.getInstance().getLowercaseProductName();
- return userHome.replace('/', File.separatorChar) + File.separator + productName.replace(" ", "") + "Projects";
- }
-
- /**
- * Returns a unique file path by appending numbers until a non-collision is found.
- */
- private static String newUniquePath(File location) {
- if (!location.exists()) {
- return location.getAbsolutePath();
- }
-
- String name = location.getName();
- File directory = location.getParentFile();
- int tries = 0;
- while (true) {
- String candidateName = String.format("%s-%02d", name, tries);
- File candidateFile = new File(directory, candidateName);
- if (!candidateFile.exists()) {
- return candidateFile.getAbsolutePath();
- }
- tries++;
- }
- }
-
- public BlazeValidationResult validate() {
- // Validate project settings fields
- String projectName = projectNameField.getText().trim();
- if (StringUtil.isEmpty(projectName)) {
- return BlazeValidationResult.failure(new BlazeValidationError("Project name is not specified"));
- }
- String projectDataDirPath = projectDataDirField.getText().trim();
- if (StringUtil.isEmpty(projectDataDirPath)) {
- return BlazeValidationResult.failure(new BlazeValidationError("Project data directory is not specified"));
- }
- File projectDataDir = new File(projectDataDirPath);
- if (!projectDataDir.isAbsolute()) {
- return BlazeValidationResult.failure(new BlazeValidationError("Project data directory is not valid"));
- }
-
- List<IssueOutput> issues = Lists.newArrayList();
-
- projectViewUi.parseProjectView(issues);
- BlazeValidationError projectViewParseError = validationErrorFromIssueList(issues);
- if (projectViewParseError != null) {
- return BlazeValidationResult.failure(projectViewParseError);
- }
-
- return BlazeValidationResult.success();
- }
-
- @Nullable
- private static BlazeValidationError validationErrorFromIssueList(List<IssueOutput> issues) {
- List<IssueOutput> errors = issues
- .stream()
- .filter(issue -> issue.getCategory() == IssueOutput.Category.ERROR)
- .collect(Collectors.toList());
-
- if (!errors.isEmpty()) {
- StringBuilder errorMessage = new StringBuilder();
- errorMessage.append("The following issues were found:\n\n");
- for (IssueOutput issue : errors) {
- errorMessage.append(issue.getMessage());
- errorMessage.append('\n');
- }
- return new BlazeValidationError(errorMessage.toString());
- }
- return null;
- }
-
- public void updateBuilder(BlazeNewProjectBuilder builder) {
- String projectName = projectNameField.getText().trim();
- String projectDataDirectory = projectDataDirField.getText().trim();
- File localProjectViewFile = ProjectViewStorageManager.getLocalProjectViewFileName(
- builder.getBuildSystem(), new File(projectDataDirectory)
- );
-
- BlazeSelectProjectViewOption selectProjectViewOption = builder.getProjectViewOption();
- boolean useSharedProjectView = projectViewUi.getUseSharedProjectView();
-
-
- // If we're using a shared project view, synthesize a local one that imports the shared one
- ProjectViewSet parseResult = projectViewUi.parseProjectView(Lists.newArrayList());
-
- final ProjectView projectView;
- final ProjectViewSet projectViewSet;
- if (useSharedProjectView && selectProjectViewOption.getSharedProjectView() != null) {
- projectView = ProjectView.builder()
- .put(ScalarSection.builder(ImportSection.KEY)
- .set(selectProjectViewOption.getSharedProjectView()))
- .build();
- projectViewSet = ProjectViewSet.builder()
- .addAll(parseResult.getProjectViewFiles())
- .add(localProjectViewFile, projectView)
- .build();
- } else {
- ProjectViewSet.ProjectViewFile projectViewFile = parseResult.getTopLevelProjectViewFile();
- assert projectViewFile != null;
- projectView = projectViewFile.projectView;
- projectViewSet = parseResult;
- }
-
- builder
- .setProjectView(projectView)
- .setProjectViewFile(localProjectViewFile)
- .setProjectViewSet(projectViewSet)
- .setProjectName(projectName)
- .setProjectDataDirectory(projectDataDirectory);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectOptionControl.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectOptionControl.java
deleted file mode 100644
index 8a5a8d6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectOptionControl.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2.ui;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.settings.ui.ProjectViewUi;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.BlazeWizardOption;
-import com.google.idea.blaze.base.wizard2.BlazeWizardUserSettings;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.ui.components.panels.HorizontalLayout;
-import com.intellij.ui.components.panels.VerticalLayout;
-
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import java.awt.*;
-import java.util.Collection;
-
-
-/**
- * UI for selecting a client during the import process.
- */
-public abstract class BlazeSelectOptionControl<T extends BlazeWizardOption> {
- private static final Logger LOG = Logger.getInstance(BlazeSelectOptionControl.class);
-
- private final BlazeWizardUserSettings userSettings;
- private final JPanel canvas;
- private final JLabel titleLabel;
- private final Collection<OptionUiEntry<T>> optionUiEntryList;
-
- static class OptionUiEntry<T> {
- final T option;
- final JRadioButton radioButton;
- OptionUiEntry(T option, JRadioButton radioButton) {
- this.option = option;
- this.radioButton = radioButton;
- }
- }
-
- BlazeSelectOptionControl(BlazeNewProjectBuilder builder,
- Collection<T> options) {
- if (options == null) {
- LOG.error("No options on select screen '" + getTitle() + "'");
- }
-
- this.userSettings = builder.getUserSettings();
-
- JPanel canvas = new JPanel(new VerticalLayout(4));
-
- Dimension minSize = ProjectViewUi.getMinimumSize();
- canvas.setPreferredSize(minSize);
-
- titleLabel = new JLabel(getTitle());
- canvas.add(titleLabel);
- canvas.add(new JSeparator());
-
- JPanel content = new JPanel(new VerticalLayout(12));
- content.setBorder(new EmptyBorder(20, 100, 0, 0));
- canvas.add(content);
-
- ButtonGroup buttonGroup = new ButtonGroup();
- Collection<OptionUiEntry<T>> optionUiEntryList = Lists.newArrayList();
- for (T option : options) {
- JPanel vertical = new JPanel(new VerticalLayout(10));
- JRadioButton radioButton = new JRadioButton();
- radioButton.setText(option.getOptionText());
- vertical.add(radioButton);
-
- JComponent optionComponent = option.getUiComponent();
- if (optionComponent != null) {
- JPanel horizontal = new JPanel(new HorizontalLayout(0));
- horizontal.setBorder(new EmptyBorder(0, 25, 0, 0));
- horizontal.add(optionComponent);
- vertical.add(horizontal);
-
- UiUtil.setEnabledRecursive(optionComponent, false);
- radioButton.addItemListener(itemEvent -> {
- boolean isSelected = radioButton.isSelected();
- UiUtil.setEnabledRecursive(optionComponent, isSelected);
- });
- }
-
- content.add(vertical);
- buttonGroup.add(radioButton);
- optionUiEntryList.add(new OptionUiEntry<>(option, radioButton));
- }
-
- OptionUiEntry selected = null;
- String previouslyChosenOption = userSettings.get(getOptionKey(), null);
- if (previouslyChosenOption != null) {
- for (OptionUiEntry<T> entry : optionUiEntryList) {
- if (entry.option.getOptionName().equals(previouslyChosenOption)) {
- selected = entry;
- break;
- }
- }
- }
- if (selected == null) {
- selected = Iterables.getFirst(optionUiEntryList, null);
- }
- if (selected != null) {
- selected.radioButton.setSelected(true);
- }
-
- this.canvas = canvas;
- this.optionUiEntryList = optionUiEntryList;
- }
-
- public BlazeValidationResult validate() {
- T option = getSelectedOption();
- if (option == null) {
- return BlazeValidationResult.failure("No option selected.");
- }
- return option.validate();
- }
-
- public JComponent getUiComponent() {
- return canvas;
- }
-
- public T getSelectedOption() {
- for (OptionUiEntry<T> entry : optionUiEntryList) {
- if (entry.radioButton.isSelected()) {
- return entry.option;
- }
- }
- return null;
- }
-
- public void commit() {
- T selectedOption = getSelectedOption();
- if (selectedOption != null) {
- userSettings.put(getOptionKey(), selectedOption.getOptionName());
- }
- }
-
- /**
- * Call when the title changes.
- */
- protected void setTitle(String newTitle) {
- titleLabel.setText(newTitle);
- }
-
- abstract String getTitle();
-
- abstract String getOptionKey();
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectProjectViewControl.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectProjectViewControl.java
deleted file mode 100644
index 9668287..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectProjectViewControl.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2.ui;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.BlazeSelectProjectViewOption;
-import com.google.idea.blaze.base.wizard2.BlazeWizardOptionProvider;
-
-import javax.swing.*;
-import java.util.Collection;
-
-
-/**
- * UI for selecting the project view during the import process.
- */
-public class BlazeSelectProjectViewControl {
-
- private BlazeSelectOptionControl<BlazeSelectProjectViewOption> selectOptionControl;
-
- public BlazeSelectProjectViewControl(BlazeNewProjectBuilder builder) {
- Collection<BlazeSelectProjectViewOption> options = Lists.newArrayList();
- for (BlazeWizardOptionProvider optionProvider : BlazeWizardOptionProvider.EP_NAME.getExtensions()) {
- options.addAll(optionProvider.getSelectProjectViewOptions(builder));
- }
-
- this.selectOptionControl =
- new BlazeSelectOptionControl<BlazeSelectProjectViewOption>(builder, options) {
- @Override
- String getTitle() {
- return BlazeSelectProjectViewControl.getTitle(builder);
- }
-
- @Override
- String getOptionKey() {
- return "select-project-view.selected-option";
- }
- };
- }
-
- public JComponent getUiComponent() {
- return selectOptionControl.getUiComponent();
- }
-
- public BlazeValidationResult validate() {
- return selectOptionControl.validate();
- }
-
- public void update(BlazeNewProjectBuilder builder) {
- selectOptionControl.setTitle(getTitle(builder));
- }
-
- public void updateBuilder(BlazeNewProjectBuilder builder) {
- builder.setProjectViewOption(selectOptionControl.getSelectedOption());
- }
-
- public void commit() {
- selectOptionControl.commit();
- }
-
- private static String getTitle(BlazeNewProjectBuilder builder) {
- String projectViewString = ProjectViewStorageManager.getProjectViewFileName(builder.getBuildSystem());
- return String.format("Select project view (%s file)", projectViewString);
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectWorkspaceControl.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectWorkspaceControl.java
deleted file mode 100644
index d32deb1..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/BlazeSelectWorkspaceControl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2.ui;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.BlazeSelectWorkspaceOption;
-import com.google.idea.blaze.base.wizard2.BlazeWizardOptionProvider;
-
-import javax.swing.*;
-import java.util.Collection;
-
-
-/**
- * UI for selecting a client during the import process.
- */
-public class BlazeSelectWorkspaceControl {
- BlazeSelectOptionControl<BlazeSelectWorkspaceOption> selectOptionControl;
-
- public BlazeSelectWorkspaceControl(BlazeNewProjectBuilder builder) {
- Collection<BlazeSelectWorkspaceOption> options = Lists.newArrayList();
- for (BlazeWizardOptionProvider optionProvider : BlazeWizardOptionProvider.EP_NAME.getExtensions()) {
- options.addAll(optionProvider.getSelectWorkspaceOptions(builder));
- }
-
- this.selectOptionControl =
- new BlazeSelectOptionControl<BlazeSelectWorkspaceOption>(builder, options) {
- @Override
- String getTitle() {
- return "Select workspace";
- }
-
- @Override
- String getOptionKey() {
- return "select-workspace.selected-option";
- }
- };
- }
-
- public JComponent getUiComponent() {
- return selectOptionControl.getUiComponent();
- }
-
- public BlazeValidationResult validate() {
- return selectOptionControl.validate();
- }
-
- public void updateBuilder(BlazeNewProjectBuilder builder) {
- builder.setWorkspaceOption(selectOptionControl.getSelectedOption());
- }
-
- public void commit() {
- selectOptionControl.commit();
- }
-}
diff --git a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/SelectBazelBinaryControl.java b/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/SelectBazelBinaryControl.java
deleted file mode 100644
index d2acbb6..0000000
--- a/blaze-base/src/com/google/idea/blaze/base/wizard2/ui/SelectBazelBinaryControl.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.wizard2.ui;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.settings.ui.BlazeUserSettingsConfigurable;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.ui.FileSelectorWithStoredHistory;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.intellij.ui.components.panels.VerticalLayout;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import javax.swing.border.EmptyBorder;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-
-/**
- * UI for selecting the build system binary during the import process.
- */
-public class SelectBazelBinaryControl {
-
- public final BlazeNewProjectBuilder builder;
-
- private boolean uiInitialized = false;
- private JPanel component;
- private FileSelectorWithStoredHistory bazelBinaryPath;
-
- public SelectBazelBinaryControl(BlazeNewProjectBuilder builder) {
- this.builder = builder;
- }
-
- public JComponent getUiComponent() {
- if (!uiInitialized) {
- initUi();
- uiInitialized = true;
- }
- return component;
- }
-
- private void initUi() {
- bazelBinaryPath = FileSelectorWithStoredHistory.create(
- BlazeUserSettingsConfigurable.BAZEL_BINARY_PATH_KEY,
- "Specify the bazel binary path");
- bazelBinaryPath.setText(getInitialBinaryPath());
-
- component = new JPanel(new VerticalLayout(4));
- component.add(new JLabel("Select a bazel binary"));
- component.add(new JSeparator());
-
- JPanel content = new JPanel(new VerticalLayout(12));
- content.setBorder(new EmptyBorder(50, 100, 0, 100));
- component.add(content);
-
- content.add(new JLabel("Specify a bazel binary to be used for all bazel projects"));
- content.add(bazelBinaryPath);
- }
-
- public BlazeValidationResult validate() {
- String binaryPath = getBazelPath();
- if (Strings.isNullOrEmpty(binaryPath)) {
- return BlazeValidationResult.failure("Select a bazel binary");
- }
- if (!FileAttributeProvider.getInstance().isFile(new File(binaryPath))) {
- return BlazeValidationResult.failure("Invalid bazel binary: file does not exist");
- }
- return BlazeValidationResult.success();
- }
-
- public void commit() {
- if (!Strings.isNullOrEmpty(getBazelPath())) {
- BlazeUserSettings.getInstance().setBazelBinaryPath(getBazelPath());
- }
- }
-
- private String getBazelPath() {
- String text = bazelBinaryPath.getText();
- return text != null ? text.trim() : "";
- }
-
- private static String getInitialBinaryPath() {
- String existingPath = BlazeUserSettings.getInstance().getBazelBinaryPath();
- if (existingPath != null) {
- return existingPath;
- }
- return guessBinaryPath();
- }
-
- /**
- * Try to guess an initial binary path
- */
- @Nullable
- private static String guessBinaryPath() {
- ByteArrayOutputStream stdout = new ByteArrayOutputStream();
- int retVal = ExternalTask.builder(new File("/"), ImmutableList.of("which", "bazel"))
- .stdout(stdout)
- .build()
- .run();
-
- if (retVal != 0) {
- return null;
- }
- return stdout.toString().trim();
- }
-
-}
diff --git a/blaze-base/src/icons/BlazeIcons.java b/blaze-base/src/icons/BlazeIcons.java
deleted file mode 100644
index b21c7ef..0000000
--- a/blaze-base/src/icons/BlazeIcons.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 icons;
-
-import com.intellij.openapi.util.IconLoader;
-
-import javax.swing.*;
-
-/**
- * Class to manage icons used by the Blaze plugin.
- */
-public class BlazeIcons {
-
- public static final Icon Blaze = load("/blaze-base/resources/icons/blaze.png"); // 16x16
- public static final Icon BlazeSlow = load("/blaze-base/resources/icons/blaze_slow.png"); // 16x16
- public static final Icon BlazeDirty = load("/blaze-base/resources/icons/blaze_dirty.png"); // 16x16
- public static final Icon BlazeClean = load("/blaze-base/resources/icons/blaze_clean.png"); // 16x16
- public static final Icon BlazeFailed = load("/blaze-base/resources/icons/blaze_failed.png"); // 16x16
- // This is just the Blaze icon scaled down to the size IJ wants for tool windows.
- public static final Icon BlazeToolWindow = load("/blaze-base/resources/icons/blazeToolWindow.png"); // 13x13
-
- public static final Icon BazelLeaf = load("/blaze-base/resources/icons/bazel_leaf.png"); // 16x16
-
- // Build file support icons
- public static final Icon BuildFile = load("/blaze-base/resources/icons/build_file.png"); // 16x16
- public static final Icon BuildRule = load("/blaze-base/resources/icons/build_rule.png"); // 16x16
-
- private static Icon load(String path) {
- return IconLoader.getIcon(path, BlazeIcons.class);
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributorTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributorTest.java
deleted file mode 100644
index 31ec67c..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ArgumentCompletionContributorTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.editor.Editor;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for code completion of funcall arguments.
- */
-public class ArgumentCompletionContributorTest extends BuildFileIntegrationTestCase {
-
- public void testIncompleteFuncall() {
- BuildFile file = createBuildFile(
- "BUILD",
- "def function(name, deps, srcs):",
- " # empty function",
- "function(d");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 2, "function(n".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isNull();
-
- assertFileContents(
- file,
- "def function(name, deps, srcs):",
- " # empty function",
- "function(deps");
- }
-
- public void testExistingKeywordArg() {
- BuildFile file = createBuildFile(
- "BUILD",
- "def function(name, deps, srcs):",
- " # empty function",
- "function(name = \"lib\")");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 2, "function(".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).hasLength(4);
- assertThat(completionItems).asList().containsAllOf("name", "deps", "srcs", "function");
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributorTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributorTest.java
deleted file mode 100644
index 7b0f616..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionAttributeCompletionContributorTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.AttributeDefinition;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for BuiltInFunctionAttributeCompletionContributor.
- */
-public class BuiltInFunctionAttributeCompletionContributorTest extends BuildFileIntegrationTestCase {
-
- private MockBuildLanguageSpecProvider specProvider;
-
- @Override
- protected void doSetup() {
- super.doSetup();
- specProvider = new MockBuildLanguageSpecProvider();
- registerApplicationService(BuildLanguageSpecProvider.class, specProvider);
- }
-
- public void testSimpleCompletion() {
- setRuleAndAttributes("sh_binary",
- "name", "deps", "srcs", "data");
-
- BuildFile file = createBuildFile(
- "BUILD",
- "sh_binary(");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, "sh_binary(".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).asList().containsAllOf("name", "deps", "srcs", "data");
- }
-
- public void testSimpleSingleCompletion() {
- setRuleAndAttributes("sh_binary",
- "name", "deps", "srcs", "data");
-
- BuildFile file = createBuildFile(
- "BUILD",
- "sh_binary(",
- " n");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 1, " n".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isNull();
- assertFileContents(file,
- "sh_binary(",
- " name");
- }
-
- public void testNoCompletionInUnknownRule() {
- setRuleAndAttributes("sh_binary",
- "name", "deps", "srcs", "data");
-
- BuildFile file = createBuildFile(
- "BUILD",
- "java_binary(");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, "java_binary(".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isEmpty();
- }
-
- public void testCompletionInSkylarkExtension() {
- setRuleAndAttributes("sh_binary",
- "name", "deps", "srcs", "data");
-
- BuildFile file = createBuildFile(
- "skylark.bzl",
- "native.sh_binary(");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, "native.sh_binary(".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).asList().containsAllOf("name", "deps", "srcs", "data");
- }
-
- private void setRuleAndAttributes(String ruleName, String... attributes) {
- ImmutableMap.Builder<String, AttributeDefinition> map = ImmutableMap.builder();
- for (String attr : attributes) {
- map.put(attr, new AttributeDefinition(attr, Build.Attribute.Discriminator.UNKNOWN, false, null, null));
- }
- RuleDefinition rule = new RuleDefinition(ruleName, map.build(), null);
- specProvider.setRules(ImmutableMap.of(ruleName, rule));
- }
-
- private static class MockBuildLanguageSpecProvider implements BuildLanguageSpecProvider {
-
- BuildLanguageSpec languageSpec;
-
- void setRules(ImmutableMap<String, RuleDefinition> rules) {
- languageSpec = new BuildLanguageSpec(rules);
- }
-
- @Nullable
- @Override
- public BuildLanguageSpec getLanguageSpec(Project project) {
- return languageSpec;
- }
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributorTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributorTest.java
deleted file mode 100644
index 008217b..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/BuiltInFunctionCompletionContributorTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpecProvider;
-import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests BuiltInFunctionCompletionContributor
- */
-public class BuiltInFunctionCompletionContributorTest extends BuildFileIntegrationTestCase {
-
- private MockBuildLanguageSpecProvider specProvider;
-
- @Override
- protected void doSetup() {
- super.doSetup();
- specProvider = new MockBuildLanguageSpecProvider();
- registerApplicationService(BuildLanguageSpecProvider.class, specProvider);
- }
-
- public void testSimpleTopLevelCompletion() {
- setRules("java_library", "android_binary");
-
- BuildFile file = createBuildFile(
- "BUILD",
- "");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, 0);
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).hasLength(2);
- assertThat(completionItems[0].getLookupString()).isEqualTo("android_binary");
- assertThat(completionItems[1].getLookupString()).isEqualTo("java_library");
-
- assertFileContents(file, "");
- }
-
- public void testUniqueTopLevelCompletion() {
- setRules("java_library", "android_binary");
-
- BuildFile file = createBuildFile(
- "BUILD",
- "ja");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, 2);
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isNull();
-
- assertFileContents(file, "java_library()");
- assertCaretPosition(editor, 0, "java_library(".length());
- }
-
- public void testSkylarkNativeCompletion() {
- setRules("java_library", "android_binary");
-
- BuildFile file = createBuildFile(
- "build_defs.bzl",
- "def function():",
- " native.j");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 1, " native.j".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isNull();
-
- assertFileContents(file,
- "def function():",
- " native.java_library()");
- assertCaretPosition(editor, 1, " native.java_library(".length());
- }
-
- public void testNoCompletionInsideRule() {
- setRules("java_library", "android_binary");
-
- String[] contents = {
- "java_library(",
- " name = \"lib\"",
- ""};
-
- BuildFile file = createBuildFile("BUILD", contents);
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 2, 0);
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isEmpty();
- assertFileContents(file, contents);
- }
-
- private void setRules(String... ruleNames) {
- ImmutableMap.Builder<String, RuleDefinition> rules = ImmutableMap.builder();
- for (String name : ruleNames) {
- rules.put(name, new RuleDefinition(name, ImmutableMap.of(), null));
- }
- specProvider.setRules(rules.build());
- }
-
- private static class MockBuildLanguageSpecProvider implements BuildLanguageSpecProvider {
-
- BuildLanguageSpec languageSpec;
-
- void setRules(ImmutableMap<String, RuleDefinition> rules) {
- languageSpec = new BuildLanguageSpec(rules);
- }
-
- @Nullable
- @Override
- public BuildLanguageSpec getLanguageSpec(Project project) {
- return languageSpec;
- }
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/FilePathCompletionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/FilePathCompletionTest.java
deleted file mode 100644
index 36b8857..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/FilePathCompletionTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests file path code completion in BUILD file labels.
- */
-public class FilePathCompletionTest extends BuildFileIntegrationTestCase {
-
- public void testUniqueDirectoryCompleted() {
- BuildFile file = createBuildFile(
- "java/BUILD",
- "'//'");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 0, "'//".length());
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "'//java'");
- // check caret remains inside closing quote
- assertCaretPosition(editor, 0, "'//java".length());
- }
-
- public void testUniqueMultiSegmentDirectoryCompleted() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "'//'");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 0, "'//".length());
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "'//java/com/google'");
- }
-
- // expected to be a typical workflow -- complete a segment, get the possibilities, then start typing
- // next segment and complete again
- public void testMultiStageCompletion() {
- createDirectory("foo");
- createDirectory("bar");
- createDirectory("other");
- createDirectory("other/foo");
- createDirectory("other/bar");
-
- BuildFile file = createBuildFile(
- "BUILD",
- "'//'");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 0, "'//".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).hasLength(3);
-
- performTypingAction(editor, 'o');
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "'//other'");
- assertCaretPosition(editor, 0, "'//other".length());
-
- performTypingAction(editor, '/');
- performTypingAction(editor, 'f');
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "'//other/foo'");
- assertCaretPosition(editor, 0, "'//other/foo".length());
- }
-
- public void testCompletionSuggestionString() {
- createDirectory("foo");
- createDirectory("bar");
- createDirectory("other");
- createDirectory("ostrich/foo");
- createDirectory("ostrich/fooz");
-
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "'//o<caret>'");
-
- String[] completionItems = getCompletionItemsAsSuggestionStrings();
- assertThat(completionItems).asList().containsExactly("other", "ostrich");
-
- performTypingAction(testFixture.getEditor(), 's');
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "'//ostrich'");
-
- completionItems = getCompletionItemsAsSuggestionStrings();
- assertThat(completionItems).asList().containsExactly("/foo", "/fooz");
-
- performTypingAction(testFixture.getEditor(), '/');
-
- completionItems = getCompletionItemsAsSuggestionStrings();
- assertThat(completionItems).asList().containsExactly("foo", "fooz");
-
- performTypingAction(testFixture.getEditor(), 'f');
-
- completionItems = getCompletionItemsAsSuggestionStrings();
- assertThat(completionItems).asList().containsExactly("foo", "fooz");
- }
-
- private VirtualFile createAndSetCaret(String filePath, String... fileContents) {
- VirtualFile file = createFile(filePath, fileContents);
- testFixture.configureFromExistingVirtualFile(file);
- return file;
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/LocalSymbolCompletionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/LocalSymbolCompletionTest.java
deleted file mode 100644
index 4d24fab..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/LocalSymbolCompletionTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.common.base.Joiner;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.psi.PsiFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests code completion works with general symbols in scope.
- */
-public class LocalSymbolCompletionTest extends BuildFileIntegrationTestCase {
-
- private PsiFile setInput(String... fileContents) {
- return testFixture.configureByText("BUILD", Joiner.on("\n").join(fileContents));
- }
-
- private void assertResult(String... resultingFileContents) {
- String s = testFixture.getFile().getText();
- testFixture.checkResult(Joiner.on("\n").join(resultingFileContents));
- }
-
- public void testLocalVariable() {
- setInput(
- "var = [a, b]",
- "def function(name, deps, srcs):",
- " v<caret>"
- );
-
- completeIfUnique();
-
- assertResult(
- "var = [a, b]",
- "def function(name, deps, srcs):",
- " var<caret>"
- );
- }
-
- public void testLocalFunction() {
- setInput(
- "def fnName():return True",
- "def function(name, deps, srcs):",
- " fnN<caret>"
- );
-
- completeIfUnique();
-
- assertResult(
- "def fnName():return True",
- "def function(name, deps, srcs):",
- " fnName<caret>"
- );
- }
-
- public void testNoCompletionAfterDot() {
- setInput(
- "var = [a, b]",
- "def function(name, deps, srcs):",
- " ext.v<caret>"
- );
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isEmpty();
- }
-
- public void testFunctionParam() {
- setInput(
- "def test(var):",
- " v<caret>"
- );
-
- completeIfUnique();
-
- assertResult(
- "def test(var):",
- " var<caret>"
- );
- }
-
- // b/28912523: when symbol is present in multiple assignment statements, should only be
- // included once in the code-completion dialog
- public void testSymbolAssignedMultipleTimes() {
- setInput(
- "var = 1",
- "var = 2",
- "var = 3",
- "<caret>"
- );
-
- completeIfUnique();
-
- assertResult(
- "var = 1",
- "var = 2",
- "var = 3",
- "var<caret>"
- );
- }
-
- public void testSymbolDefinedOutsideScope() {
- setInput(
- "<caret>",
- "var = 1"
- );
-
- assertThat(getCompletionItemsAsStrings()).isEmpty();
- }
-
- public void testSymbolDefinedOutsideScope2() {
- setInput(
- "def fn():",
- " var = 1",
- "v<caret>"
- );
-
- assertThat(testFixture.completeBasic()).isEmpty();
- }
-
- public void testSymbolDefinedOutsideScope3() {
- setInput(
- "for var in (1, 2, 3): print var",
- "v<caret>"
- );
-
- assertThat(testFixture.completeBasic()).isEmpty();
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributorTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributorTest.java
deleted file mode 100644
index 9aeb6ba..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/ParameterCompletionContributorTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.editor.Editor;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests ParameterCompletionContributor.
- */
-public class ParameterCompletionContributorTest extends BuildFileIntegrationTestCase {
-
- public void testArgsCompletion() {
- BuildFile file = createBuildFile(
- "BUILD",
- "def function(arg1, *");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, "def function(arg1, *".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isNull();
-
- assertFileContents(file, "def function(arg1, *args");
- }
-
- public void testKwargsCompletion() {
- BuildFile file = createBuildFile(
- "BUILD",
- "def function(arg1, **");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 0, "def function(arg1, **".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isNull();
-
- assertFileContents(file, "def function(arg1, **kwargs");
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/RuleTargetCompletionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/RuleTargetCompletionTest.java
deleted file mode 100644
index a2e8599..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/RuleTargetCompletionTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.openapi.editor.Editor;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests code completion of rule target labels.
- */
-public class RuleTargetCompletionTest extends BuildFileIntegrationTestCase {
-
- public void testLocalTarget() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = 'lib')",
- "java_library(",
- " name = 'test',",
- " deps = [':']");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 3, " deps = [':".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).hasLength(1);
- assertThat(completionItems[0].toString()).isEqualTo("':lib'");
- }
-
- public void testIgnoreContainingTarget() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "java_library(",
- " name = 'lib',",
- " deps = [':']");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 2, " deps = [':".length());
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems).isEmpty();
- }
-
- public void testNotCodeCompletionInNameField() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = 'lib')",
- "java_library(",
- " name = 'l'",
- ")");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 2, " name = 'l".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isEmpty();
- }
-
- public void testNonLocalTarget() {
- BuildFile foo = createBuildFile(
- "java/com/google/foo/BUILD",
- "java_library(name = 'foo_lib')");
-
- BuildFile bar = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(",
- " name = 'bar_lib',",
- " deps = '//java/com/google/foo:')");
-
- Editor editor = openFileInEditor(bar);
- setCaretPosition(editor, 2, " deps = '//java/com/google/foo:".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).asList().containsExactly("'//java/com/google/foo:foo_lib'");
- }
-
- public void testNonLocalRulesNotCompletedWithoutColon() {
- BuildFile foo = createBuildFile(
- "java/com/google/foo/BUILD",
- "java_library(name = 'foo_lib')");
-
- BuildFile bar = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(",
- " name = 'bar_lib',",
- " deps = '//java/com/google/foo')");
-
- Editor editor = openFileInEditor(bar);
- setCaretPosition(editor, 2, " deps = '//java/com/google/foo".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isEmpty();
- }
-
- public void testPackageLocalRulesCompletedWithoutColon() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = 'lib')",
- "java_library(",
- " name = 'test',",
- " deps = ['']");
-
- Editor editor = openFileInEditor(file);
- setCaretPosition(editor, 3, " deps = ['".length());
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(
- file,
- "java_library(name = 'lib')",
- "java_library(",
- " name = 'test',",
- " deps = ['lib']");
- }
-
- public void testLocalPathIgnoredForNonLocalLabels() {
- BuildFile rootPackage = createBuildFile(
- "java/BUILD",
- "java_library(name = 'root_rule')");
-
- BuildFile otherPackage = createBuildFile(
- "java/com/google/BUILD",
- "java_library(",
- "java_library(name = 'other_rule')",
- " name = 'lib',",
- " deps = ['//java:']");
-
- Editor editor = openFileInEditor(otherPackage);
- setCaretPosition(editor, 3, " deps = ['//java:".length());
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).asList().contains("'//java:root_rule'");
- assertThat(completionItems).asList().doesNotContain("'//java/com/google:other_rule'");
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionCompletionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionCompletionTest.java
deleted file mode 100644
index 01bac37..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionCompletionTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests auto-complete of skylark bzl files in 'load' statements.
- */
-public class SkylarkExtensionCompletionTest extends BuildFileIntegrationTestCase {
-
- private VirtualFile createAndSetCaret(String filePath, String... fileContents) {
- VirtualFile file = createFile(filePath, fileContents);
- testFixture.configureFromExistingVirtualFile(file);
- return file;
- }
-
- public void testSimpleCase() {
- createFile("skylark.bzl");
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl'");
- }
-
- public void testSelfNotInResults() {
- createFile("BUILD");
- VirtualFile file = createAndSetCaret(
- "self.bzl",
- "load(':<caret>'");
-
- assertThat(testFixture.completeBasic()).isEmpty();
- }
-
- public void testSelfNotInResults2() {
- createFile("skylark.bzl");
- createFile("BUILD");
- VirtualFile file = createAndSetCaret(
- "self.bzl",
- "load(':<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl'");
- }
-
- public void testNoRulesInResults() {
- createFile("java/com/google/foo/skylark.bzl");
- createFile(
- "java/com/google/foo/BUILD",
- "java_library(name = 'foo')");
- VirtualFile file = createAndSetCaret(
- "java/com/google/bar/BUILD",
- "load('//java/com/google/foo:<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load('//java/com/google/foo:skylark.bzl'");
-
- // now check that the rule would have been picked up outside of the 'load' context
- file = createAndSetCaret(
- "java/com/google/baz/BUILD",
- "'//java/com/google/foo:<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "'//java/com/google/foo:foo'");
- }
-
- public void testNonSkylarkFilesNotInResults() {
- createFile("java/com/google/foo/text.txt");
-
- VirtualFile file = createAndSetCaret(
- "java/com/google/bar/BUILD",
- "load('//java/com/google/foo:<caret>'");
-
- assertThat(testFixture.completeBasic()).isEmpty();
- }
-
- public void testLabelStartsWithColon() {
- createFile("java/com/google/skylark.bzl");
- VirtualFile file = createAndSetCaret(
- "java/com/google/BUILD",
- "load(':<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl'");
- }
-
- public void testLabelStartsWithSlashes() {
- createFile("java/com/google/skylark.bzl");
- VirtualFile file = createAndSetCaret(
- "java/com/google/BUILD",
- "load('//java/com/google:<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load('//java/com/google:skylark.bzl'");
- }
-
- public void testLabelStartsWithSlashesWithoutColon() {
- createFile("java/com/google/skylark.bzl");
- VirtualFile file = createAndSetCaret(
- "java/com/google/BUILD",
- "load('//java/com/google<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load('//java/com/google:skylark.bzl'");
- }
-
- public void testDirectoryCompletionInLoadStatement() {
- createFile("java/com/google/skylark.bzl");
- VirtualFile file = createAndSetCaret(
- "java/com/google/BUILD",
- "load('//<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load('//java/com/google'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load('//java/com/google:skylark.bzl'");
- }
-
- public void testMultipleFiles() {
- createFile("java/com/google/skylark.bzl");
- createFile("java/com/google/other.bzl");
- VirtualFile file = createAndSetCaret(
- "java/com/google/BUILD",
- "load('//java/com/google:<caret>'");
-
- String[] strings = getCompletionItemsAsStrings();
- assertThat(strings).hasLength(2);
- assertThat(strings).asList().containsExactly("'//java/com/google:other.bzl'", "'//java/com/google:skylark.bzl'");
- }
-
- // relative paths in skylark extensions which lie in subdirectories are relative to the parent blaze package directory
- public void testRelativePathInSubdirectory() {
- createFile("java/com/google/BUILD");
- createFile(
- "java/com/google/nonPackageSubdirectory/skylark.bzl",
- "def function(): return");
- VirtualFile file = createAndSetCaret(
- "java/com/google/nonPackageSubdirectory/other.bzl",
- "load(':n<caret>'");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':nonPackageSubdirectory/skylark.bzl'");
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java
deleted file mode 100644
index c5870e5..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.completion;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests auto-complete of symbols loaded from skylark bzl files.
- */
-public class SkylarkExtensionSymbolCompletionTest extends BuildFileIntegrationTestCase {
-
- private VirtualFile createAndSetCaret(String filePath, String... fileContents) {
- VirtualFile file = createFile(filePath, fileContents);
- testFixture.configureFromExistingVirtualFile(file);
- return file;
- }
-
- public void testGlobalVariable() {
- createFile(
- "skylark.bzl",
- "VAR = []");
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':skylark.bzl', '<caret>')");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl', 'VAR')");
- }
-
- public void testFunctionStatement() {
- createFile(
- "skylark.bzl",
- "def fn(param):stmt");
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':skylark.bzl', '<caret>')");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl', 'fn')");
- }
-
- public void testMultipleOptions() {
- createFile(
- "skylark.bzl",
- "def fn(param):stmt",
- "VAR = []");
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':skylark.bzl', '<caret>')");
-
- String[] options = getCompletionItemsAsStrings();
- assertThat(options).asList().containsExactly("'fn'", "'VAR'");
- }
-
- public void testRulesNotIncluded() {
- createFile(
- "skylark.bzl",
- "java_library(name = 'lib')",
- "native.java_library(name = 'foo'");
-
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':skylark.bzl', '<caret>')");
-
- assertThat(testFixture.completeBasic()).isEmpty();
- }
-
- public void testLoadedSymbols() {
- createFile(
- "other.bzl",
- "def function()");
- createFile(
- "skylark.bzl",
- "load(':other.bzl', 'function')");
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':skylark.bzl', '<caret>')");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl', 'function')");
- }
-
- public void testNotLoadedSymbolsAreNotIncluded() {
- createFile(
- "other.bzl",
- "def function():stmt",
- "def other_function():stmt");
- createFile(
- "skylark.bzl",
- "load(':other.bzl', 'function')");
- VirtualFile file = createAndSetCaret(
- "BUILD",
- "load(':skylark.bzl', '<caret>')");
-
- assertThat(completeIfUnique()).isTrue();
- assertFileContents(file, "load(':skylark.bzl', 'function')");
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildBraceMatcherTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildBraceMatcherTest.java
deleted file mode 100644
index 7f2544c..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildBraceMatcherTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.common.base.Joiner;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.psi.PsiFile;
-
-/**
- * Test brace matching (auto-inserting closing braces when appropriate)
- */
-public class BuildBraceMatcherTest extends BuildFileIntegrationTestCase {
-
- private PsiFile setInput(String... fileContents) {
- return testFixture.configureByText("BUILD", Joiner.on("\n").join(fileContents));
- }
-
- public void testClosingParenInserted() {
- PsiFile file = setInput(
- "java_library<caret>"
- );
-
- performTypingAction(testFixture.getEditor(), '(');
-
- assertFileContents(
- file,
- "java_library()"
- );
- }
-
- public void testClosingBraceInserted() {
- PsiFile file = setInput(
- "<caret>"
- );
-
- performTypingAction(testFixture.getEditor(), '{');
-
- assertFileContents(
- file,
- "{}"
- );
- }
-
-
- public void testClosingBracketInserted() {
- PsiFile file = setInput(
- "<caret>"
- );
-
- performTypingAction(testFixture.getEditor(), '[');
-
- assertFileContents(
- file,
- "[]"
- );
- }
-
- public void testNoClosingBracketInsertedIfLaterDanglingRBracket() {
- PsiFile file = setInput(
- "java_library(",
- " srcs =<caret> 'source.java']",
- ")"
- );
-
- performTypingAction(testFixture.getEditor(), '[');
-
- assertFileContents(
- file,
- "java_library(",
- " srcs =[ 'source.java']",
- ")"
- );
- }
-
- public void testClosingBracketInsertedIfFollowedByWhitespace() {
- PsiFile file = setInput(
- "java_library(",
- " srcs =<caret> 'source.java'",
- ")"
- );
-
- performTypingAction(testFixture.getEditor(), '[');
-
- assertFileContents(
- file,
- "java_library(",
- " srcs =[] 'source.java'",
- ")"
- );
- }
-
- public void testNoClosingBraceInsertedWhenFollowedByIdentifier() {
- PsiFile file = setInput(
- "hello = <caret>test"
- );
-
- performTypingAction(testFixture.getEditor(), '(');
-
- assertFileContents(
- file,
- "hello = (test"
- );
-
- file = setInput(
- "hello = <caret>test"
- );
-
- performTypingAction(testFixture.getEditor(), '[');
-
- assertFileContents(
- file,
- "hello = [test"
- );
-
- file = setInput(
- "hello = <caret>test"
- );
-
- performTypingAction(testFixture.getEditor(), '{');
-
- assertFileContents(
- file,
- "hello = {test"
- );
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildIndentOnEnterTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildIndentOnEnterTest.java
deleted file mode 100644
index 06f5c70..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildIndentOnEnterTest.java
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.common.base.Joiner;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.openapi.actionSystem.IdeActions;
-
-/**
- * Tests that indents are inserted correctly when enter is pressed.
- */
-public class BuildIndentOnEnterTest extends BuildFileIntegrationTestCase {
-
- private void setInput(String... fileContents) {
- testFixture.configureByText("BUILD", Joiner.on("\n").join(fileContents));
- }
-
- private void pressEnterAndAssertResult(String... resultingFileContents) {
- pressButton(IdeActions.ACTION_EDITOR_ENTER);
- String s = testFixture.getFile().getText();
- testFixture.checkResult(Joiner.on("\n").join(resultingFileContents));
- }
-
- public void testSimpleIndent() {
- setInput(
- "a=1<caret>");
- pressEnterAndAssertResult(
- "a=1",
- "<caret>");
- }
-
- public void testAlignInListMiddle() {
- setInput(
- "target = [a,<caret>",
- " c]");
- pressEnterAndAssertResult(
- "target = [a,",
- " <caret>",
- " c]");
- }
-
- public void testNoAlignAfterList() {
- setInput(
- "target = [",
- " arg",
- "]<caret>");
- pressEnterAndAssertResult(
- "target = [",
- " arg",
- "]",
- "<caret>");
- }
-
- public void testAlignInDict() {
- setInput(
- "some_call({'aaa': 'v1',<caret>})");
- pressEnterAndAssertResult(
- "some_call({'aaa': 'v1',",
- " <caret>})");
- }
-
- public void testAlignInDictInParams() { // PY-1947
- setInput(
- "foobar({<caret>})");
- pressEnterAndAssertResult(
- "foobar({",
- " <caret>",
- "})");
- }
-
- public void testAlignInEmptyList() {
- setInput(
- "target = [<caret>]");
- pressEnterAndAssertResult(
- "target = [",
- " <caret>",
- "]");
- }
-
- public void testAlignInEmptyParens() {
- setInput(
- "foo(<caret>)");
- pressEnterAndAssertResult(
- "foo(",
- " <caret>",
- ")");
- }
-
- public void testAlignInEmptyDict() {
- setInput(
- "{<caret>}");
- pressEnterAndAssertResult(
- "{",
- " <caret>",
- "}");
- }
-
- public void testAlignInEmptyTuple() {
- setInput(
- "(<caret>)");
- pressEnterAndAssertResult(
- "(",
- " <caret>",
- ")");
- }
-
- public void testEnterInNonEmptyArgList() {
- setInput(
- "func(<caret>params=1)");
- pressEnterAndAssertResult(
- "func(",
- " <caret>params=1)");
- }
-
- public void testEmptyFuncallStart() {
- setInput(
- "func(<caret>",
- ")");
- pressEnterAndAssertResult(
- "func(",
- " <caret>",
- ")");
- }
-
- public void testEmptyFuncallAfterNewlineNoIndent() {
- setInput(
- "func(",
- "<caret>)");
- pressEnterAndAssertResult(
- "func(",
- "",
- "<caret>)");
- }
-
- public void testEmptyFuncallAfterNewlineWithIndent() {
- setInput(
- "func(",
- " <caret>",
- ")");
- pressEnterAndAssertResult(
- "func(",
- " ",
- " <caret>",
- ")");
- }
-
- public void testFuncallAfterFirstArg() {
- setInput(
- "func(",
- " arg1,<caret>",
- ")");
- pressEnterAndAssertResult(
- "func(",
- " arg1,",
- " <caret>",
- ")");
- }
-
- public void testFuncallFirstArgOnSameLine() {
- setInput(
- "func(arg1, arg2,<caret>");
- pressEnterAndAssertResult(
- "func(arg1, arg2,",
- " <caret>");
- }
-
- public void testFuncallFirstArgOnSameLineWithClosingBrace() {
- setInput(
- "func(arg1, arg2,<caret>)");
- pressEnterAndAssertResult(
- "func(arg1, arg2,",
- " <caret>)");
- }
-
- public void testNonEmptyDict() {
- setInput(
- "{key1 : value1,<caret>}");
- pressEnterAndAssertResult(
- "{key1 : value1,",
- " <caret>}");
- }
-
- public void testNonEmptyDictFirstArgIndented() {
- setInput(
- "{",
- " key1 : value1,<caret>" +
- "}");
- pressEnterAndAssertResult(
- "{",
- " key1 : value1,",
- " <caret>" +
- "}");
- }
-
- public void testEmptyDictAlreadyIndented() {
- setInput(
- "{",
- " <caret>" +
- "}");
- pressEnterAndAssertResult(
- "{",
- " ",
- " <caret>" +
- "}");
- }
-
- public void testEmptyParamIndent() {
- setInput(
- "def fn(<caret>)");
- pressEnterAndAssertResult(
- "def fn(",
- " <caret>",
- ")");
- }
-
- public void testNonEmptyParamIndent() {
- setInput(
- "def fn(param1,<caret>)");
- pressEnterAndAssertResult(
- "def fn(param1,",
- " <caret>)");
- }
-
- public void testFunctionDefAfterColon() {
- setInput(
- "def fn():<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " <caret>");
- }
-
- // def fn():stmt* (THIS IS CURRENTLY BROKEN -- shouldn't indent but does)
- public void testFunctionDefSingleStatement() {
- setInput(
- "def fn():stmt<caret>");
- pressEnterAndAssertResult(
- "def fn():stmt",
- "<caret>");
- }
-
- public void testFunctionDefAfterFirstSuiteStatement() {
- setInput(
- "def fn():",
- " stmt1<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " stmt1",
- " <caret>");
- }
-
- public void testNoIndentAfterSuiteDedentOnEmptyLine() {
- setInput(
- "def fn():",
- " stmt1",
- " stmt2",
- "<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " stmt1",
- " stmt2",
- "",
- "<caret>");
- }
-
- public void testIndentAfterIf() {
- setInput(
- "if condition:<caret>"
- );
- pressEnterAndAssertResult(
- "if condition:",
- " <caret>"
- );
- }
-
- public void testNoIndentAfterIfPlusStatement() {
- setInput(
- "if condition:stmt<caret>"
- );
- pressEnterAndAssertResult(
- "if condition:stmt",
- "<caret>"
- );
- }
-
- public void testIndentAfterElseIf() {
- setInput(
- "if condition:",
- " stmt",
- "elif:<caret>"
- );
- pressEnterAndAssertResult(
- "if condition:",
- " stmt",
- "elif:",
- " <caret>"
- );
- }
-
- public void testNoIndentAfterElseIfPlusStatement() {
- setInput(
- "if condition:",
- " stmt",
- "elif:stmt<caret>"
- );
- pressEnterAndAssertResult(
- "if condition:",
- " stmt",
- "elif:stmt",
- "<caret>"
- );
- }
-
- public void testIndentAfterElse() {
- setInput(
- "if condition:",
- " stmt",
- "else:<caret>"
- );
- pressEnterAndAssertResult(
- "if condition:",
- " stmt",
- "else:",
- " <caret>"
- );
- }
-
- public void testNoIndentAfterElsePlusStatement() {
- setInput(
- "if condition:",
- " stmt",
- "else:stmt<caret>"
- );
- pressEnterAndAssertResult(
- "if condition:",
- " stmt",
- "else:stmt",
- "<caret>"
- );
- }
-
- public void testIndentAfterForColon() {
- setInput(
- "for x in list:<caret>"
- );
- pressEnterAndAssertResult(
- "for x in list:",
- " <caret>"
- );
- }
-
- public void testNoIndentAfterForPlusStatement() {
- setInput(
- "for x in list:do_action<caret>"
- );
- pressEnterAndAssertResult(
- "for x in list:do_action",
- "<caret>"
- );
- }
-
- public void testCommonRuleCase1() {
- setInput(
- "java_library(",
- " name = 'lib'",
- " srcs = [<caret>]");
- pressEnterAndAssertResult(
- "java_library(",
- " name = 'lib'",
- " srcs = [",
- " <caret>",
- " ]");
- }
-
- public void testCommonRuleCase2() {
- setInput(
- "java_library(",
- " name = 'lib'",
- " srcs = [",
- " 'source',<caret>",
- " ]");
- pressEnterAndAssertResult(
- "java_library(",
- " name = 'lib'",
- " srcs = [",
- " 'source',",
- " <caret>",
- " ]");
- }
-
- public void testCommonRuleCase3() {
- setInput(
- "java_library(",
- " name = 'lib'",
- " srcs = ['first',<caret>]");
- pressEnterAndAssertResult(
- "java_library(",
- " name = 'lib'",
- " srcs = ['first',",
- " <caret>]");
- }
-
- public void testDedentAfterReturn() {
- setInput(
- "def fn():",
- " return None<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " return None",
- "<caret>");
- }
-
- public void testDedentAfterEmptyReturn() {
- setInput(
- "def fn():",
- " return<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " return",
- "<caret>");
- }
-
- public void testDedentAfterReturnWithTrailingWhitespace() {
- setInput(
- "def fn():",
- " return<caret> ");
- pressEnterAndAssertResult(
- "def fn():",
- " return",
- "<caret>");
- }
-
- public void testDedentAfterComplexReturn() {
- setInput(
- "def fn():",
- " return a == b<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " return a == b",
- "<caret>");
- }
-
- public void testDedentAfterPass() {
- setInput(
- "def fn():",
- " pass<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " pass",
- "<caret>");
- }
-
- public void testDedentAfterPassInLoop() {
- setInput(
- "def fn():",
- " for a in (1,2,3):",
- " pass<caret>");
- pressEnterAndAssertResult(
- "def fn():",
- " for a in (1,2,3):",
- " pass",
- " <caret>");
- }
-
- // regression test for b/29564041
- public void testNoExceptionPressingEnterAtStartOfFile() {
- setInput("#<caret>");
- pressEnterAndAssertResult(
- "#",
- "<caret>");
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandlerTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandlerTest.java
deleted file mode 100644
index 77d45ee..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/BuildQuoteHandlerTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.common.base.Joiner;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-
-/**
- * Tests for BuildQuoteHandler.
- */
-public class BuildQuoteHandlerTest extends BuildFileIntegrationTestCase {
-
- public void testClosingQuoteInserted() {
- BuildFile file = createBuildFile("BUILD", "");
-
- performTypingAction(file, '"');
- assertFileContents(file, "\"\"");
- }
-
- public void testClosingSingleQuoteInserted() {
- BuildFile file = createBuildFile("BUILD", "");
-
- performTypingAction(file, '\'');
- assertFileContents(file, "''");
- }
-
- public void testClosingTripleQuoteInserted() {
- BuildFile file = createBuildFile("BUILD", "");
-
- performTypingAction(file, '"');
- performTypingAction(file, '"');
- performTypingAction(file, '"');
- assertFileContents(file, "\"\"\"\"\"\"");
- }
-
- public void testClosingTripleSingleQuoteInserted() {
- BuildFile file = createBuildFile("BUILD", "");
-
- performTypingAction(file, '\'');
- performTypingAction(file, '\'');
- performTypingAction(file, '\'');
- assertFileContents(file, "''''''");
- }
-
- public void testOnlyCaretMovedWhenCompletingExistingClosingQuotes() {
- BuildFile file = createBuildFile(
- "BUILD",
- "'text<caret>'",
- "laterContents");
-
- testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
-
- performTypingAction(file, '\'');
-
- testFixture.checkResult(Joiner.on("\n").join(
- "'text'<caret>",
- "laterContents"
- ));
- }
-
- public void testOnlyCaretMovedWhenCompletingExistingClosingTripleQuotes() {
- BuildFile file = createBuildFile(
- "BUILD",
- "'''text<caret>'''",
- "laterContents");
-
- testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
-
- performTypingAction(file, '\'');
-
- testFixture.checkResult(Joiner.on("\n").join(
- "'''text'<caret>''",
- "laterContents"
- ));
-
- performTypingAction(file, '\'');
-
- testFixture.checkResult(Joiner.on("\n").join(
- "'''text''<caret>'",
- "laterContents"
- ));
-
- performTypingAction(file, '\'');
-
- testFixture.checkResult(Joiner.on("\n").join(
- "'''text'''<caret>",
- "laterContents"
- ));
- }
-
- public void testAdditionalTripleQuotesNotInsertedWhenClosingQuotes() {
- BuildFile file = createBuildFile(
- "BUILD",
- "'''text''<caret>",
- "laterContents");
-
- testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
-
- performTypingAction(file, '\'');
-
- testFixture.checkResult(Joiner.on("\n").join(
- "'''text'''<caret>",
- "laterContents"
- ));
- }
-
- public void testAdditionalQuoteNotInsertedWhenClosingQuotes() {
- BuildFile file = createBuildFile(
- "BUILD",
- "'text<caret>",
- "laterContents");
-
- testFixture.configureFromExistingVirtualFile(file.getVirtualFile());
-
- performTypingAction(file, '\'');
-
- testFixture.checkResult(Joiner.on("\n").join(
- "'text'<caret>",
- "laterContents"
- ));
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/EnterInLineCommentTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/EnterInLineCommentTest.java
deleted file mode 100644
index a48dbf1..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/editor/EnterInLineCommentTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.editor;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.openapi.editor.Editor;
-
-/**
- * Test that comments are continued when creating a newline mid comment.
- */
-public class EnterInLineCommentTest extends BuildFileIntegrationTestCase {
-
- public void testInternalNewlineCommented() {
- BuildFile file = createBuildFile(
- "BUILD",
- "# first line comment",
- "# second line comment");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 1, "# second ".length());
- performTypingAction(editor, '\n');
- assertFileContents(
- file,
- "# first line comment",
- "# second ",
- "# line comment");
- assertCaretPosition(editor, 2, 2);
- }
-
- public void testNewlineAtEndOfComment() {
- BuildFile file = createBuildFile(
- "BUILD",
- "# first line comment",
- "# second line comment");
-
- Editor editor = openFileInEditor(file.getVirtualFile());
- setCaretPosition(editor, 1, "# second line comment".length());
- performTypingAction(editor, '\n');
- assertFileContents(
- file,
- "# first line comment",
- "# second line comment",
- "");
- assertCaretPosition(editor, 2, 0);
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/BlazePackageFindUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/BlazePackageFindUsagesTest.java
deleted file mode 100644
index b212f9b..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/BlazePackageFindUsagesTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that all references to a blaze package (including in the package components of labels)
- * are found by the 'Find Usages' action.
- */
-public class BlazePackageFindUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testDirectReferenceFound() {
- BuildFile foo = createBuildFile(
- "java/com/google/foo/BUILD");
-
- BuildFile bar = createBuildFile(
- "java/com/google/bar/BUILD",
- "package_group(name = \"grp\", packages = [\"//java/com/google/foo\"])");
-
- PsiReference[] references = FindUsages.findAllReferences(foo);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(ref.getContainingFile()).isEqualTo(bar);
- }
-
- public void testLabelFragmentReferenceFound() {
- BuildFile foo = createBuildFile(
- "java/com/google/foo/BUILD",
- "java_library(name = \"lib\")");
-
- BuildFile bar = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(name = \"lib2\", exports = [\"//java/com/google/foo:lib\"])");
-
- PsiReference[] references = FindUsages.findAllReferences(foo);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(ref.getContainingFile()).isEqualTo(bar);
- }
-
- /**
- * If these don't resolve, directory rename refactoring won't update all labels correctly
- */
- public void testInternalReferencesResolve() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = \"lib\")",
- "java_library(name = \"other\", deps = [\"//java/com/google:lib\"])");
-
- PsiReference[] references = FindUsages.findAllReferences(buildFile);
- assertThat(references).hasLength(1);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalFileUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalFileUsagesTest.java
deleted file mode 100644
index a83b080..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalFileUsagesTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that references to external files (e.g. Java classes, text files) are found by the 'Find Usages' action
- */
-public class ExternalFileUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testJavaClassUsagesFound() {
- PsiFile javaFile = createPsiFile(
- "com/google/foo/JavaClass.java",
- "package com.google.foo;",
- "public class JavaClass {}");
-
- BuildFile buildFile = createBuildFile(
- "com/google/foo/BUILD",
- "java_library(name = \"lib\", srcs = [\"JavaClass.java\"])");
-
- PsiReference[] references = FindUsages.findAllReferences(javaFile);
- assertThat(references).hasLength(1);
-
- Argument.Keyword arg = buildFile.findChildByClass(FuncallExpression.class)
- .getKeywordArgument("srcs");
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(PsiUtils.getParentOfType(ref, Argument.Keyword.class))
- .isEqualTo(arg);
- }
-
- public void testTextFileUsagesFound() {
- PsiFile textFile = createPsiFile("com/google/foo/data.txt");
-
- BuildFile buildFile = createBuildFile(
- "com/google/foo/BUILD",
- "filegroup(name = \"lib\", srcs = [\"data.txt\"])",
- "filegroup(name = \"lib2\", srcs = [\"//com/google/foo:data.txt\"])");
-
- PsiReference[] references = FindUsages.findAllReferences(textFile);
- assertThat(references).hasLength(2);
- }
-
- public void testInvalidReferenceDoesntResolve() {
- BuildFile packageFoo = createBuildFile("com/google/foo/BUILD");
- PsiFile textFileInFoo = createPsiFile("com/google/foo/data.txt");
-
- BuildFile packageBar = createBuildFile(
- "com/google/bar/BUILD",
- "filegroup(name = \"lib\", srcs = [\":data.txt\"])");
-
- PsiReference[] references = FindUsages.findAllReferences(textFileInFoo);
- assertThat(references).isEmpty();
- }
-
- public void testSkylarkExtensionUsagesFound() {
- BuildFile ext = createBuildFile(
- "com/google/foo/ext.bzl",
- "def fn(): return");
- createBuildFile(
- "com/google/foo/BUILD",
- "load(':ext.bzl', 'fn')",
- "load('ext.bzl', 'fn')",
- "load('//com/google/foo:ext.bzl', 'fn')"
- );
-
- PsiReference[] references = FindUsages.findAllReferences(ext);
- assertThat(references).hasLength(3);
- }
-
- public void testSkylarkExtensionInSubDirectoryUsagesFound() {
- BuildFile ext = createBuildFile(
- "com/google/foo/subdir/ext.bzl",
- "def fn(): return");
- createBuildFile(
- "com/google/foo/BUILD",
- "load(':subdir/ext.bzl', 'fn')",
- "load('subdir/ext.bzl', 'fn')",
- "load('//com/google/foo:subdir/ext.bzl', 'fn')"
- );
-
- PsiReference[] references = FindUsages.findAllReferences(ext);
- assertThat(references).hasLength(3);
- }
-
- public void testSkylarkExtensionInSubDirectoryOfDifferentPackage() {
- BuildFile otherPkg = createBuildFile(
- "com/google/foo/BUILD");
- BuildFile ext = createBuildFile(
- "com/google/foo/subdir/ext.bzl",
- "def fn(): return");
-
- createBuildFile(
- "com/google/bar/BUILD",
- "load('//com/google/foo:subdir/ext.bzl', 'fn')"
- );
-
- PsiReference[] references = FindUsages.findAllReferences(ext);
- assertThat(references).hasLength(1);
- }
-
- public void testSkylarkExtensionReferencedFromSubpackage() {
- BuildFile pkg = createBuildFile(
- "com/google/foo/BUILD");
- BuildFile ext1 = createBuildFile(
- "com/google/foo/subdir/testing.bzl",
- "def fn(): return");
- BuildFile ext2 = createBuildFile(
- "com/google/foo/subdir/other.bzl",
- "load(':subdir/testing.bzl', 'fn')");
-
- PsiReference[] references = FindUsages.findAllReferences(ext1);
- assertThat(references).hasLength(1);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindParameterUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindParameterUsagesTest.java
deleted file mode 100644
index a9a3ae8..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindParameterUsagesTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.ParameterList;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that usages of function parameters (i.e. by named args in funcall expressions) are found
- */
-public class FindParameterUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testLocalReferences() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(arg1, arg2)",
- "function(arg1 = 1, arg2 = \"name\")");
-
- FunctionStatement fn = buildFile.findChildByClass(FunctionStatement.class);
- ParameterList params = fn.getParameterList();
-
- PsiReference[] references = FindUsages.findAllReferences(params.findParameterByName("arg1"));
- assertThat(references).hasLength(1);
-
- references = FindUsages.findAllReferences(params.findParameterByName("arg2"));
- assertThat(references).hasLength(1);
- }
-
- public void testNonLocalReferences() {
- BuildFile foo = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(arg1, arg2)");
-
- BuildFile bar = createBuildFile(
- "java/com/google/other/BUILD",
- "load(\"//java/com/google:build_defs.bzl\", \"function\")",
- "function(arg1 = 1, arg2 = \"name\", extra = x)");
-
- FunctionStatement fn = foo.findChildByClass(FunctionStatement.class);
- ParameterList params = fn.getParameterList();
-
- PsiReference[] references = FindUsages.findAllReferences(params.findParameterByName("arg1"));
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement().getContainingFile()).isEqualTo(bar);
-
- references = FindUsages.findAllReferences(params.findParameterByName("arg2"));
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement().getContainingFile()).isEqualTo(bar);
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindRuleUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindRuleUsagesTest.java
deleted file mode 100644
index 3a24bfd..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FindRuleUsagesTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that usages of build rules are found
- */
-public class FindRuleUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testLocalReferences() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = \"target\")",
- "top_level_ref = \":target\"",
- "java_library(name = \"other\", deps = [\":target\"]");
-
- FuncallExpression target = buildFile.findChildByClass(FuncallExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(2);
-
- PsiElement firstRef = references[0].getElement();
- assertThat(firstRef).isInstanceOf(StringLiteral.class);
- assertThat(firstRef.getParent()).isInstanceOf(AssignmentStatement.class);
-
- PsiElement secondRef = references[1].getElement();
- assertThat(secondRef).isInstanceOf(StringLiteral.class);
- assertThat(secondRef.getParent()).isInstanceOf(ListLiteral.class);
- }
-
- // test full package references, made locally
- public void testLocalFullReference() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = \"target\")",
- "java_library(name = \"other\", deps = [\"//java/com/google:target\"]");
-
- FuncallExpression target = buildFile.findChildByClass(FuncallExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(ref.getParent()).isInstanceOf(ListLiteral.class);
- }
-
- public void testNonLocalReferences() {
- BuildFile targetFile = createBuildFile(
- "java/com/google/foo/BUILD",
- "java_library(name = \"target\")");
-
- BuildFile refFile = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(name = \"ref\", exports = [\"//java/com/google/foo:target\"])");
-
- FuncallExpression target = targetFile.findChildByClass(FuncallExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(ref.getContainingFile()).isEqualTo(refFile);
- }
-
- public void testFindUsagesWorksFromNameString() {
- BuildFile targetFile = createBuildFile(
- "java/com/google/foo/BUILD",
- "java_library(name = \"tar<caret>get\")");
-
- BuildFile refFile = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(name = \"ref\", exports = [\"//java/com/google/foo:target\"])");
-
- testFixture.configureFromExistingVirtualFile(targetFile.getVirtualFile());
-
- PsiElement targetElement = GotoDeclarationAction.findElementToShowUsagesOf(
- testFixture.getEditor(),
- testFixture.getEditor().getCaretModel().getOffset());
-
- PsiReference[] references = FindUsages.findAllReferences(targetElement);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(ref.getContainingFile()).isEqualTo(refFile);
- }
-
- public void testInvalidReferenceDoesntResolve() {
- // reference ":target" from another build file (missing package path in label)
- BuildFile targetFile = createBuildFile(
- "java/com/google/foo/BUILD",
- "java_library(name = \"target\")");
-
- BuildFile refFile = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(name = \"ref\", exports = [\":target\"])");
-
- FuncallExpression target = targetFile.findChildByClass(FuncallExpression.class);
- assertThat(target).isNotNull();
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(0);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FunctionStatementUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FunctionStatementUsagesTest.java
deleted file mode 100644
index b2840c3..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/FunctionStatementUsagesTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that usages of function declarations are found
- */
-public class FunctionStatementUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testLocalReferences() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(name, srcs, deps):",
- " # function body",
- "function(name = \"foo\")");
-
- FunctionStatement funcDef = buildFile.findChildByClass(FunctionStatement.class);
-
- PsiReference[] references = FindUsages.findAllReferences(funcDef);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(FuncallExpression.class);
- }
-
- public void testLoadedFunctionReferences() {
- BuildFile extFile = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google:build_defs.bzl\",",
- "\"function\"",
- ")");
-
- FunctionStatement funcDef = extFile.findChildByClass(FunctionStatement.class);
- LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
-
- PsiReference[] references = FindUsages.findAllReferences(funcDef);
- assertThat(references).hasLength(1);
-
- PsiElement ref = references[0].getElement();
- assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(ref.getParent()).isEqualTo(load);
- }
-
- public void testFuncallReference() {
- BuildFile extFile = createBuildFile(
- "java/com/google/tools/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = []");
-
- FunctionStatement function = extFile.firstChildOfClass(FunctionStatement.class);
- FuncallExpression funcall = buildFile.firstChildOfClass(FuncallExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(function);
- assertThat(references).hasLength(2);
-
- assertThat(references[1].getElement()).isEqualTo(funcall);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/GlobFindUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/GlobFindUsagesTest.java
deleted file mode 100644
index 57ddf67..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/GlobFindUsagesTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.google.idea.blaze.base.lang.projectview.language.ProjectViewLanguage;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiManager;
-import com.intellij.psi.PsiReference;
-import com.intellij.psi.impl.PsiManagerEx;
-import com.intellij.psi.impl.file.impl.FileManager;
-import com.intellij.testFramework.LightVirtualFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that file references in globs are included in the 'find usages' results.
- */
-public class GlobFindUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testSimpleGlobReferencingSingleFile() {
- PsiFile ref = createPsiFile("java/com/google/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
-
- PsiReference[] references = FindUsages.findAllReferences(ref);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isInstanceOf(GlobExpression.class);
- }
-
- public void testSimpleGlobReferencingSingleFile2() {
- PsiFile ref = createPsiFile("java/com/google/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(ref);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
- }
-
- public void testSimpleGlobReferencingSingleFile3() {
- PsiFile ref = createPsiFile("java/com/google/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['T*t.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(ref);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
- }
-
- public void testGlobReferencingMultipleFiles() {
- PsiFile ref1 = createPsiFile("java/com/google/Test.java");
- PsiFile ref2 = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(ref1);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
-
- references = FindUsages.findAllReferences(ref2);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
- }
-
- public void testFindsSubDirectories() {
- PsiFile ref1 = createPsiFile("java/com/google/test/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(ref1);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
- }
-
- public void testGlobWithExcludes() {
- PsiFile test = createPsiFile("java/com/google/tests/Test.java");
- PsiFile foo = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(" +
- " ['**/*.java']," +
- " exclude = ['tests/*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(foo);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
-
- assertThat(FindUsages.findAllReferences(test)).isEmpty();
- }
-
- public void testIncludeDirectories() {
- PsiDirectory dir = createPsiDirectory("java/com/google/tests");
- PsiFile test = createPsiFile("java/com/google/tests/Test.java");
- PsiFile foo = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(" +
- " ['**/*']," +
- " exclude = ['BUILD']," +
- " exclude_directories = 0)");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(dir);
- assertThat(references).hasLength(1);
- assertThat(references[0].getElement()).isEqualTo(glob);
- }
-
- public void testExcludeDirectories() {
- PsiDirectory dir = createPsiDirectory("java/com/google/tests");
- PsiFile test = createPsiFile("java/com/google/tests/Test.java");
- PsiFile foo = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(" +
- " ['**/*']," +
- " exclude = ['BUILD'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(dir);
- assertThat(references).isEmpty();
- }
-
- public void testFilesInSubpackagesExcluded() {
- BuildFile pkg = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
- BuildFile subPkg = createBuildFile("java/com/google/other/BUILD");
- createFile("java/com/google/other/Other.java");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(pkg, GlobExpression.class);
-
- PsiReference[] references = FindUsages.findAllReferences(subPkg);
- assertThat(references).isEmpty();
- }
-
- // regression test for b/29267289
- public void testInMemoryFileHandledGracefully() {
- BuildFile pkg = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
-
- LightVirtualFile inMemoryFile = new LightVirtualFile("mockProjectViewFile", ProjectViewLanguage.INSTANCE, "");
-
- FileManager fileManager = ((PsiManagerEx) PsiManager.getInstance(getProject())).getFileManager();
- fileManager.setViewProvider(inMemoryFile, fileManager.createFileViewProvider(inMemoryFile, true));
-
- PsiFile psiFile = fileManager.findFile(inMemoryFile);
-
- PsiReference[] references = FindUsages.findAllReferences(psiFile);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/LocalVariableUsagesTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/LocalVariableUsagesTest.java
deleted file mode 100644
index 3ff6409..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/LocalVariableUsagesTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.findusages;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.references.LocalReference;
-import com.google.idea.blaze.base.lang.buildfile.references.TargetReference;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that references to local variables are found by the 'Find Usages' action
- * TODO: Support comprehension suffix, and add test for it
- */
-public class LocalVariableUsagesTest extends BuildFileIntegrationTestCase {
-
- public void testLocalReferences() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "localVar = 5",
- "funcall(localVar)",
- "def function(name):",
- " tempVar = localVar");
-
- TargetExpression target = buildFile
- .findChildByClass(AssignmentStatement.class)
- .getLeftHandSideExpression();
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(2);
-
- FuncallExpression funcall = buildFile.findChildByClass(FuncallExpression.class);
- assertThat(funcall).isNotNull();
-
- PsiElement firstRef = references[0].getElement();
- assertThat(PsiUtils.getParentOfType(firstRef, FuncallExpression.class))
- .isEqualTo(funcall);
-
- FunctionStatement function = buildFile.findChildByClass(FunctionStatement.class);
- assertThat(function).isNotNull();
-
- PsiElement secondRef = references[1].getElement();
- assertThat(secondRef.getParent()).isInstanceOf(AssignmentStatement.class);
- assertThat(PsiUtils.getParentOfType(secondRef, FunctionStatement.class))
- .isEqualTo(function);
- }
-
- // the case where a symbol is the target of multiple assignment statements
- public void testMultipleAssignments() {
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "var = 5",
- "var += 1",
- "var = 0");
-
- TargetExpression target = buildFile
- .findChildByClass(AssignmentStatement.class)
- .getLeftHandSideExpression();
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(2);
-
- assertThat(references[0]).isInstanceOf(LocalReference.class);
- assertThat(references[1]).isInstanceOf(TargetReference.class);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilderTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilderTest.java
deleted file mode 100644
index 97ade21..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/formatting/BuildFileFoldingBuilderTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.formatting;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
-import com.intellij.lang.folding.FoldingDescriptor;
-import com.intellij.openapi.editor.Editor;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for {@link BuildFileFoldingBuilder}.
- */
-public class BuildFileFoldingBuilderTest extends BuildFileIntegrationTestCase {
-
- public void testEndOfFileFunctionDelcaration() {
- // bug 28618935: test no NPE in the case where there's no statement list following the func-def colon
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "def function():");
-
- getFoldingRegions(file);
- }
-
- public void testFuncDefStatementsFolded() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "# multi-line comment, not folded",
- "# second line of comment",
- "def function(arg1, arg2):",
- " stmt1",
- " stmt2",
- "",
- "variable = 1");
-
- FoldingDescriptor[] foldingRegions = getFoldingRegions(file);
- assertThat(foldingRegions).hasLength(1);
- assertThat(foldingRegions[0].getElement().getPsi())
- .isEqualTo(file.findFunctionInScope("function"));
- }
-
- public void testRulesFolded() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "java_library(",
- " name = 'lib',",
- " srcs = glob(['*.java']),",
- ")");
-
- FoldingDescriptor[] foldingRegions = getFoldingRegions(file);
- assertThat(foldingRegions).hasLength(1);
- assertThat(foldingRegions[0].getElement().getPsi())
- .isEqualTo(file.findRule("lib"));
- }
-
- public void testLoadStatementFolded() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- " '//java/com/foo/build_defs.bzl',",
- " 'function1',",
- " 'function2',",
- ")");
-
- FoldingDescriptor[] foldingRegions = getFoldingRegions(file);
- assertThat(foldingRegions).hasLength(1);
- assertThat(foldingRegions[0].getElement().getPsi())
- .isEqualTo(file.findChildByClass(LoadStatement.class));
- }
-
- private FoldingDescriptor[] getFoldingRegions(BuildFile file) {
- Editor editor = openFileInEditor(file.getVirtualFile());
- return new BuildFileFoldingBuilder().buildFoldRegions(file.getNode(), editor.getDocument());
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeTest.java
deleted file mode 100644
index b53d30e..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/language/BuildFileTypeTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.language;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.psi.PsiFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that BUILD files are recognized as such
- */
-public class BuildFileTypeTest extends BuildFileIntegrationTestCase {
-
- public void testSkylarkExtensionRecognized() {
- PsiFile file = createPsiFile("java/com/google/foo/build_defs.bzl");
- assertThat(file).isInstanceOf(BuildFile.class);
- }
-
- public void testExactNameMatch() {
- PsiFile file = createPsiFile("java/com/google/foo/BUILD");
- assertThat(file).isInstanceOf(BuildFile.class);
- }
-
- /**
- * We may want to support these in the future (and in the meantime the user can manually have them recognized as BUILD files,
- * for syntax highlighting, etc.).<br>
- * Currently, turned off by default because references won't resolve correctly -- they'll point back to normal BUILD files.
- */
- public void testOtherBuildFilesNotRecognized() {
- PsiFile file = createPsiFile("java/com/google/foo/BUILD.tools");
- assertThat(file).isNotInstanceOf(BuildFile.class);
-
- file = createPsiFile("java/com/google/foo/BUILD.bazel");
- assertThat(file).isNotInstanceOf(BuildFile.class);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/AbstractLexerTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/AbstractLexerTest.java
deleted file mode 100644
index 5c16e80..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/AbstractLexerTest.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests of tokenization behavior of {@link BuildLexerBase}.
- */
-@RunWith(JUnit4.class)
-public abstract class AbstractLexerTest {
-
- private final BuildLexerBase.LexerMode mode;
- protected String lastError;
-
- protected AbstractLexerTest(BuildLexerBase.LexerMode mode) {
- this.mode = mode;
- }
-
- /**
- * Create a lexer which takes input from the specified string. Resets the
- * error handler beforehand.
- */
- protected BuildLexerBase createLexer(String input) {
- lastError = null;
- return new BuildLexerBase(input, 0, mode) {
- @Override
- protected void error(String message, int start, int end) {
- super.error(message, start, end);
- lastError = message;
- }
- };
- }
-
- protected Token[] tokens(String input) {
- Token[] tokens = createLexer(input).getTokens().toArray(new Token[0]);
- assertNoCharactersMissing(input.length(), tokens);
- return tokens;
- }
-
- /**
- * Both the syntax highlighter and the parser require every character be accounted for by
- * a lexical element.
- */
- private static void assertNoCharactersMissing(int totalLength, Token[] tokens) {
- if (tokens.length != 0 && tokens[tokens.length - 1].right != totalLength) {
- throw new AssertionError(String.format(
- "Last tokenized character '%s' doesn't match document length '%s'",
- tokens[tokens.length - 1].right, totalLength));
- }
- int start = 0;
- for (int i = 0; i < tokens.length; i++) {
- Token token = tokens[i];
- if (token.left != start) {
- throw new AssertionError("Gap/inconsistency at: " + start);
- }
- start = token.right;
- }
- }
-
- /**
- * Returns a string containing the names of the tokens and their associated
- * values. (String-literals are printed without escaping.)
- */
- protected String values(Token[] tokens) {
- StringBuilder buffer = new StringBuilder();
- for (Token token : tokens) {
- if (isIgnored(token.kind)) {
- continue;
- }
- if (buffer.length() > 0) {
- buffer.append(' ');
- }
- buffer.append(token.kind.name());
- if (token.kind != TokenKind.WHITESPACE && token.value != null) {
- buffer.append('(').append(token.value).append(')');
- }
- }
- return buffer.toString();
- }
-
- /**
- * Returns a string containing just the names of the tokens.
- */
- protected String names(Token[] tokens) {
- StringBuilder buf = new StringBuilder();
- for (Token token : tokens) {
- if (isIgnored(token.kind)) {
- continue;
- }
- if (buf.length() > 0) {
- buf.append(' ');
- }
- buf.append(token.kind.name());
- }
- return buf.toString();
- }
-
- private boolean isIgnored(TokenKind kind) {
- if (mode == BuildLexerBase.LexerMode.Parsing) {
- return kind == TokenKind.WHITESPACE || kind == TokenKind.COMMENT;
- }
- return false;
- }
-
- /**
- * Returns a string containing just the half-open position intervals of each
- * token. e.g. "[3,4) [4,9)".
- */
- protected String positions(Token[] tokens) {
- StringBuilder buf = new StringBuilder();
- for (Token token : tokens) {
- if (isIgnored(token.kind)) {
- continue;
- }
- if (buf.length() > 0) {
- buf.append(' ');
- }
- buf.append('[')
- .append(token.left)
- .append(',')
- .append(token.right)
- .append(')');
- }
- return buf.toString();
- }
-
- @Test
- public void testIntegers() throws Exception {
- // Detection of MINUS immediately following integer constant proves we
- // don't consume too many chars.
-
- // decimal
- assertEquals("INT(12345) MINUS", values(tokens("12345-")));
-
- // octal
- assertEquals("INT(5349) MINUS", values(tokens("012345-")));
-
- // octal (bad)
- assertEquals("INT(0) MINUS", values(tokens("012349-")));
- assertEquals("invalid base-8 integer constant: 012349", lastError);
-
- // hexadecimal (uppercase)
- assertEquals("INT(1193055) MINUS", values(tokens("0X12345F-")));
-
- // hexadecimal (lowercase)
- assertEquals("INT(1193055) MINUS", values(tokens("0x12345f-")));
-
- // hexadecimal (lowercase) [note: "g" cause termination of token]
- assertEquals("INT(74565) IDENTIFIER(g) MINUS",
- values(tokens("0x12345g-")));
- }
-
- @Test
- public void testStringDelimiters() throws Exception {
- assertEquals("STRING(foo)", values(tokens("\"foo\"")));
- assertEquals("STRING(foo)", values(tokens("'foo'")));
- }
-
- @Test
- public void testQuotesInStrings() throws Exception {
- assertEquals("STRING(foo'bar)", values(tokens("'foo\\'bar'")));
- assertEquals("STRING(foo'bar)", values(tokens("\"foo'bar\"")));
- assertEquals("STRING(foo\"bar)", values(tokens("'foo\"bar'")));
- assertEquals("STRING(foo\"bar)",
- values(tokens("\"foo\\\"bar\"")));
- }
-
- @Test
- public void testStringEscapes() throws Exception {
- assertEquals("STRING(a\tb\nc\rd)",
- values(tokens("'a\\tb\\nc\\rd'"))); // \t \r \n
- assertEquals("STRING(x\\hx)",
- values(tokens("'x\\hx'"))); // \h is unknown => "\h"
- assertEquals("STRING(\\$$)", values(tokens("'\\$$'")));
- assertEquals("STRING(ab)",
- values(tokens("'a\\\nb'"))); // escape end of line
- assertEquals("STRING(abcd)",
- values(tokens("\"ab\\ucd\"")));
- assertEquals("escape sequence not implemented: \\u", lastError);
- }
-
- @Test
- public void testRawString() throws Exception {
- assertEquals("STRING(abcd)",
- values(tokens("r'abcd'")));
- assertEquals("STRING(abcd)",
- values(tokens("r\"abcd\"")));
- assertEquals("STRING(a\\tb\\nc\\rd)",
- values(tokens("r'a\\tb\\nc\\rd'"))); // r'a\tb\nc\rd'
- assertEquals("STRING(a\\\")",
- values(tokens("r\"a\\\"\""))); // r"a\""
- assertEquals("STRING(a\\\\b)",
- values(tokens("r'a\\\\b'"))); // r'a\\b'
- assertEquals("STRING(ab) IDENTIFIER(r)",
- values(tokens("r'ab'r")));
-
- // Unterminated raw string
- values(tokens("r'\\'")); // r'\'
- assertEquals("unterminated string literal at eof", lastError);
- }
-
- @Test
- public void testTripleRawString() throws Exception {
- // r'''a\ncd'''
- assertEquals("STRING(ab\\ncd)", values(tokens("r'''ab\\ncd'''")));
- // r"""ab
- // cd"""
- assertEquals(
- "STRING(ab\ncd)",
- values(tokens("\"\"\"ab\ncd\"\"\"")));
-
- // Unterminated raw string
- values(tokens("r'''\\'''")); // r'''\'''
- assertEquals("unterminated string literal at eof", lastError);
- }
-
- @Test
- public void testOctalEscapes() throws Exception {
- // Regression test for a bug.
- assertEquals("STRING(\0 \1 \t \u003f I I1 \u00ff \u00ff \u00fe)",
- values(tokens("'\\0 \\1 \\11 \\77 \\111 \\1111 \\377 \\777 \\776'")));
- // Test boundaries (non-octal char, EOF).
- assertEquals("STRING(\1b \1)", values(tokens("'\\1b \\1'")));
- }
-
- @Test
- public void testTripleQuotedStrings() throws Exception {
- assertEquals("STRING(a\"b'c \n d\"\"e)",
- values(tokens("\"\"\"a\"b'c \n d\"\"e\"\"\"")));
- assertEquals("STRING(a\"b'c \n d\"\"e)",
- values(tokens("'''a\"b'c \n d\"\"e'''")));
- }
-
- @Test
- public void testBadChar() throws Exception {
- assertEquals("IDENTIFIER(a) ILLEGAL($) IDENTIFIER(b)", values(tokens("a$b")));
- assertEquals("invalid character: '$'", lastError);
- }
-
- @Test
- public void testContainsErrors() throws Exception {
- BuildLexerBase lexerSuccess = createLexer("foo");
- assertFalse(lexerSuccess.containsErrors());
-
- BuildLexerBase lexerFail = createLexer("f$o");
- assertTrue(lexerFail.containsErrors());
-
- String s = "'unterminated";
- lexerFail = createLexer(s);
- assertTrue(lexerFail.containsErrors());
- assertEquals("STRING(unterminated)", values(tokens(s)));
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/BlazeLexerTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/BlazeLexerTest.java
deleted file mode 100644
index 6d0b2e1..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/BlazeLexerTest.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests of tokenization behavior of {@link BuildLexerBase} in 'parsing mode' (see {@link BuildLexerBase.LexerMode})
- */
-@RunWith(JUnit4.class)
-public class BlazeLexerTest extends AbstractLexerTest {
-
- public BlazeLexerTest() {
- super(BuildLexerBase.LexerMode.Parsing);
- }
-
- @Test
- public void testBasics1() throws Exception {
- assertEquals("IDENTIFIER RPAREN", names(tokens("wiz) ")));
- assertEquals("IDENTIFIER RPAREN", names(tokens("wiz )")));
- assertEquals("IDENTIFIER RPAREN", names(tokens(" wiz)")));
- assertEquals("IDENTIFIER RPAREN", names(tokens(" wiz ) ")));
- assertEquals("IDENTIFIER RPAREN", names(tokens("wiz\t)")));
- }
-
- @Test
- public void testBasics2() throws Exception {
- assertEquals("RPAREN", names(tokens(")")));
- assertEquals("RPAREN", names(tokens(" )")));
- assertEquals("RPAREN", names(tokens(" ) ")));
- assertEquals("RPAREN", names(tokens(") ")));
- }
-
- @Test
- public void testBasics3() throws Exception {
- assertEquals("INT NEWLINE INT", names(tokens("123#456\n789")));
- assertEquals("INT NEWLINE INT", names(tokens("123 #456\n789")));
- assertEquals("INT NEWLINE INT", names(tokens("123#456 \n789")));
- assertEquals("INT NEWLINE INDENT INT", names(tokens("123#456\n 789")));
- assertEquals("INT NEWLINE INT", names(tokens("123#456\n789 ")));
- }
-
- @Test
- public void testBasics4() throws Exception {
- assertEquals("", names(tokens("")));
- assertEquals("", names(tokens("# foo")));
- assertEquals("INT INT INT INT", names(tokens("1 2 3 4")));
- assertEquals("INT DOT INT", names(tokens("1.234")));
- assertEquals("IDENTIFIER LPAREN IDENTIFIER COMMA IDENTIFIER RPAREN", names(tokens("foo(bar, wiz)")));
- }
-
- @Test
- public void testIntegersAndDot() throws Exception {
- assertEquals("INT(1) DOT INT(2345)", values(tokens("1.2345")));
-
- assertEquals("INT(1) DOT INT(2) DOT INT(345)", values(tokens("1.2.345")));
-
- assertEquals("INT(1) DOT INT(0)", values(tokens("1.23E10")));
- assertEquals("invalid base-10 integer constant: 23E10", lastError);
-
- assertEquals("INT(1) DOT INT(0) MINUS INT(10)", values(tokens("1.23E-10")));
- assertEquals("invalid base-10 integer constant: 23E", lastError);
-
- assertEquals("DOT INT(123)", values(tokens(". 123")));
- assertEquals("DOT INT(123)", values(tokens(".123")));
- assertEquals("DOT IDENTIFIER(abc)", values(tokens(".abc")));
-
- assertEquals("IDENTIFIER(foo) DOT INT(123)", values(tokens("foo.123")));
- assertEquals("IDENTIFIER(foo) DOT IDENTIFIER(bcd)", values(tokens("foo.bcd"))); // 'b' are hex chars
- assertEquals("IDENTIFIER(foo) DOT IDENTIFIER(xyz)", values(tokens("foo.xyz")));
- }
-
- @Test
- public void testIndentation() throws Exception {
- assertEquals("INT(1) NEWLINE INT(2) NEWLINE INT(3)",
- values(tokens("1\n2\n3")));
- assertEquals("INT(1) NEWLINE INDENT INT(2) NEWLINE INT(3) NEWLINE DEDENT INT(4)",
- values(tokens("1\n 2\n 3\n4 ")));
- assertEquals("INT(1) NEWLINE INDENT INT(2) NEWLINE INT(3)",
- values(tokens("1\n 2\n 3")));
- assertEquals("INT(1) NEWLINE INDENT INT(2) NEWLINE INDENT INT(3)",
- values(tokens("1\n 2\n 3")));
- assertEquals("INT(1) NEWLINE INDENT INT(2) NEWLINE INDENT INT(3) NEWLINE "
- + "DEDENT INT(4) NEWLINE DEDENT INT(5)",
- values(tokens("1\n 2\n 3\n 4\n5")));
-
- assertEquals("INT(1) NEWLINE INDENT INT(2) NEWLINE INDENT INT(3) NEWLINE "
- + "DEDENT INT(4) NEWLINE DEDENT INT(5)",
- values(tokens("1\n 2\n 3\n 4\n5")));
- assertEquals("indentation error", lastError);
- }
-
- @Test
- public void testIndentationInsideParens() throws Exception {
- // Indentation is ignored inside parens:
- assertEquals("INT(1) LPAREN INT(2) INT(3) INT(4) INT(5)",
- values(tokens("1 (\n 2\n 3\n 4\n5")));
- assertEquals("INT(1) LBRACE INT(2) INT(3) INT(4) INT(5)",
- values(tokens("1 {\n 2\n 3\n 4\n5")));
- assertEquals("INT(1) LBRACKET INT(2) INT(3) INT(4) INT(5)",
- values(tokens("1 [\n 2\n 3\n 4\n5")));
- assertEquals("INT(1) LBRACKET INT(2) RBRACKET NEWLINE INDENT INT(3) "
- + "NEWLINE INT(4) NEWLINE DEDENT INT(5)",
- values(tokens("1 [\n 2]\n 3\n 4\n5")));
- }
-
- @Test
- public void testNoIndentationAtEOF() throws Exception {
- assertEquals("INDENT INT(1)", values(tokens("\n 1")));
- }
-
- @Test
- public void testBlankLineIndentation() throws Exception {
- // Blank lines and comment lines should not generate any indents
- // (but note that every input ends with).
- assertEquals("", names(tokens("\n #\n")));
- assertEquals("", names(tokens(" #")));
- assertEquals("NEWLINE", names(tokens(" #\n")));
- assertEquals("NEWLINE", names(tokens(" #comment\n")));
- assertEquals("DEF IDENTIFIER LPAREN IDENTIFIER RPAREN COLON NEWLINE "
- + "INDENT RETURN IDENTIFIER NEWLINE DEDENT",
- names(tokens("def f(x):\n"
- + " # comment\n"
- + "\n"
- + " \n"
- + " return x\n")));
- }
-
- @Test
- public void testMultipleCommentLines() throws Exception {
- assertEquals("NEWLINE "
- + "DEF IDENTIFIER LPAREN IDENTIFIER RPAREN COLON NEWLINE "
- + "INDENT RETURN IDENTIFIER NEWLINE DEDENT",
- names(tokens("# Copyright\n"
- + "#\n"
- + "# A comment line\n"
- + "# An adjoining line\n"
- + "def f(x):\n"
- + " return x\n")));
- }
-
- @Test
- public void testBackslash() throws Exception {
- // backslash followed by newline marked as whitespace (skipped by parser)
- assertEquals("IDENTIFIER IDENTIFIER",
- names(tokens("a\\\nb")));
- assertEquals("IDENTIFIER ILLEGAL IDENTIFIER",
- names(tokens("a\\ b")));
- assertEquals("IDENTIFIER LPAREN INT RPAREN",
- names(tokens("a(\\\n2)")));
- }
-
- @Test
- public void testTokenPositions() throws Exception {
- // foo ( bar , { 1 :
- assertEquals("[0,3) [3,4) [4,7) [7,8) [9,10) [10,11) [11,12)"
- // 'quux' } )
- + " [13,19) [19,20) [20,21)",
- positions(tokens("foo(bar, {1: 'quux'})")));
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/HighlightingLexerTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/HighlightingLexerTest.java
deleted file mode 100644
index 40e91fd..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/lexer/HighlightingLexerTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.lexer;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests of tokenization behavior of {@link BuildLexerBase} in 'highlighting mode' (see {@link BuildLexerBase.LexerMode})
- */
-@RunWith(JUnit4.class)
-public class HighlightingLexerTest extends AbstractLexerTest {
-
- public HighlightingLexerTest() {
- super(BuildLexerBase.LexerMode.SyntaxHighlighting);
- }
-
- @Test
- public void testBasics1() throws Exception {
- assertEquals("IDENTIFIER RPAREN WHITESPACE", names(tokens("wiz) ")));
- assertEquals("IDENTIFIER WHITESPACE RPAREN", names(tokens("wiz )")));
- assertEquals("WHITESPACE IDENTIFIER RPAREN", names(tokens(" wiz)")));
- assertEquals("WHITESPACE IDENTIFIER WHITESPACE RPAREN WHITESPACE", names(tokens(" wiz ) ")));
- assertEquals("IDENTIFIER WHITESPACE RPAREN", names(tokens("wiz\t)")));
- }
-
- @Test
- public void testBasics2() throws Exception {
- assertEquals("RPAREN", names(tokens(")")));
- assertEquals("WHITESPACE RPAREN", names(tokens(" )")));
- assertEquals("WHITESPACE RPAREN WHITESPACE", names(tokens(" ) ")));
- assertEquals("RPAREN WHITESPACE", names(tokens(") ")));
- }
-
- @Test
- public void testBasics3() throws Exception {
- assertEquals("INT COMMENT NEWLINE INT", names(tokens("123#456\n789")));
- assertEquals("INT WHITESPACE COMMENT NEWLINE INT", names(tokens("123 #456\n789")));
- assertEquals("INT COMMENT NEWLINE INT", names(tokens("123#456 \n789")));
- assertEquals("INT COMMENT NEWLINE WHITESPACE INT", names(tokens("123#456\n 789")));
- assertEquals("INT COMMENT NEWLINE INT WHITESPACE", names(tokens("123#456\n789 ")));
- }
-
- @Test
- public void testBasics4() throws Exception {
- assertEquals("", names(tokens("")));
- assertEquals("COMMENT", names(tokens("# foo")));
- assertEquals("INT WHITESPACE INT WHITESPACE INT WHITESPACE INT", names(tokens("1 2 3 4")));
- assertEquals("INT DOT INT", names(tokens("1.234")));
- assertEquals("IDENTIFIER LPAREN IDENTIFIER COMMA WHITESPACE IDENTIFIER RPAREN", names(tokens("foo(bar, wiz)")));
- }
-
- @Test
- public void testIntegersAndDot() throws Exception {
- assertEquals("INT(1) DOT INT(2345)", values(tokens("1.2345")));
-
- assertEquals("INT(1) DOT INT(2) DOT INT(345)", values(tokens("1.2.345")));
-
- assertEquals("INT(1) DOT INT(0)", values(tokens("1.23E10")));
- assertEquals("invalid base-10 integer constant: 23E10", lastError);
-
- assertEquals("INT(1) DOT INT(0) MINUS INT(10)", values(tokens("1.23E-10")));
- assertEquals("invalid base-10 integer constant: 23E", lastError);
-
- assertEquals("DOT WHITESPACE INT(123)", values(tokens(". 123")));
- assertEquals("DOT INT(123)", values(tokens(".123")));
- assertEquals("DOT IDENTIFIER(abc)", values(tokens(".abc")));
-
- assertEquals("IDENTIFIER(foo) DOT INT(123)", values(tokens("foo.123")));
- assertEquals("IDENTIFIER(foo) DOT IDENTIFIER(bcd)", values(tokens("foo.bcd"))); // 'b' are hex chars
- assertEquals("IDENTIFIER(foo) DOT IDENTIFIER(xyz)", values(tokens("foo.xyz")));
- }
-
- @Test
- public void testNoIndentation() throws Exception {
- assertEquals("INT(1) NEWLINE INT(2) NEWLINE INT(3)",
- values(tokens("1\n2\n3")));
- assertEquals("INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3) NEWLINE INT(4) WHITESPACE",
- values(tokens("1\n 2\n 3\n4 ")));
- assertEquals("INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3)",
- values(tokens("1\n 2\n 3")));
- assertEquals("INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3)",
- values(tokens("1\n 2\n 3")));
- assertEquals("INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
- values(tokens("1\n 2\n 3\n 4\n5")));
-
- assertEquals("INT(1) NEWLINE WHITESPACE INT(2) NEWLINE WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
- values(tokens("1\n 2\n 3\n 4\n5")));
- }
-
- @Test
- public void testIndentationInsideParens() throws Exception {
- // Indentation is ignored inside parens:
- assertEquals("INT(1) WHITESPACE LPAREN NEWLINE WHITESPACE INT(2) NEWLINE " +
- "WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
- values(tokens("1 (\n 2\n 3\n 4\n5")));
- assertEquals("INT(1) WHITESPACE LBRACE NEWLINE WHITESPACE INT(2) NEWLINE " +
- "WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
- values(tokens("1 {\n 2\n 3\n 4\n5")));
- assertEquals("INT(1) WHITESPACE LBRACKET NEWLINE WHITESPACE INT(2) NEWLINE " +
- "WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
- values(tokens("1 [\n 2\n 3\n 4\n5")));
- assertEquals("INT(1) WHITESPACE LBRACKET NEWLINE WHITESPACE INT(2) RBRACKET " +
- "NEWLINE WHITESPACE INT(3) NEWLINE WHITESPACE INT(4) NEWLINE INT(5)",
- values(tokens("1 [\n 2]\n 3\n 4\n5")));
- }
-
- @Test
- public void testNoIndentationAtEOF() throws Exception {
- assertEquals("NEWLINE WHITESPACE INT(1)", values(tokens("\n 1")));
- }
-
- @Test
- public void testBlankLineIndentation() throws Exception {
- // Blank lines and comment lines should not generate any newlines indents
- // (but note that every input ends with).
- assertEquals("NEWLINE WHITESPACE COMMENT NEWLINE", names(tokens("\n #\n")));
- assertEquals("WHITESPACE COMMENT", names(tokens(" #")));
- assertEquals("WHITESPACE COMMENT NEWLINE", names(tokens(" #\n")));
- assertEquals("WHITESPACE COMMENT NEWLINE", names(tokens(" #comment\n")));
- assertEquals("DEF WHITESPACE IDENTIFIER LPAREN IDENTIFIER RPAREN COLON NEWLINE WHITESPACE " +
- "COMMENT NEWLINE NEWLINE WHITESPACE NEWLINE WHITESPACE RETURN WHITESPACE IDENTIFIER NEWLINE",
- names(tokens("def f(x):\n"
- + " # comment\n"
- + "\n"
- + " \n"
- + " return x\n")));
- }
-
- @Test
- public void testMultipleCommentLines() throws Exception {
- assertEquals("COMMENT NEWLINE COMMENT NEWLINE COMMENT NEWLINE COMMENT NEWLINE DEF WHITESPACE IDENTIFIER " +
- "LPAREN IDENTIFIER RPAREN COLON NEWLINE WHITESPACE RETURN WHITESPACE IDENTIFIER NEWLINE",
- names(tokens("# Copyright\n"
- + "#\n"
- + "# A comment line\n"
- + "# An adjoining line\n"
- + "def f(x):\n"
- + " return x\n")));
- }
-
- @Test
- public void testBackslash() throws Exception {
- // illegal characters marked as whitespace (skipped by parser)
- assertEquals("IDENTIFIER WHITESPACE IDENTIFIER",
- names(tokens("a\\\nb")));
- assertEquals("IDENTIFIER ILLEGAL WHITESPACE IDENTIFIER",
- names(tokens("a\\ b")));
- assertEquals("IDENTIFIER LPAREN WHITESPACE INT RPAREN",
- names(tokens("a(\\\n2)")));
- }
-
- @Test
- public void testTokenPositions() throws Exception {
- assertEquals("[0,3) [3,4) [4,7) [7,8) [8,9) [9,10) [10,11) [11,12) [12,13) [13,19) [19,20) [20,21)",
- positions(tokens("foo(bar, {1: 'quux'})")));
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserTest.java
deleted file mode 100644
index 620bf24..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/parser/BuildParserTest.java
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.parser;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildElement;
-import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
-import com.intellij.lang.ASTNode;
-import com.intellij.lang.FileASTNode;
-import com.intellij.lang.ParserDefinition;
-import com.intellij.lang.PsiParser;
-import com.intellij.lang.impl.PsiBuilderAdapter;
-import com.intellij.lang.impl.PsiBuilderImpl;
-import com.intellij.lexer.Lexer;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.impl.source.CharTableImpl;
-import com.intellij.psi.impl.source.tree.LeafElement;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Test for the BUILD file parser (converting lexical elements into PSI elements)
- */
-public class BuildParserTest extends BuildFileIntegrationTestCase {
-
- private final List<String> errors = Lists.newArrayList();
-
- @Override
- protected void doTearDown() {
- errors.clear();
- }
-
- public void testAugmentedAssign() throws Exception {
- assertThat(parse("x += 1"))
- .isEqualTo("aug_assign(reference, int)");
- assertThat(parse("x -= 1"))
- .isEqualTo("aug_assign(reference, int)");
- assertThat(parse("x *= 1"))
- .isEqualTo("aug_assign(reference, int)");
- assertThat(parse("x /= 1"))
- .isEqualTo("aug_assign(reference, int)");
- assertThat(parse("x %= 1"))
- .isEqualTo("aug_assign(reference, int)");
- assertNoErrors();
- }
-
- public void testAssign() throws Exception {
- assertThat(parse("a, b = 5\n"))
- .isEqualTo("assignment(list(reference, target), int)");
- assertNoErrors();
- }
-
- public void testAssign2() throws Exception {
- assertThat(parse("a = b;c = d\n"))
- .isEqualTo(Joiner.on("").join(
- "assignment(target, reference), ",
- "assignment(target, reference)"));
- assertNoErrors();
- }
-
- public void testInvalidAssign() throws Exception {
- parse("1 + (b = c)");
- assertContainsErrors();
- }
-
- public void testTupleAssign() throws Exception {
- assertThat(parse("list[0] = 5; dict['key'] = value\n"))
- .isEqualTo(Joiner.on("").join(
- "assignment(function_call(reference, positional(int)), int), ",
- "assignment(function_call(reference, positional(string)), reference)"));
- assertNoErrors();
- }
-
- public void testPrimary() throws Exception {
- assertThat(parse("f(1 + 2)"))
- .isEqualTo("function_call(reference, arg_list(positional(binary_op(int, int))))");
- assertNoErrors();
- }
-
- public void testSecondary() throws Exception {
- assertThat(parse("f(1 % 2)"))
- .isEqualTo("function_call(reference, arg_list(positional(binary_op(int, int))))");
- assertNoErrors();
- }
-
- public void testDoesNotGetStuck() throws Exception {
- // Make sure the parser does not get stuck when trying
- // to parse an expression containing a syntax error.
- parse("f(1, ], 3)");
- parse("f(1, ), 3)");
- parse("[ ) for v in 3)");
- parse("f(1, [x for foo foo foo foo], 3)");
- }
-
- public void testInvalidFunctionStatementDoesNotGetStuck() throws Exception {
- // Make sure the parser does not get stuck when trying
- // to parse a function statement containing a syntax error.
- parse("def is ");
- parse("def fn(");
- parse("def empty)");
- }
-
- public void testSubstring() throws Exception {
- assertThat(parse("'FOO.CC'[:].lower()[1:]"))
- .isEqualTo(Joiner.on("").join(
- "function_call(",
- "function_call(function_call(string), reference, arg_list), ",
- "positional(int))"));
- assertNoErrors();
- }
-
- public void testFuncallExpr() throws Exception {
- assertThat(parse("foo(1, 2, bar=wiz)"))
- .isEqualTo(Joiner.on("").join(
- "function_call(reference, arg_list(",
- "positional(int), ",
- "positional(int), ",
- "keyword(reference)))"));
- assertNoErrors();
- }
-
- public void testMethCallExpr() throws Exception {
- assertThat(parse("foo.foo(1, 2, bar=wiz)"))
- .isEqualTo(Joiner.on("").join(
- "function_call(reference, reference, ",
- "arg_list(positional(int), positional(int), keyword(reference)))"));
- assertNoErrors();
- }
-
- public void testChainedMethCallExpr() throws Exception {
- assertThat(parse("foo.replace().split(1)"))
- .isEqualTo("function_call(function_call(reference, reference, arg_list), reference, arg_list(positional(int)))");
- assertNoErrors();
- }
-
- public void testPropRefExpr() throws Exception {
- assertThat(parse("foo.foo"))
- .isEqualTo("dot_expr(reference, reference)");
- assertNoErrors();
- }
-
- public void testStringMethExpr() throws Exception {
- assertThat(parse("'foo'.foo()"))
- .isEqualTo("function_call(string, reference, arg_list)");
- assertNoErrors();
- }
-
- public void testFuncallLocation() throws Exception {
- assertThat(parse("a(b);c = d\n"))
- .isEqualTo(Joiner.on("").join(
- "function_call(reference, arg_list(positional(reference))), ",
- "assignment(target, reference)"));
- assertNoErrors();
- }
-
- public void testList() throws Exception {
- assertThat(parse("[0,f(1),2]"))
- .isEqualTo("list(int, function_call(reference, arg_list(positional(int))), int)");
- assertNoErrors();
- }
-
- public void testDict() throws Exception {
- assertThat(parse("{1:2,2:f(1),3:4}"))
- .isEqualTo(Joiner.on("").join(
- "dict(",
- "dict_entry(int, int), ",
- "dict_entry(int, function_call(reference, arg_list(positional(int)))), ",
- "dict_entry(int, int)",
- ")"));
- assertNoErrors();
- }
-
- public void testArgumentList() throws Exception {
- assertThat(parse("f(0,g(1,2),2)"))
- .isEqualTo(Joiner.on("").join(
- "function_call(reference, arg_list(",
- "positional(int), ",
- "positional(function_call(reference, arg_list(positional(int), positional(int)))), ",
- "positional(int)))"));
- assertNoErrors();
- }
-
- public void testForBreakContinue() throws Exception {
- String parsed = parse(
- "def foo():",
- " for i in [1, 2]:",
- " break",
- " continue",
- " break");
- assertThat(parsed)
- .isEqualTo(Joiner.on("").join(
- "function_def(parameter_list, ",
- "stmt_list(for(target, list(int, int), ",
- "stmt_list(flow, flow, flow))))"));
- assertNoErrors();
- }
-
- public void testEmptyTuple() throws Exception {
- assertThat(parse("()"))
- .isEqualTo("list");
- assertNoErrors();
- }
-
- public void testTupleTrailingComma() throws Exception {
- assertThat(parse("(42,)"))
- .isEqualTo("list(int)");
- assertNoErrors();
- }
-
- public void testSingleton() throws Exception {
- assertThat(parse("(42)")) // not a tuple!
- .isEqualTo("list(int)");
- assertNoErrors();
- }
-
- public void testDictionaryLiterals() throws Exception {
- assertThat(parse("{1:42}"))
- .isEqualTo("dict(dict_entry(int, int))");
- assertNoErrors();
- }
-
- public void testDictionaryLiterals1() throws Exception {
- assertThat(parse("{}"))
- .isEqualTo("dict");
- assertNoErrors();
- }
-
- public void testDictionaryLiterals2() throws Exception {
- assertThat(parse("{1:42,}"))
- .isEqualTo("dict(dict_entry(int, int))");
- assertNoErrors();
- }
-
- public void testDictionaryLiterals3() throws Exception {
- assertThat(parse("{1:42,2:43,3:44}"))
- .isEqualTo(Joiner.on("").join(
- "dict(",
- "dict_entry(int, int), ",
- "dict_entry(int, int), ",
- "dict_entry(int, int))"));
- assertNoErrors();
- }
-
- public void testInvalidListComprehensionSyntax() throws Exception {
- assertThat(parse("[x for x for y in ['a']]"))
- .isEqualTo("list_comp(reference, reference)");
- assertContainsErrors();
- }
-
- public void testListComprehensionEmptyList() throws Exception {
- // At the moment, we just parse the components of comprehension suffixes.
- assertThat(parse("['foo/%s.java' % x for x in []]"))
- .isEqualTo("list_comp(binary_op(string, reference), target, list)");
- assertNoErrors();
- }
-
- public void testListComprehension() throws Exception {
- assertThat(parse("['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]"))
- .isEqualTo(Joiner.on("").join(
- "list_comp(binary_op(string, reference), ",
- "target, ",
- "list(string, string, string))"));
- assertNoErrors();
- }
-
- public void testDoesntGetStuck2() throws Exception {
- parse(
- "def foo():",
- " a = 2 for 4", // parse error
- " b = [3, 4]",
- "",
- "d = 4 ada", // parse error
- "",
- "def bar():",
- " a = [3, 4]",
- " b = 2 + + 5", // parse error
- "");
- assertContainsErrors();
- }
-
- public void testDoesntGetStuck3() throws Exception {
- parse("load(*)");
- parse("load()");
- parse("load(,)");
- parse("load)");
- parse("load(,");
- parse("load(,\"string\"");
- assertContainsErrors();
- }
-
- public void testExprAsStatement() throws Exception {
- String parsed = parse(
- "li = []",
- "li.append('a.c')",
- "\"\"\" string comment \"\"\"",
- "foo(bar)");
- assertThat(parsed)
- .isEqualTo(Joiner.on("").join(
- "assignment(target, list), ",
- "function_call(reference, reference, arg_list(positional(string))), ",
- "string, ",
- "function_call(reference, arg_list(positional(reference)))"));
- assertNoErrors();
- }
-
- public void testPrecedence1() {
- assertThat(parse("'%sx' % 'foo' + 'bar'"))
- .isEqualTo("binary_op(binary_op(string, string), string)");
- assertNoErrors();
- }
-
- public void testPrecedence2() {
- assertThat(parse("('%sx' + 'foo') * 'bar'"))
- .isEqualTo("binary_op(list(binary_op(string, string)), string)");
- assertNoErrors();
- }
-
- public void testPrecedence3() {
- assertThat(parse("'%sx' % ('foo' + 'bar')"))
- .isEqualTo("binary_op(string, list(binary_op(string, string)))");
- assertNoErrors();
- }
-
- public void testPrecedence4() throws Exception {
- assertThat(parse("1 + - (2 - 3)"))
- .isEqualTo("binary_op(int, positional(list(binary_op(int, int))))");
- assertNoErrors();
- }
-
- public void testPrecedence5() throws Exception {
- assertThat(parse("2 * x | y + 1"))
- .isEqualTo("binary_op(binary_op(int, reference), binary_op(reference, int))");
- assertNoErrors();
- }
-
- public void testNotIsIgnored() throws Exception {
- assertThat(parse("not 'b'"))
- .isEqualTo("string");
- assertNoErrors();
- }
-
- public void testNotIn() throws Exception {
- assertThat(parse("'a' not in 'b'"))
- .isEqualTo("binary_op(string, string)");
- assertNoErrors();
- }
-
- public void testParseBuildFileWithSingeRule() throws Exception {
- ASTNode tree = createAST(
- "genrule(name = 'foo',",
- " srcs = ['input.csv'],",
- " outs = [ 'result.txt',",
- " 'result.log'],",
- " cmd = 'touch result.txt result.log')");
- List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
- assertThat(stmts).hasSize(1);
- assertNoErrors();
- }
-
- public void testParseBuildFileWithMultipleRules() throws Exception {
- ASTNode tree = createAST(
- "genrule(name = 'foo',",
- " srcs = ['input.csv'],",
- " outs = [ 'result.txt',",
- " 'result.log'],",
- " srcs = ['input.csv'],",
- " cmd = 'touch result.txt result.log')",
- "",
- "genrule(name = 'bar',",
- " outs = [ 'graph.svg'],",
- " cmd = 'touch graph.svg')");
- List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
- assertThat(stmts).hasSize(2);
- assertNoErrors();
- }
-
- public void testMissingComma() throws Exception {
- // missing comma after name='foo'
- parse("genrule(name = 'foo'",
- " srcs = ['in'])");
- assertContainsError("',' expected");
- }
-
- public void testDoubleSemicolon() throws Exception {
- parse("x = 1; ; x = 2;");
- assertContainsError("expected an expression");
- }
-
- public void testMissingBlock() throws Exception {
- parse(
- "x = 1;",
- "def foo(x):",
- "x = 2;\n");
- assertContainsError("'indent' expected");
- }
-
- public void testFunCallBadSyntax() throws Exception {
- parse("f(1,\n");
- assertContainsError("')' expected");
- }
-
- public void testFunCallBadSyntax2() throws Exception {
- parse("f(1, 5, ,)\n");
- assertContainsError("expected an expression");
- }
-
- public void testLoad() throws Exception {
- ASTNode tree = createAST("load('file', 'foo', 'bar',)\n");
- List<LoadStatement> stmts = getTopLevelNodesOfType(tree, LoadStatement.class);
- assertThat(stmts).hasSize(1);
-
- LoadStatement stmt = stmts.get(0);
- assertThat(stmt.getImportedPath()).isEqualTo("file");
- assertThat(stmt.getImportedSymbolNames()).isEqualTo(new String[] {"foo", "bar"});
- assertNoErrors();
- }
-
- public void testLoadNoSymbol() throws Exception {
- parse("load('/foo/bar/file')\n");
- assertContainsError("'load' statements must include at least one loaded function");
- }
-
- public void testFunctionDefinition() throws Exception {
- ASTNode tree = createAST(
- "def function(name = 'foo', srcs, outs, *args, **kwargs):",
- " native.java_library(",
- " name = name,",
- " srcs = srcs,",
- " )",
- " return");
- List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
- assertThat(stmts).hasSize(1);
- assertNoErrors();
- }
-
- public void testFunctionCall() throws Exception {
- ASTNode tree = createAST("function(name = 'foo', srcs, *args, **kwargs)");
- List<BuildElement> stmts = getTopLevelNodesOfType(tree, BuildElement.class);
- assertThat(stmts).hasSize(1);
- assertThat(treeToString(tree))
- .isEqualTo(Joiner.on("").join(
- "function_call(reference, arg_list(",
- "keyword(string), ",
- "positional(reference), ",
- "*(reference), ",
- "**(reference)))"));
- assertNoErrors();
- }
-
- public void testConditionalStatement() throws Exception {
- // we don't yet bother specifying which kind of conditionals we hit
- assertThat(parse("if x : y elif a : b else c"))
- .isEqualTo(Joiner.on("").join(
- "if(",
- "if_part(reference, reference), ",
- "else_if_part(reference, reference), ",
- "else_part(reference))"));
- }
-
- private ASTNode createAST(String... lines) {
- StringBuilder builder = new StringBuilder();
- for (String line : lines) {
- builder.append(line).append("\n");
- }
- return createAST(builder.toString());
- }
-
- private ASTNode createAST(String text) {
- ParserDefinition definition = new BuildParserDefinition();
- PsiParser parser = definition.createParser(getProject());
- Lexer lexer = definition.createLexer(getProject());
- PsiBuilderImpl psiBuilder = new PsiBuilderImpl(getProject(), null, definition, lexer, new CharTableImpl(), text, null, null);
- PsiBuilderAdapter adapter = new PsiBuilderAdapter(psiBuilder) {
- @Override
- public void error(String messageText) {
- super.error(messageText);
- errors.add(messageText);
- }
- };
- return parser.parse(definition.getFileNodeType(), adapter);
- }
-
- private String parse(String... lines) {
- StringBuilder builder = new StringBuilder();
- for (String line : lines) {
- builder.append(line).append("\n");
- }
- return parse(builder.toString());
- }
-
- private String parse(String text) {
- ASTNode tree = createAST(text);
- return treeToString(tree);
- }
-
- private String treeToString(ASTNode tree) {
- StringBuilder builder = new StringBuilder();
- nodeToString(tree, builder);
- return builder.toString();
- }
-
- private void nodeToString(ASTNode node, StringBuilder builder) {
- if (node instanceof LeafElement || node.getPsi() == null) {
- return;
- }
- PsiElement[] childPsis = getChildBuildPsis(node);
- if (node instanceof FileASTNode) {
- appendChildren(childPsis, builder, false);
- return;
- }
- builder.append(node.getElementType());
- appendChildren(childPsis, builder, true);
- }
-
- private void appendChildren(PsiElement[] childPsis, StringBuilder builder, boolean bracket) {
- if (childPsis.length == 0) {
- return;
- }
- if (bracket) {
- builder.append("(");
- }
- nodeToString(childPsis[0].getNode(), builder);
- for (int i = 1; i < childPsis.length; i++) {
- builder.append(", ");
- nodeToString(childPsis[i].getNode(), builder);
- }
- if (bracket) {
- builder.append(")");
- }
- }
-
- private static <T> List<T> getTopLevelNodesOfType(ASTNode node, Class<T> clazz) {
- return (List) Arrays.stream(node.getChildren(null))
- .map(ASTNode::getPsi)
- .filter(psiElement -> clazz.isInstance(psiElement))
- .collect(Collectors.toList());
- }
-
- private PsiElement[] getChildBuildPsis(ASTNode node) {
- return Arrays.stream(node.getChildren(null))
- .map(ASTNode::getPsi)
- .filter(psiElement -> psiElement instanceof BuildElement)
- .toArray(PsiElement[]::new);
- }
-
- private void assertNoErrors() {
- assertThat(errors).isEmpty();
- }
-
- private void assertContainsErrors() {
- assertThat(errors).isNotEmpty();
- }
-
- private void assertContainsError(String message) {
- assertThat(errors).contains(message);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/FileCopyTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/FileCopyTest.java
deleted file mode 100644
index 0039011..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/FileCopyTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.openapi.command.WriteCommandAction;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.refactoring.copy.CopyHandler;
-
-/**
- * Tests copying files
- */
-public class FileCopyTest extends BuildFileIntegrationTestCase {
-
- public void testCopyingJavaFileReferencedByGlob() {
- createDirectory("java");
- PsiFile javaFile = createPsiFile(
- "java/Test.java",
- "package java;",
- "public class Test {}");
-
- PsiFile javaFile2 = createPsiFile(
- "java/Test2.java",
- "package java;",
- "public class Test2 {}");
-
- createBuildFile(
- "java/BUILD",
- "java_library(",
- " name = 'lib',",
- " srcs = glob(['**/*.java']),",
- ")");
-
- PsiDirectory otherDir = createPsiDirectory("java/other");
-
- WriteCommandAction.runWriteCommandAction(null, () -> {
- CopyHandler.doCopy(new PsiElement[] {javaFile, javaFile2}, otherDir);
- });
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/RenameRefactoringTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/RenameRefactoringTest.java
deleted file mode 100644
index 26e0030..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/refactor/RenameRefactoringTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.refactor;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.psi.PsiFile;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that BUILD file references are correctly updated when performing rename refactors.
- */
-public class RenameRefactoringTest extends BuildFileIntegrationTestCase {
-
- public void testRenameJavaClass() {
- PsiFile javaFile = createPsiFile(
- "com/google/foo/JavaClass.java",
- "package com.google.foo;",
- "public class JavaClass {}");
-
- BuildFile buildFile = createBuildFile(
- "com/google/foo/BUILD",
- "java_library(name = \"ref1\", srcs = [\"//com/google/foo:JavaClass.java\"])",
- "java_library(name = \"ref2\", srcs = [\"JavaClass.java\"])",
- "java_library(name = \"ref3\", srcs = [\":JavaClass.java\"])");
-
- List<StringLiteral> references = findAllReferencingElementsOfType(javaFile, StringLiteral.class);
- assertThat(references).hasSize(3);
-
- assertThat(references.get(0).getStringContents()).isEqualTo("//com/google/foo:JavaClass.java");
- assertThat(references.get(1).getStringContents()).isEqualTo("JavaClass.java");
- assertThat(references.get(2).getStringContents()).isEqualTo(":JavaClass.java");
-
- renamePsiElement(javaFile, "NewName.java");
- assertThat(references.get(0).getStringContents()).isEqualTo("//com/google/foo:NewName.java");
- assertThat(references.get(1).getStringContents()).isEqualTo("NewName.java");
- assertThat(references.get(2).getStringContents()).isEqualTo(":NewName.java");
- }
-
- public void testRenameRule() {
- BuildFile fooPackage = createBuildFile(
- "com/google/foo/BUILD",
- "rule_type(name = \"target\")",
- "java_library(name = \"local_ref\", srcs = [\":target\"])");
-
- BuildFile barPackage = createBuildFile(
- "com/google/test/bar/BUILD",
- "rule_type(name = \"ref\", arg = \"//com/google/foo:target\")",
- "top_level_ref = \"//com/google/foo:target\"");
-
- FuncallExpression targetRule = PsiUtils.findFirstChildOfClassRecursive(fooPackage, FuncallExpression.class);
- renamePsiElement(targetRule, "newTargetName");
-
- assertFileContents(fooPackage,
- "rule_type(name = \"newTargetName\")",
- "java_library(name = \"local_ref\", srcs = [\":newTargetName\"])");
-
- assertFileContents(barPackage,
- "rule_type(name = \"ref\", arg = \"//com/google/foo:newTargetName\")",
- "top_level_ref = \"//com/google/foo:newTargetName\"");
- }
-
- public void testRenameSkylarkExtension() {
- BuildFile extFile = createBuildFile(
- "java/com/google/tools/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google:tools/build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = []");
-
- renamePsiElement(extFile, "skylark.bzl");
-
- assertFileContents(buildFile,
- "load(",
- "\"//java/com/google:tools/skylark.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = []");
- }
-
- public void testRenameLoadedFunction() {
- BuildFile extFile = createBuildFile(
- "java/com/google/tools/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = []");
-
- FunctionStatement fn = extFile.findChildByClass(FunctionStatement.class);
- renamePsiElement(fn, "action");
-
- assertFileContents(extFile,
- "def action(name, deps)");
-
- assertFileContents(buildFile,
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"action\"",
- ")",
- "action(name = \"name\", deps = []");
- }
-
- public void testRenameLocalVariable() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "a = 1",
- "c = a");
-
- TargetExpression target = PsiUtils.findFirstChildOfClassRecursive(file, TargetExpression.class);
- assertThat(target.getText()).isEqualTo("a");
-
- renamePsiElement(target, "b");
-
- assertFileContents(file,
- "b = 1",
- "c = b");
- }
-
- // all references, including path fragments in labels, should be renamed.
- public void testRenameDirectory() {
- BuildFile bazPackage = createBuildFile("java/com/baz/BUILD");
- BuildFile toolsSubpackage = createBuildFile("java/com/google/tools/BUILD");
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = [\"//java/com/baz:target\"]");
-
- renameDirectory("java/com", "java/alt");
-
- assertFileContents(buildFile,
- "load(",
- "\"//java/alt/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = [\"//java/alt/baz:target\"]");
- }
-
- public void testRenameFunctionParameter() {
- BuildFile extFile = createBuildFile(
- "java/com/google/tools/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = []");
-
- FunctionStatement fn = extFile.findChildByClass(FunctionStatement.class);
- Parameter param = fn.getParameterList().findParameterByName("deps");
- renamePsiElement(param, "exports");
-
- assertFileContents(extFile,
- "def function(name, exports)");
-
- assertFileContents(buildFile,
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", exports = []");
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/GlobReferenceTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/GlobReferenceTest.java
deleted file mode 100644
index 09ffe7e..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/GlobReferenceTest.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.ResolveResult;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that glob references are resolved correctly.
- */
-public class GlobReferenceTest extends BuildFileIntegrationTestCase {
-
- public void testSimpleGlobReferencingSingleFile() {
- PsiFile ref = createPsiFile("java/com/google/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(1);
- assertThat(references).containsExactly(ref);
- }
-
- public void testSimpleGlobReferencingSingleFile2() {
- PsiFile ref = createPsiFile("java/com/google/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(1);
- assertThat(references).containsExactly(ref);
- }
-
- public void testSimpleGlobReferencingSingleFile3() {
- PsiFile ref = createPsiFile("java/com/google/Test.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['T*t.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(1);
- assertThat(references).containsExactly(ref);
- }
-
- public void testGlobReferencingMultipleFiles() {
- PsiFile ref1 = createPsiFile("java/com/google/Test.java");
- PsiFile ref2 = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(2);
- assertThat(references).containsExactly(ref1, ref2);
- }
-
- public void testFindsSubDirectories() {
- PsiFile ref1 = createPsiFile("java/com/google/test/Test.java");
- PsiFile ref2 = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(2);
- assertThat(references).containsExactly(ref1, ref2);
- }
-
- public void testGlobWithExcludes() {
- PsiFile test = createPsiFile("java/com/google/tests/Test.java");
- PsiFile foo = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(" +
- " ['**/*.java']," +
- " exclude = ['tests/*.java'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(1);
- assertThat(references).containsExactly(foo);
- }
-
- public void testIncludeDirectories() {
- createDirectory("java/com/google/tests");
- PsiFile test = createPsiFile("java/com/google/tests/Test.java");
- PsiFile foo = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(" +
- " ['**/*']," +
- " exclude = ['BUILD']," +
- " exclude_directories = 0)");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(3);
- assertThat(references).containsExactly(foo, test, test.getParent());
- }
-
- public void testExcludeDirectories() {
- createDirectory("java/com/google/tests");
- PsiFile test = createPsiFile("java/com/google/tests/Test.java");
- PsiFile foo = createPsiFile("java/com/google/Foo.java");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(" +
- " ['**/*']," +
- " exclude = ['BUILD'])");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).hasSize(2);
- assertThat(references).containsExactly(foo, test);
- }
-
- public void testFilesInSubpackagesExcluded() {
- BuildFile pkg = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
- BuildFile subPkg = createBuildFile("java/com/google/other/BUILD");
- createFile("java/com/google/other/Other.java");
-
- GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(pkg, GlobExpression.class);
- List<PsiElement> references = multiResolve(glob);
- assertThat(references).isEmpty();
- }
-
- private List<PsiElement> multiResolve(GlobExpression glob) {
- ResolveResult[] result = glob.getReference().multiResolve(false);
- return Arrays.stream(result)
- .map(ResolveResult::getElement)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
- }
-
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/KeywordReferenceTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/KeywordReferenceTest.java
deleted file mode 100644
index da60773..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/KeywordReferenceTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that keyword references are correctly resolved.
- */
-public class KeywordReferenceTest extends BuildFileIntegrationTestCase {
-
- public void testPlainKeywordReference() {
- BuildFile file = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(name, deps)",
- "function(name = \"name\", deps = [])");
-
- ParameterList params = file.firstChildOfClass(FunctionStatement.class).getParameterList();
- assertThat(params.getElements()).hasLength(2);
-
- ArgumentList args = file.firstChildOfClass(FuncallExpression.class).getArgList();
- assertThat(args.getKeywordArgument("name").getReferencedElement())
- .isEqualTo(params.findParameterByName("name"));
-
- assertThat(args.getKeywordArgument("deps").getReferencedElement())
- .isEqualTo(params.findParameterByName("deps"));
- }
-
- public void testKwargsReference() {
- BuildFile file = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(name, **kwargs)",
- "function(name = \"name\", deps = [])");
-
- ArgumentList args = file.firstChildOfClass(FuncallExpression.class).getArgList();
- assertThat(args.getKeywordArgument("deps").getReferencedElement()).isInstanceOf(Parameter.StarStar.class);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LabelReferenceTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LabelReferenceTest.java
deleted file mode 100644
index 09bdbff..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LabelReferenceTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiReference;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that string literal references are correctly resolved.
- */
-public class LabelReferenceTest extends BuildFileIntegrationTestCase {
-
- public void testExternalFileReference() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "exports_files([\"test.txt\", \"//java/com/google:plugin.xml\"])");
-
- PsiFile txtFile = createPsiFile("java/com/google/test.txt");
- PsiFile xmlFile = createPsiFile("java/com/google/plugin.xml");
-
- List<StringLiteral> strings = PsiUtils.findAllChildrenOfClassRecursive(file, StringLiteral.class);
- assertThat(strings).hasSize(2);
- assertThat(strings.get(0).getReferencedElement())
- .isEqualTo(txtFile);
- assertThat(strings.get(1).getReferencedElement())
- .isEqualTo(xmlFile);
- }
-
- public void testLocalRuleReference() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "java_library(name = \"lib\")",
- "java_library(name = \"foo\", deps = [\":lib\"])",
- "java_library(name = \"bar\", deps = [\"//java/com/google:lib\"])");
-
- FuncallExpression lib = file.findRule("lib");
- FuncallExpression foo = file.findRule("foo");
- FuncallExpression bar = file.findRule("bar");
-
- assertThat(lib).isNotNull();
-
- StringLiteral label = PsiUtils.findFirstChildOfClassRecursive(foo.getKeywordArgument("deps"), StringLiteral.class);
- assertThat(label.getReferencedElement()).isEqualTo(lib);
-
- label = PsiUtils.findFirstChildOfClassRecursive(bar.getKeywordArgument("deps"), StringLiteral.class);
- assertThat(label.getReferencedElement()).isEqualTo(lib);
- }
-
- public void testTargetInAnotherPackageResolves() {
- BuildFile targetFile = createBuildFile(
- "java/com/google/foo/BUILD",
- "rule(name = \"target\")");
-
- BuildFile referencingFile = createBuildFile(
- "java/com/google/bar/BUILD",
- "rule(name = \"other\", dep = \"//java/com/google/foo:target\")");
-
- FuncallExpression target = targetFile.findRule("target");
- assertThat(target).isNotNull();
-
- Argument.Keyword depArgument = referencingFile
- .findRule("other")
- .getKeywordArgument("dep");
-
- assertThat(depArgument.getValue().getReferencedElement())
- .isEqualTo(target);
- }
-
- public void testRuleNameDoesntCrossPackageBoundaries() {
- BuildFile targetFile = createBuildFile(
- "java/com/google/pkg/subpkg/BUILD",
- "rule(name = \"target\")");
-
- BuildFile referencingFile = createBuildFile(
- "java/com/google/pkg/BUILD",
- "rule(name = \"other\", dep = \":subpkg/target\")");
-
- Argument.Keyword depArgument = referencingFile
- .findRule("other")
- .getKeywordArgument("dep");
-
- LabelReference ref = (LabelReference) depArgument.getValue().getReference();
- assertThat(ref.resolve()).isNull();
-
- replaceStringContents(ref.getElement(), "//java/com/google/pkg/subpkg:target");
- assertThat(ref.resolve()).isNotNull();
- assertThat(ref.resolve()).isEqualTo(targetFile.findRule("target"));
- }
-
- public void testLabelWithImplicitRuleName() {
- BuildFile targetFile = createBuildFile(
- "java/com/google/foo/BUILD",
- "rule(name = \"foo\")");
-
- BuildFile referencingFile = createBuildFile(
- "java/com/google/bar/BUILD",
- "rule(name = \"other\", dep = \"//java/com/google/foo\")");
-
- FuncallExpression target = targetFile.findRule("foo");
- assertThat(target).isNotNull();
-
- Argument.Keyword depArgument = referencingFile
- .findRule("other")
- .getKeywordArgument("dep");
-
- assertThat(depArgument.getValue().getReferencedElement())
- .isEqualTo(target);
- }
-
- public void testAbsoluteLabelInSkylarkExtension() {
- BuildFile targetFile = createBuildFile(
- "java/com/google/foo/BUILD",
- "rule(name = \"foo\")");
-
- BuildFile referencingFile = createBuildFile(
- "java/com/google/foo/skylark.bzl",
- "LIST = ['//java/com/google/foo:foo']");
-
- FuncallExpression target = targetFile.findRule("foo");
- assertThat(target).isNotNull();
-
- StringLiteral label = PsiUtils.findFirstChildOfClassRecursive(referencingFile, StringLiteral.class);
- assertThat(label.getReferencedElement()).isEqualTo(target);
- }
-
- public void testRulePreferredOverFile() {
- BuildFile targetFile = createBuildFile(
- "java/com/foo/BUILD",
- "java_library(name = 'lib')");
-
- createDirectory("java/com/foo/lib");
-
- BuildFile referencingFile = createBuildFile(
- "java/com/google/bar/BUILD",
- "java_library(",
- " name = 'bar',",
- " src = glob(['**/*.java'])," +
- " deps = ['//java/com/foo:lib'],",
- ")");
-
- FuncallExpression target = targetFile.findRule("lib");
- assertThat(target).isNotNull();
-
- PsiReference[] references = FindUsages.findAllReferences(target);
- assertThat(references).hasLength(1);
-
- PsiElement element = references[0].getElement();
- FuncallExpression rule = PsiUtils.getParentOfType(element, FuncallExpression.class);
- assertThat(rule.getName()).isEqualTo("bar");
- assertThat(rule.getContainingFile()).isEqualTo(referencingFile);
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LoadedSkylarkExtensionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LoadedSkylarkExtensionTest.java
deleted file mode 100644
index d1c6356..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LoadedSkylarkExtensionTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
-import com.google.idea.blaze.base.lang.buildfile.psi.LoadStatement;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that funcall references and load statement contents are correctly resolved.
- */
-public class LoadedSkylarkExtensionTest extends BuildFileIntegrationTestCase {
-
- public void testStandardLoadReference() {
- BuildFile extFile = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google:build_defs.bzl\",",
- "\"function\"",
- ")");
-
- LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
- assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
-
- FunctionStatement function = extFile.firstChildOfClass(FunctionStatement.class);
- assertThat(function).isNotNull();
-
- assertThat(load.getImportedSymbolElements()).hasLength(1);
- assertThat(load.getImportedSymbolElements()[0].getReferencedElement()).isEqualTo(function);
- }
-
- // TODO: If we want to support this deprecated format, we should start by relaxing the ":" requirement in Label
- //public void testDeprecatedImportLabelFormat() {
- // BuildFile extFile = createBuildFile(
- // "java/com/google/build_defs.bzl",
- // "def function(name, deps)");
- //
- // BuildFile buildFile = createBuildFile(
- // "java/com/google/tools/BUILD",
- // "load(",
- // "\"//java/com/google/build_defs.bzl\",",
- // "\"function\"",
- // ")");
- //
- // LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
- // assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
- //}
-
- public void testPackageLocalImportLabelFormat() {
- BuildFile extFile = createBuildFile(
- "java/com/google/tools/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/tools/BUILD",
- "load(",
- "\":build_defs.bzl\",",
- "\"function\"",
- ")");
-
- LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
- assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
- }
-
- public void testMultipleImportedFunctions() {
- BuildFile extFile = createBuildFile(
- "java/com/google/build_defs.bzl",
- "def fn1(name, deps)",
- "def fn2(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google:build_defs.bzl\",",
- "\"fn1\"",
- "\"fn2\"",
- ")");
-
- LoadStatement load = buildFile.firstChildOfClass(LoadStatement.class);
- assertThat(load.getImportPsiElement().getReferencedElement()).isEqualTo(extFile);
-
- FunctionStatement[] functions = extFile.childrenOfClass(FunctionStatement.class);
- assertThat(functions).hasLength(2);
- assertThat(load.getImportedFunctionReferences()).isEqualTo(functions);
- }
-
- public void testFuncallReference() {
- BuildFile extFile = createBuildFile(
- "java/com/google/tools/build_defs.bzl",
- "def function(name, deps)");
-
- BuildFile buildFile = createBuildFile(
- "java/com/google/BUILD",
- "load(",
- "\"//java/com/google/tools:build_defs.bzl\",",
- "\"function\"",
- ")",
- "function(name = \"name\", deps = []");
-
- FunctionStatement function = extFile.firstChildOfClass(FunctionStatement.class);
- FuncallExpression funcall = buildFile.firstChildOfClass(FuncallExpression.class);
-
- assertThat(function).isNotNull();
- assertThat(funcall.getReferencedElement()).isEqualTo(function);
- }
-
- // relative paths in skylark extensions which lie in subdirectories are relative to the parent blaze package directory
- public void testRelativePathInSubdirectory() {
- createFile("java/com/google/BUILD");
- BuildFile referencedFile = createBuildFile(
- "java/com/google/nonPackageSubdirectory/skylark.bzl",
- "def function(): return");
- BuildFile file = createBuildFile(
- "java/com/google/nonPackageSubdirectory/other.bzl",
- "load(" +
- " ':nonPackageSubdirectory/skylark.bzl',",
- " 'function',",
- ")",
- "function()"
- );
-
- FunctionStatement function = referencedFile.firstChildOfClass(FunctionStatement.class);
- FuncallExpression funcall = file.firstChildOfClass(FuncallExpression.class);
-
- assertThat(function).isNotNull();
- assertThat(funcall.getReferencedElement()).isEqualTo(function);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LocalReferenceTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LocalReferenceTest.java
deleted file mode 100644
index b50325f..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/LocalReferenceTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.*;
-import com.intellij.psi.PsiElement;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that local references (to TargetExpressions within a given file) are correctly resolved.
- */
-public class LocalReferenceTest extends BuildFileIntegrationTestCase {
-
- public void testCreatesReference() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "a = 1",
- "c = a");
-
- AssignmentStatement[] stmts = file.childrenOfClass(AssignmentStatement.class);
- assertThat(stmts).hasLength(2);
- assertThat(stmts[1].getAssignedValue()).isInstanceOf(ReferenceExpression.class);
-
- ReferenceExpression ref = (ReferenceExpression) stmts[1].getAssignedValue();
- assertThat(ref.getReference()).isInstanceOf(LocalReference.class);
- }
-
- public void testReferenceResolves() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "a = 1",
- "c = a");
-
- AssignmentStatement[] stmts = file.childrenOfClass(AssignmentStatement.class);
- ReferenceExpression ref = (ReferenceExpression) stmts[1].getAssignedValue();
-
- PsiElement referencedElement = ref.getReferencedElement();
- assertThat(referencedElement).isEqualTo(stmts[0].getLeftHandSideExpression());
- }
-
- public void testTargetInOuterScope() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "a = 1",
- "function(c = a)");
-
- TargetExpression target = file.findChildByClass(TargetExpression.class);
- FuncallExpression funcall = file.findChildByClass(FuncallExpression.class);
- ReferenceExpression ref = funcall.firstChildOfClass(ReferenceExpression.class);
- assertThat(ref.getReferencedElement()).isEqualTo(target);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java
deleted file mode 100644
index eed179a..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.references;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.Argument;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.FuncallExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.psi.PsiReference;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests that package references in string literals are correctly resolved.
- */
-public class PackageReferenceTest extends BuildFileIntegrationTestCase {
-
- public void testDirectReferenceResolves() {
- BuildFile buildFile1 = createBuildFile(
- "java/com/google/tools/BUILD",
- "# contents");
-
- BuildFile buildFile2 = createBuildFile(
- "java/com/google/other/BUILD",
- "package_group(name = \"grp\", packages = [\"//java/com/google/tools\"])");
-
- Argument.Keyword packagesArg = buildFile2.firstChildOfClass(FuncallExpression.class).getArgList().getKeywordArgument("packages");
- StringLiteral string = PsiUtils.findFirstChildOfClassRecursive(packagesArg, StringLiteral.class);
- assertThat(string.getReferencedElement()).isEqualTo(buildFile1);
- }
-
- public void testLabelFragmentResolves() {
- BuildFile buildFile1 = createBuildFile(
- "java/com/google/tools/BUILD",
- "java_library(name = \"lib\")");
-
- BuildFile buildFile2 = createBuildFile(
- "java/com/google/other/BUILD",
- "java_library(name = \"lib2\", exports = [\"//java/com/google/tools:lib\"])");
-
- FuncallExpression libTarget = buildFile1.firstChildOfClass(FuncallExpression.class);
- assertThat(libTarget).isNotNull();
-
- Argument.Keyword packagesArg = buildFile2.firstChildOfClass(FuncallExpression.class).getArgList().getKeywordArgument("exports");
- StringLiteral string = PsiUtils.findFirstChildOfClassRecursive(packagesArg, StringLiteral.class);
-
- PsiReference[] references = string.getReferences();
- assertThat(references).hasLength(2);
- assertThat(references[0].resolve()).isEqualTo(libTarget);
- assertThat(references[1].resolve()).isEqualTo(buildFile1);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageTest.java
deleted file mode 100644
index c7e9240..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/BlazePackageTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.psi.PsiFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for BlazePackage
- */
-public class BlazePackageTest extends BuildFileIntegrationTestCase {
-
- public void testFindPackage() {
- BuildFile packageFile = createBuildFile("java/com/google/BUILD");
- PsiFile subDirFile = createPsiFile("java/com/google/tools/test.txt");
- BlazePackage blazePackage = BlazePackage.getContainingPackage(subDirFile);
- assertThat(blazePackage).isNotNull();
- assertThat(blazePackage.buildFile).isEqualTo(packageFile);
- }
-
- public void testScopeDoesntCrossPackageBoundary() {
- BuildFile pkg = createBuildFile("java/com/google/BUILD");
- BuildFile subpkg = createBuildFile("java/com/google/other/BUILD");
-
- BlazePackage blazePackage = BlazePackage.getContainingPackage(pkg);
- assertThat(blazePackage.buildFile).isEqualTo(pkg);
- assertFalse(blazePackage.getSearchScope(false).contains(subpkg.getVirtualFile()));
- }
-
- public void testScopeIncludesSubdirectoriesWhichAreNotBlazePackages() {
- BuildFile pkg = createBuildFile("java/com/google/BUILD");
- BuildFile subpkg = createBuildFile("java/com/google/foo/bar/BUILD");
- PsiFile subDirFile = createPsiFile("java/com/google/foo/test.txt");
-
- BlazePackage blazePackage = BlazePackage.getContainingPackage(subDirFile);
- assertThat(blazePackage.buildFile).isEqualTo(pkg);
- assertTrue(blazePackage.getSearchScope(false).contains(subDirFile.getVirtualFile()));
- }
-
- public void testScopeLimitedToBlazeFiles() {
- BuildFile pkg = createBuildFile("java/com/google/BUILD");
- BuildFile subpkg = createBuildFile("java/com/google/foo/bar/BUILD");
- PsiFile subDirFile = createPsiFile("java/com/google/foo/test.txt");
-
- BlazePackage blazePackage = BlazePackage.getContainingPackage(subDirFile);
- assertThat(blazePackage.buildFile).isEqualTo(pkg);
- assertFalse(blazePackage.getSearchScope(true).contains(subDirFile.getVirtualFile()));
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/GlobalWordIndexTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/GlobalWordIndexTest.java
deleted file mode 100644
index 83350b1..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/search/GlobalWordIndexTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.search;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.impl.cache.CacheManager;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.search.UsageSearchContext;
-import org.intellij.lang.annotations.MagicConstant;
-
-import java.util.Arrays;
-
-/**
- * Test the WordScanner indexes keywords in the way we expect.<br>
- * This is vital for navigation, refactoring, highlighting etc.
- */
-public class GlobalWordIndexTest extends BuildFileIntegrationTestCase {
-
- public void testWordsInComments() {
- VirtualFile file = createFile("java/com/google/BUILD",
- "# words in comments");
- assertContainsWords(file, UsageSearchContext.IN_COMMENTS, "words", "in", "comments");
- }
-
- public void testWordsInStrings() {
- VirtualFile file = createFile("java/com/google/BUILD",
- "name = \"long name with spaces\",",
- "src = [\"name_without_spaces\"]");
- assertContainsWords(file, UsageSearchContext.IN_STRINGS, "long", "name", "with", "spaces", "name_without_spaces");
- }
-
- public void testWordsInCode() {
- VirtualFile file = createFile("java/com/google/BUILD",
- "java_library(",
- "name = \"long name with spaces\",",
- "src = [\"name_without_spaces\"]",
- ")");
- assertContainsWords(file, UsageSearchContext.IN_CODE, "java_library", "name", "src");
- }
-
- private void assertContainsWords(
- VirtualFile file,
- @MagicConstant(flagsFromClass = UsageSearchContext.class) short occurenceMask,
- String... words) {
-
- for (String word : words) {
- VirtualFile[] files = CacheManager.SERVICE.getInstance(getProject()).getVirtualFilesWithWord(
- word,
- occurenceMask,
- GlobalSearchScope.fileScope(getProject(), file),
- true);
- if (!Arrays.asList(files).contains(file)) {
- fail(String.format("Word '%s' not found in file '%s'", word, file));
- }
- }
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/GlobValidationTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/GlobValidationTest.java
deleted file mode 100644
index 108bfbc..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/GlobValidationTest.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile.validation;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.codeInsight.daemon.impl.AnnotationHolderImpl;
-import com.intellij.lang.annotation.Annotation;
-import com.intellij.lang.annotation.AnnotationHolder;
-import com.intellij.lang.annotation.AnnotationSession;
-import com.intellij.psi.PsiFile;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests glob validation.
- */
-public class GlobValidationTest extends BuildFileIntegrationTestCase {
-
- public void testNormalGlob() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'])");
-
- assertNoErrors(file);
- }
-
- public void testNamedIncludeArgument() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(include = ['**/*.java'])");
-
- assertNoErrors(file);
- }
-
- public void testAllArguments() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'], exclude = ['test/*.java'], exclude_directories = 0)");
-
- assertNoErrors(file);
- }
-
- public void testEmptyExcludeList() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'], exclude = [])");
-
- assertNoErrors(file);
- }
-
- public void testNoIncludesError() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(exclude = ['BUILD'])");
-
- assertHasError(file, "Glob expression must contain at least one included string");
- }
-
- public void testSingletonExcludeArgumentError() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'], exclude = 'BUILD')");
-
- assertHasError(file, "Glob parameter 'exclude' must be a list of strings");
- }
-
- public void testSingletonIncludeArgumentError() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(include = '**/*.java')");
-
- assertHasError(file, "Glob parameter 'include' must be a list of strings");
- }
-
- public void testInvalidExcludeDirectoriesValue() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'], exclude = ['test/*.java'], exclude_directories = true)");
-
- assertHasError(file, "exclude_directories parameter to glob must be 0 or 1");
- }
-
- public void testUnrecognizedArgumentError() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(['**/*.java'], exclude = ['test/*.java'], extra = 1)");
-
- assertHasError(file, "Unrecognized glob argument");
- }
-
- public void testInvalidListArgumentValue() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(include = foo)");
-
- assertHasError(file, "Glob parameter 'include' must be a list of strings");
- }
-
- public void testLocalVariableReference() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "foo = ['*.java']",
- "glob(include = foo)");
-
- assertNoErrors(file);
- }
-
- public void testLoadedVariableReference() {
- BuildFile ext = createBuildFile(
- "java/com/foo/vars.bzl",
- "LIST_VAR = ['*']");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "load('//java/com/foo:vars.bzl', 'LIST_VAR')",
- "glob(include = LIST_VAR)");
-
- assertNoErrors(file);
- }
-
- public void testInvalidLoadedVariableReference() {
- BuildFile ext = createBuildFile(
- "java/com/foo/vars.bzl",
- "LIST_VAR = ['*']",
- "def function()");
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "load('//java/com/foo:vars.bzl', 'LIST_VAR', 'function')",
- "glob(include = function)");
-
- assertHasError(file, "Glob parameter 'include' must be a list of strings");
- }
-
- public void testUnresolvedReferenceExpression() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(include = ref)");
-
- assertHasError(file, "Glob parameter 'include' must be a list of strings");
- }
-
- public void testPossibleListExpressionFuncallExpression() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(include = fn.list)");
-
- assertNoErrors(file);
- }
-
- public void testPossibleListExpressionParameter() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "def function(param1, param2):",
- " glob(include = param1)");
-
- assertNoErrors(file);
- }
-
- public void testNestedGlobs() {
- // blaze accepts nested globs
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(glob(['*.java']))");
-
- assertNoErrors(file);
- }
-
- public void testKnownInvalidResolvedListExpression() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "bool_literal = True",
- "glob(bool_literal)");
-
- assertHasError(file, "Glob parameter 'include' must be a list of strings");
- }
-
- public void testKnownInvalidResolvedString() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "bool_literal = True",
- "glob([bool_literal])");
-
- assertHasError(file, "Glob parameter 'include' must be a list of strings");
- }
-
- public void testPossibleStringLiteralIfStatement() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "glob(include = ['*.java', if test : a else b])");
-
- // we don't know what the IfStatement evaluates to
- assertNoErrors(file);
- }
-
- public void testPossibleStringLiteralParameter() {
- BuildFile file = createBuildFile(
- "java/com/google/BUILD",
- "def function(param1, param2):",
- " glob(include = [param1])");
-
- assertNoErrors(file);
- }
-
- private void assertNoErrors(BuildFile file) {
- assertThat(validateFile(file)).isEmpty();
- }
-
- private void assertHasError(BuildFile file, String error) {
- assertHasError(validateFile(file), error);
- }
-
- private void assertHasError(List<Annotation> annotations, String error) {
- List<String> messages = annotations.stream()
- .map(Annotation::getMessage)
- .collect(Collectors.toList());
-
- assertThat(messages).contains(error);
- }
-
- private List<Annotation> validateFile(BuildFile file) {
- GlobErrorAnnotator annotator = createAnnotator(file);
- for (GlobExpression glob : PsiUtils.findAllChildrenOfClassRecursive(file, GlobExpression.class)) {
- annotator.visitGlobExpression(glob);
- }
- return annotationHolder;
- }
-
- private GlobErrorAnnotator createAnnotator(PsiFile file) {
- annotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
- return new GlobErrorAnnotator() {
- @Override
- protected AnnotationHolder getHolder() {
- return annotationHolder;
- }
- };
- }
-
- private AnnotationHolderImpl annotationHolder = null;
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewCompletionTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewCompletionTest.java
deleted file mode 100644
index a9b4b79..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewCompletionTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview;
-
-import com.google.common.base.Joiner;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.projectview.section.sections.Sections;
-import com.intellij.codeInsight.lookup.Lookup;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.psi.PsiFile;
-
-import java.util.Arrays;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests auto-complete in project view files
- */
-public class ProjectViewCompletionTest extends ProjectViewIntegrationTestCase {
-
- private PsiFile setInput(String... fileContents) {
- return testFixture.configureByText(".blazeproject", Joiner.on("\n").join(fileContents));
- }
-
- private void assertResult(String... resultingFileContents) {
- String s = testFixture.getFile().getText();
- testFixture.checkResult(Joiner.on("\n").join(resultingFileContents));
- }
-
- public void testSectionTypeKeywords() {
- setInput(
- "<caret>");
- String[] keywords = getCompletionItemsAsStrings();
-
- assertThat(keywords).asList().containsAllIn(
- Sections.getUndeprecatedParsers().stream().map(SectionParser::getName).collect(Collectors.toList()));
- }
-
- public void testColonAndNewLineAndIndentInsertedAfterListSection() {
- setInput(
- "direc<caret>");
- assertThat(completeIfUnique()).isTrue();
- assertResult(
- "directories:",
- " <caret>");
- }
-
- public void testWhitespaceDividerInsertedAfterScalarSection() {
- setInput(
- "impo<caret>");
-
- LookupElement[] completionItems = testFixture.completeBasic();
- assertThat(completionItems[0].getLookupString()).isEqualTo("import");
-
- testFixture.getLookup().setCurrentItem(completionItems[0]);
- testFixture.finishLookup(Lookup.NORMAL_SELECT_CHAR);
-
- assertResult(
- "import <caret>");
- }
-
- public void testColonDividerAndSpaceInsertedAfterScalarSection() {
- setInput(
- "works<caret>");
- assertThat(completeIfUnique()).isTrue();
- assertResult(
- "workspace_type: <caret>");
- }
-
- public void testNoKeywordCompletionInListItem() {
- setInput(
- "directories:",
- " <caret>");
-
- String[] completionItems = getCompletionItemsAsStrings();
- if (completionItems == null) {
- fail("Spurious completion. New file contents: " + testFixture.getFile().getText());
- }
- assertThat(completionItems).isEmpty();
- }
-
- public void testNoKeywordCompletionAfterKeyword() {
- setInput(
- "import <caret>");
-
- String[] completionItems = getCompletionItemsAsStrings();
- if (completionItems == null) {
- fail("Spurious completion. New file contents: " + testFixture.getFile().getText());
- }
- assertThat(completionItems).isEmpty();
- }
-
- public void testWorkspaceTypeCompletion() {
- setInput(
- "workspace_type: <caret>");
-
- String[] types = getCompletionItemsAsStrings();
-
- assertThat(types).asList().containsAllIn(
- Arrays.stream(WorkspaceType.values()).map(WorkspaceType::getName).collect(Collectors.toList()));
- }
-
- public void testAdditionalLanguagesCompletion() {
- setInput(
- "additional_languages:",
- " <caret>");
-
- String[] types = getCompletionItemsAsStrings();
-
- assertThat(types).asList().containsAllIn(
- Arrays.stream(LanguageClass.values()).map(LanguageClass::getName).collect(Collectors.toList()));
- }
-
- public void testUniqueDirectoryCompleted() {
- setInput(
- "import <caret>");
-
- createDirectory("java");
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isNull();
- assertResult(
- "import java<caret>"
- );
- }
-
- public void testUniqueMultiSegmentDirectoryCompleted() {
- setInput(
- "import <caret>");
-
- createDirectory("java/com/google");
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isNull();
- assertResult(
- "import java/com/google<caret>"
- );
- }
-
- public void testNonDirectoriesIgnored() {
- setInput(
- "import <caret>");
-
- createDirectory("java/com/google");
- createFile("java/IgnoredFile.java");
-
- String[] completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isNull();
- assertResult(
- "import java/com/google<caret>"
- );
- }
-
- public void testMultipleDirectoryOptions() {
- createDirectory("foo");
- createDirectory("bar");
- createDirectory("other");
- createDirectory("ostrich/foo");
- createDirectory("ostrich/fooz");
-
- setInput(
- "targets:",
- " //o<caret>");
-
- String[] completionItems = getCompletionItemsAsSuggestionStrings();
- assertThat(completionItems).asList().containsExactly("other", "ostrich");
-
- performTypingAction(testFixture.getEditor(), 's');
-
- completionItems = getCompletionItemsAsStrings();
- assertThat(completionItems).isNull();
- assertResult(
- "targets:",
- " //ostrich<caret>");
- }
-
- public void testRuleCompletion() {
- createFile(
- "BUILD",
- "java_library(name = 'lib')"
- );
-
- setInput(
- "targets:",
- " //:<caret>");
-
- String[] completionItems = getCompletionItemsAsSuggestionStrings();
- assertThat(completionItems).isNull();
- assertResult(
- "targets:",
- " //:lib<caret>");
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewIntegrationTestCase.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewIntegrationTestCase.java
deleted file mode 100644
index a282bdb..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewIntegrationTestCase.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.BlazeIntegrationTestCase;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-
-/**
- * Project view file specific integration test base
- */
-public abstract class ProjectViewIntegrationTestCase extends BlazeIntegrationTestCase {
-
- @Override
- protected void doSetup() {
- mockBlazeProjectDataManager(getMockBlazeProjectData());
- }
-
- private BlazeProjectData getMockBlazeProjectData() {
- BlazeRoots fakeRoots = new BlazeRoots(
- null,
- ImmutableList.of(workspaceRoot.directory()),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen")
- );
- return new BlazeProjectData(0,
- ImmutableMap.of(),
- fakeRoots,
- new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()),
- new WorkspacePathResolverImpl(workspaceRoot, fakeRoots),
- null,
- null,
- null);
- }
-
-}
\ No newline at end of file
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewParserTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewParserTest.java
deleted file mode 100644
index b6a081c..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/ProjectViewParserTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewPsiElement;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiErrorElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.impl.source.tree.LeafElement;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for the project view file parser
- */
-public class ProjectViewParserTest extends ProjectViewIntegrationTestCase {
-
- private final List<String> errors = Lists.newArrayList();
-
- @Override
- protected void doSetup() {
- errors.clear();
- super.doSetup();
- }
-
- public void testStandardFile() {
- assertThat(parse(
- "directories:",
- " java/com/google/work",
- " java/com/google/other",
- "",
- "targets:",
- " //java/com/google/work/...:all",
- " //java/com/google/other/...:all"
- )).isEqualTo(Joiner.on("").join(
- "list_section(list_item, list_item), ",
- "list_section(list_item, list_item)"
- ));
- assertNoErrors();
- }
-
- public void testIncludeScalarSections() {
- assertThat(parse(
- "import java/com/google/work/.blazeproject",
- "",
- "workspace_type: intellij_plugin",
- "",
- "import_target_output:",
- " //java/com/google/work:target",
- "",
- "excluded_libraries:",
- " java/com/google/common/*"
- )).isEqualTo(Joiner.on("").join(
- "scalar_section(scalar_item), ",
- "scalar_section(scalar_item), ",
- "list_section(list_item), ",
- "list_section(list_item)"
- ));
- assertNoErrors();
- }
-
- public void testUnrecognizedKeyword() {
- parse(
- "impart java/com/google/work/.blazeproject",
- "",
- "workspace_trype: intellij_plugin"
- );
-
- assertContainsErrors(
- "Unrecognized keyword: impart",
- "Unrecognized keyword: workspace_trype");
- }
-
- private String parse(String... lines) {
- PsiFile file = createPsiFile(".blazeproject", lines);
- collectErrors(file);
- return treeToString(file);
- }
-
- private String treeToString(PsiElement psi) {
- StringBuilder builder = new StringBuilder();
- nodeToString(psi, builder);
- return builder.toString();
- }
-
- private void nodeToString(PsiElement psi, StringBuilder builder) {
- if (psi.getNode() instanceof LeafElement) {
- return;
- }
- PsiElement[] children = Arrays.stream(psi.getChildren())
- .filter(t -> t instanceof ProjectViewPsiElement)
- .toArray(PsiElement[]::new);
- if (psi instanceof ProjectViewPsiElement) {
- builder.append(psi.getNode().getElementType());
- appendChildren(children, builder, true);
- } else {
- appendChildren(children, builder, false);
- }
- }
-
- private void appendChildren(PsiElement[] childPsis, StringBuilder builder, boolean bracket) {
- if (childPsis.length == 0) {
- return;
- }
- if (bracket) {
- builder.append("(");
- }
- nodeToString(childPsis[0], builder);
- for (int i = 1; i < childPsis.length; i++) {
- builder.append(", ");
- nodeToString(childPsis[i], builder);
- }
- if (bracket) {
- builder.append(")");
- }
- }
-
- private void assertNoErrors() {
- assertThat(errors).isEmpty();
- }
-
- private void assertContainsErrors(String... errors) {
- assertThat(this.errors).containsAllIn(Arrays.asList(errors));
- }
-
- private void collectErrors(PsiElement psi) {
- errors.addAll(PsiUtils.findAllChildrenOfClassRecursive(psi, PsiErrorElement.class)
- .stream()
- .map(PsiErrorElement::getErrorDescription)
- .collect(Collectors.toList()));
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerTest.java
deleted file mode 100644
index f37da9e..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/lang/projectview/lexer/ProjectViewLexerTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.projectview.lexer;
-
-import com.google.common.base.Joiner;
-import com.google.idea.blaze.base.lang.projectview.ProjectViewIntegrationTestCase;
-import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewLexerBase.Token;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for the project view file lexer
- */
-public class ProjectViewLexerTest extends ProjectViewIntegrationTestCase {
-
- public void testStandardCase() {
- String result = tokenize(
- "directories:",
- " java/com/google/work",
- " java/com/google/other",
- "",
- "targets:",
- " //java/com/google/work/...:all",
- " //java/com/google/other/...:all");
-
- assertThat(result).isEqualTo(Joiner.on(" ").join(
- "list_keyword :",
- "indent identifier",
- "indent identifier",
- "list_keyword :",
- "indent identifier : identifier",
- "indent identifier : identifier"));
- }
-
- public void testIncludeScalarSections() {
- String result = tokenize(
- "import java/com/google/work/.blazeproject",
- "",
- "workspace_type: intellij_plugin",
- "",
- "import_target_output:",
- " //java/com/google/work:target",
- "",
- "excluded_libraries:",
- " java/com/google/common/*");
-
- assertThat(result).isEqualTo(Joiner.on(" ").join(
- "scalar_keyword identifier",
- "scalar_keyword : identifier",
- "list_keyword :",
- "indent identifier : identifier",
- "list_keyword :",
- "indent identifier"));
- }
-
- public void testUnrecognizedKeyword() {
- String result = tokenize(
- "impart java/com/google/work/.blazeproject",
- "",
- "workspace_trype: intellij_plugin");
-
- assertThat(result).isEqualTo(Joiner.on(" ").join(
- "identifier identifier",
- "identifier : identifier"));
- }
-
- private static String tokenize(String... lines) {
- return names(tokens(Joiner.on("\n").join(lines)));
- }
-
- private static Token[] tokens(String input) {
- Token[] tokens = new ProjectViewLexerBase(input).getTokens().toArray(new Token[0]);
- assertNoCharactersMissing(input.length(), tokens);
- return tokens;
- }
-
- /**
- * Both the syntax highlighter and the parser require every character be accounted for by
- * a lexical element.
- */
- private static void assertNoCharactersMissing(int totalLength, Token[] tokens) {
- if (tokens.length != 0 && tokens[tokens.length - 1].right != totalLength) {
- throw new AssertionError(String.format(
- "Last tokenized character '%s' doesn't match document length '%s'",
- tokens[tokens.length - 1].right, totalLength));
- }
- int start = 0;
- for (int i = 0; i < tokens.length; i++) {
- Token token = tokens[i];
- if (token.left != start) {
- throw new AssertionError("Gap/inconsistency at: " + start);
- }
- start = token.right;
- }
- }
-
- /**
- * Returns a string containing the names of the tokens.
- */
- private static String names(Token[] tokens) {
- StringBuilder buf = new StringBuilder();
- for (Token token : tokens) {
- if (isIgnored(token.type)) {
- continue;
- }
- if (buf.length() > 0) {
- buf.append(' ');
- }
- buf.append(token.type);
- }
- return buf.toString();
- }
-
- private static boolean isIgnored(ProjectViewTokenType kind) {
- return kind == ProjectViewTokenType.WHITESPACE || kind == ProjectViewTokenType.NEWLINE;
- }
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/sync/BlazeSyncTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/sync/BlazeSyncTest.java
deleted file mode 100644
index 04fd4ac..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/sync/BlazeSyncTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.sync.actions.IncrementalSyncProjectAction;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for the blaze sync process {@link BlazeSyncTask}
- */
-public class BlazeSyncTest extends BlazeSyncIntegrationTestCase {
-
- public void testSimpleSync() throws Exception {
- setProjectView(
- "directories:",
- " java/com/google",
- "targets:",
- " //java/com/google:lib",
- "workspace_type: java"
- );
-
- createFile(
- "java/com/google/Source.java",
- "package com.google;",
- "public class Source {}"
- );
-
- createFile(
- "java/com/google/Other.java",
- "package com.google;",
- "public class Other {}"
- );
-
- ImmutableMap<Label, RuleIdeInfo> ruleMap = RuleMapBuilder.builder()
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("java/com/google/BUILD"))
- .setLabel("//java/com/google:lib")
- .setKind("java_library")
- .addSource(sourceRoot("java/com/google/Source.java"))
- .addSource(sourceRoot("java/com/google/Other.java")))
- .build();
-
- setRuleMap(ruleMap);
-
- runBlazeSync(IncrementalSyncProjectAction.manualSyncParams);
-
- assertNoErrors();
-
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
- assertThat(blazeProjectData).isNotNull();
- assertThat(blazeProjectData.ruleMap).isEqualTo(ruleMap);
- assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
- .isEqualTo(WorkspaceType.JAVA);
- }
-
-}
diff --git a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java b/blaze-base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java
deleted file mode 100644
index 8fe8f63..0000000
--- a/blaze-base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.BlazeIntegrationTestCase;
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.sync.projectview.ImportRoots;
-
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for ImportRoots
- */
-public class ImportRootsTest extends BlazeIntegrationTestCase {
-
- public void testBazelArtifactDirectoriesExcluded() {
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, BuildSystem.Bazel)
- .add(new DirectoryEntry(new WorkspacePath(""), true))
- .build();
-
- ImmutableList<String> artifactDirs = BuildSystemProvider.getBuildSystemProvider(BuildSystem.Bazel)
- .buildArtifactDirectories(workspaceRoot);
-
- assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath(""));
- assertThat(
- importRoots.excludeDirectories()
- .stream()
- .map(WorkspacePath::relativePath)
- .collect(Collectors.toList())
- ).containsExactlyElementsIn(artifactDirs);
-
- assertThat(artifactDirs).contains("bazel-" + workspaceRoot.directory().getName());
- }
-
- public void testNoAddedExclusionsWithoutWorkspaceRootInclusion() {
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, BuildSystem.Bazel)
- .add(new DirectoryEntry(new WorkspacePath("foo/bar"), true))
- .build();
-
- assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath("foo/bar"));
- assertThat(importRoots.excludeDirectories()).isEmpty();
- }
-
- public void testNoAddedExclusionsForBlaze() {
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
- .add(new DirectoryEntry(new WorkspacePath(""), true))
- .build();
-
- assertThat(importRoots.rootDirectories()).containsExactly(new WorkspacePath(""));
- assertThat(importRoots.excludeDirectories()).isEmpty();
- }
-
- // if the workspace root is an included directory, all rules should be imported as sources.
- public void testAllLabelsIncludedUnderWorkspaceRoot() {
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
- .add(new DirectoryEntry(new WorkspacePath(""), true))
- .build();
-
- assertThat(importRoots.importAsSource(new Label("//:target"))).isTrue();
- assertThat(importRoots.importAsSource(new Label("//foo/bar:target"))).isTrue();
- }
-
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/BlazeIconsTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/BlazeIconsTest.java
deleted file mode 100644
index 85fbc34..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/BlazeIconsTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Test;
-
-import javax.swing.Icon;
-
-import icons.BlazeIcons;
-
-/**
- * Tests for BlazeIcons
- */
-public class BlazeIconsTest {
-
- @Test
- public void testIcon() {
- Icon icon = BlazeIcons.Blaze;
-
- assertNotNull(icon);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandNameTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandNameTest.java
deleted file mode 100644
index 7a55d93..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandNameTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-/**
- * Tests for {@link BlazeCommandName}.
- */
-@RunWith(JUnit4.class)
-public class BlazeCommandNameTest {
- @Test
- public void emptyNameShouldThrow() {
- try {
- BlazeCommandName.fromString("");
- fail("Empty commands should not be allowed.");
- }
- catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void hardcodedNamesShouldBeKnown() {
- assertThat(BlazeCommandName.knownCommands()).contains(BlazeCommandName.MOBILE_INSTALL);
- }
-
- @Test
- public void userCommandNamesShouldBecomeKnown() {
- Collection<String> knownCommandStrings =
- Collections2.transform(BlazeCommandName.knownCommands(),
- new Function<BlazeCommandName, String>() {
- @Nullable
- @Override
- public String apply(BlazeCommandName input) {
- return input.toString();
- }
- });
- assertThat(knownCommandStrings).doesNotContain("user-command");
- BlazeCommandName userCommand = BlazeCommandName.fromString("user-command");
- assertThat(BlazeCommandName.knownCommands()).contains(userCommand);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java
deleted file mode 100644
index 1782ebc..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.command;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for {@link BlazeCommand}.
- */
-@RunWith(JUnit4.class)
-public class BlazeCommandTest extends BlazeTestCase {
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- ExperimentService experimentService = new MockExperimentService();
- applicationServices.register(ExperimentService.class, experimentService);
- applicationServices.register(BlazeUserSettings.class, new BlazeUserSettings());
- }
-
- @Test
- public void addedFlagsShouldGoAtStart() {
- List<String> flagsCommand = BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"))
- .addBlazeFlags("--flag1", "--flag2")
- .addExeFlags("--exeFlag1", "--exeFlag2")
- .build()
- .toList();
- // First three strings are always 'blaze run --tool_tag=ijwb:IDEA:ultimate'
- assertThat(flagsCommand.subList(3, 5))
- .isEqualTo(ImmutableList.of("--flag1", "--flag2"));
- }
-
- @Test
- public void targetsShouldGoAfterBlazeFlagsAndDoubleHyphen() {
- List<String> command = BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"), new Label("//c:d"))
- .addBlazeFlags("--flag1", "--flag2")
- .addExeFlags("--exeFlag1", "--exeFlag2")
- .build()
- .toList();
- // First six strings should be 'blaze run --tool_tag=ijwb:IDEA:ultimate --flag1 --flag2 --'
- assertThat(command.indexOf("--")).isEqualTo(5);
- assertThat(Collections.indexOfSubList(command, ImmutableList.of("//a:b", "//c:d"))).isEqualTo(6);
- }
-
- @Test
- public void exeFlagsShouldGoLast() {
- List<String> command = BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"), new Label("//c:d"))
- .addBlazeFlags("--flag1", "--flag2")
- .addExeFlags("--exeFlag1", "--exeFlag2")
- .build()
- .toList();
- List<String> finalTwoFlags = command.subList(command.size() - 2, command.size());
- assertThat(finalTwoFlags).containsExactly("--exeFlag1", "--exeFlag2");
- }
-
- @Test
- public void maintainUserOrderingOfTargets() {
- List<String> command = BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"), TargetExpression.fromString("-//e:f"), new Label("//c:d"))
- .addBlazeFlags("--flag1", "--flag2")
- .addExeFlags("--exeFlag1", "--exeFlag2")
- .build()
- .toList();
-
- ImmutableList<Object> expected = ImmutableList.builder()
- .add("/usr/bin/blaze")
- .add("run")
- .add(BlazeFlags.getToolTagFlag())
- .add("--flag1")
- .add("--flag2")
- .add("--")
- .add("//a:b")
- .add("-//e:f")
- .add("//c:d")
- .add("--exeFlag1")
- .add("--exeFlag2")
- .build();
- assertThat(command).isEqualTo(expected);
- }
-
- @Test
- public void binaryAndCommandShouldComeFirst() {
- List<String> command = BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.BUILD)
- .addBlazeFlags("--flag")
- .addExeFlags("--exeFlag")
- .build()
- .toList();
- assertThat(command.subList(0, 2)).isEqualTo(ImmutableList.of("/usr/bin/blaze", "build"));
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/experiments/ExperimentServiceImplTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/experiments/ExperimentServiceImplTest.java
deleted file mode 100644
index 15255e4..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/experiments/ExperimentServiceImplTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.collect.ImmutableMap;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.util.Map;
-
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for {@link ExperimentServiceImpl}.
- */
-public class ExperimentServiceImplTest {
-
- @Test
- public void testBooleanPropertyTrue() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(new MapExperimentLoader("test.property", "1"));
- assertThat(experimentService.getExperiment("test.property", false)).isTrue();
- }
-
- @Test
- public void testBooleanPropertyFalse() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(new MapExperimentLoader("test.property", "0"));
- assertThat(experimentService.getExperiment("test.property", true)).isFalse();
- }
-
- @Test
- public void testBooleanPropertyReturnsDefaultWhenMissing() {
- ExperimentService experimentService = new ExperimentServiceImpl(new MapExperimentLoader());
- assertThat(experimentService.getExperiment("test.notthere", true)).isTrue();
- }
-
- @Test
- public void testStringProperty() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(new MapExperimentLoader("test.property", "hi"));
- assertThat(experimentService.getExperimentString("test.property", null)).isEqualTo("hi");
- }
-
- @Test
- public void testStringPropertyReturnsDefaultWhenMissing() {
- ExperimentService experimentService = new ExperimentServiceImpl(new MapExperimentLoader());
- assertThat(experimentService.getExperimentString("test.property", "bye")).isEqualTo("bye");
- }
-
- @Test
- public void testFirstLoaderOverridesSecond() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(
- new MapExperimentLoader("test.property", "1"),
- new MapExperimentLoader("test.property", "0"));
- assertThat(experimentService.getExperiment("test.property", false)).isTrue();
- }
-
- @Test
- public void testOnlyInSecondLoader() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(
- new MapExperimentLoader(), new MapExperimentLoader("test.property", "1"));
- assertThat(experimentService.getExperiment("test.property", false)).isTrue();
- }
-
- @Test
- public void testIntProperty() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(new MapExperimentLoader("test.property", "10"));
- assertThat(experimentService.getExperimentInt("test.property", 0)).isEqualTo(10);
- }
-
- @Test
- public void testIntPropertyDefaultValue() {
- ExperimentService experimentService = new ExperimentServiceImpl(new MapExperimentLoader());
- assertThat(experimentService.getExperimentInt("test.property", 100)).isEqualTo(100);
- }
-
- @Test
- public void testIntPropertyThatDoesntParseReturnsDefaultValue() {
- ExperimentService experimentService =
- new ExperimentServiceImpl(new MapExperimentLoader("test.property", "hello"));
- assertThat(experimentService.getExperimentInt("test.property", 111)).isEqualTo(111);
- }
-
- private static class MapExperimentLoader implements ExperimentLoader {
-
- private final Map<String, String> map;
-
- private MapExperimentLoader(String... keysAndValues) {
- checkState(keysAndValues.length % 2 == 0);
- ImmutableMap.Builder<String, String> mapBuilder = ImmutableMap.builder();
- for (int i = 0; i < keysAndValues.length; i += 2) {
- mapBuilder.put(keysAndValues[i], keysAndValues[i + 1]);
- }
- map = mapBuilder.build();
- }
-
- @Override
- public Map<String, String> getExperiments() {
- return map;
- }
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/experiments/SystemPropertyExperimentLoaderTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/experiments/SystemPropertyExperimentLoaderTest.java
deleted file mode 100644
index 61eb30d..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/experiments/SystemPropertyExperimentLoaderTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class SystemPropertyExperimentLoaderTest {
-
- private static final String EXPERIMENT = "test.foo";
- private static final String PROPERTY = "blaze.experiment.test.foo";
- private static final String VALUE = "true";
-
- @Before
- public void setUp() {
- System.setProperty(PROPERTY, VALUE);
- }
-
- @After
- public void tearDown() {
- System.clearProperty(PROPERTY);
- }
-
- @Test
- public void testGetExperiment() {
- ExperimentLoader loader = new SystemPropertyExperimentLoader();
- assertThat(loader.getExperiments().get(EXPERIMENT)).isEqualTo(VALUE);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/io/MockWorkspaceScanner.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/io/MockWorkspaceScanner.java
deleted file mode 100644
index 9229bfb..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/io/MockWorkspaceScanner.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.io;
-
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.sync.projectview.ImportRoots;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Set;
-
-/**
- * Mocks the file system.
- */
-public final class MockWorkspaceScanner implements WorkspaceScanner {
-
- Set<WorkspacePath> files = Sets.newHashSet();
- Set<WorkspacePath> directories = Sets.newHashSet();
-
- public MockWorkspaceScanner addFile(@NotNull WorkspacePath file) {
- files.add(file);
- return this;
- }
-
- public MockWorkspaceScanner addDirectory(@NotNull WorkspacePath file) {
- addFile(file);
- directories.add(file);
- return this;
- }
-
- public MockWorkspaceScanner addPackage(@NotNull WorkspacePath file) {
- addFile(new WorkspacePath(file + "/BUILD"));
- addDirectory(file);
- return this;
- }
-
- public MockWorkspaceScanner addPackages(@NotNull Iterable<WorkspacePath> files) {
- for (WorkspacePath workspacePath : files) {
- addPackage(workspacePath);
- }
- return this;
- }
-
- public MockWorkspaceScanner addImportRoots(@NotNull ImportRoots importRoots) {
- addPackages(importRoots.rootDirectories());
- addPackages(importRoots.excludeDirectories());
- return this;
- }
-
- public MockWorkspaceScanner addProjectView(WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
- ImportRoots importRoots = ImportRoots.builder(workspaceRoot, BuildSystem.Blaze).add(projectViewSet).build();
- return addImportRoots(importRoots);
- }
-
- @Override
- public boolean exists(WorkspaceRoot workspaceRoot, WorkspacePath file) {
- return files.contains(file);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java
deleted file mode 100644
index 7b256e6..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.issueparser;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.io.File;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * Tests for {@link BlazeIssueParser}.
- */
-public class BlazeIssueParserTest extends BlazeTestCase {
-
- private ProjectViewManager projectViewManager;
- private WorkspaceRoot workspaceRoot;
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
-
- applicationServices.register(ExperimentService.class, new MockExperimentService());
-
- projectViewManager = mock(ProjectViewManager.class);
- projectServices.register(ProjectViewManager.class, projectViewManager);
-
- workspaceRoot = new WorkspaceRoot(new File("/root"));
- }
-
- @Test
- public void testParseTargetError() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "ERROR: invalid target format '//javatests/com/google/devtools/aswb/testapps/aswbtestlib/...:alls': invalid package name 'javatests/com/google/devtools/aswb/testapps/aswbtestlib/...': package name component contains only '.' characters."
- );
- assertNotNull(issue);
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testParseCompileError() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "java/com/google/android/samples/helloroot/math/DivideMath.java:17: error: non-static variable this cannot be referenced from a static context"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(
- "/root/java/com/google/android/samples/helloroot/math/DivideMath.java");
- assertThat(issue.getLine()).isEqualTo(17);
- assertThat(issue.getMessage()).isEqualTo("non-static variable this cannot be referenced from a static context");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testParseCompileErrorWithColumn() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "java/com/google/devtools/aswb/pluginrepo/googleplex/PluginsEndpoint.java:33:26: error: '|' is not preceded with whitespace."
- );
- assertNotNull(issue);
- assertThat(issue.getLine()).isEqualTo(33);
- assertThat(issue.getMessage()).isEqualTo("'|' is not preceded with whitespace.");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testParseCompileErrorWithAbsolutePath() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "/root/java/com/google/android/samples/helloroot/math/DivideMath.java:17: error: non-static variable this cannot be referenced from a static context"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(
- "/root/java/com/google/android/samples/helloroot/math/DivideMath.java");
- }
-
- @Test
- public void testParseCompileErrorWithDepotPath() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "//depot/google3/package_path/DivideMath.java:17: error: non-static variable this cannot be referenced from a static context"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(
- "/root/package_path/DivideMath.java");
- }
-
- @Test
- public void testParseBuildError() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "ERROR: /path/to/root/javatests/package_path/BUILD:42:12: Target '//java/package_path:helloroot_visibility' failed"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(
- "/path/to/root/javatests/package_path/BUILD");
- assertThat(issue.getLine()).isEqualTo(42);
- assertThat(issue.getMessage()).isEqualTo("Target '//java/package_path:helloroot_visibility' failed");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testParseLinelessBuildError() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "ERROR: /path/to/root/java/package_path/BUILD:char offsets 1222--1229: name 'grubber' is not defined"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(
- "/path/to/root/java/package_path/BUILD");
- assertThat(issue.getMessage()).isEqualTo("name 'grubber' is not defined");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testLabelProjectViewParser() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(new File(".blazeproject"), ProjectView.builder()
- .put(ListSection.builder(TargetSection.KEY)
- .add(TargetExpression.fromString("//package/path:hello4")))
- .build())
- .build();
- when(projectViewManager.getProjectViewSet()).thenReturn(projectViewSet);
-
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "no such target '//package/path:hello4': target 'hello4' not declared in package 'package/path' defined by /path/to/root/package/path/BUILD"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(".blazeproject");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testPackageProjectViewParser() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(new File(".blazeproject"), ProjectView.builder()
- .put(ListSection.builder(TargetSection.KEY)
- .add(TargetExpression.fromString("//package/path:hello4")))
- .build())
- .build();
- when(projectViewManager.getProjectViewSet()).thenReturn(projectViewSet);
-
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "no such package 'package/path': BUILD file not found on package path"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo(".blazeproject");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testDeletedBUILDFileButLeftPackageInLocalTargets() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(new File(".blazeproject"), ProjectView.builder()
- .put(ListSection.builder(TargetSection.KEY)
- .add(TargetExpression.fromString("//tests/com/google/a/b/c/d/baz:baz")))
- .build())
- .build();
- when(projectViewManager.getProjectViewSet()).thenReturn(projectViewSet);
-
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "Error:com.google.a.b.Exception exception in Bar: no targets found beneath " +
- "'tests/com/google/a/b/c/d/baz' Thrown during call: ..."
- );
- assertNotNull(issue);
- assertNotNull(issue.getFile());
- assertThat(issue.getFile().getPath()).isEqualTo(".blazeproject");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- assertThat(issue.getMessage()).isEqualTo(
- "no targets found beneath 'tests/com/google/a/b/c/d/baz'"
- );
- }
-
- @Test
- public void testMultilineTraceback() {
- String[] lines = new String[]{
- "ERROR: /home/plumpy/whatever:9:12: Traceback (most recent call last):",
- "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 8",
- "\t\tpackage_group(name = BAD_FUNCTION(\"hellogoogle...\"), ...\"])",
- "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 9, in package_group",
- "\t\tBAD_FUNCTION",
- "name 'BAD_FUNCTION' is not defined."};
-
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- for (int i = 0; i < lines.length - 1; ++i) {
- IssueOutput issue = blazeIssueParser.parseIssue(lines[i]);
- assertNull(issue);
- }
-
- IssueOutput issue = blazeIssueParser.parseIssue(lines[lines.length - 1]);
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo("/home/plumpy/whatever");
- assertThat(issue.getMessage().split("\n")).hasLength(lines.length);
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testLineAfterTracebackIsAlsoParsed() {
- String[] lines = new String[]{
- "ERROR: /home/plumpy/whatever:9:12: Traceback (most recent call last):",
- "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 8",
- "\t\tpackage_group(name = BAD_FUNCTION(\"hellogoogle...\"), ...\"])",
- "\tFile \"/path/to/root/java/com/google/android/samples/helloroot/BUILD\", line 9, in package_group",
- "\t\tBAD_FUNCTION",
- "name 'BAD_FUNCTION' is not defined."};
-
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- for (int i = 0; i < lines.length; ++i) {
- blazeIssueParser.parseIssue(lines[i]);
- }
-
- IssueOutput issue = blazeIssueParser.parseIssue(
- "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined"
- );
- assertNotNull(issue);
- assertThat(issue.getFile().getPath()).isEqualTo("/home/plumpy/whatever");
- assertThat(issue.getMessage()).isEqualTo("name 'grubber' is not defined");
- assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
- }
-
- @Test
- public void testMultipleIssues() {
- BlazeIssueParser blazeIssueParser = new BlazeIssueParser(project, workspaceRoot);
- IssueOutput issue = blazeIssueParser.parseIssue(
- "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined"
- );
- assertNotNull(issue);
- issue = blazeIssueParser.parseIssue(
- "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined"
- );
- assertNotNull(issue);
- issue = blazeIssueParser.parseIssue(
- "ERROR: /home/plumpy/whatever:char offsets 1222--1229: name 'grubber' is not defined"
- );
- assertNotNull(issue);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/metrics/ActionTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/metrics/ActionTest.java
deleted file mode 100644
index 6e0d869..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/metrics/ActionTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.metrics;
-
-import com.google.common.collect.Sets;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class ActionTest {
-
- @Test
- public void ensureAllActionEnumsHaveUniqueNames() {
- HashSet<String> names = Sets.newHashSet();
- for (Action action : Action.values()) {
- String name = action.getName();
- Assert.assertTrue(name + " is not unique", names.add(name));
- }
- }
-
- @Test
- public void ensureAllActionEnumNamesAreAlphanumeric() {
- Pattern pattern = Pattern.compile("[a-zA-Z0-9]*");
- for (Action action : Action.values()) {
- String name = action.getName();
- Matcher matcher = pattern.matcher(name);
- Assert.assertTrue(name + " is not valid", matcher.matches());
- }
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/DeepEqualsTesterTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/DeepEqualsTesterTest.java
deleted file mode 100644
index 8227ee1..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/DeepEqualsTesterTest.java
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.blaze;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTester;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTester.TestCorrectnessException;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTesterUtil;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples.ExampleNotFoundException;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Tests to verify that our equals tester is working correctly
- */
-public class DeepEqualsTesterTest {
-
- // The equals method does not work correctly if T is an array
- private static class Box<T> implements Serializable {
-
- public T data;
-
- public Box(T data) {
- this.data = data;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- Box<?> box = (Box<?>)o;
- return Objects.equal(data, box.data);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(data);
- }
- }
-
- private static class CorrectEqualsAndHash implements Serializable {
-
- public String name;
-
- public CorrectEqualsAndHash(String name) {
- this.name = name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- CorrectEqualsAndHash foo = (CorrectEqualsAndHash)o;
- return Objects.equal(name, foo.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(name);
- }
- }
-
- private static class ClassWithCorrectEqualsMember implements Serializable {
-
- public String myName;
- public CorrectEqualsAndHash myCorrectEqualsAndHash;
-
- public ClassWithCorrectEqualsMember(String name, String innerName) {
- this.myName = name;
- this.myCorrectEqualsAndHash = new CorrectEqualsAndHash(innerName);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ClassWithCorrectEqualsMember that = (ClassWithCorrectEqualsMember)o;
- return Objects.equal(myName, that.myName) &&
- Objects.equal(myCorrectEqualsAndHash, that.myCorrectEqualsAndHash);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(myName, myCorrectEqualsAndHash);
- }
- }
-
- private static class IncorrectHash implements Serializable {
-
- public String name;
- public int num;
-
- public IncorrectHash(String name, int num) {
- this.name = name;
- this.num = num;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- IncorrectHash foo = (IncorrectHash)o;
- return Objects.equal(name, foo.name) && Objects.equal(num, foo.num);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(name);
- }
- }
-
- private static class IncorrectEqualsAndHash implements Serializable {
-
- public String name;
- public int num;
-
- public IncorrectEqualsAndHash(String name, int num) {
- this.name = name;
- this.num = num;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- IncorrectEqualsAndHash foo = (IncorrectEqualsAndHash)o;
- return Objects.equal(name, foo.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(name);
- }
- }
-
- private static class ClassWithIncorrectEqualsMember implements Serializable {
-
- public String myName;
- public IncorrectEqualsAndHash myIncorrectEqualsAndHash;
-
- public ClassWithIncorrectEqualsMember(String name, String innerName, int innerNum) {
- this.myName = name;
- this.myIncorrectEqualsAndHash = new IncorrectEqualsAndHash(innerName, innerNum);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ClassWithIncorrectEqualsMember that = (ClassWithIncorrectEqualsMember)o;
- return Objects.equal(myName, that.myName) &&
- Objects.equal(myIncorrectEqualsAndHash, that.myIncorrectEqualsAndHash);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(myName, myIncorrectEqualsAndHash);
- }
- }
-
- private static class IncorrectEqualsWithArray implements Serializable {
-
- public IncorrectEqualsAndHash[] array;
-
- public IncorrectEqualsWithArray(IncorrectEqualsAndHash[] array) {
- this.array = array;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- IncorrectEqualsWithArray that = (IncorrectEqualsWithArray)o;
- return Arrays.equals(array, that.array);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode((Object[])array);
- }
- }
-
- private static class SubIncorrectEqualsAndHash extends IncorrectEqualsAndHash {
-
- public Long num;
-
- public SubIncorrectEqualsAndHash(String name, int iNum, Long num) {
- super(name, iNum);
- this.num = num;
- }
- }
-
- private static enum ENUMS {
- ONE, TWO, THREE
- }
-
- private static class DeepClass<T> implements Serializable {
-
- public ENUMS myEnum;
- public char myC;
- public T data;
- public File f;
-
- public DeepClass(ENUMS myEnum, char c, T data, File f) {
- this.myEnum = myEnum;
- this.myC = c;
- this.data = data;
- this.f = f;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- DeepClass<?> deepClass = (DeepClass<?>)o;
- return Objects.equal(myC, deepClass.myC) &&
- Objects.equal(myEnum, deepClass.myEnum) &&
- Objects.equal(data, deepClass.data) &&
- Objects.equal(f, deepClass.f);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(myEnum, myC, data, f);
- }
- }
-
- private static class SimpleClassWithSet implements Serializable {
-
- public Set<File> files;
-
- public SimpleClassWithSet(Set<File> files) {
- this.files = files;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- SimpleClassWithSet that = (SimpleClassWithSet)o;
- return Objects.equal(files, that.files);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(files);
- }
- }
-
- private static class MapWithIncorrectKey implements Serializable {
-
- public Map<IncorrectEqualsAndHash, File> files;
-
- public MapWithIncorrectKey(Map<IncorrectEqualsAndHash, File> files) {
- this.files = files;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- MapWithIncorrectKey that = (MapWithIncorrectKey)o;
- return Objects.equal(files, that.files);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(files);
- }
- }
-
- private static class MapWithIncorrectValue implements Serializable {
-
- public Map<String, IncorrectEqualsAndHash> map;
-
- public MapWithIncorrectValue(Map<String, IncorrectEqualsAndHash> map) {
- this.map = map;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- MapWithIncorrectValue that = (MapWithIncorrectValue)o;
- return Objects.equal(map, that.map);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(map);
- }
- }
-
- private static class MapWithCorrectKeyAndValues implements Serializable {
-
- public Map<String, String> map;
-
- public MapWithCorrectKeyAndValues(Map<String, String> map) {
- this.map = map;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- MapWithCorrectKeyAndValues that = (MapWithCorrectKeyAndValues)o;
- return Objects.equal(map, that.map);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(map);
- }
- }
-
- private Examples testExamples;
-
- @Before
- public void populateExtraExamples() {
- testExamples = new Examples();
- testExamples.addExample(CorrectEqualsAndHash.class, new CorrectEqualsAndHash("A"),
- new CorrectEqualsAndHash("B"));
- testExamples.addExample(IncorrectEqualsAndHash.class, new IncorrectEqualsAndHash("A", 100),
- new IncorrectEqualsAndHash("A", 200));
- testExamples
- .addExample(IncorrectHash.class, new IncorrectHash("A", 100), new IncorrectHash("A", 200));
- }
-
- @Test
- public void testCorrectEqualsAndHashPassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectEqualsFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectHashFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectHash myFoo = new IncorrectHash("test", 4);
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Test
- public void testCorrectDeepEqualsAndHashPassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- ClassWithCorrectEqualsMember myFoo = new ClassWithCorrectEqualsMember("test", "inner test");
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testDeepIncorrectEqualsFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- ClassWithIncorrectEqualsMember myFoo = new ClassWithIncorrectEqualsMember("test", "inner test",
- 4);
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectEqualsInSuperclassFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- SubIncorrectEqualsAndHash myFoo = new SubIncorrectEqualsAndHash("test", 4, new Long(39903));
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Test
- public void testCorrectEqualsAndHashInArrayPassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
- CorrectEqualsAndHash[] array = new CorrectEqualsAndHash[1];
- array[0] = myFoo;
- DeepEqualsTester.doDeepEqualsAndHashTest(array, testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectEqualsInArrayFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
- IncorrectEqualsAndHash[] array = new IncorrectEqualsAndHash[1];
- array[0] = myFoo;
- IncorrectEqualsWithArray toTest = new IncorrectEqualsWithArray(array);
- DeepEqualsTester.doDeepEqualsAndHashTest(toTest, testExamples);
- }
-
- @Test
- public void testClassWithSetWithCorrectDeepEqualsAndHashPassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- Set<File> myFiles = Sets.newHashSet();
- myFiles.add(new File("foo"));
- myFiles.add(new File("bar"));
- SimpleClassWithSet myFoo = new SimpleClassWithSet(myFiles);
- DeepEqualsTester.doDeepEqualsAndHashTest(myFoo, testExamples);
- }
-
- @Ignore("causes java reflection return a type variable instead of a concrete type")
- @Test
- public void testCorrectEqualsAndHashInSetPassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
- HashSet<CorrectEqualsAndHash> set = Sets.newHashSet();
- set.add(myFoo);
- DeepEqualsTester.doDeepEqualsAndHashTest(new Box<HashSet<CorrectEqualsAndHash>>(set),
- testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectEqualsInSetFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
- HashSet<IncorrectEqualsAndHash> set = Sets.newHashSet();
- set.add(myFoo);
- DeepEqualsTester.doDeepEqualsAndHashTest(new Box<HashSet<IncorrectEqualsAndHash>>(set),
- testExamples);
- }
-
- @Ignore("causes java reflection return a type variable instead of a concrete type")
- @Test
- public void testCorrectDeepEqualsAndHashInSetPassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- CorrectEqualsAndHash myFoo = new CorrectEqualsAndHash("test");
- DeepClass<CorrectEqualsAndHash> data = new DeepClass<CorrectEqualsAndHash>(ENUMS.THREE, 'z',
- myFoo,
- new File("home"));
- HashSet<DeepClass<CorrectEqualsAndHash>> set = Sets.newHashSet();
- set.add(data);
- DeepEqualsTester
- .doDeepEqualsAndHashTest(new Box<HashSet<DeepClass<CorrectEqualsAndHash>>>(set),
- testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectDeepEqualsInSetFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
- DeepClass<IncorrectEqualsAndHash> data = new DeepClass<IncorrectEqualsAndHash>(ENUMS.ONE, 'e',
- myFoo,
- new File("home"));
- HashSet<DeepClass<IncorrectEqualsAndHash>> set = Sets.newHashSet();
- set.add(data);
- DeepEqualsTester
- .doDeepEqualsAndHashTest(new Box<HashSet<DeepClass<IncorrectEqualsAndHash>>>(set),
- testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectEqualsForMapKeyFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
- Map<IncorrectEqualsAndHash, File> map = Maps.newHashMap();
- map.put(myFoo, new File("file"));
- MapWithIncorrectKey data = new MapWithIncorrectKey(map);
- DeepEqualsTester.doDeepEqualsAndHashTest(data, testExamples);
- }
-
- @Test(expected = AssertionError.class)
- public void testIncorrectEqualsForMapValueFailsTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- IncorrectEqualsAndHash myFoo = new IncorrectEqualsAndHash("test", 4);
- Map<String, IncorrectEqualsAndHash> map = Maps.newHashMap();
- map.put("first", myFoo);
- MapWithIncorrectValue data = new MapWithIncorrectValue(map);
- DeepEqualsTester.doDeepEqualsAndHashTest(data, testExamples);
- }
-
- @Test
- public void testCorrectEqualsAndHashForMapKeyValuePassesTester()
- throws IllegalAccessException, InstantiationException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- Map<String, String> map = Maps.newHashMap();
- map.put("key", "value");
- MapWithCorrectKeyAndValues data = new MapWithCorrectKeyAndValues(map);
- DeepEqualsTester.doDeepEqualsAndHashTest(data, testExamples);
- }
-
- @Test
- public void testEqualsAfterCloneReturnsTrue() {
- CorrectEqualsAndHash myData = new CorrectEqualsAndHash("my data");
- CorrectEqualsAndHash clone = (CorrectEqualsAndHash)DeepEqualsTesterUtil
- .cloneWithSerialization(myData);
- Assert.assertEquals(myData, clone);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTester.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTester.java
deleted file mode 100644
index bb8b982..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTester.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples.ExampleNotFoundException;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.Examples.Pair;
-import com.google.idea.blaze.base.model.blaze.deepequalstester.ReachabilityAnalysis.ReachableClasses;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Assert;
-
-import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.List;
-
-public final class DeepEqualsTester {
-
- public static class TestCorrectnessException extends Exception {
-
- public TestCorrectnessException(String s) {
- super(s);
- }
- }
-
- /**
- * Ensure that the equals method of {@param rootObject} uses all of its fields in its comparison.
- * Recurse into every field of {@param rootObject} to ensure that they also use all of their
- * fields in their equals method. Continue recursion until primitives are hit.
- * <p/>
- * If multiple failures could occur, there is no guarantee that they will always occur in the same
- * order. Only the first failure is reported.
- *
- * @param rootObject an example instantiation of the class we want to test for deep equals sanity.
- * The object must be a standard java object (no collections, no arrays, no primitives). If you
- * would like to pass these types in, you should put them in a box first.
- * @param examples examples of objects to use for comparison. This should contain a pair of
- * examples for every type that could be reachable from the root object. This value may be
- * mutated by this test.
- */
- public static <T extends Serializable> void doDeepEqualsAndHashTest(@NotNull T rootObject,
- Examples examples)
- throws InstantiationException, IllegalAccessException, NoSuchFieldException, ExampleNotFoundException, TestCorrectnessException {
- ReachableClasses reachableClasses = new ReachableClasses();
-
- try {
- ArrayList<String> initialPath = Lists.newArrayList("root");
- // Find all of the classes reachable from the root object. This is not sound since it
- // ignores subtypes (or supertypes) that could be used
- ReachabilityAnalysis
- .computeReachableFromObject(rootObject, rootObject.getClass(), initialPath,
- reachableClasses);
- }
- catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
-
- // Add the root object to our list of reachable classes so we can do all the testing in one
- // loop
- reachableClasses.addPath(rootObject.getClass(), Lists.newArrayList("root"));
- // In our situations, we never need a second example of the root object
- examples.addExample(rootObject.getClass(), rootObject, rootObject);
- // For each reachable class, do a shallow equals test where we change each value of the
- // object one at a time and test for equality
- for (Class<? extends Serializable> clazz : reachableClasses.getClasses()) {
- Serializable workitem = (Serializable)examples.getExamples(clazz).getFirst();
- testShallowEquals(workitem, reachableClasses, examples);
- }
- }
-
- private static String getFailureMessage(String method, Field field, List<String> examplePath) {
- StringBuilder sb = new StringBuilder();
- sb.append(field.toString()).append(" is not represented in it's parent's ")
- .append(method).append(" method\n");
- for (String path : examplePath) {
- sb.append("\t").append(path).append("\n");
- }
- sb.append("\n");
- return sb.toString();
- }
-
- /**
- * Mutate each field in the object one at a time and test for equality of the object. Assert a
- * failure if any mutation doesn't result in the two objects not being equal
- */
- private static <T extends Serializable> void testShallowEquals(@NotNull T original,
- ReachableClasses reachableClasses, Examples examples)
- throws ExampleNotFoundException, IllegalAccessException, TestCorrectnessException {
- T clone = (T)DeepEqualsTesterUtil.cloneWithSerialization(original);
- List<Field> allFields = DeepEqualsTesterUtil.getAllFields(original.getClass());
- for (Field field : allFields) {
- if (!Modifier.isStatic(field.getModifiers())) {
- field.setAccessible(true);
- Pair<?, ?> examplesPair = examples.
- getExamples((Class<? extends Serializable>)field.getType());
- Object newValueForOriginal = examplesPair.getFirst();
- Object newValueForClone = examplesPair.getSecond();
- Object oldValueForOriginal = field.get(original);
- Object oldValueForClone = field.get(clone);
- // Ensure that the two objects really are equal before we tweak them
- boolean objectsTheSameBeforeTweak = original.equals(clone);
- if (!objectsTheSameBeforeTweak) {
- throw new TestCorrectnessException(
- "original was not equal to clone before tweaking them");
- }
- boolean objectsHashTheSameBeforeTweak = original.hashCode() == clone.hashCode();
- if (!objectsHashTheSameBeforeTweak) {
- throw new TestCorrectnessException(
- "original hash code was not equal to clone hash code before tweaking the objects");
- }
- field.set(original, newValueForOriginal);
- field.set(clone, newValueForClone);
- boolean equalsWorksAsIntended = !original.equals(clone);
- boolean hashWorksAsIntended = original.hashCode() != clone.hashCode();
- // Return to our original state before possibly failing
- field.set(original, oldValueForOriginal);
- field.set(clone, oldValueForClone);
- Assert.assertTrue(getFailureMessage("equals", field, reachableClasses.getExamplePathTo(
- original.getClass())), equalsWorksAsIntended);
- Assert.assertTrue(getFailureMessage("hash", field, reachableClasses.getExamplePathTo(
- original.getClass())), hashWorksAsIntended);
- }
- }
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTesterUtil.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTesterUtil.java
deleted file mode 100644
index 71f0c6d..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/DeepEqualsTesterUtil.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.lang.reflect.Field;
-import java.util.List;
-
-@VisibleForTesting
-public final class DeepEqualsTesterUtil {
- public static List<Field> getAllFields(Class<?> clazz) {
- List<Field> fields = Lists.newArrayList();
-
- Field[] declaredFields = clazz.getDeclaredFields();
- for (Field field : declaredFields) {
- fields.add(field);
- }
-
- Class<?> superclass = clazz.getSuperclass();
- if (superclass != null) {
- fields.addAll(getAllFields(superclass));
- }
- return fields;
- }
-
- public static Class getClass(Class declaredClass, Object o) {
- if (o == null) {
- return declaredClass;
- }
- // The two classes *should* be the same in this case, but the class from o.getClass won't
- // return true from isPrimitive
- if (declaredClass.isPrimitive()) {
- return declaredClass;
- }
- return o.getClass();
- }
-
- /**
- * Do a deep clone of an object using reflection
- */
- public static Object cloneWithSerialization(Object o) {
- if (o == null) {
- return null;
- }
-
- try {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- ObjectOutputStream objOut = new ObjectOutputStream(outputStream);
- objOut.writeObject(o);
- ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
- ObjectInputStream objIn = new ObjectInputStream(inputStream);
- return objIn.readObject();
- }
- catch (Exception e) {
- return null;
- }
- }
-
- public static boolean isSubclassOf(@Nullable Class<?> possibleSubClass, @NotNull Class<?> possibleSuperClass) {
- if (possibleSubClass == null) {
- return false;
- }
-
- if (possibleSubClass.equals(possibleSuperClass)) {
- return true;
- }
-
- if (possibleSubClass.equals(Object.class)) {
- return false;
- }
-
- Class<?>[] interfaces = possibleSubClass.getInterfaces();
- for (Class<?> interfaze : interfaces) {
- if (interfaze.equals(possibleSuperClass)) {
- return true;
- }
- }
-
- return isSubclassOf(possibleSubClass.getSuperclass(), possibleSuperClass);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/Examples.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/Examples.java
deleted file mode 100644
index c989196..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/Examples.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-import java.io.Serializable;
-import java.lang.reflect.Array;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static com.google.idea.blaze.base.model.blaze.deepequalstester.DeepEqualsTesterUtil.isSubclassOf;
-
-public final class Examples {
-
- public static final class Pair<First, Second> {
-
- private final First first;
- private final Second second;
-
- public static <First, Second> Pair<First, Second> of(First first, Second second) {
- return new Pair<First, Second>(first, second);
- }
-
- public Pair(First first, Second second) {
- this.first = first;
- this.second = second;
- }
-
- First getFirst() {
- return first;
- }
-
- Second getSecond() {
- return second;
- }
- }
-
- private static Map<Class<? extends Object>, Pair<? extends Object, ? extends Object>> BASE_EXAMPLES;
- private static Map<Class<? extends Object>, Pair<? extends Object, ? extends Object>> ARRAY_EXAMPLES;
-
- private final Map<Class<? extends Object>, Pair<? extends Object, ? extends Object>> customExamples;
-
- static {
- BASE_EXAMPLES = Maps.newHashMap();
- BASE_EXAMPLES.put(String.class, Pair.of("foo", "foobar"));
- BASE_EXAMPLES.put(File.class, Pair.of(new File("a"), new File("b")));
- BASE_EXAMPLES.put(Integer.class, Pair.of(1, 2));
- BASE_EXAMPLES.put(Integer.TYPE, Pair.of(1, 2));
- BASE_EXAMPLES.put(Long.class, Pair.of(1L, 2L));
- BASE_EXAMPLES.put(Long.TYPE, Pair.of(1L, 2L));
- BASE_EXAMPLES.put(Short.class, Pair.of((short)1, (short)2));
- BASE_EXAMPLES.put(Short.TYPE, Pair.of((short)1, (short)2));
- BASE_EXAMPLES.put(Character.class, Pair.of('a', 'b'));
- BASE_EXAMPLES.put(Character.TYPE, Pair.of('a', 'b'));
- BASE_EXAMPLES.put(Byte.class, Pair.of((byte)1, (byte)2));
- BASE_EXAMPLES.put(Byte.TYPE, Pair.of((byte)1, (byte)2));
- BASE_EXAMPLES.put(Float.class, Pair.of((float)1.0, (float)2.0));
- BASE_EXAMPLES.put(Float.TYPE, Pair.of((float)1.0, (float)2.0));
- BASE_EXAMPLES.put(Double.class, Pair.of(1.0, 2.0));
- BASE_EXAMPLES.put(Double.TYPE, Pair.of(1.0, 2.0));
- BASE_EXAMPLES.put(Boolean.class, Pair.of(true, false));
- BASE_EXAMPLES.put(Boolean.TYPE, Pair.of(true, false));
- Map<String, String> mapA = Maps.newHashMap();
- mapA.put("foo", "bar");
- Map<String, String> mapB = Maps.newHashMap();
- mapB.put("tip", "top");
- BASE_EXAMPLES.put(Map.class, Pair.of(mapA, mapB));
- Set<String> setA = new ImmutableSet.Builder<String>().add("A").build();
- Set<String> setB = new ImmutableSet.Builder<String>().add("A").add("B").build();
- BASE_EXAMPLES.put(Set.class, Pair.of(setA, setB));
- BASE_EXAMPLES.put(Collection.class, Pair.of(setA, setB));
- Builder<String> listABuilder = ImmutableList.builder();
- List<String> listA = listABuilder.add("A").build();
- Builder<String> listBBuilder = ImmutableList.builder();
- List<String> listB = listBBuilder.add("A").add("B").build();
- BASE_EXAMPLES.put(List.class, Pair.of(listA, listB));
-
- ARRAY_EXAMPLES = Maps.newHashMap();
- int[] intArrA = {1, 2};
- int[] intArrB = {3, 4};
- ARRAY_EXAMPLES.put(Integer.TYPE, Pair.of(intArrA, intArrB));
- long[] longArrA = {1, 2};
- long[] longArrB = {3, 4};
- ARRAY_EXAMPLES.put(Long.TYPE, Pair.of(longArrA, longArrB));
- short[] shortArrA = {1, 2};
- short[] shortArrB = {3, 4};
- ARRAY_EXAMPLES.put(Short.TYPE, Pair.of(shortArrA, shortArrB));
- char[] charArrA = {'a', 'b'};
- char[] charArrB = {'c', 'd'};
- ARRAY_EXAMPLES.put(Character.TYPE, Pair.of(charArrA, charArrB));
- byte[] byteArrA = {1, 2};
- byte[] byteArrB = {3, 4};
- ARRAY_EXAMPLES.put(Byte.TYPE, Pair.of(byteArrA, byteArrB));
- boolean[] boolArrA = {true, false};
- boolean[] boolArrB = {false, false};
- ARRAY_EXAMPLES.put(Boolean.TYPE, Pair.of(boolArrA, boolArrB));
- float[] floatArrA = {1.0f, 2.0f};
- float[] floatArrB = {3.0f, 4.0f};
- ARRAY_EXAMPLES.put(Float.TYPE, Pair.of(floatArrA, floatArrB));
- double[] doubleArrA = {1.0, 2.0};
- double[] doubleArrB = {3.0, 4.0};
- ARRAY_EXAMPLES.put(Double.TYPE, Pair.of(doubleArrA, doubleArrB));
- }
-
- public static class ExampleNotFoundException extends Exception {
-
- private final Class<?> clazz;
-
- public ExampleNotFoundException(Class<?> clazz) {
- this.clazz = clazz;
- }
-
- @Override
- public String getMessage() {
- return "Could not find example for: " + clazz.toString();
- }
- }
-
- public Examples() {
- this.customExamples = Maps.newHashMap();
- }
-
- public void addExample(Class<? extends Object> clazz, Object a, Object b) {
- customExamples.put(clazz, Pair.of(a, b));
- }
-
- public <T extends Serializable> Pair<? extends Object, ? extends Object> getExamples(
- @NotNull Class<T> clazz)
- throws ExampleNotFoundException {
- if (customExamples.containsKey(clazz)) {
- return customExamples.get(clazz);
- }
- if (BASE_EXAMPLES.containsKey(clazz)) {
- return BASE_EXAMPLES.get(clazz);
- }
- // Special case subclasses of collections
- if (isSubclassOf(clazz, Set.class)) {
- return BASE_EXAMPLES.get(Set.class);
- }
- if (isSubclassOf(clazz, List.class)) {
- return BASE_EXAMPLES.get(List.class);
- }
- if (isSubclassOf(clazz, Collection.class)) {
- return BASE_EXAMPLES.get(Collection.class);
- }
-
- // If we have an array of Objects, we have to do a little trickery to create one we can swap
- // in
- if (clazz.isArray()) {
- Class<?> arrayType = clazz.getComponentType();
- if (!arrayType.isPrimitive()) {
- Pair<?, ?> examples = getExamples((Class<? extends Serializable>)arrayType);
- Object arrayA = Array.newInstance(arrayType, 1);
- Array.set(arrayA, 0, examples.getFirst());
- Object arrayB = Array.newInstance(arrayType, 1);
- Array.set(arrayB, 0, examples.getSecond());
- return Pair.of(arrayA, arrayB);
- }
- if (ARRAY_EXAMPLES.containsKey(arrayType)) {
- return ARRAY_EXAMPLES.get(arrayType);
- }
- }
-
- throw new ExampleNotFoundException(clazz);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/ReachabilityAnalysis.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/ReachabilityAnalysis.java
deleted file mode 100644
index f8485c8..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/blaze/deepequalstester/ReachabilityAnalysis.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.blaze.deepequalstester;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import org.junit.Assert;
-
-import java.io.File;
-import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-public final class ReachabilityAnalysis {
-
- /**
- * Wrapper around a map from class to set of paths that lead to that path from the root object
- */
- public static final class ReachableClasses {
-
- Map<Class<? extends Serializable>, Set<List<String>>> map;
-
- public ReachableClasses() {
- map = Maps.newHashMap();
- }
-
- boolean alreadyFound(Class<? extends Serializable> clazz) {
- return map.containsKey(clazz);
- }
-
- void addPath(Class<? extends Serializable> clazz, List<String> path) {
- Set<List<String>> paths;
- if (map.containsKey(clazz)) {
- paths = map.get(clazz);
- }
- else {
- paths = Sets.newHashSet();
- map.put(clazz, paths);
- }
- paths.add(path);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- Set<? extends Entry<Class<? extends Serializable>, ? extends Set<? extends List<String>>>> entries = map
- .entrySet();
- for (Entry<Class<? extends Serializable>, ? extends Set<? extends List<String>>> entry : entries) {
- sb.append(entry.getKey().toString());
- sb.append("\n");
- }
-
- return sb.toString();
- }
-
- public Set<Class<? extends Serializable>> getClasses() {
- return map.keySet();
- }
-
- public List<String> getExamplePathTo(Class<? extends Serializable> aClass) {
- if (map.containsKey(aClass)) {
- return map.get(aClass).iterator().next();
- }
- return Lists.newArrayList();
- }
- }
-
- /**
- * Find all of the classes reachable from a root object
- *
- * @param root object to start reachability calculation from
- * @param declaredRootClass declared class of the root object
- * @param currentPath field access path to get to root
- * @param reachableClasses output: add classes reachable from root to this object
- * @throws IllegalAccessException
- * @throws ClassNotFoundException
- */
- public static void computeReachableFromObject(Object root, Class<?> declaredRootClass,
- List<String> currentPath, ReachableClasses reachableClasses)
- throws IllegalAccessException, ClassNotFoundException {
- final Class<?> concreteRootClass = DeepEqualsTesterUtil.getClass(declaredRootClass, root);
- List<Field> allFields = DeepEqualsTesterUtil.getAllFields(concreteRootClass);
- for (Field field : allFields) {
- if (!Modifier.isStatic(field.getModifiers())) {
- field.setAccessible(true);
- final Object fieldObject;
- if (root == null) {
- fieldObject = null;
- }
- else {
- fieldObject = field.get(root);
- }
- List<String> childPath = Lists.newArrayList();
- childPath.addAll(currentPath);
- childPath.add(field.toString());
- addToReachableAndRecurse(fieldObject, field.getType(), field.getGenericType(),
- childPath, reachableClasses);
- }
- }
- }
-
- /**
- * Determine the action we should take based on the type of Object and then take it. In the
- * normal object case, this results in a recursive call to
- * {@link #computeReachableFromObject(Object, Class, List, ReachableClasses)}. In the case of
- * Collections, we skip the Collection type and continue on with the type contained in the
- * collection.
- */
- private static void addToReachableAndRecurse(Object object, Class<?> declaredObjectClass,
- Type genericType, List<String> currentPath, ReachableClasses reachableClasses)
- throws ClassNotFoundException, IllegalAccessException {
- Class<? extends Serializable> objectType = DeepEqualsTesterUtil
- .getClass(declaredObjectClass, object);
- // TODO(salguarnieri) modify if so all ignored classes are taken care of together
- if (objectType.isPrimitive()) {
- // ignore
- }
- else if (objectType.isEnum()) {
- // assume enums do the right thing, ignore
- }
- else if (DeepEqualsTesterUtil.isSubclassOf(objectType, String.class)) {
- // ignore
- }
- else if (DeepEqualsTesterUtil.isSubclassOf(objectType, File.class)) {
- // ignore
- }
- else if (DeepEqualsTesterUtil.isSubclassOf(objectType, Collection.class) || DeepEqualsTesterUtil
- .isSubclassOf(objectType, Map.class)) {
- if (genericType instanceof ParameterizedType) {
- ParameterizedType parameterType = (ParameterizedType)genericType;
- Type[] actualTypeArguments = parameterType.getActualTypeArguments();
- for (Type typeArgument : actualTypeArguments) {
- if (typeArgument instanceof Class) {
- List<String> childPath = Lists.newArrayList();
- childPath.addAll(currentPath);
- childPath.add("[[IN COLLECTION]]");
- // this does not properly handle subtyping
- addToReachableAndRecurse(null, (Class)typeArgument, null, childPath,
- reachableClasses);
- }
- else {
- Assert.fail("This case is not handled yet");
- }
- }
- }
- else {
- Assert.fail("This case is not handled yet");
- }
- }
- else if (objectType.isArray()) {
- Class<?> typeInArray = objectType.getComponentType();
- // This does not properly handle subtyping
- List<String> childPath = Lists.newArrayList();
- childPath.addAll(currentPath);
- childPath.add("[[IN ARRAY]]");
- addToReachableAndRecurse(null, typeInArray, null, childPath, reachableClasses);
- }
- else {
- boolean doRecursion = !reachableClasses.alreadyFound(objectType);
- reachableClasses.addPath(objectType, currentPath);
- if (doRecursion) {
- computeReachableFromObject(object, declaredObjectClass, currentPath, reachableClasses);
- }
- }
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/ExecutionRootPathTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/ExecutionRootPathTest.java
deleted file mode 100644
index b0426fb..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/ExecutionRootPathTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.mockito.stubbing.Answer;
-
-import java.io.File;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class ExecutionRootPathTest extends BlazeTestCase {
- @Test
- public void testSingleLevelPathEndInSlash() {
- ExecutionRootPath executionRootPath = new ExecutionRootPath("foo");
- assertThat(executionRootPath.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/"));
-
- ExecutionRootPath executionRootPath2 = new ExecutionRootPath("foo/");
- assertThat(executionRootPath2.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/"));
- }
-
- @Test
- public void testMultiLevelPathEndInSlash() {
- ExecutionRootPath executionRootPath = new ExecutionRootPath("foo/bar");
- assertThat(executionRootPath.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/bar/"));
-
- ExecutionRootPath executionRootPath2 = new ExecutionRootPath("foo/bar/");
- assertThat(executionRootPath2.getAbsoluteOrRelativeFile()).isEqualTo(new File("foo/bar/"));
- }
-
- @Test
- public void testAbsoluteFileDoesNotGetRerooted() {
- ExecutionRootPath executionRootPath = new ExecutionRootPath("/root/foo/bar");
- File rootedFile = executionRootPath.getFileRootedAt(new File("/core/dev"));
- assertThat(rootedFile).isEqualTo(new File("/root/foo/bar"));
- }
-
- @Test
- public void testRelativeFileGetsRerooted() {
- ExecutionRootPath executionRootPath = new ExecutionRootPath("foo/bar");
- File rootedFile = executionRootPath.getFileRootedAt(new File("/root"));
- assertThat(rootedFile).isEqualTo(new File("/root/foo/bar"));
- }
-
- @Test
- public void testCreateRelativePathWithTwoRelativePaths() {
- ExecutionRootPath relativePathFragment = ExecutionRootPath.createAncestorRelativePath(
- createMockDirectory("code/lib/fastmath"),
- createMockDirectory("code/lib/fastmath/lib1")
- );
- assertThat(relativePathFragment).isNotNull();
- assertThat(relativePathFragment.getAbsoluteOrRelativeFile()).isEqualTo(new File("lib1"));
- }
-
- @Test
- public void testCreateRelativePathWithTwoRelativePathsWithNoRelativePath() {
- ExecutionRootPath relativePathFragment = ExecutionRootPath.createAncestorRelativePath(
- createMockDirectory("obj/lib/fastmath"),
- createMockDirectory("code/lib/slowmath")
- );
- assertThat(relativePathFragment).isNull();
- }
-
- @Test
- public void testCreateRelativePathWithTwoAbsolutePaths() {
- ExecutionRootPath relativePathFragment = ExecutionRootPath.createAncestorRelativePath(
- createMockDirectory("/code/lib/fastmath"),
- createMockDirectory("/code/lib/fastmath/lib1")
- );
- assertThat(relativePathFragment).isNotNull();
- assertThat(relativePathFragment.getAbsoluteOrRelativeFile()).isEqualTo(new File("lib1"));
- }
-
- @Test
- public void testCreateRelativePathWithTwoAbsolutePathsWithNoRelativePath() {
- ExecutionRootPath relativePathFragment = ExecutionRootPath.createAncestorRelativePath(
- createMockDirectory("/obj/lib/fastmath"),
- createMockDirectory("/code/lib/slowmath")
- );
- assertThat(relativePathFragment).isNull();
- }
-
- @Test
- public void testCreateRelativePathWithOneAbsolutePathAndOneRelativePathReturnsNull1() {
- ExecutionRootPath relativePathFragment = ExecutionRootPath.createAncestorRelativePath(
- createMockDirectory("/code/lib/fastmath"),
- createMockDirectory("code/lib/fastmath/lib1")
- );
- assertThat(relativePathFragment).isNull();
- }
-
- @Test
- public void testCreateRelativePathWithOneAbsolutePathAndOneRelativePathReturnsNull2() {
- ExecutionRootPath relativePathFragment = ExecutionRootPath.createAncestorRelativePath(
- createMockDirectory("code/lib/fastmath"),
- createMockDirectory("/code/lib/slowmath")
- );
- assertThat(relativePathFragment).isNull();
- }
-
- private static File createMockDirectory(String path) {
- File org = new File(path);
- File spy = Mockito.spy(org);
- Mockito.when(spy.isDirectory()).then((Answer<Boolean>)invocationOnMock -> true);
- return spy;
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/LabelTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/LabelTest.java
deleted file mode 100644
index a865ff1..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/LabelTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class LabelTest extends BlazeTestCase {
-
- @Override
- protected void initTest(
- @NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- }
-
- @Test
- public void testValidatePackage() {
- // Legal names
- assertThat(Label.validatePackagePath("foo")).isTrue();
- assertThat(Label.validatePackagePath("f")).isTrue();
- assertThat(Label.validatePackagePath("fooBAR")).isTrue();
- assertThat(Label.validatePackagePath("foo/bar")).isTrue();
- assertThat(Label.validatePackagePath("f9oo")).isTrue();
- assertThat(Label.validatePackagePath("f_9oo")).isTrue();
- // This is not advised but is technically legal
- assertThat(Label.validatePackagePath("")).isTrue();
-
- // Illegal names
- assertThat(Label.validatePackagePath("Foo")).isFalse();
- assertThat(Label.validatePackagePath("foo//bar")).isFalse();
- assertThat(Label.validatePackagePath("foo/")).isFalse();
- assertThat(Label.validatePackagePath("9oo")).isFalse();
- }
-
- @Test
- public void testValidateLabel() {
- // Valid labels
- assertThat(Label.validate("//foo:bar")).isTrue();
- assertThat(Label.validate("//foo/baz:bar")).isTrue();
- assertThat(Label.validate("//:bar")).isTrue();
-
- // Invalid labels
- assertThat(Label.validate("//foo")).isFalse();
- assertThat(Label.validate("foo")).isFalse();
- assertThat(Label.validate("foo:bar")).isFalse();
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/RuleNameTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/RuleNameTest.java
deleted file mode 100644
index 34ccbe7..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/RuleNameTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class RuleNameTest extends BlazeTestCase {
-
- @Test
- public void testValidateRuleName() {
- // Legal names
- assertThat(RuleName.validate("foo")).isTrue();
- assertThat(RuleName.validate(".")).isTrue();
- assertThat(RuleName.validate(".foo")).isTrue();
- assertThat(RuleName.validate("foo+")).isTrue();
- assertThat(RuleName.validate("_foo")).isTrue();
- assertThat(RuleName.validate("-foo")).isTrue();
- assertThat(RuleName.validate("foo-bar")).isTrue();
- assertThat(RuleName.validate("foo..")).isTrue();
- assertThat(RuleName.validate("..foo")).isTrue();
-
- // Illegal names
- assertThat(RuleName.validate("")).isFalse();
- assertThat(RuleName.validate("/foo")).isFalse();
- assertThat(RuleName.validate("../foo")).isFalse();
- assertThat(RuleName.validate("./foo")).isFalse();
- assertThat(RuleName.validate("..")).isFalse();
- assertThat(RuleName.validate("foo/../bar")).isFalse();
- assertThat(RuleName.validate("foo/./bar")).isFalse();
- assertThat(RuleName.validate("foo//bar")).isFalse();
- assertThat(RuleName.validate("foo/..")).isFalse();
- assertThat(RuleName.validate("/..")).isFalse();
- assertThat(RuleName.validate("foo/")).isFalse();
- assertThat(RuleName.validate("/")).isFalse();
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/TargetExpressionTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/TargetExpressionTest.java
deleted file mode 100644
index a59a77b..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/TargetExpressionTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-/**
- * Tests for {@link com.google.idea.blaze.base.model.primitives.TargetExpressionFactory}.
- */
-@RunWith(JUnit4.class)
-public class TargetExpressionTest extends BlazeTestCase {
- @Override
- protected void initTest(
- @NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- }
-
- @Test
- public void validLabelShouldYieldLabel() {
- TargetExpression target = TargetExpression.fromString("//package:rule");
- assertThat(target).isInstanceOf(Label.class);
- }
-
- @Test
- public void globExpressionShouldYieldGeneralTargetExpression() {
- TargetExpression target = TargetExpression.fromString("//package/...");
- assertThat(target.getClass()).isSameAs(TargetExpression.class);
- }
-
- @Test
- public void emptyExpressionShouldThrow() {
- try {
- TargetExpression.fromString("");
- fail("Empty expressions should not be allowed.");
- }
- catch (IllegalArgumentException expected) {
- }
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/WorkspacePathTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/WorkspacePathTest.java
deleted file mode 100644
index 0e0c049..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/model/primitives/WorkspacePathTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.model.primitives;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.ui.BlazeValidationError;
-import org.junit.Test;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class WorkspacePathTest extends BlazeTestCase {
-
- @Test
- public void testValidation() {
- // Valid workspace paths
- assertThat(WorkspacePath.validate("")).isTrue();
- assertThat(WorkspacePath.validate("foo")).isTrue();
- assertThat(WorkspacePath.validate("foo")).isTrue();
- assertThat(WorkspacePath.validate("foo/bar")).isTrue();
- assertThat(WorkspacePath.validate("foo/bar/baz")).isTrue();
-
- // Invalid workspace paths
- assertThat(WorkspacePath.validate("/foo")).isFalse();
- assertThat(WorkspacePath.validate("//foo")).isFalse();
- assertThat(WorkspacePath.validate("/")).isFalse();
- assertThat(WorkspacePath.validate("foo/")).isFalse();
- assertThat(WorkspacePath.validate("foo:")).isFalse();
- assertThat(WorkspacePath.validate(":")).isFalse();
- assertThat(WorkspacePath.validate("foo:bar")).isFalse();
-
-
- List<BlazeValidationError> errors = Lists.newArrayList();
-
- WorkspacePath.validate("/foo", errors);
- assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not start with '/': /foo");
- errors.clear();
-
- WorkspacePath.validate("/", errors);
- assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not start with '/': /");
- errors.clear();
-
- WorkspacePath.validate("foo/", errors);
- assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not end with '/': foo/");
- errors.clear();
-
- WorkspacePath.validate("foo:bar", errors);
- assertThat(errors.get(0).getError()).isEqualTo("Workspace path may not contain ':': foo:bar");
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java
deleted file mode 100644
index 0c295cf..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.TestUtils;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.model.primitives.*;
-import com.google.idea.blaze.base.projectview.section.*;
-import com.google.idea.blaze.base.projectview.section.sections.*;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class ProjectViewSetTest extends BlazeTestCase {
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
- }
-
- @Test
- public void testProjectViewSetSerializable() throws Exception {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY).add(DirectoryEntry.include(new WorkspacePath("test"))))
- .put(ListSection.builder(TargetSection.KEY).add(TargetExpression.fromString("//test:all")))
- .put(ScalarSection.builder(ImportSection.KEY).set(new WorkspacePath("test")))
- .put(ListSection.builder(TestSourceSection.KEY).add(new Glob("javatests/*")))
- .put(ListSection.builder(ExcludedSourceSection.KEY).add(new Glob("*.java")))
- .put(ListSection.builder(BuildFlagsSection.KEY).add("--android_sdk=abcd"))
- .put(ListSection.builder(ImportTargetOutputSection.KEY).add(new Label("//test:test")))
- .put(ListSection.builder(ExcludeTargetSection.KEY).add(new Label("//test:test")))
- .put(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.JAVA))
- .put(ListSection.builder(AdditionalLanguagesSection.KEY).add(LanguageClass.JAVA))
- .put(ScalarSection.builder(MetricsProjectSection.KEY).set("my project"))
- .build())
- .build();
-
- // Assert we have all sections
- assert projectViewSet.getTopLevelProjectViewFile() != null;
- ProjectView projectView = projectViewSet.getTopLevelProjectViewFile().projectView;
- for (SectionParser parser : Sections.getParsers()) {
- Section section = projectView.getSectionOfType(parser.getSectionKey());
- assertThat(section).isNotNull();
- }
-
- TestUtils.assertIsSerializable(projectViewSet);
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java
deleted file mode 100644
index c643521..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.io.MockWorkspaceScanner;
-import com.google.idea.blaze.base.io.WorkspaceScanner;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ErrorCollector;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.io.File;
-
-/**
- * Tests for ProjectViewVerifier
- */
-public class ProjectViewVerifierTest extends BlazeTestCase {
-
- private String FAKE_ROOT = "/root";
- private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File(FAKE_ROOT));
- private MockWorkspaceScanner workspaceScanner;
- private ErrorCollector errorCollector = new ErrorCollector();
- private BlazeContext context;
- private WorkspaceLanguageSettings workspaceLanguageSettings = new WorkspaceLanguageSettings(
- WorkspaceType.JAVA,
- ImmutableSet.of( LanguageClass.JAVA)
- );
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
-
- workspaceScanner = new MockWorkspaceScanner();
- applicationServices.register(WorkspaceScanner.class, workspaceScanner);
- context = new BlazeContext();
- context.addOutputSink(IssueOutput.class, errorCollector);
- }
-
- @Test
- public void testNoIssues() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example2"))))
- .build())
- .build();
- workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertNoIssues();
- }
-
- @Test
- public void testExcludingExactRootResultsInIssue() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.exclude(new WorkspacePath("java/com/google/android/apps/example"))))
- .build())
- .build();
- workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertIssues(
- "java/com/google/android/apps/example is included, but that contradicts java/com/google/android/apps/example which was excluded");
- }
-
- @Test
- public void testExcludingRootViaParentResultsInIssue() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.exclude(new WorkspacePath("java/com/google/android/apps"))))
- .build())
- .build();
- workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertIssues(
- "java/com/google/android/apps/example is included, but that contradicts java/com/google/android/apps which was excluded");
- }
-
- @Test
- public void testExcludingSubdirectoryOfRootResultsInNoIssues() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.exclude(new WorkspacePath("java/com/google/android/apps/example/subdir"))))
- .build())
- .build();
- workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertNoIssues();
- }
-
- @Test
- public void testImportRootMissingResultsInIssue() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example"))))
- .build())
- .build();
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertIssues(
- String.format("Directory '%s' specified in import roots not found under workspace root '%s'",
- "java/com/google/android/apps/example", "/root"));
- }
-
- @Test
- public void testOverlappingDirectoriesResultInIssue() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example"))))
- .build())
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android"))))
- .build())
- .build();
- workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertIssues(
- "Overlapping directories: java/com/google/android/apps/example already included by java/com/google/android"
- );
- }
-
- @Test
- public void testRootDirectoryNotSpuriouslyOverlappingItself() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("."))))
- .build())
- .build();
- workspaceScanner.addProjectView(workspaceRoot, projectViewSet);
- ProjectViewVerifier.verifyProjectView(context, workspaceRoot, projectViewSet, workspaceLanguageSettings);
- errorCollector.assertNoIssues();
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/parser/ProjectViewParserTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/parser/ProjectViewParserTest.java
deleted file mode 100644
index b7a8e84..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/projectview/parser/ProjectViewParserTest.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.projectview.parser;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
-import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
-import com.google.idea.blaze.base.projectview.section.sections.ImportSection;
-import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ErrorCollector;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.junit.Test;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Map;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class ProjectViewParserTest extends BlazeTestCase {
- private ProjectViewParser projectViewParser;
- private BlazeContext context;
- private ErrorCollector errorCollector;
- private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/"));
- private MockProjectViewStorageManager projectViewStorageManager;
-
- static class MockProjectViewStorageManager extends ProjectViewStorageManager {
- Map<String, String> projectViewFiles = Maps.newHashMap();
- @Nullable
- @Override
- public String loadProjectView(@NotNull File projectViewFile) throws IOException {
- return projectViewFiles.get(projectViewFile.getPath());
- }
-
- @Override
- public void writeProjectView(@NotNull String projectViewText, @NotNull File projectViewFile) throws IOException {
- // no-op
- }
-
- void add(String name, String... text) {
- projectViewFiles.put(name, Joiner.on('\n').join(text));
- }
- }
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- context = new BlazeContext();
- errorCollector = new ErrorCollector();
- context.addOutputSink(IssueOutput.class, errorCollector);
- projectViewParser = new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot));
- projectViewStorageManager = new MockProjectViewStorageManager();
- applicationServices.register(ProjectViewStorageManager.class, projectViewStorageManager);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
- }
-
- @Test
- public void testDirectoriesAndTargets() throws Exception {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- " java/com/google",
- " java/com/google/android",
- " -java/com/google/android/notme",
- "",
- "targets:",
- " //java/com/google:all",
- " //java/com/google/...:all",
- " -//java/com/google:thistarget"
- );
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertNoIssues();
-
- ProjectViewSet projectViewSet = projectViewParser.getResult();
- ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
- assertThat(projectViewFile).isNotNull();
- assertThat(projectViewFile.projectViewFile).isEqualTo(new File(".blazeproject"));
- assertThat(projectViewSet.getProjectViewFiles()).containsExactly(projectViewFile);
-
- ProjectView projectView = projectViewFile.projectView;
- assertThat(projectView.getSectionOfType(DirectorySection.KEY).items())
- .containsExactly(
- new DirectoryEntry(new WorkspacePath("java/com/google"), true),
- new DirectoryEntry(new WorkspacePath("java/com/google/android"), true),
- new DirectoryEntry(new WorkspacePath("java/com/google/android/notme"), false)
- );
- assertThat(projectView.getSectionOfType(TargetSection.KEY).items())
- .containsExactly(
- TargetExpression.fromString("//java/com/google:all"),
- TargetExpression.fromString("//java/com/google/...:all"),
- TargetExpression.fromString("-//java/com/google:thistarget")
- );
- }
-
- @Test
- public void testRootDirectory() throws Exception {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- " .",
- " -java/com/google/android/notme",
- "",
- "targets:",
- " //java/com/google:all"
- );
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertNoIssues();
-
- ProjectViewSet projectViewSet = projectViewParser.getResult();
- ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
- assertThat(projectViewFile).isNotNull();
- assertThat(projectViewFile.projectViewFile).isEqualTo(new File(".blazeproject"));
- assertThat(projectViewSet.getProjectViewFiles()).containsExactly(projectViewFile);
-
- ProjectView projectView = projectViewFile.projectView;
- assertThat(projectView.getSectionOfType(DirectorySection.KEY).items())
- .containsExactly(
- new DirectoryEntry(new WorkspacePath(""), true),
- new DirectoryEntry(new WorkspacePath("java/com/google/android/notme"), false)
- );
- assertThat(projectView.getSectionOfType(TargetSection.KEY).items())
- .containsExactly(
- TargetExpression.fromString("//java/com/google:all")
- );
-
- String text = ProjectViewParser.projectViewToString(projectView);
- assertThat(text).isEqualTo(
- Joiner.on('\n').join(
- "directories:",
- " .",
- " -java/com/google/android/notme",
- "",
- "targets:",
- " //java/com/google:all",
- ""
- )
- );
- }
-
- @Test
- public void testPrint() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/one")))
- .add(DirectoryEntry.exclude(new WorkspacePath("java/com/google/two"))))
- .put(ListSection.builder(TargetSection.KEY)
- .add(TargetExpression.fromString("//java/com/google:one"))
- .add(TargetExpression.fromString("//java/com/google:two")))
- .put(ScalarSection.builder(ImportSection.KEY)
- .set(new WorkspacePath("some/file.blazeproject")))
- .build();
- String text = ProjectViewParser.projectViewToString(projectView);
- assertThat(text).isEqualTo(
- Joiner.on('\n').join(
- "import some/file.blazeproject",
- "",
- "directories:",
- " java/com/google/one",
- " -java/com/google/two",
- "",
- "targets:",
- " //java/com/google:one",
- " //java/com/google:two",
- ""
- ));
- }
-
- @Test
- public void testImport() {
- projectViewStorageManager.add("/parent.blazeproject",
- "directories:",
- " parent",
- "");
- projectViewStorageManager.add(".blazeproject",
- "import parent.blazeproject",
- "directories:",
- " child",
- "");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertNoIssues();
-
- ProjectViewSet projectViewSet = projectViewParser.getResult();
- assertThat(projectViewSet.getProjectViewFiles()).hasSize(2);
- Collection<DirectoryEntry> entries = projectViewSet.listItems(DirectorySection.KEY);
- assertThat(entries).containsExactly(
- new DirectoryEntry(new WorkspacePath("parent"), true),
- new DirectoryEntry(new WorkspacePath("child"), true)
- );
- }
-
- @Test
- public void testMinimumIndentRequired() {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- " java/com/google",
- "java/com/google2",
- "");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Could not parse: 'java/com/google2'");
- }
-
- @Test
- public void testIncorrectIndentationResultsInIssue() {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- " java/com/google",
- " java/com/google2",
- "");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Invalid indentation. Project view files are indented with 2 spaces.");
- }
-
- @Test
- public void testCanParseWithMissingCarriageReturnAtEndOfSection() {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- " java/com/google");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- ProjectView projectView = projectViewParser.getResult().getTopLevelProjectViewFile().projectView;
- assertThat(projectView.getSectionOfType(DirectorySection.KEY).items())
- .containsExactly(new DirectoryEntry(new WorkspacePath("java/com/google"), true));
- }
-
- @Test
- public void testWhitespaceIsIgnoredBetweenSections() {
- projectViewStorageManager.add(".blazeproject",
- "",
- "directories:",
- " java/com/google",
- "",
- "");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- ProjectView projectView = projectViewParser.getResult().getTopLevelProjectViewFile().projectView;
- assertThat(projectView.getSectionOfType(DirectorySection.KEY).items())
- .containsExactly(new DirectoryEntry(new WorkspacePath("java/com/google"), true));
- }
-
- @Test
- public void testImportMissingFileResultsInIssue() {
- projectViewStorageManager.add(".blazeproject",
- "import parent.blazeproject");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Could not load project view file: '/parent.blazeproject'");
- }
-
- @Test
- public void testDuplicateSectionsResultsInIssue() {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- " java/com/google",
- "directories:",
- " java/com/google");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Duplicate attribute: 'directories'");
- }
-
- @Test
- public void testMissingSectionResultsInIssue() {
- projectViewStorageManager.add(".blazeproject",
- "nosuchsection:",
- " java/com/google");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Could not parse: 'nosuchsection:'");
- }
-
- @Test
- public void testMissingColonResultInIssue() {
- projectViewStorageManager.add(".blazeproject",
- "directories",
- " java/com/google");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Could not parse: 'directories'");
- }
-
- @Test
- public void testEmptySectionYieldsError() {
- projectViewStorageManager.add(".blazeproject",
- "directories:",
- "");
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertIssues("Empty section: 'directories'");
- }
-
- @Test
- public void testCommentsAreSkipped() throws Exception {
- projectViewStorageManager.add(".blazeproject",
- "# comment",
- "directories:",
- "# another comment",
- " java/com/google",
- " # comment",
- " java/com/google/android",
- ""
- );
- projectViewParser.parseProjectView(new File(".blazeproject"));
- errorCollector.assertNoIssues();
-
- ProjectViewSet projectViewSet = projectViewParser.getResult();
- ProjectViewSet.ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
- ProjectView projectView = projectViewFile.projectView;
- assertThat(projectView.getSectionOfType(DirectorySection.KEY).items())
- .containsExactly(
- new DirectoryEntry(new WorkspacePath("java/com/google"), true),
- new DirectoryEntry(new WorkspacePath("java/com/google/android"), true)
- );
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/rulemaps/ReverseDependencyMapTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/rulemaps/ReverseDependencyMapTest.java
deleted file mode 100644
index 7a3a524..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/rulemaps/ReverseDependencyMapTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.rulemaps;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class ReverseDependencyMapTest extends BlazeTestCase {
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- }
-
- @Test
- public void testSingleDep() {
- RuleMapBuilder builder = RuleMapBuilder.builder();
- ImmutableMap<Label, RuleIdeInfo> ruleMap = builder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l1")
- .setKind("java_library")
- .addDependency("//l:l2"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l2")
- .setKind("java_library"))
- .build();
-
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(reverseDependencies).containsEntry(new Label("//l:l2"), new Label("//l:l1"));
- }
-
- @Test
- public void testLabelDepsOnTwoLabels() {
- RuleMapBuilder builder = RuleMapBuilder.builder();
- ImmutableMap<Label, RuleIdeInfo> ruleMap = builder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l1")
- .setKind("java_library")
- .addDependency("//l:l2")
- .addDependency("//l:l3"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l2")
- .setKind("java_library"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l3")
- .setKind("java_library"))
- .build();
-
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(reverseDependencies).containsEntry(new Label("//l:l2"), new Label("//l:l1"));
- assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l1"));
- }
-
- @Test
- public void testTwoLabelsDepOnSameLabel() {
- RuleMapBuilder builder = RuleMapBuilder.builder();
- ImmutableMap<Label, RuleIdeInfo> ruleMap = builder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l1")
- .setKind("java_library")
- .addDependency("//l:l3"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l2")
- .addDependency("//l:l3")
- .setKind("java_library"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l3")
- .setKind("java_library"))
- .build();
-
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l1"));
- assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l2"));
- }
-
- @Test
- public void testThreeLevelGraph() {
- RuleMapBuilder builder = RuleMapBuilder.builder();
- ImmutableMap<Label, RuleIdeInfo> ruleMap = builder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l1")
- .setKind("java_library")
- .addDependency("//l:l3"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l2")
- .addDependency("//l:l3")
- .setKind("java_library"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l3")
- .setKind("java_library"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l4")
- .addDependency("//l:l3")
- .setKind("java_library"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//l:l5")
- .addDependency("//l:l4")
- .setKind("java_library"))
- .build();
-
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l1"));
- assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l2"));
- assertThat(reverseDependencies).containsEntry(new Label("//l:l3"), new Label("//l:l4"));
- assertThat(reverseDependencies).containsEntry(new Label("//l:l4"), new Label("//l:l5"));
- }
-
- private static ArtifactLocation sourceRoot(String relativePath) {
- return ArtifactLocation.builder()
- .setRootPath("/")
- .setRelativePath(relativePath)
- .setIsSource(true)
- .build();
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/run/testmap/TestMapTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/run/testmap/TestMapTest.java
deleted file mode 100644
index 2930623..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/run/testmap/TestMapTest.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.run.testmap;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.rulemaps.ReverseDependencyMap;
-import com.google.idea.blaze.base.run.testmap.TestRuleFinderImpl.TestMap;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.io.File;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class TestMapTest extends BlazeTestCase {
- private RuleMapBuilder ruleMapBuilder;
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- ruleMapBuilder = RuleMapBuilder.builder();
- }
-
- @Test
- public void testTrivialTestMap() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .addSource(sourceRoot("test/Test.java")))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), null))
- .containsExactly(new Label("//test:test"));
- }
-
- @Test
- public void testOneStepRemovedTestMap() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .addDependency("//test:lib"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), null))
- .containsExactly(new Label("//test:test"));
- }
-
- @Test
- public void testTwoCandidatesTestMap() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .addDependency("//test:lib"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test2")
- .setKind("java_test")
- .addDependency("//test:lib"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), null))
- .containsExactly(new Label("//test:test"), new Label("//test:test2"));
- }
-
- @Test
- public void testBfsPreferred() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib2")
- .setKind("java_library")
- .addDependency("//test:lib"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test2")
- .setKind("java_test")
- .addDependency("//test:lib2"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .addDependency("//test:lib"))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), null))
- .containsExactly(new Label("//test:test"), new Label("//test:test2"))
- .inOrder();
- }
-
- @Test
- public void testTestSizeFilter() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib2")
- .setKind("java_library")
- .addDependency("//test:lib"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test2")
- .setKind("java_test")
- .setTestInfo(TestIdeInfo.builder()
- .setTestSize(TestIdeInfo.TestSize.LARGE))
- .addDependency("//test:lib2"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .setTestInfo(TestIdeInfo.builder())
- .addDependency("//test:lib"))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), TestIdeInfo.TestSize.LARGE))
- .containsExactly(new Label("//test:test2"))
- .inOrder();
- }
-
- @Test
- public void testSourceIncludedMultipleTimesFindsAll() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .addDependency("//test:lib"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test2")
- .setKind("java_test")
- .addDependency("//test:lib2"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib2")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), null))
- .containsExactly(new Label("//test:test"), new Label("//test:test2"));
- }
-
- @Test
- public void testSourceIncludedMultipleTimesShouldOnlyGiveOneInstanceOfTest() throws Exception {
- ImmutableMap<Label, RuleIdeInfo> ruleMap = ruleMapBuilder
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:test")
- .setKind("java_test")
- .addDependency("//test:lib")
- .addDependency("//test:lib2"))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("test/BUILD"))
- .setLabel("//test:lib2")
- .setKind("java_library")
- .addSource(sourceRoot("test/Test.java")))
- .build();
-
- TestMap testMap = new TestMap(project, ruleMap);
- ImmutableMultimap<Label, Label> reverseDependencies = ReverseDependencyMap.createRdepsMap(ruleMap);
- assertThat(testMap.testTargetsForSourceFile(reverseDependencies, new File("/test/Test.java"), null))
- .containsExactly(new Label("//test:test"));
- }
-
- private ArtifactLocation sourceRoot(String relativePath) {
- return ArtifactLocation.builder()
- .setRootPath("/")
- .setRelativePath(relativePath)
- .setIsSource(true)
- .build();
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/scope/BlazeContextTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/scope/BlazeContextTest.java
deleted file mode 100644
index 0b0f2a5..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/scope/BlazeContextTest.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.BlazeTestCase;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests for {@link BlazeContext}.
- */
-public class BlazeContextTest extends BlazeTestCase {
-
- @Test
- public void testScopeBeginsWhenPushedToContext() {
- BlazeContext context = new BlazeContext();
- final BlazeScope scope = mock(BlazeScope.class);
- context.push(scope);
- verify(scope).onScopeBegin(context);
- }
-
- @Test
- public void testScopeEndsWhenContextEnds() {
- BlazeContext context = new BlazeContext();
- final BlazeScope scope = mock(BlazeScope.class);
- context.push(scope);
- context.endScope();
- verify(scope).onScopeEnd(context);
- }
-
- @Test
- public void testEndingTwiceHasNoEffect() {
- BlazeContext context = new BlazeContext();
- final BlazeScope scope = mock(BlazeScope.class);
- context.push(scope);
- context.endScope();
- context.endScope();
- verify(scope).onScopeEnd(context);
- }
-
- @Test
- public void testEndingScopeNormallyDoesntEndParent() {
- BlazeContext parentContext = new BlazeContext();
- BlazeContext childContext = new BlazeContext(parentContext);
- childContext.endScope();
- assertTrue(childContext.isEnding());
- assertFalse(parentContext.isEnding());
- }
-
- @Test
- public void testCancellingScopeCancelsParent() {
- BlazeContext parentContext = new BlazeContext();
- BlazeContext childContext = new BlazeContext(parentContext);
- childContext.setCancelled();
- assertTrue(childContext.isCancelled());
- assertTrue(parentContext.isCancelled());
- }
-
- /**
- * A simple scope that records its start and end by ID.
- */
- static class RecordScope implements BlazeScope {
- private final int id;
- private final List<String> record;
-
- public RecordScope(int id, List<String> record) {
- this.id = id;
- this.record = record;
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
- record.add("begin" + id);
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- record.add("end" + id);
- }
- }
-
- @Test
- public void testScopesBeginAndEndInStackOrder() {
- List<String> record = Lists.newArrayList();
- BlazeContext context = new BlazeContext();
- context
- .push(new RecordScope(1, record))
- .push(new RecordScope(2, record))
- .push(new RecordScope(3, record));
- context.endScope();
- assertThat(record)
- .isEqualTo(ImmutableList.of("begin1", "begin2", "begin3", "end3", "end2", "end1"));
- }
-
- @Test
- public void testParentFoundInStackOrder() {
- BlazeContext context = new BlazeContext();
- BlazeScope scope1 = mock(BlazeScope.class);
- BlazeScope scope2 = mock(BlazeScope.class);
- BlazeScope scope3 = mock(BlazeScope.class);
- context
- .push(scope1)
- .push(scope2)
- .push(scope3);
- assertThat(context.getParentScope(scope3)).isEqualTo(scope2);
- assertThat(context.getParentScope(scope2)).isEqualTo(scope1);
- assertThat(context.getParentScope(scope1)).isNull();
- }
-
- @Test
- public void testParentFoundInStackOrderAcrossContexts() {
- BlazeContext parentContext = new BlazeContext();
- BlazeContext childContext = new BlazeContext(parentContext);
- BlazeScope scope1 = mock(BlazeScope.class);
- BlazeScope scope2 = mock(BlazeScope.class);
- BlazeScope scope3 = mock(BlazeScope.class);
- parentContext
- .push(scope1)
- .push(scope2);
- childContext
- .push(scope3);
- assertThat(childContext.getParentScope(scope3)).isEqualTo(scope2);
- }
-
- static class TestOutput1 implements Output {
- }
-
- static class TestOutput2 implements Output {
- }
-
- static class TestOutputSink<T extends Output> implements OutputSink<T> {
- public boolean gotOutput;
-
- @Override
- public Propagation onOutput(@NotNull T output) {
- gotOutput = true;
- return Propagation.Continue;
- }
- }
-
- static class TestOutputSink1 extends TestOutputSink<TestOutput1> {
- }
-
- static class TestOutputSink2 extends TestOutputSink<TestOutput2> {
- }
-
- @Test
- public void testOutputGoesToRegisteredSink() {
- BlazeContext context = new BlazeContext();
- TestOutputSink1 sink = new TestOutputSink1();
- context.addOutputSink(TestOutput1.class, sink);
-
- assertFalse(sink.gotOutput);
- context.output(new TestOutput1());
- assertTrue(sink.gotOutput);
- }
-
- @Test
- public void testOutputDoesntGoToWrongSink() {
- BlazeContext context = new BlazeContext();
- TestOutputSink2 sink = new TestOutputSink2();
- context.addOutputSink(TestOutput2.class, sink);
-
- assertFalse(sink.gotOutput);
- context.output(new TestOutput1());
- assertFalse(sink.gotOutput);
- }
-
- @Test
- public void testOutputGoesToParentContexts() {
- BlazeContext parentContext = new BlazeContext();
- BlazeContext childContext = new BlazeContext(parentContext);
- TestOutputSink1 sink = new TestOutputSink1();
- parentContext.addOutputSink(TestOutput1.class, sink);
-
- assertFalse(sink.gotOutput);
- childContext.output(new TestOutput1());
- assertTrue(sink.gotOutput);
- }
-
- @Test
- public void testHoldingPreventsEndingContext() {
- BlazeContext context = new BlazeContext();
- context.hold();
- context.endScope();
- assertFalse(context.isEnding());
- context.release();
- assertTrue(context.isEnding());
- }
-
- private static class StringScope implements BlazeScope {
-
- public final String str;
-
- public StringScope(String s) {
- this.str = s;
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
-
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
-
- }
- }
-
- private static class CollectorScope implements BlazeScope {
-
- public final List<String> output;
-
- public CollectorScope(List<String> output) {
- this.output = output;
- }
-
- @Override
- public void onScopeBegin(@NotNull BlazeContext context) {
-
- }
-
- @Override
- public void onScopeEnd(@NotNull BlazeContext context) {
- List<StringScope> scopes = context.getScopes(StringScope.class, this);
- for (StringScope scope : scopes) {
- output.add(scope.str);
- }
- }
- }
-
- @Test
- public void testGetScopesOnlyReturnsScopesLowerOnTheStack() {
- List<String> output1 = Lists.newArrayList();
- List<String> output2 = Lists.newArrayList();
- List<String> output3 = Lists.newArrayList();
-
- BlazeContext context = new BlazeContext();
- context.push(new StringScope("a"));
- context.push(new StringScope("b"));
- CollectorScope scope = new CollectorScope(output1);
- context.push(scope);
- context.push(new StringScope("c"));
- context.push(new CollectorScope(output2));
- context.push(new StringScope("d"));
- context.push(new StringScope("e"));
- context.push(new CollectorScope(output3));
- context.endScope();
-
- assertThat(output1).isEqualTo(ImmutableList.of("b", "a"));
- assertThat(output2).isEqualTo(ImmutableList.of("c", "b", "a"));
- assertThat(output3).isEqualTo(ImmutableList.of("e", "d", "c", "b", "a"));
- }
-
- @Test
- public void testGetScopesOnlyReturnsScopesLowerOnTheStackForMultipleContexts() {
- List<String> output1 = Lists.newArrayList();
- List<String> output2 = Lists.newArrayList();
- List<String> output3 = Lists.newArrayList();
-
- BlazeContext context1 = new BlazeContext();
- context1.push(new StringScope("a"));
- context1.push(new StringScope("b"));
- CollectorScope scope = new CollectorScope(output1);
- context1.push(scope);
-
- BlazeContext context2 = new BlazeContext(context1);
- context2.push(new StringScope("c"));
- context2.push(new CollectorScope(output2));
- context2.push(new StringScope("d"));
- context2.push(new StringScope("e"));
-
- BlazeContext context3 = new BlazeContext(context2);
- context3.push(new CollectorScope(output3));
- context3.endScope();
- context2.endScope();
- context1.endScope();
-
- assertThat(output1).isEqualTo(ImmutableList.of("b", "a"));
- assertThat(output2).isEqualTo(ImmutableList.of("c", "b", "a"));
- assertThat(output3).isEqualTo(ImmutableList.of("e", "d", "c", "b", "a"));
- }
-
- @Test
- public void testGetScopesOnlyReturnsScopesIfStartingScopeInContext() {
- List<String> output1 = Lists.newArrayList();
-
- BlazeContext context1 = new BlazeContext();
- context1.push(new StringScope("a"));
- context1.push(new StringScope("b"));
- CollectorScope scope = new CollectorScope(output1);
- context1.push(scope);
-
- BlazeContext context2 = new BlazeContext(context1);
- context2.push(new StringScope("c"));
-
- List<StringScope> scopes = context2.getScopes(StringScope.class, scope);
- assertThat(scopes).isEqualTo(ImmutableList.of());
- }
-
- @Test
- public void testGetScopesIncludesStartingScope() {
- BlazeContext context1 = new BlazeContext();
- StringScope a = new StringScope("a");
- context1.push(a);
- StringScope b = new StringScope("b");
- context1.push(b);
-
- List<StringScope> scopes = context1.getScopes(StringScope.class, b);
- assertThat(scopes).isEqualTo(ImmutableList.of(b, a));
- }
-
- @Test
- public void testGetScopesIndexIsNoninclusive() {
- BlazeContext context1 = new BlazeContext();
- StringScope scopeA = new StringScope("a");
- context1.push(scopeA);
- StringScope scopeB = new StringScope("b");
- context1.push(scopeB);
-
- List<StringScope> scopes = Lists.newArrayList();
- context1.getScopes(scopes, StringScope.class, 1);
- assertThat(scopes).isEqualTo(ImmutableList.of(scopeA));
- }
-
- @Test
- public void testGetScopesWithoutStartScopeGetsAll() {
- BlazeContext context1 = new BlazeContext();
- StringScope a = new StringScope("a");
- context1.push(a);
- StringScope b = new StringScope("b");
- context1.push(b);
-
- List<StringScope> scopes = context1.getScopes(StringScope.class);
- assertThat(scopes).isEqualTo(ImmutableList.of(b, a));
- }
-
- static class NonPropagatingOutputSink implements OutputSink<TestOutput1> {
- boolean gotOutput;
-
- @Override
- public Propagation onOutput(@NotNull TestOutput1 output) {
- this.gotOutput = true;
- return Propagation.Stop;
- }
- }
-
- @Test
- public void testOutputIsTerminatedByFirstSink() {
- NonPropagatingOutputSink sink1 = new NonPropagatingOutputSink();
- NonPropagatingOutputSink sink2 = new NonPropagatingOutputSink();
- NonPropagatingOutputSink sink3 = new NonPropagatingOutputSink();
-
- BlazeContext context1 = new BlazeContext();
- context1.addOutputSink(TestOutput1.class, sink1);
-
- BlazeContext context2 = new BlazeContext(context1);
- context2.addOutputSink(TestOutput1.class, sink2);
- context2.addOutputSink(TestOutput1.class, sink3);
-
- context2.output(new TestOutput1());
-
- assertThat(sink1.gotOutput).isFalse();
- assertThat(sink2.gotOutput).isFalse();
- assertThat(sink3.gotOutput).isTrue();
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/scope/ScopeTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/scope/ScopeTest.java
deleted file mode 100644
index e9db247..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/scope/ScopeTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import com.google.idea.blaze.base.BlazeTestCase;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-/**
- * Tests for {@link Scope}.
- */
-public class ScopeTest extends BlazeTestCase {
-
- @Test
- public void testScopedOperationRuns() {
- final boolean[] ran = new boolean[1];
- Scope.root(new ScopedOperation() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- ran[0] = true;
- }
- });
- assertTrue(ran[0]);
- }
-
- @Test
- public void testScopedFunctionReturnsValue() {
- String result = Scope.root(new ScopedFunction<String>() {
- @Override
- public String execute(@NotNull BlazeContext context) {
- return "test";
- }
- });
- assertThat(result).isEqualTo("test");
- }
-
- @Test
- public void testScopedOperationEndsContext() {
- final BlazeScope scope = mock(BlazeScope.class);
- Scope.root(new ScopedOperation() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- context.push(scope);
- }
- });
- verify(scope).onScopeEnd(any(BlazeContext.class));
- }
-
- @Test
- public void testScopedFunctionEndsContext() {
- final BlazeScope scope = mock(BlazeScope.class);
- Scope.root(new ScopedFunction<String>() {
- @Override
- public String execute(@NotNull BlazeContext context) {
- context.push(scope);
- return "";
- }
- });
- verify(scope).onScopeEnd(any(BlazeContext.class));
- }
-
- /*
- @Test
- public void testThrowingExceptionEndsScopedOperationWithFailure() {
- final RuntimeException e = new RuntimeException();
- final BlazeScope scope = mock(BlazeScope.class);
- Throwable throwable = Scope.root(project, new ScopedOperation() {
- @Override
- public void execute(@NotNull BlazeContext context) {
- context.push(scope);
- throw e;
- }
- }).throwable;
- verify(scope).onScopeEnd(any(BlazeContext.class));
- assertThat(e).isEqualTo(throwable);
- }
-
- @Test
- public void testThrowingExceptionEndsScopeFunctionWithFailure() {
- final RuntimeException e = new RuntimeException();
- final BlazeScope scope = mock(BlazeScope.class);
- Throwable throwable = Scope.root(project, new ScopedFunction<String>() {
- @Override
- public String execute(@NotNull BlazeContext context) {
- context.push(scope);
- throw e;
- }
- }).throwable;
- verify(scope).onScopeEnd(any(BlazeContext.class));
- assertThat(e).isEqualTo(throwable);
- }
- */
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java
deleted file mode 100644
index 7318c00..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.sections.WorkspaceTypeSection;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ErrorCollector;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.util.Set;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Test cases for {@link LanguageSupport}
- */
-public class LanguageSupportTest extends BlazeTestCase {
- private ErrorCollector errorCollector = new ErrorCollector();
- private BlazeContext context;
- private ExtensionPointImpl<BlazeSyncPlugin> syncPlugins;
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
-
- syncPlugins = registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
-
- context = new BlazeContext();
- context.addOutputSink(IssueOutput.class, errorCollector);
- }
-
- @Test
- public void testSimpleCase() {
- syncPlugins.registerExtension(new BlazeSyncPlugin.Adapter() {
- @Override
- public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- return ImmutableSet.of(LanguageClass.C);
- }
- });
-
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ScalarSection.builder(WorkspaceTypeSection.KEY)
- .set(WorkspaceType.C))
- .build())
- .build();
- WorkspaceLanguageSettings workspaceLanguageSettings = LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
- errorCollector.assertNoIssues();
- assertThat(workspaceLanguageSettings).isEqualTo(
- new WorkspaceLanguageSettings(WorkspaceType.C, ImmutableSet.of(LanguageClass.C))
- );
- }
-
- @Test
- public void testFailWithUnsupportedLanguage() {
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ScalarSection.builder(WorkspaceTypeSection.KEY)
- .set(WorkspaceType.C))
- .build())
- .build();
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
- errorCollector.assertIssues(
- "Language 'c' is not supported for this plugin with workspace type: 'c'");
- }
-
- /**
- * Tests that we ask for java and android when the workspace type is android.
- */
- @Test
- public void testWorkspaceTypeImpliesLanguages() {
- syncPlugins.registerExtension(new BlazeSyncPlugin.Adapter() {
- @Override
- public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- return ImmutableSet.of(LanguageClass.ANDROID, LanguageClass.JAVA, LanguageClass.C);
- }
- });
-
- ProjectViewSet projectViewSet = ProjectViewSet.builder()
- .add(ProjectView.builder()
- .put(ScalarSection.builder(WorkspaceTypeSection.KEY)
- .set(WorkspaceType.ANDROID))
- .build())
- .build();
- WorkspaceLanguageSettings workspaceLanguageSettings = LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
- assertThat(workspaceLanguageSettings).isEqualTo(
- new WorkspaceLanguageSettings(WorkspaceType.ANDROID, ImmutableSet.of(LanguageClass.JAVA, LanguageClass.ANDROID))
- );
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImplTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImplTest.java
deleted file mode 100644
index 0f9b711..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImplTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.TestUtils;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.model.primitives.*;
-import com.google.idea.blaze.base.sync.filediff.FileDiffService;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.io.File;
-
-/**
- * Tests for {@link BlazeIdeInterfaceAspectsImpl}.
- */
-public class BlazeIdeInterfaceAspectsImplTest extends BlazeTestCase {
-
- private static final File DUMMY_ROOT = new File("/");
- private static final WorkspaceRoot WORKSPACE_ROOT = new WorkspaceRoot(DUMMY_ROOT);
- private static final BlazeRoots BLAZE_ROOTS = new BlazeRoots(
- DUMMY_ROOT,
- ImmutableList.of(DUMMY_ROOT),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen")
- );
- private static final ArtifactLocationDecoder DUMMY_DECODER = new ArtifactLocationDecoder(
- BLAZE_ROOTS,
- new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_ROOTS)
- );
-
- @Override
- protected void initTest(@NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- applicationServices.register(FileAttributeProvider.class, new FileAttributeProvider());
- }
-
- @Test
- public void testRuleIdeInfoIsSerializable() {
- AndroidStudioIdeInfo.RuleIdeInfo ideProto = AndroidStudioIdeInfo.RuleIdeInfo.newBuilder()
- .setLabel("//test:test")
- .setBuildFile("build")
- .setKindString("android_binary")
- .addDependencies("//test:dep")
- .addTags("tag")
- .setJavaRuleIdeInfo(AndroidStudioIdeInfo.JavaRuleIdeInfo.newBuilder()
- .addJars(AndroidStudioIdeInfo.LibraryArtifact.newBuilder()
- .setJar(artifactLocation("jar.jar")).build())
- .addGeneratedJars(AndroidStudioIdeInfo.LibraryArtifact.newBuilder()
- .setJar(artifactLocation("jar.jar")).build())
- .addSources(artifactLocation("source.java")))
- .setAndroidRuleIdeInfo(AndroidStudioIdeInfo.AndroidRuleIdeInfo.newBuilder()
- .addResources(artifactLocation("res"))
- .setApk(artifactLocation("apk"))
- .addDependencyApk(artifactLocation("apk"))
- .setJavaPackage("package"))
- .build();
-
- WorkspaceLanguageSettings workspaceLanguageSettings = new WorkspaceLanguageSettings(WorkspaceType.ANDROID,
- ImmutableSet.of(LanguageClass.ANDROID));
- RuleIdeInfo ruleIdeInfo = IdeInfoFromProtobuf.makeRuleIdeInfo(workspaceLanguageSettings, DUMMY_DECODER, ideProto);
- TestUtils.assertIsSerializable(ruleIdeInfo);
- }
-
- @Test
- public void testBlazeStateIsSerializable() {
- BlazeIdeInterfaceAspectsImpl.State state = new BlazeIdeInterfaceAspectsImpl.State();
- state.fileToLabel = ImmutableMap.of(new File("fileName"), new Label("//java/com/test:test"));
- state.fileState = new FileDiffService.State();
- state.androidPlatformDirectory = new File("");
- state.androidPlatformDirectory = new File("dir");
- state.ruleMap = ImmutableMap.of(); // Tested separately in testRuleIdeInfoIsSerializable
-
- TestUtils.assertIsSerializable(state);
- }
-
-
- static AndroidStudioIdeInfo.ArtifactLocation artifactLocation(String relativePath) {
- return artifactLocation(DUMMY_ROOT.toString(), relativePath);
- }
-
- static AndroidStudioIdeInfo.ArtifactLocation artifactLocation(String rootPath, String relativePath) {
- return AndroidStudioIdeInfo.ArtifactLocation.newBuilder().setRootPath(rootPath).setRelativePath(relativePath).build();
- }
-
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptionsTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptionsTest.java
deleted file mode 100644
index e95f0eb..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptionsTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.aspects;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.BlazeTestCase;
-import org.junit.Test;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class UnfilteredCompilerOptionsTest extends BlazeTestCase {
- @Test
- public void testUnfilteredOptionsParsingForISystemOptions() {
- ImmutableList<String> unfilteredOptions = ImmutableList.of(
- "-isystem",
- "sys/inc1",
- "-VER2",
- "-isystem",
- "sys2/inc1",
- "-isystem",
- "sys3/inc1",
- "-isystm",
- "sys4/inc1"
- );
- List<String> sysIncludes = Lists.newArrayList();
- List<String> flags = Lists.newArrayList();
- UnfilteredCompilerOptions.splitUnfilteredCompilerOptions(unfilteredOptions, sysIncludes, flags);
-
- assertThat(sysIncludes).containsExactly(
- "sys/inc1",
- "sys2/inc1",
- "sys3/inc1"
- );
-
- assertThat(flags).containsExactly(
- "-VER2",
- "-isystm",
- "sys4/inc1"
- );
- }
-
- @Test
- public void testUnfilteredOptionsParsingForISystemOptionsNoSpaceAfterIsystem() {
- ImmutableList<String> unfilteredOptions = ImmutableList.of(
- "-isystem",
- "sys/inc1",
- "-VER2",
- "-isystemsys2/inc1",
- "-isystem",
- "sys3/inc1"
- );
- List<String> sysIncludes = Lists.newArrayList();
- List<String> flags = Lists.newArrayList();
- UnfilteredCompilerOptions.splitUnfilteredCompilerOptions(unfilteredOptions, sysIncludes, flags);
-
- assertThat(sysIncludes).containsExactly(
- "sys/inc1",
- "sys2/inc1",
- "sys3/inc1"
- );
-
- assertThat(flags).containsExactly("-VER2");
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/filediff/FileDiffServiceTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/filediff/FileDiffServiceTest.java
deleted file mode 100644
index b5d107e..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/filediff/FileDiffServiceTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.filediff;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for FileDiffService
- */
-public class FileDiffServiceTest extends BlazeTestCase {
- private MockFileAttributeProvider fileModificationProvider;
- private FileDiffService fileDiffService;
-
- private static class MockFileAttributeProvider extends FileAttributeProvider {
- List<Long> times = Lists.newArrayList();
- int index;
-
- public MockFileAttributeProvider add(long time) {
- times.add(time);
- return this;
- }
-
- @Override
- public long getFileModifiedTime(@NotNull File file) {
- return times.get(index++);
- }
- }
-
- @Override
- protected void initTest(@NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- applicationServices.register(BlazeExecutor.class, new MockBlazeExecutor());
-
- this.fileModificationProvider = new MockFileAttributeProvider();
- applicationServices.register(FileAttributeProvider.class, fileModificationProvider);
- this.fileDiffService = new FileDiffService();
- }
-
- @Test
- public void testDiffWithDiffMethodTimestamp() throws Exception {
- Map<File, FileDiffService.FileEntry> oldFiles = fileMap(
- fileEntry("file1", 13),
- fileEntry("file2", 17),
- fileEntry("file3", 21)
- );
- FileDiffService.State oldState = new FileDiffService.State();
- oldState.fileEntryMap = oldFiles;
- List<File> fileList = ImmutableList.of(new File("file1"), new File("file2"));
- fileModificationProvider.add(13).add(122);
-
- List<File> newFiles = Lists.newArrayList();
- List<File> removedFiles = Lists.newArrayList();
- fileDiffService.updateFiles(
- oldState,
- fileList,
- newFiles,
- removedFiles
- );
-
- assertThat(newFiles).containsExactly(new File("file2"));
- assertThat(removedFiles).containsExactly(new File("file3"));
- }
-
- static Map<File, FileDiffService.FileEntry> fileMap(FileDiffService.FileEntry... fileEntries) {
- ImmutableMap.Builder<File, FileDiffService.FileEntry> builder = ImmutableMap.builder();
- for (FileDiffService.FileEntry fileEntry : fileEntries) {
- builder.put(fileEntry.file, fileEntry);
- }
- return builder.build();
- }
-
- static FileDiffService.FileEntry fileEntry(@NotNull String filePath, long timestamp) {
- FileDiffService.FileEntry fileEntry = new FileDiffService.FileEntry();
- fileEntry.file = new File(filePath);
- fileEntry.timestamp = timestamp;
- return fileEntry;
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderTest.java
deleted file mode 100644
index 3440275..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderTest.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.AndroidStudioIdeInfo;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-import java.util.List;
-import java.util.Set;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Test cases for {@link ArtifactLocationDecoder}.
- */
-@RunWith(JUnit4.class)
-public class ArtifactLocationDecoderTest extends BlazeTestCase {
-
- private static final WorkspaceRoot WORKSPACE_ROOT = new WorkspaceRoot(new File("/path/to/root"));
- private static final String EXECUTION_ROOT = "/path/to/_blaze_user/1234bf129e/root";
-
- private static final BlazeRoots BLAZE_GIT5_ROOTS = new BlazeRoots(
- new File(EXECUTION_ROOT),
- ImmutableList.of(
- WORKSPACE_ROOT.directory(),
- new File(WORKSPACE_ROOT.directory().getParentFile(), "READONLY/root")
- ),
- new ExecutionRootPath("root/blaze-out/crosstool/bin"),
- new ExecutionRootPath("root/blaze-out/crosstool/genfiles")
- );
-
- private static final BlazeRoots BLAZE_CITC_ROOTS = new BlazeRoots(
- new File(EXECUTION_ROOT),
- ImmutableList.of(WORKSPACE_ROOT.directory()),
- new ExecutionRootPath("root/blaze-out/crosstool/bin"),
- new ExecutionRootPath("root/blaze-out/crosstool/genfiles")
- );
-
- static class MockFileAttributeProvider extends FileAttributeProvider {
- final Set<File> files = Sets.newHashSet();
-
- void addFiles(@NotNull File... files) {
- this.files.addAll(Lists.newArrayList(files));
- }
-
- @Override
- public boolean exists(@NotNull File file) {
- return files.contains(file);
- }
- }
-
- private MockFileAttributeProvider fileChecker;
-
- @Override
- protected void initTest(
- @NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
-
- fileChecker = new MockFileAttributeProvider();
- applicationServices.register(
- FileAttributeProvider.class,
- fileChecker
- );
- }
-
- @Test
- public void testManualPackagePaths() throws Exception {
- List<File> packagePaths = ImmutableList.of(
- WORKSPACE_ROOT.directory(),
- new File(WORKSPACE_ROOT.directory().getParentFile(), "READONLY/root"),
- new File(WORKSPACE_ROOT.directory().getParentFile(), "CUSTOM/root")
- );
-
- BlazeRoots BLAZE_ROOTS = new BlazeRoots(
- new File(EXECUTION_ROOT),
- packagePaths,
- new ExecutionRootPath("root/blaze-out/crosstool/bin"),
- new ExecutionRootPath("root/blaze-out/crosstool/genfiles")
- );
-
- fileChecker.addFiles(new File(packagePaths.get(0), "com/google/Bla.java"),
- new File(packagePaths.get(1), "com/google/Foo.java"),
- new File(packagePaths.get(2), "com/other/Test.java"));
-
- ArtifactLocationDecoder decoder = new ArtifactLocationDecoder(BLAZE_ROOTS, new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_ROOTS));
-
- ArtifactLocationBuilder builder = new ArtifactLocationBuilder()
- .setRootPath("UNUSED_DUMMY")
- .setRelativePath("com/google/Bla.java")
- .setIsSource(true)
- .setVersion(Version.Current);
-
- assertThat(decoder.decode(builder.buildIdeInfoArtifact()).getRootPath())
- .isEqualTo(packagePaths.get(0).toString());
-
- builder.setRelativePath("com/google/Foo.java");
-
- assertThat(decoder.decode(builder.buildIdeInfoArtifact()).getRootPath())
- .isEqualTo(packagePaths.get(1).toString());
-
- builder.setRelativePath("com/other/Test.java");
-
- assertThat(decoder.decode(builder.buildIdeInfoArtifact()).getRootPath())
- .isEqualTo(packagePaths.get(2).toString());
-
- builder
- .setRootPath(WORKSPACE_ROOT.toString())
- .setRelativePath("third_party/other/Temp.java");
-
- assertThat(decoder.decode(builder.buildIdeInfoArtifact())).isNull();
- }
-
- @Test
- public void testDerivedArtifactAllVersions() throws Exception {
- ArtifactLocationBuilder builder = new ArtifactLocationBuilder()
- .setRootPath(EXECUTION_ROOT + "/blaze-out/bin")
- .setRootExecutionPathFragment("/blaze-out/bin")
- .setRelativePath("com/google/Bla.java")
- .setIsSource(false)
- .setVersion(Version.Current);
-
- ArtifactLocationDecoder decoder = new ArtifactLocationDecoder(BLAZE_CITC_ROOTS, null);
-
- ArtifactLocation parsed = decoder.decode(builder.buildIdeInfoArtifact());
-
- assertThat(parsed)
- .isEqualTo(decoder.decode(builder.buildManifestArtifact()));
-
- assertThat(parsed).isEqualTo(
- ArtifactLocation.builder()
- .setRootPath(EXECUTION_ROOT + "/blaze-out/bin")
- .setRootExecutionPathFragment("/blaze-out/bin")
- .setRelativePath("com/google/Bla.java")
- .setIsSource(false)
- .build());
-
- assertThat(parsed).isEqualTo(
- decoder.decode(
- builder.setVersion(Version.Past).buildIdeInfoArtifact()
- ));
-
- ArtifactLocation future = decoder.decode(
- builder.setVersion(Version.Future).buildIdeInfoArtifact());
-
- assertThat(future).isEqualTo(
- ArtifactLocation.builder()
- .setRootPath(EXECUTION_ROOT + "/blaze-out/bin")
- .setRootExecutionPathFragment("/blaze-out/bin")
- .setRelativePath("com/google/Bla.java")
- .setIsSource(false)
- .build());
- }
-
- @Test
- public void testSourceArtifactAllVersions() throws Exception {
- ArtifactLocationBuilder builder = new ArtifactLocationBuilder()
- .setRootPath(WORKSPACE_ROOT.toString())
- .setRelativePath("com/google/Bla.java")
- .setIsSource(true)
- .setVersion(Version.Current);
-
- ArtifactLocationDecoder decoder = new ArtifactLocationDecoder(BLAZE_CITC_ROOTS,
- new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS));
-
- ArtifactLocation parsed = decoder.decode(builder.buildIdeInfoArtifact());
-
- assertThat(parsed)
- .isEqualTo(decoder.decode(builder.buildManifestArtifact()));
-
- assertThat(parsed).isEqualTo(
- ArtifactLocation.builder()
- .setRootPath(WORKSPACE_ROOT.toString())
- .setRelativePath("com/google/Bla.java")
- .setIsSource(true)
- .build());
-
- assertThat(parsed).isEqualTo(
- decoder.decode(
- builder.setVersion(Version.Past).buildIdeInfoArtifact()
- ));
-
- ArtifactLocation future = decoder.decode(
- builder.setVersion(Version.Future).buildIdeInfoArtifact());
-
- assertThat(future).isEqualTo(
- ArtifactLocation.builder()
- .setRootPath(WORKSPACE_ROOT.toString())
- .setRelativePath("com/google/Bla.java")
- .setIsSource(true)
- .build());
- }
-
- enum Version {
- Past, // no rootExecutionPathFragment
- Current, // everything
- Future // no rootPath
- }
-
- static class ArtifactLocationBuilder {
- Version version;
- String rootPath;
- String rootExecutionPathFragment = "";
- String relativePath;
- boolean isSource;
-
-
- ArtifactLocationBuilder setVersion(Version version) {
- this.version = version;
- return this;
- }
-
- ArtifactLocationBuilder setRootPath(String rootPath) {
- this.rootPath = rootPath;
- return this;
- }
-
- ArtifactLocationBuilder setRootExecutionPathFragment(String rootExecutionPathFragment) {
- this.rootExecutionPathFragment = rootExecutionPathFragment;
- return this;
- }
-
- ArtifactLocationBuilder setRelativePath(String relativePath) {
- this.relativePath = relativePath;
- return this;
- }
-
- ArtifactLocationBuilder setIsSource(boolean isSource) {
- this.isSource = isSource;
- return this;
- }
-
- AndroidStudioIdeInfo.ArtifactLocation buildIdeInfoArtifact() {
- AndroidStudioIdeInfo.ArtifactLocation.Builder builder = AndroidStudioIdeInfo.ArtifactLocation.newBuilder()
- .setIsSource(isSource)
- .setRelativePath(relativePath);
- if (version != Version.Past) {
- builder.setRootExecutionPathFragment(rootExecutionPathFragment);
- }
- if (version != Version.Future) {
- builder.setRootPath(rootPath);
- }
- return builder.build();
- }
-
- PackageManifestOuterClass.ArtifactLocation buildManifestArtifact() {
- PackageManifestOuterClass.ArtifactLocation.Builder builder = PackageManifestOuterClass.ArtifactLocation.newBuilder()
- .setIsSource(isSource)
- .setRelativePath(relativePath);
- if (version != Version.Past) {
- builder.setRootExecutionPathFragment(rootExecutionPathFragment);
- }
- if (version != Version.Future) {
- builder.setRootPath(rootPath);
- }
- return builder.build();
- }
- }
-
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImplTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImplTest.java
deleted file mode 100644
index 95b7efe..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImplTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync.workspace;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import org.junit.Test;
-
-import java.io.File;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class WorkspacePathResolverImplTest extends BlazeTestCase {
- private static final WorkspaceRoot WORKSPACE_ROOT = new WorkspaceRoot(new File("/path/to/root"));
- private static final String EXECUTION_ROOT = "/path/to/_blaze_user/1234bf129e/root";
-
- private static final BlazeRoots BLAZE_CITC_ROOTS = new BlazeRoots(
- new File(EXECUTION_ROOT),
- ImmutableList.of(WORKSPACE_ROOT.directory()),
- new ExecutionRootPath("blaze-out/crosstool/bin"),
- new ExecutionRootPath("blaze-out/crosstool/genfiles")
- );
-
- @Test
- public void testResolveToIncludeDirectories() {
- WorkspacePathResolver workspacePathResolver = new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS);
- ImmutableList<File> files = workspacePathResolver.resolveToIncludeDirectories(new ExecutionRootPath("tools/fast"));
- assertThat(files).containsExactly(new File("/path/to/root/tools/fast"));
- }
-
- @Test
- public void testResolveToIncludeDirectoriesForExecRootPath() {
- WorkspacePathResolver workspacePathResolver = new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS);
- ImmutableList<File> files = workspacePathResolver.resolveToIncludeDirectories(
- new ExecutionRootPath("blaze-out/crosstool/bin/tools/fast")
- );
- assertThat(files).containsExactly(new File("/path/to/root/blaze-out/crosstool/bin/tools/fast"));
- }
-}
diff --git a/blaze-base/tests/unittests/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessorTest.java b/blaze-base/tests/unittests/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessorTest.java
deleted file mode 100644
index 8bb373e..0000000
--- a/blaze-base/tests/unittests/com/google/idea/blaze/base/vcs/git/GitStatusLineProcessorTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.vcs.git;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.io.File;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for {@link GitStatusLineProcessor}
- */
-@RunWith(JUnit4.class)
-public class GitStatusLineProcessorTest {
-
- @Test
- public void testGitStatusParser() {
- GitStatusLineProcessor lineProcessor = new GitStatusLineProcessor(new WorkspaceRoot(new File("/usr/blah")), "/usr/blah");
- for (String line : ImmutableList.of(
- "D root/README",
- "M root/blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java",
- "A root/blah",
- "A java/com/google/Test.java",
- "M java/com/other/"
- )) {
- lineProcessor.processLine(line);
- }
- assertThat(lineProcessor.addedFiles).containsExactly(
- new WorkspacePath("root/blah"),
- new WorkspacePath("java/com/google/Test.java")
- );
- assertThat(lineProcessor.modifiedFiles).containsExactly(
- new WorkspacePath("root/blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java"),
- new WorkspacePath("java/com/other")
- );
- assertThat(lineProcessor.deletedFiles).containsExactly(
- new WorkspacePath("root/README")
- );
- }
-
- @Test
- public void testGitStatusParserDifferentRoots() {
- GitStatusLineProcessor lineProcessor = new GitStatusLineProcessor(new WorkspaceRoot(new File("/usr/blah/root")), "/usr/blah");
- for (String line : ImmutableList.of(
- "D root/README",
- "M root/blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java",
- "A root/blah",
- "A java/com/google/Test.java",
- "M java/com/other/"
- )) {
- lineProcessor.processLine(line);
- }
- assertThat(lineProcessor.addedFiles).containsExactly(
- new WorkspacePath("blah")
- );
- assertThat(lineProcessor.modifiedFiles).containsExactly(
- new WorkspacePath("blaze-base/src/com/google/idea/blaze/base/root/citc/CitcUtil.java")
- );
- assertThat(lineProcessor.deletedFiles).containsExactly(
- new WorkspacePath("README")
- );
- }
-}
diff --git a/blaze-base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java b/blaze-base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java
deleted file mode 100644
index 16cda1f..0000000
--- a/blaze-base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.io.InputStreamProvider;
-import com.google.idea.blaze.base.lang.buildfile.search.FindUsages;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
-
-import com.intellij.codeInsight.lookup.Lookup;
-import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.codeInsight.lookup.LookupElementPresentation;
-import com.intellij.openapi.actionSystem.IdeActions;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.command.CommandProcessor;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.LogicalPosition;
-import com.intellij.openapi.extensions.ExtensionPoint;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.ProjectJdkTable;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.ex.temp.TempFileSystem;
-import com.intellij.psi.*;
-import com.intellij.psi.impl.source.PostprocessReformattingAspect;
-import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesProcessor;
-import com.intellij.testFramework.*;
-import com.intellij.testFramework.EditorTestUtil.CaretAndSelectionState;
-import com.intellij.testFramework.EditorTestUtil.CaretInfo;
-import com.intellij.testFramework.fixtures.*;
-import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
-import org.picocontainer.MutablePicoContainer;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Base test class for blaze integration tests.
- */
-public abstract class BlazeIntegrationTestCase extends UsefulTestCase {
-
- private static final LightProjectDescriptor projectDescriptor = LightCodeInsightFixtureTestCase.JAVA_8;
-
- private static boolean isRunThroughBlaze() {
- return System.getenv("JAVA_RUNFILES") != null;
- }
-
- protected CodeInsightTestFixture testFixture;
- protected WorkspaceRoot workspaceRoot;
- private String oldPluginPathProperty;
-
- @Override
- protected final void setUp() throws Exception {
- if (!isRunThroughBlaze()) {
- // If running directly through the IDE, don't try to load plugins from the sandbox environment.
- // Instead we'll rely on the slightly more hermetic module classpath
- oldPluginPathProperty = System.getProperty(PathManager.PROPERTY_PLUGINS_PATH);
- System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, "/dev/null");
- }
-
- super.setUp();
-
- IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory();
- TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder = factory.createLightFixtureBuilder(projectDescriptor);
- final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture();
- testFixture = factory.createCodeInsightFixture(fixture, createTempDirFixture());
- testFixture.setUp();
-
- ApplicationManager.getApplication().runWriteAction(() -> ProjectJdkTable.getInstance().addJdk(IdeaTestUtil.getMockJdk18()));
-
- workspaceRoot = new WorkspaceRoot(new File(LightPlatformTestCase.getSourceRoot().getPath()));
- setBlazeImportSettings(new BlazeImportSettings(
- workspaceRoot.toString(),
- "test-project",
- workspaceRoot + "/project-data-dir",
- "location-hash",
- workspaceRoot + "/project-view-file",
- buildSystem()
- ));
-
- registerApplicationService(FileAttributeProvider.class, new TempFileAttributeProvider());
- registerApplicationService(InputStreamProvider.class, file -> {
- VirtualFile vf = findFile(file.getPath());
- if (vf == null) {
- throw new FileNotFoundException();
- }
- return vf.getInputStream();
- });
-
- doSetup();
- }
-
- /**
- * Override to run tests with bazel specified as the project's build system.
- */
- protected BuildSystem buildSystem() {
- return BuildSystem.Blaze;
- }
-
- protected void doSetup() throws Exception {
- }
-
- @Override
- protected final void tearDown() throws Exception {
- if (oldPluginPathProperty != null) {
- System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, oldPluginPathProperty);
- } else {
- System.clearProperty(PathManager.PROPERTY_PLUGINS_PATH);
- }
- testFixture.tearDown();
- testFixture = null;
- super.tearDown();
- clearFields(this);
- doTearDown();
- }
-
- protected void doTearDown() throws Exception {
- }
-
- protected void setBlazeImportSettings(BlazeImportSettings importSettings) {
- BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(importSettings);
- }
-
- /**
- * @return fixture to be used as temporary dir.
- */
- protected TempDirTestFixture createTempDirFixture() {
- return new LightTempDirTestFixtureImpl(true); // "tmp://src/" dir by default
- }
-
- /**
- * Absolute file paths are prohibited -- the TempDirTestFixture used in these tests
- * will prepend it's own root to the path.
- */
- protected void assertPathIsNotAbsolute(String filePath) {
- assertThat(FileUtil.isAbsolute(filePath)).isFalse();
- }
-
- /**
- * Creates a file with the specified contents and file path in the test project
- */
- protected VirtualFile createFile(String filePath) {
- return testFixture.getTempDirFixture().createFile(filePath);
- }
-
- /**
- * Creates a file with the specified contents and file path in the test project
- */
- protected VirtualFile createFile(String filePath, String... contentLines) {
- return createFile(filePath, Joiner.on("\n").join(contentLines));
- }
-
- /**
- * Creates a file with the specified contents and file path in the test project
- */
- protected VirtualFile createFile(String filePath, String contents) {
- assertPathIsNotAbsolute(filePath);
- try {
- return testFixture.getTempDirFixture().createFile(filePath, contents);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected PsiDirectory createPsiDirectory(String path) {
- return getPsiDirectory(createDirectory(path));
- }
-
- protected VirtualFile createDirectory(String path) {
- assertPathIsNotAbsolute(path);
- try {
- return testFixture.getTempDirFixture().findOrCreateDir(path);
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected Editor openFileInEditor(PsiFile file) {
- return openFileInEditor(file.getVirtualFile());
- }
-
- protected Editor openFileInEditor(VirtualFile file) {
- testFixture.openFileInEditor(file);
- return testFixture.getEditor();
- }
-
- /**
- * @return null if the only item was auto-completed
- */
- @Nullable
- protected String[] getCompletionItemsAsStrings() {
- LookupElement[] completionItems = testFixture.completeBasic();
- if (completionItems == null) {
- return null;
- }
- return Arrays.stream(completionItems)
- .map(LookupElement::getLookupString)
- .toArray(String[]::new);
- }
-
- /**
- * @return null if the only item was auto-completed
- */
- @Nullable
- protected String[] getCompletionItemsAsSuggestionStrings() {
- LookupElement[] completionItems = testFixture.completeBasic();
- if (completionItems == null) {
- return null;
- }
- LookupElementPresentation presentation = new LookupElementPresentation();
- String[] strings = new String[completionItems.length];
- for (int i = 0; i < strings.length; i++) {
- completionItems[i].renderElement(presentation);
- strings[i] = presentation.getItemText();
- }
- return strings;
- }
-
- /**
- * @return true if a LookupItem was inserted.
- */
- protected boolean completeIfUnique() {
- LookupElement[] completionItems = testFixture.completeBasic();
- if (completionItems == null) {
- return true;
- }
- if (completionItems.length != 1) {
- return false;
- }
- testFixture.getLookup().setCurrentItem(completionItems[0]);
- testFixture.finishLookup(Lookup.NORMAL_SELECT_CHAR);
- return true;
- }
-
- /**
- * Simulates a user typing action, at current caret position of file.
- */
- protected void performTypingAction(PsiFile file, char typedChar) {
- performTypingAction(openFileInEditor(file.getVirtualFile()), typedChar);
- }
-
- /**
- * Simulates a user typing action, at current caret position of document.
- */
- protected void performTypingAction(Editor editor, char typedChar) {
- EditorTestUtil.performTypingAction(editor, typedChar);
- getProject().getComponent(PostprocessReformattingAspect.class).doPostponedFormatting();
- PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
- }
-
- /**
- * Clicks the specified button in current document at the current caret position
- *
- * @param action which button to click (see {@link IdeActions})
- */
- protected final void pressButton(final String action) {
- CommandProcessor.getInstance().executeCommand(
- getProject(),
- () -> testFixture.performEditorAction(action),
- "",
- null);
- }
-
- protected void setCaretPosition(Editor editor, int lineNumber, int columnNumber) {
- CaretInfo info = new CaretInfo(new LogicalPosition(lineNumber, columnNumber), null);
- EditorTestUtil.setCaretsAndSelection(editor, new CaretAndSelectionState(ImmutableList.of(info), null));
- }
-
- protected void assertCaretPosition(Editor editor, int lineNumber, int columnNumber) {
- CaretInfo info = new CaretInfo(new LogicalPosition(lineNumber, columnNumber), null);
- EditorTestUtil.verifyCaretAndSelectionState(editor, new CaretAndSelectionState(ImmutableList.of(info), null));
- }
-
- protected Project getProject() {
- return testFixture.getProject();
- }
-
- protected VirtualFile findFile(String filePath) {
- VirtualFile vf = TempFileSystem.getInstance().findFileByPath(filePath);
- if (vf == null) {
- // this might be a relative path
- vf = testFixture.getTempDirFixture().getFile(filePath);
- }
- return vf;
- }
-
- protected void assertFileContents(String filePath, String... contentLines) {
- assertFileContents(findFile(filePath), contentLines);
- }
-
- protected void assertFileContents(VirtualFile file, String... contentLines) {
- assertFileContents(getPsiFile(file), contentLines);
- }
-
- protected void assertFileContents(PsiFile file, String... contentLines) {
- String contents = Joiner.on("\n").join(contentLines);
- assertThat(file.getText()).isEqualTo(contents);
- }
-
- /**
- * Creates a file with the specified contents and file path in the test project
- */
- protected PsiFile createPsiFile(String filePath) {
- return getPsiFile(testFixture.getTempDirFixture().createFile(filePath));
- }
-
- /**
- * Creates a file with the specified contents and file path in the test project
- */
- protected PsiFile createPsiFile(String filePath, String... contentLines) {
- return getPsiFile(createFile(filePath, contentLines));
- }
-
- /**
- * Finds PsiFile, and asserts that it's not null.
- */
- protected PsiFile getPsiFile(VirtualFile file) {
- PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file);
- assertThat(psiFile).isNotNull();
- return psiFile;
- }
-
- /**
- * Finds PsiDirectory, and asserts that it's not null.
- */
- protected PsiDirectory getPsiDirectory(VirtualFile file) {
- PsiDirectory psiFile = PsiManager.getInstance(getProject()).findDirectory(file);
- assertThat(psiFile).isNotNull();
- return psiFile;
- }
-
- protected PsiDirectory renameDirectory(String oldPath, String newPath) {
- try {
- VirtualFile original = findFile(oldPath);
- PsiDirectory originalPsi = PsiManager.getInstance(getProject()).findDirectory(original);
- assertThat(originalPsi).isNotNull();
-
- VirtualFile destination = testFixture.getTempDirFixture().findOrCreateDir(newPath);
- PsiDirectory destPsi = PsiManager.getInstance(getProject()).findDirectory(destination);
- assertThat(destPsi).isNotNull();
-
- new MoveDirectoryWithClassesProcessor(getProject(), new PsiDirectory[] {originalPsi}, destPsi, true, true, false, null).run();
- return destPsi;
-
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected void renamePsiElement(PsiNamedElement element, String newName) {
- testFixture.renameElement(element, newName);
- }
-
- protected void handleRename(PsiReference reference, String newName) {
- doRenameOperation(() -> reference.handleElementRename(newName));
- }
-
- protected void doRenameOperation(Runnable renameOp) {
- ApplicationManager.getApplication().runWriteAction(
- () -> CommandProcessor.getInstance().runUndoTransparentAction(renameOp));
- }
-
- protected static <T> List<T> findAllReferencingElementsOfType(PsiElement target, Class<T> referenceType) {
- return Arrays.stream(FindUsages.findAllReferences(target))
- .map(PsiReference::getElement)
- .filter(referenceType::isInstance)
- .map(e -> (T) e)
- .collect(Collectors.toList());
- }
-
- protected void mockBlazeProjectDataManager(BlazeProjectData data) {
- BlazeProjectDataManager mockProjectDataManager = new BlazeProjectDataManager() {
- @Nullable
- @Override
- public BlazeProjectData getBlazeProjectData() {
- return data;
- }
- @Override
- public BlazeSyncPlugin.ModuleEditor editModules() {
- return ModuleEditorProvider.getInstance().getModuleEditor(
- getProject(),
- BlazeImportSettingsManager.getInstance(getProject()).getImportSettings()
- );
- }
- };
- registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
- }
-
- protected <T> void registerApplicationService(Class<T> key, T implementation) {
- registerComponentInstance((MutablePicoContainer) ApplicationManager.getApplication().getPicoContainer(), key, implementation);
- }
-
- protected <T> void registerProjectService(Class<T> key, T implementation) {
- registerComponentInstance((MutablePicoContainer) getProject().getPicoContainer(), key, implementation);
- }
-
- protected <T> void registerComponentInstance(MutablePicoContainer container, Class<T> key, T implementation) {
- Object old = container.getComponentInstance(key);
- container.unregisterComponent(key.getName());
- container.registerComponentInstance(key.getName(), implementation);
- Disposer.register(getTestRootDisposable(), () -> {
- container.unregisterComponent(key.getName());
- if (old != null) {
- container.registerComponentInstance(key.getName(), old);
- }
- });
- }
-
- protected <T> void registerExtension(ExtensionPointName<T> name, T instance) {
- ExtensionPoint<T> ep = Extensions.getRootArea().getExtensionPoint(name);
- ep.registerExtension(instance);
- Disposer.register(getTestRootDisposable(), () -> ep.unregisterExtension(instance));
- }
-
- /**
- * Redirects file system checks via the TempFileSystem used for these tests.
- */
- private static class TempFileAttributeProvider extends FileAttributeProvider {
-
- final TempFileSystem fileSystem = TempFileSystem.getInstance();
-
- @Override
- public boolean exists(File file) {
- VirtualFile vf = getVirtualFile(file);
- return vf != null && vf.exists();
- }
-
- @Override
- public boolean isDirectory(File file) {
- VirtualFile vf = getVirtualFile(file);
- return vf != null && vf.isDirectory();
- }
-
- @Override
- public boolean isFile(File file) {
- VirtualFile vf = getVirtualFile(file);
- return vf != null && vf.exists() && !vf.isDirectory();
- }
-
- private VirtualFile getVirtualFile(File file) {
- return fileSystem.findFileByPath(file.getPath());
- }
- }
-
-}
diff --git a/blaze-base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java b/blaze-base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java
deleted file mode 100644
index 6db82a3..0000000
--- a/blaze-base/tests/utils/integration/com/google/idea/blaze/base/lang/buildfile/BuildFileIntegrationTestCase.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.lang.buildfile;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.BlazeIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiFile;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * BUILD file specific integration test base
- */
-public abstract class BuildFileIntegrationTestCase extends BlazeIntegrationTestCase {
-
- @Override
- protected void doSetup() {
- mockBlazeProjectDataManager(getMockBlazeProjectData());
- }
-
- /**
- * Creates a file with the specified contents and file path in the test project,
- * and asserts that it's parsed as a BuildFile
- */
- protected BuildFile createBuildFile(String filePath, String... contentLines) {
- PsiFile file = createPsiFile(filePath, contentLines);
- assertThat(file).isInstanceOf(BuildFile.class);
- return (BuildFile) file;
- }
-
- protected void replaceStringContents(StringLiteral string, String newStringContents) {
- doRenameOperation(() -> {
- ASTNode node = string.getNode();
- node.replaceChild(node.getFirstChildNode(), PsiUtils.createNewLabel(string.getProject(), newStringContents));
- });
- }
-
- private BlazeProjectData getMockBlazeProjectData() {
- BlazeRoots fakeRoots = new BlazeRoots(
- null,
- ImmutableList.of(workspaceRoot.directory()),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen")
- );
- return new BlazeProjectData(0,
- ImmutableMap.of(),
- fakeRoots,
- new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()),
- new WorkspacePathResolverImpl(workspaceRoot, fakeRoots),
- null,
- null,
- null);
- }
-
-}
diff --git a/blaze-base/tests/utils/integration/com/google/idea/blaze/base/sync/BlazeSyncIntegrationTestCase.java b/blaze-base/tests/utils/integration/com/google/idea/blaze/base/sync/BlazeSyncIntegrationTestCase.java
deleted file mode 100644
index 1ca2255..0000000
--- a/blaze-base/tests/utils/integration/com/google/idea/blaze/base/sync/BlazeSyncIntegrationTestCase.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.sync;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.idea.blaze.base.BlazeIntegrationTestCase;
-import com.google.idea.blaze.base.command.info.BlazeInfo;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.io.WorkspaceScanner;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ErrorCollector;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.aspects.BlazeIdeInterface;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorImpl;
-import com.google.idea.blaze.base.sync.projectstructure.ModuleEditorProvider;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-import com.google.idea.blaze.base.vcs.BlazeVcsHandler;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.testFramework.fixtures.TempDirTestFixture;
-import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Sets up mocks required for integration tests of the blaze sync process.
- */
-public abstract class BlazeSyncIntegrationTestCase extends BlazeIntegrationTestCase {
-
- // root directory for all files outside the project directory.
- protected TempDirTestFixture tempDirectoryHandler;
- protected VirtualFile tempDirectory;
-
- // blaze-info data
- private static final String EXECUTION_ROOT = "/execroot/root";
- private static final String BLAZE_BIN = EXECUTION_ROOT + "/blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin";
- private static final String BLAZE_GENFILES = EXECUTION_ROOT + "/blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/genfiles";
-
- private static final String PROJECT_DATA_DIR = "project-data-dir";
-
- private MockProjectViewManager projectViewManager;
- private MockBlazeVcsHandler vcsHandler;
- private MockBlazeInfo blazeInfoData;
- private MockBlazeIdeInterface blazeIdeInterface;
-
- protected ErrorCollector errorCollector;
- protected BlazeContext context;
-
- @Override
- protected void doSetup() throws IOException {
- // Set up a workspace root outside of the tracked temp file system.
- tempDirectoryHandler = new LightTempDirTestFixtureImpl();
- tempDirectory = tempDirectoryHandler.getFile("");
- workspaceRoot = new WorkspaceRoot(new File(tempDirectory.getPath()));
- setBlazeImportSettings(new BlazeImportSettings(
- workspaceRoot.toString(),
- "test-project",
- workspaceRoot + "/"+ PROJECT_DATA_DIR,
- "location-hash",
- workspaceRoot + "/project-view-file",
- BuildSystem.Blaze
- ));
-
- projectViewManager = new MockProjectViewManager();
- vcsHandler = new MockBlazeVcsHandler();
- blazeInfoData = new MockBlazeInfo();
- blazeIdeInterface = new MockBlazeIdeInterface();
- registerProjectService(ProjectViewManager.class, projectViewManager);
- registerExtension(BlazeVcsHandler.EP_NAME, vcsHandler);
- registerApplicationService(WorkspaceScanner.class, (workspaceRoot, workspacePath) -> true);
- registerApplicationService(BlazeInfo.class, blazeInfoData);
- registerApplicationService(BlazeIdeInterface.class, blazeIdeInterface);
- registerApplicationService(ModuleEditorProvider.class, new ModuleEditorProvider() {
- @Override
- public ModuleEditorImpl getModuleEditor(Project project, BlazeImportSettings importSettings) {
- return new ModuleEditorImpl(project, importSettings) {
- @Override
- public void commit() {
- // don't commit module changes, but make sure they're properly disposed when the test is finished
- for (ModifiableRootModel model : modifiableModels) {
- Disposer.register(myTestRootDisposable, model::dispose);
- }
- }
- };
- }
- });
-
- errorCollector = new ErrorCollector();
- context = new BlazeContext();
- context.addOutputSink(IssueOutput.class, errorCollector);
-
- tempDirectoryHandler.findOrCreateDir(PROJECT_DATA_DIR + "/.blaze/modules");
-
- setBlazeInfoResults(ImmutableMap.of(
- BlazeInfo.blazeBinKey(Blaze.getBuildSystem(getProject())), BLAZE_BIN,
- BlazeInfo.blazeGenfilesKey(Blaze.getBuildSystem(getProject())), BLAZE_GENFILES,
- BlazeInfo.EXECUTION_ROOT_KEY, EXECUTION_ROOT,
- BlazeInfo.PACKAGE_PATH_KEY, workspaceRoot.toString()
- ));
- }
-
- @Override
- protected void doTearDown() throws Exception {
- if (tempDirectoryHandler != null) {
- tempDirectoryHandler.tearDown();
- }
- super.doTearDown();
- }
-
- protected VirtualFile createWorkspaceFile(String relativePath, @Nullable String... contents) {
- try {
- String content = contents != null ? Joiner.on("\n").join(contents) : "";
- return tempDirectoryHandler.createFile(relativePath, content);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected void assertNoErrors() {
- errorCollector.assertNoIssues();
- }
-
- protected ArtifactLocation sourceRoot(String relativePath) {
- return ArtifactLocation.builder()
- .setRootPath(workspaceRoot.toString())
- .setRelativePath(relativePath)
- .setIsSource(true)
- .build();
- }
-
- protected void setProjectView(String... contents) {
- ProjectViewParser projectViewParser = new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot));
- projectViewParser.parseProjectView(Joiner.on("\n").join(contents));
-
- ProjectViewSet result = projectViewParser.getResult();
- assertThat(result.getProjectViewFiles()).isNotEmpty();
- assertNoErrors();
- setProjectViewSet(result);
- }
-
- protected void setProjectViewSet(ProjectViewSet projectViewSet) {
- projectViewManager.projectViewSet = projectViewSet;
- }
-
- protected void setRuleMap(Map<Label, RuleIdeInfo> rules) {
- blazeIdeInterface.ruleMap.clear();
- blazeIdeInterface.ruleMap.putAll(rules);
- }
-
- protected void setBlazeInfoResults(Map<String, String> blazeInfoResults) {
- blazeInfoData.setResults(blazeInfoResults);
- }
-
- protected void runBlazeSync(BlazeSyncParams syncParams) {
- Project project = getProject();
- final BlazeSyncTask syncTask = new BlazeSyncTask(
- project,
- BlazeImportSettingsManager.getInstance(project).getImportSettings(),
- syncParams);
- syncTask.syncProject(context);
- }
-
- private static class MockProjectViewManager extends ProjectViewManager {
-
- private ProjectViewSet projectViewSet;
-
- @Nullable
- @Override
- public ProjectViewSet getProjectViewSet() {
- return projectViewSet;
- }
-
- @Nullable
- @Override
- public ProjectViewSet reloadProjectView(BlazeContext context, WorkspacePathResolver workspacePathResolver) {
- return getProjectViewSet();
- }
- }
-
- private class MockBlazeVcsHandler implements BlazeVcsHandler {
-
- private List<WorkspacePath> addedFiles = Lists.newArrayList();
-
- @Nullable
- @Override
- public String getClientName(WorkspaceRoot workspaceRoot) {
- return null;
- }
-
- @Override
- public boolean handlesProject(Project project, WorkspaceRoot workspaceRoot) {
- return project == getProject();
- }
-
- @Override
- public ListenableFuture<WorkingSet> getWorkingSet(Project project, WorkspaceRoot workspaceRoot, ListeningExecutorService executor) {
- WorkingSet workingSet = new WorkingSet(ImmutableList.copyOf(addedFiles), ImmutableList.of(), ImmutableList.of());
- return Futures.immediateFuture(workingSet);
- }
-
- @Nullable
- @Override
- public BlazeVcsSyncHandler createSyncHandler(Project project,
- WorkspaceRoot workspaceRoot) {
- return null;
- }
- }
-
- protected static class MockBlazeInfo extends BlazeInfo {
- private final Map<String, String> results = Maps.newHashMap();
-
- @Override
- public ListenableFuture<String> runBlazeInfo(@Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags,
- String key) {
- return Futures.immediateFuture(results.get(key));
- }
-
- @Override
- public ListenableFuture<byte[]> runBlazeInfoGetBytes(@Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags,
- String key) {
- return Futures.immediateFuture(null);
- }
-
- @Override
- public ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(@Nullable BlazeContext context,
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- List<String> blazeFlags) {
- return Futures.immediateFuture(ImmutableMap.copyOf(results));
- }
-
- public void setResults(Map<String, String> results) {
- this.results.clear();
- this.results.putAll(results);
- }
- }
-
- protected static class MockBlazeIdeInterface extends BlazeIdeInterface {
- private final Map<Label, RuleIdeInfo> ruleMap = Maps.newHashMap();
-
- @Nullable
- @Override
- public IdeResult updateBlazeIdeState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder artifactLocationDecoder,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState,
- boolean requiresAndroidSdk) {
- return new IdeResult(ImmutableMap.copyOf(ruleMap), null);
- }
-
- @Override
- public void resolveIdeArtifacts(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- List<TargetExpression> targets) {
- }
- }
-
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java
deleted file mode 100644
index b1a90aa..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base;
-
-import com.intellij.mock.MockProject;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.extensions.*;
-import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
-import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Disposer;
-import org.jetbrains.annotations.NotNull;
-import org.junit.After;
-import org.junit.Before;
-import org.picocontainer.MutablePicoContainer;
-
-/**
- * Test base class.
- * <p/>
- * <p>Provides a mock application and a mock project.
- */
-public class BlazeTestCase {
-
- protected Project project;
- private ExtensionsAreaImpl extensionsArea;
- private Disposable testDisposable;
-
- private static class RootDisposable implements Disposable {
- @Override
- public void dispose() {
- }
- }
-
- public static class Container {
- private final MutablePicoContainer container;
-
- Container(@NotNull MutablePicoContainer container) {
- this.container = container;
- }
-
- public <T> Container register(Class<T> klass, T instance) {
- this.container.registerComponentInstance(klass.getName(), instance);
- return this;
- }
- }
-
- @Before
- public final void setup() {
- testDisposable = new RootDisposable();
- TestUtils.createMockApplication(testDisposable);
- MutablePicoContainer applicationContainer = (MutablePicoContainer)
- ApplicationManager.getApplication().getPicoContainer();
- MockProject mockProject = TestUtils.mockProject(applicationContainer, testDisposable);
-
- Extensions.cleanRootArea(testDisposable);
- extensionsArea = (ExtensionsAreaImpl) Extensions.getRootArea();
-
- this.project = mockProject;
-
- initTest(
- new Container(applicationContainer),
- new Container(mockProject.getPicoContainer())
- );
- }
-
- @After
- public final void tearDown() {
- Disposer.dispose(testDisposable);
- }
-
- public final Project getProject() {
- return project;
- }
-
- protected void initTest(
- @NotNull Container applicationServices,
- @NotNull Container projectServices) {
- }
-
- protected <T> ExtensionPointImpl<T> registerExtensionPoint(@NotNull ExtensionPointName<T> name, @NotNull Class<T> type) {
- ExtensionPointImpl<T> extensionPoint = new ExtensionPointImpl<T>(
- name.getName(),
- type.getName(),
- ExtensionPoint.Kind.INTERFACE,
- extensionsArea,
- null,
- new Extensions.SimpleLogProvider(),
- new DefaultPluginDescriptor(PluginId.getId(type.getName()), type.getClassLoader())
- );
- extensionsArea.registerExtensionPoint(extensionPoint);
- return extensionPoint;
- }
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java
deleted file mode 100644
index c04062c..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base;
-
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.intellij.mock.MockApplicationEx;
-import com.intellij.mock.MockProject;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.Application;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.fileTypes.FileTypeManager;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.vfs.encoding.EncodingManager;
-import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
-import com.intellij.util.pico.DefaultPicoContainer;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.picocontainer.PicoContainer;
-
-import java.io.*;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
-
-import static org.junit.Assert.fail;
-
-/**
- * Test utilities.
- */
-public class TestUtils {
-
- static class BlazeMockApplication extends MockApplicationEx {
- private final ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
-
- public BlazeMockApplication(@NotNull Disposable parentDisposable) {
- super(parentDisposable);
- }
-
- @NotNull
- @Override
- public Future<?> executeOnPooledThread(@NotNull Runnable action) {
- return executor.submit(action);
- }
-
- @NotNull
- @Override
- public <T> Future<T> executeOnPooledThread(@NotNull Callable<T> action) {
- return executor.submit(action);
- }
- }
-
- public static void createMockApplication(Disposable parentDisposable) {
- final BlazeMockApplication instance = new BlazeMockApplication(parentDisposable);
-
- // If there was no previous application, ApplicationManager leaves the MockApplication in place, which can break future tests.
- Application oldApplication = ApplicationManager.getApplication();
- if (oldApplication == null) {
- Disposer.register(parentDisposable, () -> {
- new ApplicationManager() {
- { ourApplication = null; }
- };
- });
- }
-
- ApplicationManager.setApplication(instance,
- FileTypeManager::getInstance,
- parentDisposable);
- instance.registerService(EncodingManager.class, EncodingManagerImpl.class);
- }
-
- @NotNull
- public static MockProject mockProject(@Nullable PicoContainer container,
- Disposable parentDisposable) {
- Extensions.registerAreaClass("IDEA_PROJECT", null);
- container = container != null
- ? container
- : new DefaultPicoContainer();
- return new MockProject(container, parentDisposable);
- }
-
- public static void assertIsSerializable(@NotNull Serializable object) {
- ObjectOutputStream out = null;
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- try {
- out = new ObjectOutputStream(byteArrayOutputStream);
- out.writeObject(object);
- }
- catch (NotSerializableException e) {
- fail("An object is not serializable: " + e.getMessage());
- }
- catch (IOException e) {
- fail("Could not serialize object: " + e.getMessage());
- }
- finally {
- if (out != null) {
- try {
- out.close();
- }
- catch (IOException e) {
- // ignore
- }
- }
- try {
- byteArrayOutputStream.close();
- }
- catch (IOException e) {
- // ignore
- }
- }
- }
-
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/async/executor/MockBlazeExecutor.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/async/executor/MockBlazeExecutor.java
deleted file mode 100644
index b7c8691..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/async/executor/MockBlazeExecutor.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.async.executor;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import java.util.concurrent.Callable;
-
-/**
- * Used in tests.
- */
-public class MockBlazeExecutor extends BlazeExecutor {
-
- private final ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
-
- @Override
- public <T> ListenableFuture<T> submit(final Callable<T> callable) {
- return executor.submit(callable);
- }
-
- @Override
- public ListeningExecutorService getExecutor() {
- return executor;
- }
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/experiments/MockExperimentService.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/experiments/MockExperimentService.java
deleted file mode 100644
index ece1b23..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/experiments/MockExperimentService.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.experiments;
-
-import com.google.common.collect.Maps;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Map;
-
-/**
- * Used for tests.
- */
-public class MockExperimentService implements ExperimentService {
-
- private Map<String, Object> experiments = Maps.newHashMap();
-
- @Override
- public void reloadExperiments() {
- }
-
- @Override
- public void startExperimentScope() {
- }
-
- @Override
- public void endExperimentScope() {
- }
-
- public void setExperiment(@NotNull BoolExperiment experiment, @NotNull boolean value) {
- experiments.put(experiment.getKey(), value);
- }
-
- @Override
- public boolean getExperiment(@NotNull String key, boolean defaultValue) {
- if (experiments.containsKey(key)) {
- return (Boolean)experiments.get(key);
- }
- return defaultValue;
- }
-
- @Override
- @Nullable
- public String getExperimentString(@NotNull String key, @Nullable String defaultValue) {
- if (experiments.containsKey(key)) {
- return (String)experiments.get(key);
- }
- return defaultValue;
- }
-
- @Override
- public int getExperimentInt(@NotNull String key, int defaultValue) {
- if (experiments.containsKey(key)) {
- return (Integer)experiments.get(key);
- }
- return defaultValue;
- }
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/ideinfo/RuleMapBuilder.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/ideinfo/RuleMapBuilder.java
deleted file mode 100644
index fd20f3f..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/ideinfo/RuleMapBuilder.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.ideinfo;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * Builds a rule map.
- */
-public class RuleMapBuilder {
- private List<RuleIdeInfo> rules = Lists.newArrayList();
-
- public static RuleMapBuilder builder() {
- return new RuleMapBuilder();
- }
-
- @NotNull
- public RuleMapBuilder addRule(@NotNull RuleIdeInfo ruleOrLibrary) {
- rules.add(ruleOrLibrary);
- return this;
- }
- @NotNull
- public RuleMapBuilder addRule(@NotNull RuleIdeInfo.Builder ruleOrLibrary) {
- return addRule(ruleOrLibrary.build());
- }
-
- @NotNull
- public ImmutableMap<Label, RuleIdeInfo> build() {
- ImmutableMap.Builder<Label, RuleIdeInfo> ruleMap = ImmutableMap.builder();
- for (RuleIdeInfo rule : rules) {
- ruleMap.put(rule.label, rule);
- }
- return ruleMap.build();
- }
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/prefetch/MockPrefetchService.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/prefetch/MockPrefetchService.java
deleted file mode 100644
index 85c08b7..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/prefetch/MockPrefetchService.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.prefetch;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.intellij.openapi.project.Project;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Mocks the prefetch service.
- */
-public class MockPrefetchService implements PrefetchService {
- @Override
- public ListenableFuture<?> prefetchFiles(List<File> files, boolean synchronous) {
- return Futures.immediateFuture(null);
- }
-
- @Override
- public void prefetchProjectFiles(Project project) {
- }
-}
diff --git a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/scope/ErrorCollector.java b/blaze-base/tests/utils/unit/com/google/idea/blaze/base/scope/ErrorCollector.java
deleted file mode 100644
index 4b5cb71..0000000
--- a/blaze-base/tests/utils/unit/com/google/idea/blaze/base/scope/ErrorCollector.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.base.scope;
-
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Test class that collects issues.
- */
-public class ErrorCollector implements OutputSink<IssueOutput> {
- List<IssueOutput> issues = Lists.newArrayList();
-
- @Override
- public Propagation onOutput(@NotNull IssueOutput output) {
- issues.add(output);
- return Propagation.Continue;
- }
-
- public void assertNoIssues() {
- assertThat(issues).isEmpty();
- }
-
- public void assertIssues(@NotNull String... requiredMessages) {
- List<String> messages = Lists.newArrayList();
- for (IssueOutput issue : issues) {
- messages.add(issue.getMessage());
- }
- assertThat(messages).containsExactly((Object[]) requiredMessages);
- }
-
- public void assertIssueContaining(@NotNull String s) {
- assertThat(issues.stream().anyMatch((issue) -> issue.getMessage().contains(s)))
- .named("Issues must contain: " + s)
- .isTrue();
- }
-}
-
diff --git a/blaze-cpp/BUILD b/blaze-cpp/BUILD
deleted file mode 100644
index 9e7261b..0000000
--- a/blaze-cpp/BUILD
+++ /dev/null
@@ -1,28 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-java_library(
- name = "blaze-cpp",
- srcs = glob(["src/**/*.java"]),
- deps = [
- "//blaze-base",
- "//intellij-platform-sdk:plugin_api",
- "//third_party:jsr305",
- ],
-)
-
-filegroup(
- name = "plugin_xml",
- srcs = ["src/META-INF/blaze-cpp.xml"],
-)
-
-java_library(
- name = "test_lib",
- srcs = glob(["tests/**/*.java"]),
- deps = [
- ":blaze-cpp",
- "//blaze-base:unit_test_utils",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
diff --git a/blaze-cpp/src/META-INF/blaze-cpp.xml b/blaze-cpp/src/META-INF/blaze-cpp.xml
deleted file mode 100644
index 668e64a..0000000
--- a/blaze-cpp/src/META-INF/blaze-cpp.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- ~ Copyright 2016 The Bazel Authors. All rights reserved.
- ~
- ~ 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.
- -->
-<idea-plugin>
- <depends>com.intellij.modules.cidr.lang</depends>
- <depends>com.intellij.modules.cidr.debugger</depends>
-
- <extensions defaultExtensionNs="com.google.idea.blaze">
- <SyncPlugin implementation="com.google.idea.blaze.cpp.BlazeCSyncPlugin"/>
- </extensions>
-
- <extensions defaultExtensionNs="cidr.lang">
- <languageKindHelper implementation="com.google.idea.blaze.cpp.BlazeLanguageKindCalculatorHelper"/>
- </extensions>
- <extensions defaultExtensionNs="com.intellij">
- <projectService serviceImplementation="com.google.idea.blaze.cpp.BlazeCWorkspace"/>
- </extensions>
-</idea-plugin>
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
deleted file mode 100644
index 75a7297..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.jetbrains.cidr.lang.workspace.OCWorkspace;
-import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
-
-import javax.annotation.Nullable;
-import java.util.Set;
-
-public final class BlazeCSyncPlugin extends BlazeSyncPlugin.Adapter {
- @Override
- public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- if (workspaceType == WorkspaceType.C) {
- return ImmutableSet.of(LanguageClass.C);
- }
- return ImmutableSet.of();
- }
-
- @Override
- public void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel) {
- if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C)) {
- return;
- }
-
- Scope.push(context, childContext -> {
- childContext.push(new TimingScope("Setup C Workspace"));
-
- OCWorkspace workspace = OCWorkspaceManager.getWorkspace(project);
- if (workspace instanceof BlazeCWorkspace) {
- BlazeCWorkspace blazeCWorkspace = (BlazeCWorkspace)workspace;
- blazeCWorkspace.update(childContext, blazeProjectData);
- }
- });
- }
-}
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
deleted file mode 100644
index 2c6f8ef..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.metrics.LoggingService;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.cidr.lang.symbols.OCSymbol;
-import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
-import com.jetbrains.cidr.lang.workspace.OCWorkspace;
-import com.jetbrains.cidr.lang.workspace.OCWorkspaceModificationTrackers;
-
-import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Main entry point for C/CPP configuration data.
- */
-public final class BlazeCWorkspace implements OCWorkspace {
- private static final Logger LOG = Logger.getInstance(BlazeCWorkspace.class);
-
- @Nullable private final Project project;
- @Nullable private final OCWorkspaceModificationTrackers modTrackers;
-
- @Nullable private BlazeConfigurationResolver configurationResolver;
-
- private BlazeCWorkspace(Project project) {
- if (Blaze.isBlazeProject(project)) {
- this.project = project;
- this.modTrackers = new OCWorkspaceModificationTrackers(project);
- this.configurationResolver = new BlazeConfigurationResolver(project);
- } else {
- this.project = null;
- this.modTrackers = null;
- }
- }
-
- public static BlazeCWorkspace getInstance(Project project) {
- return ServiceManager.getService(project, BlazeCWorkspace.class);
- }
-
- public void update(BlazeContext context, BlazeProjectData blazeProjectData) {
- LOG.assertTrue(project != null);
- LOG.assertTrue(modTrackers != null);
- LOG.assertTrue(configurationResolver != null);
-
- long start = System.currentTimeMillis();
- // Non-incremental update to our c configurations.
- configurationResolver.update(context, blazeProjectData);
- long end = System.currentTimeMillis();
-
- LOG.info(String.format("Blaze OCWorkspace update took: %d ms", (end - start)));
-
- ApplicationManager.getApplication().runReadAction(() -> {
- if (project.isDisposed()) {
- return;
- }
-
- // TODO(salguarnieri) Avoid bumping all of these trackers; figure out what has changed.
- modTrackers.getProjectFilesListTracker().incModificationCount();
- modTrackers.getSourceFilesListTracker().incModificationCount();
- modTrackers.getBuildConfigurationChangesTracker().incModificationCount();
- modTrackers.getBuildSettingsChangesTracker().incModificationCount();
- });
- }
-
- @Override
- public Collection<VirtualFile> getLibraryFilesToBuildSymbols() {
- // This method should return all the header files themselves, not the head file directories.
- // (And not header files in the project; just the ones in the SDK and in any dependencies)
- return ImmutableList.of();
- }
-
- @Override
- public boolean areFromSameProject(@Nullable VirtualFile a, @Nullable VirtualFile b) {
- return false;
- }
-
- @Override
- public boolean areFromSamePackage(@Nullable VirtualFile a, @Nullable VirtualFile b) {
- return false;
- }
-
- @Override
- public boolean isInSDK(@Nullable VirtualFile file) {
- return false;
- }
-
- @Override
- public boolean isFromWrongSDK(OCSymbol symbol, @Nullable VirtualFile contextFile) {
- return false;
- }
-
- @Nullable
- @Override
- public OCResolveConfiguration getSelectedResolveConfiguration() {
- return null;
- }
-
- @Override
- public OCWorkspaceModificationTrackers getModificationTrackers() {
- LOG.assertTrue(modTrackers != null);
- return modTrackers;
- }
-
- @Override
- public List<? extends OCResolveConfiguration> getConfigurations() {
- return configurationResolver == null ? ImmutableList.of() : configurationResolver.getAllConfigurations();
- }
-
- @Override
- public List<? extends OCResolveConfiguration> getConfigurationsForFile(@Nullable VirtualFile sourceFile) {
- LoggingService.reportEvent(project, Action.C_RESOLVE_FILE);
-
- if (sourceFile == null || !sourceFile.isValid() || configurationResolver == null) {
- return ImmutableList.of();
- }
- OCResolveConfiguration config = configurationResolver.getConfigurationForFile(sourceFile);
- return config == null ? ImmutableList.of() : ImmutableList.of(config);
- }
-}
-
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
deleted file mode 100644
index 168f691..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiFile;
-import com.jetbrains.cidr.lang.preprocessor.OCInclusionContext;
-import com.jetbrains.cidr.lang.preprocessor.OCInclusionContextUtil;
-import com.jetbrains.cidr.lang.workspace.compiler.CidrCompilerResult;
-import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerMacros;
-import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
-import com.jetbrains.cidr.toolchains.CompilerInfoCache;
-
-import java.util.Map;
-
-final class BlazeCompilerMacros extends OCCompilerMacros {
- private final CompilerInfoCache compilerInfoCache;
- private final ImmutableList<String> globalDefines;
- private final ImmutableMap<String, String> globalFeatures;
- private final OCCompilerSettings compilerSettings;
- private final Project project;
-
- public BlazeCompilerMacros(
- Project project,
- CompilerInfoCache compilerInfoCache,
- OCCompilerSettings compilerSettings,
- ImmutableList<String> defines,
- ImmutableMap<String, String> features
- ) {
- this.project = project;
- this.compilerInfoCache = compilerInfoCache;
- this.compilerSettings = compilerSettings;
- this.globalDefines = defines;
- this.globalFeatures = features;
- }
-
- @Override
- protected void fillFileMacros(OCInclusionContext context, PsiFile sourceFile) {
- // Get the default compiler info for this file.
- VirtualFile vf = OCInclusionContextUtil.getVirtualFile(sourceFile);
- CidrCompilerResult<CompilerInfoCache.Entry> compilerInfoProvider = compilerInfoCache.getCompilerInfoCache(
- project,
- compilerSettings,
- context.getLanguageKind(),
- vf
- );
- CompilerInfoCache.Entry compilerInfo = compilerInfoProvider.getResult();
-
- // Combine the info we got from Blaze with the info we get from IntelliJ's methods.
- UniqueListBuilder<String> allDefinesBuilder = new UniqueListBuilder<>();
- // IntelliJ expects a string of "#define [VAR_NAME]\n#define [VAR_NAME2]\n..."
- for (String globalDefine : globalDefines) {
- allDefinesBuilder.add("#define " + globalDefine);
- }
- if (compilerInfo != null) {
- String[] split = compilerInfo.defines.split("\n");
- for (String s : split) {
- allDefinesBuilder.add(s);
- }
- }
- final String allDefines = Joiner.on("\n").join(allDefinesBuilder.build());
-
- Map<String, String> allFeatures = Maps.newHashMap();
- allFeatures.putAll(globalFeatures);
- if (compilerInfo != null) {
- allFeatures.putAll(compilerInfo.features);
- }
-
- fillSubstitutions(context, allDefines);
- enableClangFeatures(context, allFeatures);
- enableClangExtensions(context, allFeatures);
- }
-}
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
deleted file mode 100644
index e3ba4df..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.cidr.lang.OCLanguageKind;
-import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
-import com.jetbrains.cidr.lang.toolchains.CidrSwitchBuilder;
-import com.jetbrains.cidr.lang.toolchains.CidrToolEnvironment;
-import com.jetbrains.cidr.lang.toolchains.DefaultCidrToolEnvironment;
-import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerKind;
-import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.List;
-
-final class BlazeCompilerSettings extends OCCompilerSettings {
- private final CidrToolEnvironment toolEnvironment = new DefaultCidrToolEnvironment();
-
- private final Project project;
- @Nullable private final File cCompiler;
- @Nullable private final File cppCompiler;
- private final ImmutableList<String> cFlags;
- private final ImmutableList<String> cppFlags;
-
- BlazeCompilerSettings(
- Project project,
- @Nullable File cCompiler,
- @Nullable File cppCompiler,
- ImmutableList<String> cFlags,
- ImmutableList<String> cppFlags
- ) {
- this.project = project;
- this.cCompiler = cCompiler;
- this.cppCompiler = cppCompiler;
- this.cFlags = cFlags;
- this.cppFlags = cppFlags;
- }
-
- @Override
- public OCCompilerKind getCompiler(OCLanguageKind languageKind) {
- return null;
- }
-
- @Override
- public File getCompilerExecutable(@NotNull OCLanguageKind lang) {
- if (lang == OCLanguageKind.C) {
- return cCompiler;
- } else if (lang == OCLanguageKind.CPP) {
- return cppCompiler;
- }
- // We don't support objective c/c++.
- return null;
- }
-
- @Override
- public File getCompilerWorkingDir() {
- return WorkspaceRoot.fromProject(project).directory();
- }
-
- @Override
- public CidrToolEnvironment getEnvironment() {
- return toolEnvironment;
- }
-
- @Override
- public CidrCompilerSwitches getCompilerSwitches(OCLanguageKind lang, @Nullable VirtualFile sourceFile) {
- final List<String> allCompilerFlags;
- if (lang == OCLanguageKind.C) {
- allCompilerFlags = cFlags;
- } else if (lang == OCLanguageKind.CPP) {
- allCompilerFlags = cppFlags;
- } else {
- allCompilerFlags = ImmutableList.of();
- }
-
- CidrSwitchBuilder builder = new CidrSwitchBuilder();
- // Because there can be both escaped and unescaped spaces in the flag, first unescape the spaces and then escape all of them.
- allCompilerFlags.stream()
- .map(flag -> flag.replace("\\ ", " "))
- .map(flag -> flag.replace(" ", "\\ "))
- .forEach(builder::addSingle);
-
- return builder.build();
- }
-}
-
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
deleted file mode 100644
index a6deb7e..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.*;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.ScopedFunction;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VfsUtilCore;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-
-final class BlazeConfigurationResolver {
- private static final class MapEntry {
- public final Label label;
- public final BlazeResolveConfiguration configuration;
-
- public MapEntry(Label label, BlazeResolveConfiguration configuration) {
- this.label = label;
- this.configuration = configuration;
- }
- }
-
- private static final Logger LOG = Logger.getInstance(BlazeConfigurationResolver.class);
- private final Project project;
-
- private ImmutableMap<Label, BlazeResolveConfiguration> resolveConfigurations = ImmutableMap.of();
-
- public BlazeConfigurationResolver(Project project) {
- this.project = project;
- }
-
- public void update(BlazeContext context, BlazeProjectData blazeProjectData) {
- WorkspacePathResolver workspacePathResolver = blazeProjectData.workspacePathResolver;
- ImmutableMap<Label, CToolchainIdeInfo> toolchainLookupMap = BlazeResolveConfiguration.buildToolchainLookupMap(
- context,
- blazeProjectData.ruleMap,
- blazeProjectData.reverseDependencies
- );
- resolveConfigurations = buildBlazeConfigurationMap(context, blazeProjectData, toolchainLookupMap, workspacePathResolver);
- }
-
- private ImmutableMap<Label, BlazeResolveConfiguration> buildBlazeConfigurationMap(
- BlazeContext parentContext,
- BlazeProjectData blazeProjectData,
- ImmutableMap<Label, CToolchainIdeInfo> toolchainLookupMap,
- WorkspacePathResolver workspacePathResolver
- ) {
- // Type specification needed to avoid incorrect type inference during command line build.
- return Scope.push(parentContext, (ScopedFunction<ImmutableMap<Label, BlazeResolveConfiguration>>)context -> {
- context.push(new TimingScope("Build C configuration map"));
-
- ConcurrentMap<CToolchainIdeInfo, File> compilerWrapperCache = Maps.newConcurrentMap();
- List<ListenableFuture<MapEntry>> mapEntryFutures = Lists.newArrayList();
-
- for (RuleIdeInfo rule : blazeProjectData.ruleMap.values()) {
- if (rule.kind.getLanguageClass() == LanguageClass.C) {
- ListenableFuture<MapEntry> future =
- submit(
- () -> createResolveConfiguration(
- rule,
- toolchainLookupMap,
- compilerWrapperCache,
- workspacePathResolver,
- blazeProjectData)
- );
- mapEntryFutures.add(future);
- }
- }
-
- ImmutableMap.Builder<Label, BlazeResolveConfiguration> newResolveConfigurations = ImmutableMap.builder();
- List<MapEntry> mapEntries;
- try {
- mapEntries = Futures.allAsList(mapEntryFutures).get();
- }
- catch (InterruptedException | ExecutionException e) {
- Thread.currentThread().interrupt();
- LOG.warn("Could not build C resolve configurations", e);
- context.setCancelled();
- return ImmutableMap.of();
- }
-
- for (MapEntry mapEntry : mapEntries) {
- // Skip over labels that don't have C configuration data.
- if (mapEntry != null) {
- newResolveConfigurations.put(mapEntry.label, mapEntry.configuration);
- }
- }
- return newResolveConfigurations.build();
- });
- }
-
- private static ListenableFuture<MapEntry> submit(Callable<MapEntry> callable) {
- return BlazeExecutor.getInstance().submit(callable);
- }
-
- @Nullable
- private MapEntry createResolveConfiguration(
- RuleIdeInfo rule,
- ImmutableMap<Label, CToolchainIdeInfo> toolchainLookupMap,
- ConcurrentMap<CToolchainIdeInfo, File> compilerWrapperCache,
- WorkspacePathResolver workspacePathResolver,
- BlazeProjectData blazeProjectData
- ) {
- Label label = rule.label;
- LOG.info("Resolving " + label.toString());
- CToolchainIdeInfo toolchainIdeInfo = toolchainLookupMap.get(label);
- if (toolchainIdeInfo != null) {
- File compilerWrapper = findOrCreateCompilerWrapperScript(
- compilerWrapperCache,
- toolchainIdeInfo,
- workspacePathResolver,
- rule.label
- );
- if (compilerWrapper != null) {
- BlazeResolveConfiguration config = BlazeResolveConfiguration.createConfigurationForTarget(
- project,
- workspacePathResolver,
- blazeProjectData.ruleMap.get(label),
- toolchainIdeInfo,
- compilerWrapper
- );
- if (config != null) {
- return new MapEntry(label, config);
- }
- }
- }
- return null;
- }
-
- @Nullable
- private static File findOrCreateCompilerWrapperScript(
- Map<CToolchainIdeInfo, File> compilerWrapperCache,
- CToolchainIdeInfo toolchainIdeInfo,
- WorkspacePathResolver workspacePathResolver,
- Label label
- ) {
- File compilerWrapper = compilerWrapperCache.get(toolchainIdeInfo);
- if (compilerWrapper == null) {
- File cppExecutable = workspacePathResolver.resolveToFile(toolchainIdeInfo.cppExecutable.getAbsoluteOrRelativeFile().getPath());
- if (cppExecutable == null) {
- String errorMessage = String.format(
- "Unable to find compiler executable: %s for rule %s",
- toolchainIdeInfo.cppExecutable.toString(),
- label.toString());
- LOG.warn(errorMessage);
- compilerWrapper = null;
- } else {
- compilerWrapper = createCompilerExecutableWrapper(cppExecutable);
- if (compilerWrapper != null) {
- compilerWrapperCache.put(toolchainIdeInfo, compilerWrapper);
- }
- }
- }
- return compilerWrapper;
- }
-
- /**
- * Create a wrapper script that transforms the CLion compiler invocation into a safe invocation of the compiler script that blaze uses.
- *
- * CLion passes arguments to the compiler in an arguments file. The c toolchain compiler wrapper script doesn't handle arguments files, so
- * we need to move the compiler arguments from the file to the command line.
- *
- * @param blazeCompilerExecutableFile blaze compiler wrapper
- * @return The wrapper script that CLion can call.
- */
- @Nullable
- private static File createCompilerExecutableWrapper(File blazeCompilerExecutableFile) {
- try {
- File blazeCompilerWrapper = FileUtil.createTempFile("blaze_compiler", ".sh", true /* deleteOnExit */);
- if (!blazeCompilerWrapper.setExecutable(true)) {
- return null;
- }
- ImmutableList<String> COMPILER_WRAPPER_SCRIPT_LINES = ImmutableList.of(
- "#!/bin/bash",
- "",
- "# The c toolchain compiler wrapper script doesn't handle arguments files, so we",
- "# need to move the compiler arguments from the file to the command line.",
- "",
- "if [ $# -ne 2 ]; then",
- " echo \"Usage: $0 @arg-file compile-file\"",
- " exit 2;",
- "fi",
- "",
- "if [[ $1 != @* ]]; then",
- " echo \"Usage: $0 @arg-file compile-file\"",
- " exit 3;",
- "fi",
- "",
- " # Remove the @ before the arguments file path",
- "ARG_FILE=${1#@}",
- "# The actual compiler wrapper script we get from blaze",
- "EXE=" + blazeCompilerExecutableFile.getPath(),
- "# Read in the arguments file so we can pass the arguments on the command line.",
- "ARGS=`cat $ARG_FILE`",
- "$EXE $ARGS $2"
- );
-
- try (PrintWriter pw = new PrintWriter(blazeCompilerWrapper)) {
- COMPILER_WRAPPER_SCRIPT_LINES.forEach(pw::println);
- }
- return blazeCompilerWrapper;
- }
- catch (IOException e) {
- return null;
- }
- }
-
- @Nullable
- public OCResolveConfiguration getConfigurationForFile(VirtualFile sourceFile) {
- SourceToRuleMap sourceToRuleMap = SourceToRuleMap.getInstance(project);
- List<Label> targetsForSourceFile =
- Lists.newArrayList(sourceToRuleMap.getTargetsForSourceFile(VfsUtilCore.virtualToIoFile(sourceFile)));
- if (targetsForSourceFile.isEmpty()) {
- return null;
- }
-
- // If a source file is in two different targets, we can't possibly show how it will be interpreted in both contexts at the same time
- // in the IDE, so just pick the first target after we sort.
- targetsForSourceFile.sort((o1, o2) -> o1.toString().compareTo(o2.toString()));
- Label target = Iterables.getFirst(targetsForSourceFile, null);
- assert(target != null);
-
- return resolveConfigurations.get(target);
- }
-
- public List<? extends OCResolveConfiguration> getAllConfigurations() {
- return ImmutableList.copyOf(resolveConfigurations.values());
- }
-}
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeLanguageKindCalculatorHelper.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeLanguageKindCalculatorHelper.java
deleted file mode 100644
index a3f4b91..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeLanguageKindCalculatorHelper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.io.FileUtilRt;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.cidr.lang.OCLanguageKind;
-import com.jetbrains.cidr.lang.workspace.OCLanguageKindCalculatorHelper;
-
-import javax.annotation.Nullable;
-
-public final class BlazeLanguageKindCalculatorHelper implements OCLanguageKindCalculatorHelper {
- @Nullable
- @Override
- public OCLanguageKind getSpecifiedLanguage(Project project, VirtualFile file) {
- return null;
- }
-
- @Nullable
- @Override
- public OCLanguageKind getLanguageByExtension(Project project, String name) {
- if (Blaze.isBlazeProject(project)) {
- String extension = FileUtilRt.getExtension(name);
- if (extension.equalsIgnoreCase("c")) {
- return OCLanguageKind.C;
- }
- if (extension.equalsIgnoreCase("cc")) {
- return OCLanguageKind.CPP;
- }
- }
- return null;
- }
-}
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfiguration.java b/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfiguration.java
deleted file mode 100644
index 06c3f0f..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfiguration.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.*;
-import com.google.idea.blaze.base.ideinfo.CRuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.UserDataHolderBase;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.jetbrains.cidr.lang.OCFileTypeHelpers;
-import com.jetbrains.cidr.lang.OCLanguageKind;
-import com.jetbrains.cidr.lang.preprocessor.OCImportGraph;
-import com.jetbrains.cidr.lang.workspace.OCLanguageKindCalculator;
-import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
-import com.jetbrains.cidr.lang.workspace.OCResolveRootAndConfiguration;
-import com.jetbrains.cidr.lang.workspace.OCWorkspaceUtil;
-import com.jetbrains.cidr.lang.workspace.compiler.CidrCompilerResult;
-import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerMacros;
-import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
-import com.jetbrains.cidr.lang.workspace.headerRoots.HeaderRoots;
-import com.jetbrains.cidr.lang.workspace.headerRoots.HeadersSearchRoot;
-import com.jetbrains.cidr.lang.workspace.headerRoots.IncludedHeadersRoot;
-import com.jetbrains.cidr.toolchains.CompilerInfoCache;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-
-public final class BlazeResolveConfiguration extends UserDataHolderBase implements OCResolveConfiguration {
- public static final Logger LOG = Logger.getInstance(BlazeResolveConfiguration.class);
-
- private final WorkspacePathResolver workspacePathResolver;
-
- private final Project project;
- private final Label label;
-
- private final ImmutableList<HeadersSearchRoot> cLibraryIncludeRoots;
- private final ImmutableList<HeadersSearchRoot> cppLibraryIncludeRoots;
- private final HeaderRoots projectIncludeRoots;
-
- private final CompilerInfoCache compilerInfoCache;
- private final BlazeCompilerMacros compilerMacros;
- private final BlazeCompilerSettings compilerSettings;
-
- @Nullable
- public static BlazeResolveConfiguration createConfigurationForTarget(
- Project project,
- WorkspacePathResolver workspacePathResolver,
- RuleIdeInfo ruleIdeInfo,
- CToolchainIdeInfo toolchainIdeInfo,
- File compilerWrapper
- ) {
- CRuleIdeInfo cRuleIdeInfo = ruleIdeInfo.cRuleIdeInfo;
- if (cRuleIdeInfo == null) {
- return null;
- }
-
- UniqueListBuilder<ExecutionRootPath> systemIncludesBuilder = new UniqueListBuilder<>();
- systemIncludesBuilder.addAll(cRuleIdeInfo.transitiveSystemIncludeDirectories);
- systemIncludesBuilder.addAll(toolchainIdeInfo.builtInIncludeDirectories);
- systemIncludesBuilder.addAll(toolchainIdeInfo.unfilteredToolchainSystemIncludes);
-
- UniqueListBuilder<ExecutionRootPath> userIncludesBuilder = new UniqueListBuilder<>();
- userIncludesBuilder.addAll(cRuleIdeInfo.transitiveIncludeDirectories);
-
- UniqueListBuilder<ExecutionRootPath> userQuoteIncludesBuilder = new UniqueListBuilder<>();
- userQuoteIncludesBuilder.addAll(cRuleIdeInfo.transitiveQuoteIncludeDirectories);
-
- ImmutableList.Builder<String> cFlagsBuilder = ImmutableList.builder();
- cFlagsBuilder.addAll(toolchainIdeInfo.baseCompilerOptions);
- cFlagsBuilder.addAll(toolchainIdeInfo.cCompilerOptions);
- cFlagsBuilder.addAll(toolchainIdeInfo.unfilteredCompilerOptions);
-
- ImmutableList.Builder<String> cppFlagsBuilder = ImmutableList.builder();
- cppFlagsBuilder.addAll(toolchainIdeInfo.baseCompilerOptions);
- cppFlagsBuilder.addAll(toolchainIdeInfo.cppCompilerOptions);
- cppFlagsBuilder.addAll(toolchainIdeInfo.unfilteredCompilerOptions);
-
- ImmutableMap<String, String> features = ImmutableMap.of();
-
- return new BlazeResolveConfiguration(
- project,
- workspacePathResolver,
- ruleIdeInfo.label,
- systemIncludesBuilder.build(),
- systemIncludesBuilder.build(),
- userQuoteIncludesBuilder.build(),
- userIncludesBuilder.build(),
- userIncludesBuilder.build(),
- cRuleIdeInfo.transitiveDefines,
- features,
- compilerWrapper,
- compilerWrapper,
- cFlagsBuilder.build(),
- cppFlagsBuilder.build()
- );
- }
-
- public static ImmutableMap<Label, CToolchainIdeInfo> buildToolchainLookupMap(
- BlazeContext context,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- ImmutableMultimap<Label, Label> reverseDependencies
- ) {
- return Scope.push(context, childContext -> {
- childContext.push(new TimingScope("Build toolchain lookup map"));
-
- List<Label> seeds = Lists.newArrayList();
- for (Map.Entry<Label, RuleIdeInfo> entry : ruleMap.entrySet()) {
- CToolchainIdeInfo cToolchainIdeInfo = entry.getValue().cToolchainIdeInfo;
- if (cToolchainIdeInfo != null) {
- seeds.add(entry.getKey());
- }
- }
-
- Map<Label, CToolchainIdeInfo> lookupTable = Maps.newHashMap();
- for (Label seed : seeds) {
- CToolchainIdeInfo toolchainInfo = ruleMap.get(seed).cToolchainIdeInfo;
- LOG.assertTrue(toolchainInfo != null);
- List<Label> worklist = Lists.newArrayList(reverseDependencies.get(seed));
- while (!worklist.isEmpty()) {
- // We should never see a label depend on two different toolchains.
- Label l = worklist.remove(0);
- CToolchainIdeInfo previousValue = lookupTable.putIfAbsent(l, toolchainInfo);
- // Don't propagate the toolchain twice.
- if (previousValue == null) {
- worklist.addAll(reverseDependencies.get(l));
- }
- else {
- LOG.assertTrue(previousValue.equals(toolchainInfo));
- }
- }
- }
- return ImmutableMap.copyOf(lookupTable);
- });
- }
-
- public BlazeResolveConfiguration(
- Project project,
- WorkspacePathResolver workspacePathResolver,
- Label label,
- ImmutableList<ExecutionRootPath> cSystemIncludeDirs,
- ImmutableList<ExecutionRootPath> cppSystemIncludeDirs,
- ImmutableList<ExecutionRootPath> quoteIncludeDirs,
- ImmutableList<ExecutionRootPath> cIncludeDirs,
- ImmutableList<ExecutionRootPath> cppIncludeDirs,
- ImmutableList<String> defines,
- ImmutableMap<String, String> features,
- File cCompilerExecutable,
- File cppCompilerExecutable,
- ImmutableList<String> cCompilerFlags,
- ImmutableList<String> cppCompilerFlags
- ) {
- this.workspacePathResolver = workspacePathResolver;
- this.project = project;
- this.label = label;
-
- ImmutableList.Builder<HeadersSearchRoot> cIncludeRootsBuilder = ImmutableList.builder();
- collectHeaderRoots(cIncludeRootsBuilder, cIncludeDirs, true /* isUserHeader */);
- collectHeaderRoots(cIncludeRootsBuilder, cSystemIncludeDirs, false /* isUserHeader */);
- this.cLibraryIncludeRoots = cIncludeRootsBuilder.build();
-
- ImmutableList.Builder<HeadersSearchRoot> cppIncludeRootsBuilder = ImmutableList.builder();
- collectHeaderRoots(cppIncludeRootsBuilder, cppIncludeDirs, true /* isUserHeader */);
- collectHeaderRoots(cppIncludeRootsBuilder, cppSystemIncludeDirs, false /* isUserHeader */);
- this.cppLibraryIncludeRoots = cppIncludeRootsBuilder.build();
-
- ImmutableList.Builder<HeadersSearchRoot> quoteIncludeRootsBuilder = ImmutableList.builder();
- collectHeaderRoots(quoteIncludeRootsBuilder, quoteIncludeDirs, true /* isUserHeader */);
- this.projectIncludeRoots = new HeaderRoots(quoteIncludeRootsBuilder.build());
-
- this.compilerSettings = new BlazeCompilerSettings(
- project,
- cCompilerExecutable,
- cppCompilerExecutable,
- cCompilerFlags,
- cppCompilerFlags
- );
-
- this.compilerInfoCache = new CompilerInfoCache();
- this.compilerMacros = new BlazeCompilerMacros(
- project,
- compilerInfoCache,
- compilerSettings,
- defines,
- features
- );
- }
-
- @Override
- public Project getProject() {
- return project;
- }
-
- @Override
- public String getDisplayName(boolean shorten) {
- return label.toString();
- }
-
- @Nullable
- @Override
- public VirtualFile getPrecompiledHeader() {
- return null;
- }
-
- @Nullable
- @Override
- public OCLanguageKind getDeclaredLanguageKind(VirtualFile sourceOrHeaderFile) {
- String fileName = sourceOrHeaderFile.getName();
- if (OCFileTypeHelpers.isSourceFile(fileName)) {
- return getLanguageKind(sourceOrHeaderFile);
- }
-
- if (OCFileTypeHelpers.isHeaderFile(fileName)) {
- return getLanguageKind(getSourceFileForHeaderFile(sourceOrHeaderFile));
- }
-
- return null;
- }
-
- private OCLanguageKind getLanguageKind(@Nullable VirtualFile sourceFile) {
- OCLanguageKind kind = OCLanguageKindCalculator.tryFileTypeAndExtension(project, sourceFile);
- return kind != null ? kind : getMaximumLanguageKind();
- }
-
- @Nullable
- private VirtualFile getSourceFileForHeaderFile(VirtualFile headerFile) {
- ArrayList<VirtualFile> roots = new ArrayList<>(OCImportGraph.getAllHeaderRoots(project, headerFile));
-
- final String headerNameWithoutExtension = headerFile.getNameWithoutExtension();
- for (VirtualFile root : roots) {
- if (root.getNameWithoutExtension().equals(headerNameWithoutExtension)) {
- return root;
- }
- }
- return null;
- }
-
- @Override
- public OCLanguageKind getPrecompiledLanguageKind() {
- return getMaximumLanguageKind();
- }
-
- @Override
- public OCLanguageKind getMaximumLanguageKind() {
- return OCLanguageKind.CPP;
- }
-
- @Override
- public HeaderRoots getProjectHeadersRoots() {
- return projectIncludeRoots;
- }
-
- @Override
- public HeaderRoots getLibraryHeadersRoots(OCResolveRootAndConfiguration headerContext) {
- OCLanguageKind languageKind = headerContext.getKind();
- VirtualFile sourceFile = headerContext.getRootFile();
- if (languageKind == null) {
- languageKind = getLanguageKind(sourceFile);
- }
-
- UniqueListBuilder<HeadersSearchRoot> roots = new UniqueListBuilder<>();
- if (languageKind == OCLanguageKind.C) {
- roots.addAll(cLibraryIncludeRoots);
- } else {
- roots.addAll(cppLibraryIncludeRoots);
- }
-
- CidrCompilerResult<CompilerInfoCache.Entry> compilerInfoCacheHolder = compilerInfoCache.getCompilerInfoCache(
- project,
- compilerSettings,
- languageKind,
- sourceFile
- );
- CompilerInfoCache.Entry compilerInfo = compilerInfoCacheHolder.getResult();
- if (compilerInfo != null) {
- roots.addAll(compilerInfo.headerSearchPaths);
- }
-
- return new HeaderRoots(roots.build());
- }
-
- private void collectHeaderRoots(
- ImmutableList.Builder<HeadersSearchRoot> roots,
- ImmutableList<ExecutionRootPath> paths,
- boolean isUserHeader
- ) {
- for (ExecutionRootPath executionRootPath : paths) {
- ImmutableList<File> possibleDirectories = workspacePathResolver.resolveToIncludeDirectories(executionRootPath);
- for (File f : possibleDirectories) {
- VirtualFile vf = getVirtualFile(f);
- if (vf == null) {
- LOG.debug(String.format("Header root %s could not be converted to a virtual file", f.getAbsolutePath()));
- }
- else {
- roots.add(new IncludedHeadersRoot(project, vf, false /* recursive */, isUserHeader));
- }
- }
- }
- }
-
- @Nullable
- private static VirtualFile getVirtualFile(File file) {
- // Fail fast if the file doesn't even exist.
- if (!file.exists()) {
- return null;
- }
- return VfsUtil.findFileByIoFile(file, true);
- }
-
- @Override
- public OCCompilerMacros getCompilerMacros() {
- return compilerMacros;
- }
-
- @Override
- public OCCompilerSettings getCompilerSettings() {
- return compilerSettings;
- }
-
- @Nullable
- @Override
- public Object getIndexingCluster() {
- return null;
- }
-
- @Override
- public int compareTo(OCResolveConfiguration other) {
- return OCWorkspaceUtil.compareConfigurations(this, other);
- }
-
- @Override
- public int hashCode() {
- // There should only be one configuration per label.
- return Objects.hash(label);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
-
- if (!(obj instanceof BlazeResolveConfiguration)) {
- return false;
- }
-
- BlazeResolveConfiguration that = (BlazeResolveConfiguration)obj;
- return compareTo(that) == 0;
- }
-}
-
diff --git a/blaze-cpp/src/com/google/idea/blaze/cpp/UniqueListBuilder.java b/blaze-cpp/src/com/google/idea/blaze/cpp/UniqueListBuilder.java
deleted file mode 100644
index a9ebfba..0000000
--- a/blaze-cpp/src/com/google/idea/blaze/cpp/UniqueListBuilder.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
-
-import java.util.Set;
-
-/**
- * A list where an item is only added if it is not already in the list.
- */
-final class UniqueListBuilder<T> {
- private final Set<T> set = Sets.newLinkedHashSet();
-
- /**
- * Add {@param element} if it is not already in the list.
- * @return true if the element has been added, false otherwise.
- */
- public boolean add(T element) {
- return set.add(element);
- }
-
- /**
- * For each element in {@param elements} add the element to the list if it is not already in the list.
- */
- public void addAll(Iterable<T> elements) {
- for (T element : elements) {
- add(element);
- }
- }
-
- public ImmutableList<T> build() {
- return ImmutableList.copyOf(set);
- }
-}
diff --git a/blaze-cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java b/blaze-cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
deleted file mode 100644
index fe69893..0000000
--- a/blaze-cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.cpp;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.jetbrains.cidr.lang.OCLanguageKind;
-import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
-import org.junit.Test;
-
-import java.io.File;
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-public class BlazeCompilerSettingsTest extends BlazeTestCase {
- @Test
- public void testCompilerSwitchesSimple() {
- File cppExe = new File("bin/cpp");
- ImmutableList<String> cFlags = ImmutableList.of("-fast", "-slow");
- BlazeCompilerSettings settings = new BlazeCompilerSettings(
- getProject(),
- cppExe,
- cppExe,
- cFlags,
- cFlags
- );
-
- CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
- List<String> commandLineArgs = compilerSwitches.getCommandLineArgs();
- assertThat(commandLineArgs).containsExactly("-fast", "-slow");
- }
-
- @Test
- public void testCompilerSwitchesWithUnescapedSpaces() {
- File cppExe = new File("bin/cpp");
- ImmutableList<String> cFlags = ImmutableList.of("-f ast", "-slo w");
- BlazeCompilerSettings settings = new BlazeCompilerSettings(
- getProject(),
- cppExe,
- cppExe,
- cFlags,
- cFlags
- );
-
- CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
- List<String> commandLineArgs = compilerSwitches.getCommandLineArgs();
- assertThat(commandLineArgs).containsExactly("-f\\ ast", "-slo\\ w");
- }
-
- @Test
- public void testCompilerSwitchesWithEscapedSpaces() {
- File cppExe = new File("bin/cpp");
- ImmutableList<String> cFlags = ImmutableList.of("-f\\ ast", "-slo\\ w");
- BlazeCompilerSettings settings = new BlazeCompilerSettings(
- getProject(),
- cppExe,
- cppExe,
- cFlags,
- cFlags
- );
-
- CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
- List<String> commandLineArgs = compilerSwitches.getCommandLineArgs();
- assertThat(commandLineArgs).containsExactly("-f\\ ast", "-slo\\ w");
- }
-
- @Test
- public void testCompilerSwitchesWithUnescapedAndEscapedSpaces() {
- File cppExe = new File("bin/cpp");
- ImmutableList<String> cFlags = ImmutableList.of("-f ast", "-slo\\ w");
- BlazeCompilerSettings settings = new BlazeCompilerSettings(
- getProject(),
- cppExe,
- cppExe,
- cFlags,
- cFlags
- );
-
- CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
- List<String> commandLineArgs = compilerSwitches.getCommandLineArgs();
- assertThat(commandLineArgs).containsExactly("-f\\ ast", "-slo\\ w");
- }
-}
diff --git a/blaze-java/BUILD b/blaze-java/BUILD
deleted file mode 100644
index fa0a1e6..0000000
--- a/blaze-java/BUILD
+++ /dev/null
@@ -1,57 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-java_library(
- name = "blaze-java",
- srcs = glob(["src/**/*.java"]),
- deps = [
- "//blaze-base",
- "//blaze-base:proto-deps",
- "//intellij-platform-sdk:plugin_api",
- "//third_party:jsr305",
- ],
-)
-
-filegroup(
- name = "plugin_xml",
- srcs = ["src/META-INF/blaze-java.xml"],
-)
-
-load(
- "//intellij_test:test_defs.bzl",
- "intellij_test",
-)
-
-intellij_test(
- name = "unit_tests",
- srcs = glob(["tests/unittests/**/*.java"]),
- test_package_root = "com.google.idea.blaze.java",
- deps = [
- ":blaze-java",
- "//blaze-base",
- "//blaze-base:proto-deps",
- "//blaze-base:unit_test_utils",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//intellij_test:lib",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
-
-intellij_test(
- name = "integration_tests",
- srcs = glob(["tests/integrationtests/**/*.java"]),
- integration_tests = True,
- required_plugins = "com.google.idea.blaze.ijwb",
- test_package_root = "com.google.idea.blaze.java",
- deps = [
- ":blaze-java",
- "//blaze-base",
- "//blaze-base:integration_test_utils",
- "//blaze-base:unit_test_utils",
- "//ijwb:ijwb_bazel",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//intellij_test:lib",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
diff --git a/blaze-java/src/META-INF/blaze-java.xml b/blaze-java/src/META-INF/blaze-java.xml
deleted file mode 100644
index 132125d..0000000
--- a/blaze-java/src/META-INF/blaze-java.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-<!--
- ~ Copyright 2016 The Bazel Authors. All rights reserved.
- ~
- ~ 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.
- -->
-<idea-plugin>
- <depends>com.intellij.modules.java</depends>
- <depends>JUnit</depends>
-
- <actions>
- <action class="com.google.idea.blaze.java.libraries.ExcludeLibraryAction"
- id="Blaze.ExcludeLibraryAction"
- icon="BlazeIcons.Blaze"
- text="Exclude Library and Resync">
- <add-to-group group-id="Blaze.ProjectViewPopupMenu"/>
- </action>
- <action class="com.google.idea.blaze.java.libraries.AttachSourceJarAction"
- id="Blaze.AttachSourceJarAction"
- icon="BlazeIcons.Blaze"
- text="Attach Source Jar">
- <add-to-group group-id="Blaze.ProjectViewPopupMenu"/>
- </action>
-
- <!-- IntelliJ specific actions -->
-
- <action id="Blaze.ImportProject2" class="com.google.idea.blaze.java.wizard2.BlazeImportProjectAction" icon="BlazeIcons.Blaze">
- <add-to-group group-id="WelcomeScreen.QuickStart" />
- <add-to-group group-id="OpenProjectGroup" relative-to-action="ImportProject" anchor="after"/>
- </action>
-
- <action id="Blaze.ImportProject" class="com.google.idea.blaze.java.wizard.BlazeImportNewJavaProjectAction" text="Import Blaze Project (old)..." icon="BlazeIcons.Blaze">
- <add-to-group group-id="WelcomeScreen.QuickStart" />
- <add-to-group group-id="OpenProjectGroup" relative-to-action="ImportProject" anchor="after"/>
- </action>
-
- <!-- End IntelliJ specific actions -->
-
- </actions>
-
- <extensions defaultExtensionNs="com.google.idea.blaze">
- <SyncPlugin implementation="com.google.idea.blaze.java.sync.BlazeJavaSyncPlugin"/>
- <PsiFileProvider implementation="com.google.idea.blaze.java.psi.JavaPsiFileProvider" />
- </extensions>
-
- <extensions defaultExtensionNs="com.intellij">
- <runConfigurationProducer
- implementation="com.google.idea.blaze.java.run.producers.BlazeJavaTestClassConfigurationProducer"
- order="first"/>
- <runConfigurationProducer
- implementation="com.google.idea.blaze.java.run.producers.BlazeJavaTestMethodConfigurationProducer"
- order="first"/>
- <projectViewNodeDecorator implementation="com.google.idea.blaze.java.syncstatus.BlazeJavaSyncStatusClassNodeDecorator"/>
- <editorTabColorProvider implementation="com.google.idea.blaze.java.syncstatus.BlazeJavaSyncStatusEditorTabColorProvider"/>
- <editorTabTitleProvider implementation="com.google.idea.blaze.java.syncstatus.BlazeJavaSyncStatusEditorTabTitleProvider"/>
- <applicationService serviceInterface="com.google.idea.blaze.java.sync.source.JavaSourcePackageReader"
- serviceImplementation="com.google.idea.blaze.java.sync.source.JavaSourcePackageReader"/>
- <applicationService serviceInterface="com.google.idea.blaze.java.sync.source.PackageManifestReader"
- serviceImplementation="com.google.idea.blaze.java.sync.source.PackageManifestReader"/>
- <runConfigurationProducer
- implementation="com.google.idea.blaze.java.run.producers.AllInPackageBlazeConfigurationProducer"
- order="first"/>
- <configurationType implementation="com.google.idea.blaze.java.run.BlazeCommandRunConfigurationType"/>
- <programRunner implementation="com.google.idea.blaze.java.run.BlazeCommandDebuggerRunner"/>
- <projectService serviceInterface="com.google.idea.blaze.base.ui.BlazeProblemsView"
- serviceImplementation="com.google.idea.blaze.java.ui.BlazeIntelliJProblemsView"/>
- <projectService serviceImplementation="com.google.idea.blaze.java.libraries.SourceJarManager"/>
- <refactoring.safeDeleteProcessor id="build_file_safe_delete" order="before javaProcessor"
- implementation="com.google.idea.blaze.java.lang.build.BuildFileSafeDeleteProcessor"/>
-
- <!-- IntelliJ specific extension points -->
- <projectImportProvider implementation="com.google.idea.blaze.java.wizard.BlazeNewProjectImportProvider"/>
- <projectImportBuilder implementation="com.google.idea.blaze.java.wizard.BlazeNewJavaProjectImportBuilder"/>
- <attachSourcesProvider implementation="com.google.idea.blaze.java.libraries.BlazeAttachSourceProvider"/>
- <!-- End IntelliJ specific extension points -->
- </extensions>
-
- <extensionPoints>
- <extensionPoint qualifiedName="com.google.idea.blaze.java.JavaSyncAugmenter"
- interface="com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter"/>
- </extensionPoints>
-</idea-plugin>
diff --git a/blaze-java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java b/blaze-java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java
deleted file mode 100644
index 7fe5066..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.lang.build;
-
-import com.google.idea.blaze.base.lang.buildfile.references.GlobReference;
-import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
-import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFileSystemItem;
-import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor;
-import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo;
-import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteUsageInfo;
-import com.intellij.usageView.UsageInfo;
-import com.intellij.util.IncorrectOperationException;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Removes glob references which don't refer directly to the item(s) being deleted (b/28979434)
- * (e.g. indirect references from glob([*.java])).<p>
- *
- * Runs before JavaSafeDeleteProcessor, and delegates to it, removing indirect glob references.
- * Only the first valid SafeDeleteProcessorDelegate is used in almost all cases*, so this class effectively
- * replaces JavaSafeDeleteProcessor (*in the situations where all processors are used, this class has no effect).
- */
-public class BuildFileSafeDeleteProcessor extends JavaSafeDeleteProcessor {
-
- /**
- * Delegates to JavaSafeDeleteProcessor, then removes indirect glob references which we don't want to block safe delete.
- */
- @Nullable
- @Override
- public NonCodeUsageSearchInfo findUsages(@NotNull PsiElement element,
- @NotNull PsiElement[] allElementsToDelete,
- @NotNull List<UsageInfo> result) {
- NonCodeUsageSearchInfo superResult = super.findUsages(element, allElementsToDelete, result);
- Iterator<UsageInfo> iter = result.iterator();
- while (iter.hasNext()) {
- if (ignoreUsage(iter.next())) {
- iter.remove();
- }
- }
- return superResult;
- }
-
- /**
- * We keep globs which reference the file directly (i.e. without wildcards), and remove all
- * indirect references for the purposes of the 'safe delete' action.
- */
- private static boolean ignoreUsage(UsageInfo usage) {
- if (usage.getReference() instanceof GlobReference && usage instanceof SafeDeleteUsageInfo) {
- PsiElement referencedElement = ((SafeDeleteUsageInfo) usage).getReferencedElement();
- PsiFileSystemItem file = ResolveUtil.asFileSystemItemSearch(referencedElement);
- String relativePath = getBlazePackageRelativePathToFile(file);
- if (relativePath == null) {
- return false;
- }
- return !((GlobReference) usage.getReference()).matchesDirectly(relativePath, file.isDirectory());
- }
- return false;
- }
-
- @Nullable
- private static String getBlazePackageRelativePathToFile(@Nullable PsiFileSystemItem file) {
- if (file == null) {
- return null;
- }
- BlazePackage containingPackage = BlazePackage.getContainingPackage(file);
- if (containingPackage == null) {
- return null;
- }
- return containingPackage.getRelativePathToChild(file.getVirtualFile());
- }
-
- @Override
- public boolean handlesElement(PsiElement element) {
- return super.handlesElement(element);
- }
-
- @Nullable
- @Override
- public Collection<? extends PsiElement> getElementsToSearch(@NotNull PsiElement element,
- @Nullable Module module,
- @NotNull Collection<PsiElement> allElementsToDelete) {
- return super.getElementsToSearch(element, module, allElementsToDelete);
- }
-
- @Nullable
- @Override
- public Collection<PsiElement> getAdditionalElementsToDelete(@NotNull PsiElement element,
- @NotNull Collection<PsiElement> allElementsToDelete,
- boolean askUser) {
- return super.getAdditionalElementsToDelete(element, allElementsToDelete, askUser);
- }
-
- @Nullable
- @Override
- public Collection<String> findConflicts(@NotNull PsiElement element, @NotNull PsiElement[] allElementsToDelete) {
- return super.findConflicts(element, allElementsToDelete);
- }
-
- @Nullable
- @Override
- public UsageInfo[] preprocessUsages(Project project, UsageInfo[] usages) {
- return usages;
- }
-
- @Override
- public void prepareForDeletion(PsiElement element) throws IncorrectOperationException {
- }
-
- @Override
- public boolean isToSearchInComments(PsiElement element) {
- return super.isToSearchInComments(element);
- }
-
- @Override
- public void setToSearchInComments(PsiElement element, boolean enabled) {
- super.setToSearchInComments(element, enabled);
- }
-
- @Override
- public boolean isToSearchForTextOccurrences(PsiElement element) {
- return super.isToSearchForTextOccurrences(element);
- }
-
- @Override
- public void setToSearchForTextOccurrences(PsiElement element, boolean enabled) {
- super.setToSearchForTextOccurrences(element, enabled);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/libraries/AttachSourceJarAction.java b/blaze-java/src/com/google/idea/blaze/java/libraries/AttachSourceJarAction.java
deleted file mode 100644
index 143ba48..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/libraries/AttachSourceJarAction.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.libraries;
-
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.projectstructure.LibraryEditor;
-import com.intellij.CommonBundle;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.roots.libraries.LibraryTable;
-import com.intellij.openapi.ui.Messages;
-import org.jetbrains.annotations.NotNull;
-
-public class AttachSourceJarAction extends BlazeAction {
- @Override
- public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- assert project != null;
- Library library = LibraryActionHelper.findLibraryForAction(e);
- if (library != null) {
- BlazeLibrary blazeLibrary = LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
- if (blazeLibrary == null) {
- Messages.showErrorDialog(project, "Could not find this library in the project.", CommonBundle.getErrorTitle());
- return;
- }
-
- final LibraryArtifact libraryArtifact = blazeLibrary.getLibraryArtifact();
- if (libraryArtifact == null) {
- return;
- }
- if (libraryArtifact.sourceJar == null) {
- return;
- }
- SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
- boolean attachSourceJar = !sourceJarManager.hasSourceJarAttached(blazeLibrary.getKey());
- sourceJarManager.setHasSourceJarAttached(blazeLibrary.getKey(), attachSourceJar);
-
- ApplicationManager.getApplication().runWriteAction(() -> {
- LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
- LibraryTable.ModifiableModel libraryTableModel =
- libraryTable.getModifiableModel();
- LibraryEditor.updateLibrary(libraryTable, libraryTableModel, blazeLibrary, attachSourceJar);
- libraryTableModel.commit();
- });
- }
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent e) {
- Presentation presentation = e.getPresentation();
- String text = "Attach Source Jar";
- boolean visible = false;
- boolean enabled = false;
- Project project = e.getProject();
- if (project != null) {
- Library library = LibraryActionHelper.findLibraryForAction(e);
- if (library != null) {
- visible = true;
-
- BlazeLibrary blazeLibrary = LibraryActionHelper.findLibraryFromIntellijLibrary(e.getProject(), library);
- if (blazeLibrary != null && blazeLibrary.getLibraryArtifact() != null && blazeLibrary.getLibraryArtifact().sourceJar != null) {
- enabled = true;
- if (SourceJarManager.getInstance(project).hasSourceJarAttached(blazeLibrary.getKey())) {
- text = "Detach Source Jar";
- }
- }
- }
- }
- presentation.setVisible(visible);
- presentation.setEnabled(enabled);
- presentation.setText(text);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/libraries/BlazeAttachSourceProvider.java b/blaze-java/src/com/google/idea/blaze/java/libraries/BlazeAttachSourceProvider.java
deleted file mode 100644
index c9475a1..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/libraries/BlazeAttachSourceProvider.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.libraries;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-import com.google.idea.blaze.java.sync.projectstructure.LibraryEditor;
-import com.intellij.codeInsight.AttachSourcesProvider;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.LibraryOrderEntry;
-import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.roots.libraries.LibraryTable;
-import com.intellij.openapi.util.ActionCallback;
-import com.intellij.psi.PsiFile;
-import com.intellij.util.ui.UIUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * @author Sergey Evdokimov
- */
-public class BlazeAttachSourceProvider implements AttachSourcesProvider {
- private static final Logger LOG = Logger.getInstance(BlazeAttachSourceProvider.class);
-
- @NotNull
- @Override
- public Collection<AttachSourcesAction> getActions(List<LibraryOrderEntry> orderEntries, final PsiFile psiFile) {
- Project project = psiFile.getProject();
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return ImmutableList.of();
- }
-
- List<BlazeLibrary> librariesToAttachSourceTo = Lists.newArrayList();
- for (LibraryOrderEntry orderEntry : orderEntries) {
- Library library = orderEntry.getLibrary();
- if (library == null) {
- continue;
- }
- LibraryKey libraryKey = LibraryKey.fromIntelliJLibrary(library);
- if (SourceJarManager.getInstance(project).hasSourceJarAttached(libraryKey)) {
- continue;
- }
- BlazeLibrary blazeLibrary = LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
- if (blazeLibrary == null) {
- continue;
- }
- LibraryArtifact libraryArtifact = blazeLibrary.getLibraryArtifact();
- if (libraryArtifact == null) {
- continue;
- }
- ArtifactLocation artifactLocation = libraryArtifact.sourceJar;
- if (artifactLocation == null) {
- continue;
- }
- librariesToAttachSourceTo.add(blazeLibrary);
- }
-
- if (librariesToAttachSourceTo.isEmpty()) {
- return ImmutableList.of();
- }
-
- /**
- * Semi-hack: When sources are requested and we have them, we attach
- * them automatically if the corresponding user setting is active.
- */
- if (BlazeUserSettings.getInstance().getAttachSourcesOnDemand()) {
- UIUtil.invokeLaterIfNeeded(() -> {
- attachSources(project, librariesToAttachSourceTo);
- });
- return ImmutableList.of();
- }
-
- return ImmutableList.of(new AttachSourcesAction() {
- @Override
- public String getName() {
- return "Attach Blaze Source Jars";
- }
-
- @Override
- public String getBusyText() {
- return "Attaching source jars...";
- }
-
- @Override
- public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
- attachSources(project, librariesToAttachSourceTo);
- return ActionCallback.DONE;
- }
- });
- }
-
- static void attachSources(Project project, Collection<BlazeLibrary> librariesToAttachSourceTo) {
- ApplicationManager.getApplication().runWriteAction(() -> {
- LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
- LibraryTable.ModifiableModel libraryTableModel =
- libraryTable.getModifiableModel();
- for (BlazeLibrary blazeLibrary : librariesToAttachSourceTo) {
- // Make sure we don't do it twice
- if (SourceJarManager.getInstance(project).hasSourceJarAttached(blazeLibrary.getKey())) {
- continue;
- }
- LibraryEditor.updateLibrary(libraryTable, libraryTableModel, blazeLibrary, true);
- SourceJarManager.getInstance(project).setHasSourceJarAttached(blazeLibrary.getKey(), true);
- }
- libraryTableModel.commit();
- });
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/libraries/ExcludeLibraryAction.java b/blaze-java/src/com/google/idea/blaze/java/libraries/ExcludeLibraryAction.java
deleted file mode 100644
index 330e811..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/libraries/ExcludeLibraryAction.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.libraries;
-
-import com.google.idea.blaze.base.actions.BlazeAction;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.projectview.ProjectViewEdit;
-import com.google.idea.blaze.base.projectview.section.Glob;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.sync.BlazeSyncManager;
-import com.google.idea.blaze.base.sync.BlazeSyncParams;
-import com.google.idea.blaze.java.projectview.ExcludeLibrarySection;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.intellij.CommonBundle;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.ui.Messages;
-import org.jetbrains.annotations.NotNull;
-
-public class ExcludeLibraryAction extends BlazeAction {
- @Override
- public void actionPerformed(AnActionEvent e) {
- Project project = e.getProject();
- assert project != null;
- Library library = LibraryActionHelper.findLibraryForAction(e);
- if (library != null) {
- BlazeLibrary blazeLibrary = LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
- if (blazeLibrary == null) {
- Messages.showErrorDialog(project, "Could not find this library in the project.", CommonBundle.getErrorTitle());
- return;
- }
-
- final LibraryArtifact libraryArtifact = blazeLibrary.getLibraryArtifact();
- if (libraryArtifact == null) {
- return;
- }
-
- final String path = libraryArtifact.jar.getRelativePath();
-
- ProjectViewEdit edit = ProjectViewEdit.editLocalProjectView(project, builder -> {
- builder.put(ListSection
- .update(ExcludeLibrarySection.KEY, builder.get(ExcludeLibrarySection.KEY))
- .add(new Glob(path))
- );
- return true;
- });
- edit.apply();
-
- BlazeSyncManager.getInstance(project).requestProjectSync(new BlazeSyncParams.Builder(
- "Sync",
- BlazeSyncParams.SyncMode.INCREMENTAL
- ).setDoBuild(false).build());
- }
- }
-
- @Override
- protected void doUpdate(@NotNull AnActionEvent e) {
- Presentation presentation = e.getPresentation();
- boolean enabled = LibraryActionHelper.findLibraryForAction(e) != null;
- presentation.setVisible(enabled);
- presentation.setEnabled(enabled);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java b/blaze-java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
deleted file mode 100644
index ad52920..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.libraries;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-import com.intellij.ide.projectView.impl.nodes.NamedLibraryElementNode;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.roots.libraries.LibraryTable;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.pom.Navigatable;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public class LibraryActionHelper {
-
- static BlazeLibrary findLibraryFromIntellijLibrary(Project project, Library library) {
- LibraryKey libraryKey = LibraryKey.fromIntelliJLibrary(library);
- BlazeProjectData projectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (projectData == null) {
- return null;
- }
- BlazeJavaSyncData syncData = projectData.syncState.get(BlazeJavaSyncData.class);
- if (syncData == null) {
- Messages.showErrorDialog(project, "Project isn't synced. Please resync project.", "Error");
- return null;
- }
-
- return syncData.importResult.libraries.get(libraryKey);
- }
-
- @Nullable
- public static Library findLibraryForAction(@NotNull AnActionEvent e) {
- Project project = e.getProject();
- if (project != null) {
- NamedLibraryElementNode node = findLibraryNode(e.getDataContext());
- if (node != null) {
- String libraryName = node.getName();
- if (StringUtil.isNotEmpty(libraryName)) {
- LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
- return libraryTable.getLibraryByName(libraryName);
- }
- }
- }
- return null;
- }
-
- @Nullable
- private static NamedLibraryElementNode findLibraryNode(@NotNull DataContext dataContext) {
- Navigatable[] navigatables = CommonDataKeys.NAVIGATABLE_ARRAY.getData(dataContext);
- if (navigatables != null && navigatables.length == 1) {
- Navigatable navigatable = navigatables[0];
- if (navigatable instanceof NamedLibraryElementNode) {
- return (NamedLibraryElementNode)navigatable;
- }
- }
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/libraries/SourceJarManager.java b/blaze-java/src/com/google/idea/blaze/java/libraries/SourceJarManager.java
deleted file mode 100644
index 17bc762..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/libraries/SourceJarManager.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.libraries;
-
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-import com.intellij.openapi.components.*;
-import com.intellij.openapi.project.Project;
-import org.jdom.Element;
-
-import java.util.Set;
-
-/**
- * Keeps track of which libraries have source jars attached.
- */
-@State(name = "BlazeSourceJarManager", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
-public class SourceJarManager implements PersistentStateComponent<Element> {
- private Set<LibraryKey> librariesWithSourceJarsAttached = Sets.newHashSet();
-
- public static SourceJarManager getInstance(Project project) {
- return ServiceManager.getService(project, SourceJarManager.class);
- }
-
- public boolean hasSourceJarAttached(LibraryKey libraryKey) {
- return librariesWithSourceJarsAttached.contains(libraryKey);
- }
-
- public void setHasSourceJarAttached(LibraryKey libraryKey, boolean hasSourceJar) {
- if (hasSourceJar) {
- librariesWithSourceJarsAttached.add(libraryKey);
- } else {
- librariesWithSourceJarsAttached.remove(libraryKey);
- }
- }
-
- @Override
- public Element getState() {
- Element element = new Element("state");
- for (LibraryKey libraryKey : librariesWithSourceJarsAttached) {
- Element libElement = new Element("library");
- libElement.setText(libraryKey.getIntelliJLibraryName());
- element.addContent(libElement);
- }
- return element;
- }
-
- @Override
- public void loadState(Element state) {
- Set<LibraryKey> librariesWithSourceJars = Sets.newHashSet();
- for (Element libElement : state.getChildren()) {
- LibraryKey libraryKey = LibraryKey.fromIntelliJLibraryName(libElement.getText());
- librariesWithSourceJars.add(libraryKey);
- }
- this.librariesWithSourceJarsAttached = librariesWithSourceJars;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/projectview/ExcludeLibrarySection.java b/blaze-java/src/com/google/idea/blaze/java/projectview/ExcludeLibrarySection.java
deleted file mode 100644
index 5323201..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/projectview/ExcludeLibrarySection.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.projectview;
-
-import com.google.idea.blaze.base.projectview.section.*;
-
-/**
- * Section for excluding libraries.
- */
-public class ExcludeLibrarySection {
- public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("exclude_library");
- public static final SectionParser PARSER = new GlobSectionParser(KEY);
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/projectview/ExcludedLibrarySection.java b/blaze-java/src/com/google/idea/blaze/java/projectview/ExcludedLibrarySection.java
deleted file mode 100644
index 5988d3b..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/projectview/ExcludedLibrarySection.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.projectview;
-
-import com.google.idea.blaze.base.projectview.section.*;
-
-/**
- * Section for excluding libraries.
- */
-@Deprecated
-public class ExcludedLibrarySection {
- public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("excluded_libraries");
- public static final SectionParser PARSER = new GlobSectionParser(KEY) {
- @Override
- public boolean isDeprecated() {
- return true;
- }
- };
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/projectview/JavaLanguageLevelSection.java b/blaze-java/src/com/google/idea/blaze/java/projectview/JavaLanguageLevelSection.java
deleted file mode 100644
index b94b60d..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/projectview/JavaLanguageLevelSection.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.projectview;
-
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.parser.ParseContext;
-import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
-import com.google.idea.blaze.base.projectview.section.ScalarSection;
-import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
-import com.google.idea.blaze.base.projectview.section.SectionKey;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.intellij.pom.java.LanguageLevel;
-
-import javax.annotation.Nullable;
-
-public class JavaLanguageLevelSection {
- public static final SectionKey<Integer, ScalarSection<Integer>> KEY =
- SectionKey.of("java_language_level");
- public static final SectionParser PARSER = new JavaLanguageLevelParser();
-
- public static LanguageLevel getLanguageLevel(ProjectViewSet projectViewSet, LanguageLevel defaultValue) {
- Integer level = projectViewSet.getSectionValue(KEY, null);
- if (level == null) {
- return defaultValue;
- }
- return getLanguageLevel(level, defaultValue);
- }
-
- @Nullable
- private static LanguageLevel getLanguageLevel(Integer level, @Nullable LanguageLevel defaultValue) {
- switch (level) {
- case 3:
- return LanguageLevel.JDK_1_3;
- case 4:
- return LanguageLevel.JDK_1_4;
- case 5:
- return LanguageLevel.JDK_1_5;
- case 6:
- return LanguageLevel.JDK_1_6;
- case 7:
- return LanguageLevel.JDK_1_7;
- case 8:
- return LanguageLevel.JDK_1_8;
- case 9:
- return LanguageLevel.JDK_1_9;
- default:
- return defaultValue;
- }
- }
-
- private static class JavaLanguageLevelParser extends ScalarSectionParser<Integer> {
- public JavaLanguageLevelParser() {
- super(KEY, ':');
- }
-
- @Nullable
- @Override
- protected Integer parseItem(ProjectViewParser parser, ParseContext parseContext, String rest) {
- try {
- Integer value = Integer.parseInt(rest);
- if (getLanguageLevel(value, null) != null) {
- return value;
- }
- // Fall through to error handler
- } catch (NumberFormatException e) {
- // Fall through to error handler
- }
- parseContext.addError("Illegal java language level: " + rest);
- return null;
- }
-
- @Override
- protected void printItem(StringBuilder sb, Integer value) {
- sb.append(value.toString());
- }
-
- @Override
- public ItemType getItemType() {
- return ItemType.Other;
- }
- }
-}
\ No newline at end of file
diff --git a/blaze-java/src/com/google/idea/blaze/java/psi/JavaPsiFileProvider.java b/blaze-java/src/com/google/idea/blaze/java/psi/JavaPsiFileProvider.java
deleted file mode 100644
index 1844300..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/psi/JavaPsiFileProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.psi;
-
-import com.google.idea.blaze.base.lang.buildfile.search.PsiFileProvider;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-
-import javax.annotation.Nullable;
-
-/**
- * Replaces top-level java classes with their corresponding PsiFile
- */
-public class JavaPsiFileProvider implements PsiFileProvider {
-
- @Nullable
- @Override
- public PsiFile asFileSearch(PsiElement elementToSearch) {
- if (elementToSearch instanceof PsiClass) {
- elementToSearch = elementToSearch.getParent();
- }
- return elementToSearch instanceof PsiFile ? (PsiFile) elementToSearch : null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandDebuggerRunner.java b/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandDebuggerRunner.java
deleted file mode 100644
index cb68930..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandDebuggerRunner.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-import com.intellij.debugger.impl.GenericDebuggerRunner;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.configurations.*;
-import com.intellij.execution.executors.DefaultDebugExecutor;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.execution.ui.RunContentDescriptor;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * A runner that adapts the GenericDebuggerRunner to work with Blaze run configurations.
- */
-public class BlazeCommandDebuggerRunner extends GenericDebuggerRunner {
- @Override
- @NotNull
- public String getRunnerId() {
- return "Blaze-Debug";
- }
-
- @Override
- public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) {
- return executorId.equals(DefaultDebugExecutor.EXECUTOR_ID)
- && profile instanceof BlazeCommandRunConfiguration;
- }
-
- @Override
- public void patch(JavaParameters javaParameters, RunnerSettings runnerSettings,
- RunProfile runProfile, final boolean beforeExecution) {
- // We don't want to support Java run configuration patching.
- }
-
- @Override
- @Nullable
- public RunContentDescriptor createContentDescriptor(
- @NotNull RunProfileState state, @NotNull ExecutionEnvironment environment)
- throws ExecutionException {
- if (!(state instanceof BlazeCommandRunProfileState)) {
- return null;
- }
- BlazeCommandRunProfileState blazeState = (BlazeCommandRunProfileState)state;
- RemoteConnection connection = blazeState.getRemoteConnection();
- return attachVirtualMachine(state, environment, connection, true /* pollConnection */);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunConfiguration.java b/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunConfiguration.java
deleted file mode 100644
index bf97eea..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunConfiguration.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.run.BlazeRunConfiguration;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.Executor;
-import com.intellij.execution.configurations.ConfigurationFactory;
-import com.intellij.execution.configurations.LocatableConfigurationBase;
-import com.intellij.execution.configurations.RuntimeConfigurationError;
-import com.intellij.execution.configurations.RuntimeConfigurationException;
-import com.intellij.execution.executors.DefaultDebugExecutor;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.ComboBox;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
-import com.intellij.util.execution.ParametersListUtil;
-import org.jdom.Element;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.util.List;
-
-/**
- * A run configuration which executes Blaze commands.
- */
-public class BlazeCommandRunConfiguration extends LocatableConfigurationBase implements BlazeRunConfiguration {
- private static final String TARGET_TAG = "blaze-target";
- private static final String COMMAND_ATTR = "blaze-command";
- private static final String USER_BLAZE_FLAG_TAG = "blaze-user-flag";
- private static final String USER_EXE_FLAG_TAG = "blaze-user-exe-flag";
-
- protected final String buildSystemName;
-
- @Nullable private TargetExpression target;
- @Nullable private BlazeCommandName command;
- private ImmutableList<String> blazeFlags = ImmutableList.of();
- private ImmutableList<String> exeFlags = ImmutableList.of();
-
- public BlazeCommandRunConfiguration(Project project,
- ConfigurationFactory factory,
- String name) {
- super(project, factory, name);
- buildSystemName = Blaze.buildSystemName(project);
- }
-
- @Override
- @Nullable
- public TargetExpression getTarget() {
- return target;
- }
-
- @Nullable
- public BlazeCommandName getCommand() {
- return command;
- }
-
- /**
- * @return The list of blaze flags that the user specified manually.
- */
- protected List<String> getBlazeFlags() {
- return blazeFlags;
- }
-
- /**
- * @return The list of executable flags the user specified manually.
- */
- protected List<String> getExeFlags() {
- return exeFlags;
- }
-
- /**
- * @return The list of all flags to be used on the Blaze command line for blaze. Subclasses should override this method to add flags for
- * higher-level settings (e.g. "run locally").
- */
- public List<String> getAllBlazeFlags() {
- return getBlazeFlags();
- }
-
- /**
- * @return The list of all flags to be used for the executable on the Blaze command line. Subclasses should override this method to add
- * flags if desired.
- */
- public List<String> getAllExeFlags() {
- return getExeFlags();
- }
-
- public void setTarget(@Nullable TargetExpression target) {
- this.target = target;
- }
-
- public void setCommand(@Nullable BlazeCommandName command) {
- this.command = command;
- }
-
- public final void setBlazeFlags(List<String> flags) {
- this.blazeFlags = ImmutableList.copyOf(flags);
- }
-
- public final void setExeFlags(List<String> flags) {
- this.exeFlags = ImmutableList.copyOf(flags);
- }
-
- @Override
- public void checkConfiguration() throws RuntimeConfigurationException {
- if (target == null) {
- throw new RuntimeConfigurationError(String.format("You must specify a %s target expression.", buildSystemName));
- }
- if (command == null) {
- throw new RuntimeConfigurationError(String.format("You must specify a command.", buildSystemName));
- }
- }
-
- @Override
- public void readExternal(Element element) throws InvalidDataException {
- super.readExternal(element);
- // Target is persisted as a tag to permit multiple targets in the future.
- Element targetElement = element.getChild(TARGET_TAG);
- if (targetElement != null && !Strings.isNullOrEmpty(targetElement.getTextTrim())) {
- target = TargetExpression.fromString(targetElement.getTextTrim());
- }
- else {
- target = null;
- }
- String commandString = element.getAttributeValue(COMMAND_ATTR);
- command = Strings.isNullOrEmpty(commandString) ?
- null : BlazeCommandName.fromString(commandString);
- blazeFlags = loadUserFlags(element, USER_BLAZE_FLAG_TAG);
- exeFlags = loadUserFlags(element, USER_EXE_FLAG_TAG);
- }
-
- private static ImmutableList<String> loadUserFlags(Element root, String tag) {
- ImmutableList.Builder<String> flagsBuilder = ImmutableList.builder();
- for (Element e : root.getChildren(tag)) {
- String flag = e.getTextTrim();
- if (flag != null && !flag.isEmpty()) {
- flagsBuilder.add(flag);
- }
- }
- return flagsBuilder.build();
- }
-
- @Override
- public void writeExternal(Element element) throws WriteExternalException {
- super.writeExternal(element);
- if (target != null) {
- // Target is persisted as a tag to permit multiple targets in the future.
- Element targetElement = new Element(TARGET_TAG);
- targetElement.setText(target.toString());
- element.addContent(targetElement);
- }
- if (command != null) {
- element.setAttribute(COMMAND_ATTR, command.toString());
- }
- saveUserFlags(element, blazeFlags, USER_BLAZE_FLAG_TAG);
- saveUserFlags(element, exeFlags, USER_EXE_FLAG_TAG);
- }
-
- private static void saveUserFlags(Element root, List<String> flags, String tag) {
- for (String flag : flags) {
- Element child = new Element(tag);
- child.setText(flag);
- root.addContent(child);
- }
- }
-
- @Override
- public BlazeCommandRunConfiguration clone() {
- final BlazeCommandRunConfiguration configuration = (BlazeCommandRunConfiguration)super.clone();
- configuration.target = target;
- configuration.command = command;
- configuration.blazeFlags = blazeFlags;
- configuration.exeFlags = exeFlags;
- return configuration;
- }
-
- @Override
- @Nullable
- public String suggestedName() {
- TargetExpression target = getTarget();
- if (!(target instanceof Label)) {
- return null;
- }
- return String.format("%s %s: %s", buildSystemName, command.toString(), ((Label)target).ruleName().toString());
- }
-
-
- @Nullable
- @Override
- public BlazeCommandRunProfileState getState(Executor executor,
- ExecutionEnvironment environment) throws ExecutionException {
- return new BlazeCommandRunProfileState(environment, executor instanceof DefaultDebugExecutor);
- }
-
- @Override
- public SettingsEditor<? extends BlazeCommandRunConfiguration> getConfigurationEditor() {
- return new BlazeCommandRunConfigurationSettingsEditor(buildSystemName);
- }
-
- @VisibleForTesting
- static class BlazeCommandRunConfigurationSettingsEditor extends SettingsEditor<BlazeCommandRunConfiguration> {
- private final String buildSystemName;
- private final JTextField targetField = new JTextField();
- private final ComboBox commandCombo;
- private final JTextArea blazeFlagsField = new JTextArea(5, 0);
- private final JTextArea exeFlagsField = new JTextArea(5, 0);
-
- public BlazeCommandRunConfigurationSettingsEditor(String buildSystemName) {
- this.buildSystemName = buildSystemName;
- commandCombo = new ComboBox(
- new DefaultComboBoxModel(BlazeCommandName.knownCommands().toArray()));
- // Allow the user to manually specify an unlisted command.
- commandCombo.setEditable(true);
- }
-
- @VisibleForTesting
- @Override
- public void resetEditorFrom(BlazeCommandRunConfiguration s) {
- targetField.setText(s.target == null ? null : s.target.toString());
- commandCombo.setSelectedItem(s.command);
- blazeFlagsField.setText(ParametersListUtil.join(s.blazeFlags));
- exeFlagsField.setText(ParametersListUtil.join(s.exeFlags));
- }
-
- @VisibleForTesting
- @Override
- public void applyEditorTo(BlazeCommandRunConfiguration s) throws ConfigurationException {
- String targetString = targetField.getText();
- s.target = Strings.isNullOrEmpty(targetString) ?
- null : TargetExpression.fromString(targetString);
- Object selectedCommand = commandCombo.getSelectedItem();
- if (selectedCommand instanceof BlazeCommandName) {
- s.command = (BlazeCommandName)selectedCommand;
- }
- else {
- s.command = Strings.isNullOrEmpty((String)selectedCommand) ?
- null : BlazeCommandName.fromString(selectedCommand.toString());
- }
- s.blazeFlags = ImmutableList.copyOf(ParametersListUtil.parse(Strings.nullToEmpty(blazeFlagsField.getText())));
- s.exeFlags = ImmutableList.copyOf(ParametersListUtil.parse(Strings.nullToEmpty(exeFlagsField.getText())));
- }
-
- @Override
- protected JComponent createEditor() {
- return UiUtil.createBox(
- new JLabel("Target expression:"),
- targetField,
- new JLabel(buildSystemName + " command:"),
- commandCombo,
- new JLabel(buildSystemName +" flags:"),
- blazeFlagsField,
- new JLabel("Executable flags:"),
- exeFlagsField
- );
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunConfigurationType.java b/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunConfigurationType.java
deleted file mode 100644
index c3705a3..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunConfigurationType.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.execution.BeforeRunTask;
-import com.intellij.execution.configurations.ConfigurationFactory;
-import com.intellij.execution.configurations.ConfigurationType;
-import com.intellij.execution.configurations.ConfigurationTypeUtil;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Key;
-import icons.BlazeIcons;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-
-/**
- * A type for run configurations that execute Blaze commands.
- */
-public class BlazeCommandRunConfigurationType implements ConfigurationType {
- @NotNull
- private final BlazeCommandRunConfigurationFactory factory =
- new BlazeCommandRunConfigurationFactory(this);
-
- public static class BlazeCommandRunConfigurationFactory extends ConfigurationFactory {
- protected BlazeCommandRunConfigurationFactory(@NotNull ConfigurationType type) {
- super(type);
- }
-
- @Override
- public boolean isApplicable(@NotNull Project project) {
- return Blaze.isBlazeProject(project);
- }
-
- @Override
- public BlazeCommandRunConfiguration createTemplateConfiguration(Project project) {
- return new BlazeCommandRunConfiguration(project, this, "Unnamed");
- }
-
- @Override
- public void configureBeforeRunTaskDefaults(
- Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
- // We don't need or want any before run tasks by default.
- task.setEnabled(false);
- }
-
- @Override
- public boolean isConfigurationSingletonByDefault() {
- return true;
- }
- }
-
- @NotNull
- public static BlazeCommandRunConfigurationType getInstance() {
- return ConfigurationTypeUtil.findConfigurationType(BlazeCommandRunConfigurationType.class);
- }
-
- @NotNull
- @Override
- public String getDisplayName() {
- return Blaze.defaultBuildSystemName() + " Command";
- }
-
- @NotNull
- @Override
- public String getConfigurationTypeDescription() {
- return String.format("Configuration for launching arbitrary %s commands.", Blaze.guessBuildSystemName());
- }
-
- @NotNull
- @Override
- public Icon getIcon() {
- return BlazeIcons.Blaze;
- }
-
- @NotNull
- @Override
- public String getId() {
- return "BlazeCommandRunConfigurationType";
- }
-
- @NotNull
- @Override
- public BlazeCommandRunConfigurationFactory[] getConfigurationFactories() {
- return new BlazeCommandRunConfigurationFactory[]{factory};
- }
-
- @NotNull
- public BlazeCommandRunConfigurationFactory getFactory() {
- return factory;
- }
-
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunProfileState.java b/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunProfileState.java
deleted file mode 100644
index 93bef0b..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/BlazeCommandRunProfileState.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.run.processhandler.LineProcessingProcessAdapter;
-import com.google.idea.blaze.base.run.processhandler.ScopedBlazeProcessHandler;
-import com.google.idea.blaze.base.scope.scopes.IssuesScope;
-import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.configurations.CommandLineState;
-import com.intellij.execution.configurations.RemoteConnection;
-import com.intellij.execution.configurations.RemoteState;
-import com.intellij.execution.configurations.RunProfile;
-import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.process.ProcessListener;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.project.Project;
-
-/**
- * A Blaze run configuration set up with a an executor, program runner, and other settings, ready to
- * be executed. This class creates a command line for Blaze and exposes debug connection information
- * when using a debug executor.
- */
-final class BlazeCommandRunProfileState extends CommandLineState implements RemoteState {
- // Blaze seems to always use this port for --java_debug.
- // TODO(joshgiles): Look at manually identifying and setting port.
- private static final int DEBUG_PORT = 5005;
- private static final String DEBUG_HOST_NAME = "localhost";
-
- private final BlazeCommandRunConfiguration configuration;
- private final boolean debug;
-
- public BlazeCommandRunProfileState(ExecutionEnvironment environment, boolean debug) {
- super(environment);
- RunProfile runProfile = environment.getRunProfile();
- assert runProfile instanceof BlazeCommandRunConfiguration;
- configuration = (BlazeCommandRunConfiguration)runProfile;
- this.debug = debug;
- }
-
- @Override
- protected ProcessHandler startProcess() throws ExecutionException {
- Project project = configuration.getProject();
- BlazeImportSettings importSettings =
- BlazeImportSettingsManager.getInstance(project).getImportSettings();
- assert importSettings != null;
-
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- assert projectViewSet != null;
-
- BlazeCommand blazeCommand = getBlazeCommand(project, configuration, projectViewSet, debug);
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
- return new ScopedBlazeProcessHandler(
- blazeCommand,
- workspaceRoot,
- new ScopedBlazeProcessHandler.ScopedProcessHandlerDelegate() {
- @Override
- public void onBlazeContextStart(BlazeContext context) {
- context
- .push(new LoggedTimingScope(project, Action.BLAZE_COMMAND_USAGE))
- .push(new IssuesScope(project))
- ;
- }
-
- @Override
- public ImmutableList<ProcessListener> createProcessListeners(BlazeContext context) {
- LineProcessingOutputStream outputStream = LineProcessingOutputStream.of(
- new IssueOutputLineProcessor(project, context, workspaceRoot)
- );
- return ImmutableList.of(new LineProcessingProcessAdapter(outputStream));
- }
- }
- );
- }
-
- @Override
- public RemoteConnection getRemoteConnection() {
- if (!debug) {
- return null;
- }
- return new RemoteConnection(true /* useSockets */,
- DEBUG_HOST_NAME,
- Integer.toString(DEBUG_PORT),
- false /* serverMode */
- );
- }
-
- @VisibleForTesting
- static BlazeCommand getBlazeCommand(
- Project project,
- BlazeCommandRunConfiguration configuration,
- ProjectViewSet projectViewSet,
- boolean debug) {
-
- BlazeCommandName blazeCommand = configuration.getCommand();
- assert blazeCommand != null;
- BlazeCommand.Builder command = BlazeCommand.builder(Blaze.getBuildSystem(project), blazeCommand)
- .addTargets(configuration.getTarget())
- .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
- .addBlazeFlags(configuration.getAllBlazeFlags())
- ;
-
- if (debug) {
- boolean isJavaBinary = false;
- TargetExpression targetExpression = configuration.getTarget();
- if (targetExpression instanceof Label) {
- RuleIdeInfo rule = RuleFinder.getInstance().ruleForTarget(configuration.getProject(), (Label)targetExpression);
- if (rule != null && (rule.kind == Kind.JAVA_BINARY)) {
- isJavaBinary = true;
- }
- }
-
- if (isJavaBinary) {
- command.addExeFlags(BlazeFlags.JAVA_BINARY_DEBUG);
- } else {
- command.addBlazeFlags(BlazeFlags.JAVA_TEST_DEBUG);
- }
-
- }
-
- command.addExeFlags(configuration.getAllExeFlags());
- return command.build();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/RunUtil.java b/blaze-java/src/com/google/idea/blaze/java/run/RunUtil.java
deleted file mode 100644
index 963245e..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/RunUtil.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-import com.google.common.collect.Iterables;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.run.TestRuleFinder;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-
-/**
- * Utility methods for finding rules and Android facets.
- */
-public final class RunUtil {
-
- private RunUtil() {
- }
-
- /**
- * @return The Blaze test rule containing the target test class. In the case of multiple
- * containing rules, the first rule sorted alphabetically by label.
- */
- @Nullable
- public static RuleIdeInfo ruleForTestClass(@NotNull Project project,
- @NotNull PsiClass testClass,
- @Nullable TestIdeInfo.TestSize testSize) {
- File testFile = getFileForClass(testClass);
- if (testFile == null) {
- return null;
- }
- TestRuleFinder testRuleFinder = TestRuleFinder.getInstance(project);
- // We don't expose multiple rule choices, just pick first
- Label testLabel = Iterables.getFirst(testRuleFinder.testTargetsForSourceFile(testFile, testSize), null);
- if (testLabel == null) {
- return null;
- }
- return RuleFinder.getInstance().ruleForTarget(project, testLabel);
- }
-
- /**
- * Returns an instance of {@link java.io.File} related to the containing file of the given class.
- * It returns {@code null} if the given class is not contained in a file and only exists in
- * memory.
- */
- @Nullable
- private static File getFileForClass(@NotNull PsiClass aClass) {
- PsiFile containingFile = aClass.getContainingFile();
- if (containingFile == null) {
- return null;
- }
-
- VirtualFile virtualFile = containingFile.getVirtualFile();
- if (virtualFile == null) {
- return null;
- }
-
- return new File(virtualFile.getPath());
- }
-
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/AllInPackageBlazeConfigurationProducer.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/AllInPackageBlazeConfigurationProducer.java
deleted file mode 100644
index 0dccb0f..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/AllInPackageBlazeConfigurationProducer.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfiguration;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfigurationType;
-import com.intellij.execution.ExecutionBundle;
-import com.intellij.execution.actions.ConfigurationContext;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiDirectory;
-import com.intellij.psi.PsiElement;
-
-import javax.annotation.Nullable;
-
-/**
- * Runs tests in all packages below selected directory
- */
-public class AllInPackageBlazeConfigurationProducer extends BlazeTestRunConfigurationProducer<BlazeCommandRunConfiguration> {
-
- public AllInPackageBlazeConfigurationProducer() {
- super(BlazeCommandRunConfigurationType.getInstance());
- }
-
- @Override
- protected boolean doSetupConfigFromContext(
- BlazeCommandRunConfiguration configuration,
- ConfigurationContext context,
- Ref<PsiElement> sourceElement) {
-
- PsiDirectory dir = getTestDirectory(context);
- if (dir == null) {
- return false;
- }
- WorkspaceRoot root = WorkspaceRoot.fromProject(context.getModule().getProject());
- WorkspacePath packagePath = getWorkspaceRelativeDirectoryPath(root, dir);
- if (packagePath == null) {
- return false;
- }
- sourceElement.set(dir);
-
- configuration.setCommand(BlazeCommandName.TEST);
- configuration.setTarget(TargetExpression.allFromPackageRecursive(packagePath));
- configuration.setName(
- String.format("%s %s",
- Blaze.buildSystemName(context.getProject()),
- ExecutionBundle.message("test.in.scope.presentable.text", packagePath)));
- return true;
- }
-
- @Override
- protected boolean doIsConfigFromContext(
- BlazeCommandRunConfiguration configuration,
- ConfigurationContext context) {
-
- PsiDirectory dir = getTestDirectory(context);
- if (dir == null) {
- return false;
- }
- WorkspaceRoot root = WorkspaceRoot.fromProject(context.getModule().getProject());
- WorkspacePath packagePath = getWorkspaceRelativeDirectoryPath(root, dir);
- if (packagePath == null) {
- return false;
- }
- return configuration.getCommand() == BlazeCommandName.TEST &&
- configuration.getTarget() == TargetExpression.allFromPackageRecursive(packagePath);
- }
-
- @Nullable
- private static PsiDirectory getTestDirectory(ConfigurationContext context) {
- WorkspaceRoot root = WorkspaceRoot.fromProject(context.getModule().getProject());
- PsiElement location = context.getPsiLocation();
- if (location instanceof PsiDirectory) {
- PsiDirectory dir = (PsiDirectory) location;
- if (isInWorkspace(root, dir)) {
- return dir;
- }
- }
- return null;
- }
-
- @Nullable
- private static WorkspacePath getWorkspaceRelativeDirectoryPath(
- WorkspaceRoot root,
- PsiDirectory dir) {
- VirtualFile file = dir.getVirtualFile();
- if (isInWorkspace(root, dir)) {
- return root.workspacePathFor(file);
- }
- return null;
- }
-
- private static boolean isInWorkspace(WorkspaceRoot root,
- PsiDirectory dir) {
- return root.isInWorkspace(dir.getVirtualFile());
- }
-
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java
deleted file mode 100644
index 7c1c39a..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.java.run.RunUtil;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfiguration;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfigurationType;
-import com.intellij.execution.JavaExecutionUtil;
-import com.intellij.execution.Location;
-import com.intellij.execution.actions.ConfigurationContext;
-import com.intellij.execution.junit.JUnitUtil;
-import com.intellij.openapi.util.Ref;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiMethod;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * Producer for run configurations related to Java test classes in Blaze.
- */
-public class BlazeJavaTestClassConfigurationProducer extends BlazeTestRunConfigurationProducer<BlazeCommandRunConfiguration> {
-
- public BlazeJavaTestClassConfigurationProducer() {
- super(BlazeCommandRunConfigurationType.getInstance());
- }
-
- @Override
- protected boolean doSetupConfigFromContext(
- @NotNull BlazeCommandRunConfiguration configuration,
- @NotNull ConfigurationContext context,
- @NotNull Ref<PsiElement> sourceElement) {
-
- final Location contextLocation = context.getLocation();
- assert contextLocation != null;
- final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);
- if (location == null) {
- return false;
- }
-
- if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
- return false;
- }
-
- PsiClass testClass = JUnitUtil.getTestClass(location);
- if (testClass == null) {
- return false;
- }
- sourceElement.set(testClass);
-
- TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(testClass);
- RuleIdeInfo rule = RunUtil.ruleForTestClass(context.getProject(), testClass, testSize);
- if (rule == null) {
- return false;
- }
-
- configuration.setCommand(BlazeCommandName.TEST);
- configuration.setTarget(rule.label);
-
- ImmutableList.Builder<String> flags = ImmutableList.builder();
-
- String qualifiedName = testClass.getQualifiedName();
- if (qualifiedName != null) {
- flags.add(BlazeFlags.testFilterFlagForClass(qualifiedName));
- }
-
- flags.add(BlazeFlags.TEST_OUTPUT_STREAMED);
-
- configuration.setBlazeFlags(flags.build());
- configuration.setName(
- String.format("%s test: %s (%s)",
- Blaze.buildSystemName(configuration.getProject()),
- testClass.getName(),
- rule.label.toString()));
- return true;
- }
-
- @Override
- protected boolean doIsConfigFromContext(
- @NotNull BlazeCommandRunConfiguration configuration,
- @NotNull ConfigurationContext context) {
-
- final Location contextLocation = context.getLocation();
- assert contextLocation != null;
- final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);
- if (location == null) {
- return false;
- }
-
- if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
- return false;
- }
-
- Location<PsiMethod> methodLocation = ProducerUtils.getMethodLocation(contextLocation);
- if (methodLocation != null) {
- return false;
- }
-
- PsiClass testClass = JUnitUtil.getTestClass(location);
- if (testClass == null) {
- return false;
- }
-
- return checkIfAttributesAreTheSame(configuration, testClass);
- }
-
- private boolean checkIfAttributesAreTheSame(
- @NotNull BlazeCommandRunConfiguration configuration,
- @NotNull PsiClass testClass) {
-
- List<String> flags = configuration.getAllBlazeFlags();
-
- return flags.contains(BlazeFlags.testFilterFlagForClass(testClass.getQualifiedName()));
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java
deleted file mode 100644
index da906ca..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfiguration;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfigurationType;
-import com.google.idea.blaze.java.run.RunUtil;
-import com.intellij.execution.Location;
-import com.intellij.execution.actions.ConfigurationContext;
-import com.intellij.openapi.util.Ref;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiMethod;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.List;
-
-/**
- * Producer for run configurations related to Java test methods in Blaze.
- */
-public class BlazeJavaTestMethodConfigurationProducer extends BlazeTestRunConfigurationProducer<BlazeCommandRunConfiguration> {
-
- public BlazeJavaTestMethodConfigurationProducer() {
- super(BlazeCommandRunConfigurationType.getInstance());
- }
-
- @Override
- protected boolean doSetupConfigFromContext(
- @NotNull BlazeCommandRunConfiguration configuration,
- @NotNull ConfigurationContext context,
- @NotNull Ref<PsiElement> sourceElement) {
-
- if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
- return false;
- }
-
- final Location contextLocation = context.getLocation();
- assert contextLocation != null;
- Location<PsiMethod> methodLocation = ProducerUtils.getMethodLocation(contextLocation);
- if (methodLocation == null) {
- return false;
- }
-
- final PsiMethod psiMethod = methodLocation.getPsiElement();
- sourceElement.set(psiMethod);
-
- final PsiClass containingClass = psiMethod.getContainingClass();
- if (containingClass == null) {
- return false;
- }
-
- TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(psiMethod);
- RuleIdeInfo rule = RunUtil.ruleForTestClass(context.getProject(), containingClass, testSize);
- if (rule == null) {
- return false;
- }
-
- configuration.setCommand(BlazeCommandName.TEST);
- configuration.setTarget(rule.label);
-
- ImmutableList.Builder<String> flags = ImmutableList.builder();
-
- String qualifiedName = containingClass.getQualifiedName();
- if (qualifiedName != null) {
- flags.add(BlazeFlags.testFilterFlagForClassAndMethod(qualifiedName, psiMethod.getName()));
- }
-
- flags.add(BlazeFlags.TEST_OUTPUT_STREAMED);
-
- configuration.setBlazeFlags(flags.build());
- configuration.setName(
- String.format("%s test: %s.%s (%s)",
- Blaze.buildSystemName(configuration.getProject()),
- containingClass.getName(),
- psiMethod.getName(),
- rule.label.toString()));
- return true;
- }
-
- @Override
- protected boolean doIsConfigFromContext(
- @NotNull BlazeCommandRunConfiguration configuration,
- @NotNull ConfigurationContext context) {
-
- if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
- return false;
- }
-
- final Location contextLocation = context.getLocation();
- assert contextLocation != null;
-
- Location<PsiMethod> methodLocation = ProducerUtils.getMethodLocation(contextLocation);
- if (methodLocation == null) {
- return false;
- }
-
- final PsiMethod psiMethod = methodLocation.getPsiElement();
- final PsiClass containingClass = psiMethod.getContainingClass();
- if (containingClass == null) {
- return false;
- }
-
- return checkIfAttributesAreTheSame(configuration, psiMethod);
- }
-
- private static boolean checkIfAttributesAreTheSame(
- BlazeCommandRunConfiguration configuration, PsiMethod testMethod) {
-
- List<String> flags = configuration.getAllBlazeFlags();
-
- return flags.contains(BlazeFlags.testFilterFlagForClassAndMethod(testMethod.getContainingClass().getQualifiedName(), testMethod.getName()));
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeTestRunConfigurationProducer.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeTestRunConfigurationProducer.java
deleted file mode 100644
index fc0e439..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/BlazeTestRunConfigurationProducer.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.execution.actions.ConfigurationContext;
-import com.intellij.execution.actions.ConfigurationFromContext;
-import com.intellij.execution.actions.RunConfigurationProducer;
-import com.intellij.execution.configurations.ConfigurationType;
-import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.util.NullUtils;
-import com.intellij.openapi.util.Ref;
-import com.intellij.psi.PsiElement;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Base class for Blaze test run configuration producers.
- */
-public abstract class BlazeTestRunConfigurationProducer<T extends RunConfiguration> extends RunConfigurationProducer<T> {
-
- protected BlazeTestRunConfigurationProducer(ConfigurationType configurationType) {
- super(configurationType);
- }
-
- @Override
- public boolean isPreferredConfiguration(ConfigurationFromContext self, ConfigurationFromContext other) {
- return Blaze.isBlazeProject(self.getConfiguration().getProject());
- }
-
- @Override
- public boolean shouldReplace(ConfigurationFromContext self, ConfigurationFromContext other) {
- return Blaze.isBlazeProject(self.getConfiguration().getProject()) &&
- !other.isProducedBy(BlazeTestRunConfigurationProducer.class);
- }
-
- @Override
- protected final boolean setupConfigurationFromContext(T configuration, ConfigurationContext context, Ref<PsiElement> sourceElement) {
- if (NullUtils.hasNull(configuration, context, sourceElement)) {
- return false;
- }
- if (!validContext(context)) {
- return false;
- }
- return doSetupConfigFromContext(configuration, context, sourceElement);
- }
-
- protected abstract boolean doSetupConfigFromContext(
- @NotNull T configuration,
- @NotNull ConfigurationContext context,
- @NotNull Ref<PsiElement> sourceElement);
-
- @Override
- public final boolean isConfigurationFromContext(T configuration, ConfigurationContext context) {
- if (NullUtils.hasNull(configuration, context)) {
- return false;
- }
- if (!validContext(context)) {
- return false;
- }
- return doIsConfigFromContext(configuration, context);
- }
-
- protected abstract boolean doIsConfigFromContext(
- @NotNull T configuration,
- @NotNull ConfigurationContext context);
-
- private static boolean validContext(@NotNull ConfigurationContext context) {
- Module module = context.getModule();
- if (module == null) {
- return false;
- }
- if (!isBlazeContext(context)) {
- return false;
- }
- return true;
- }
-
- private static boolean isBlazeContext(@NotNull ConfigurationContext context) {
- return Blaze.isBlazeProject(context.getProject());
- }
-
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java
deleted file mode 100644
index fa757c4..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.intellij.execution.Location;
-import com.intellij.execution.actions.ConfigurationContext;
-import com.intellij.execution.junit.JUnitUtil;
-import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
-import com.intellij.execution.junit2.info.MethodLocation;
-import com.intellij.execution.testframework.TestsUIUtil;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.*;
-import com.intellij.psi.search.PsiElementProcessor;
-import com.intellij.psi.util.ClassUtil;
-
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-
-/**
- * Cloned from PatternConfigurationProducer, stripped down to only contain isMultipleElementsSelected.
- */
-public class JUnitConfigurationUtil {
- protected static boolean isTestClass(PsiClass psiClass) {
- return JUnitUtil.isTestClass(psiClass);
- }
-
- protected static boolean isTestMethod(boolean checkAbstract, PsiElement psiElement) {
- return JUnitUtil.getTestMethod(psiElement, checkAbstract) != null;
- }
-
- public static boolean isMultipleElementsSelected(ConfigurationContext context) {
- final DataContext dataContext = context.getDataContext();
- if (TestsUIUtil.isMultipleSelectionImpossible(dataContext)) return false;
- final LinkedHashSet<String> classes = new LinkedHashSet<String>();
- final PsiElementProcessor.CollectElementsWithLimit<PsiElement> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiElement>(2);
- final PsiElement[] locationElements = collectLocationElements(classes, dataContext);
- if (locationElements != null) {
- collectTestMembers(locationElements, false, false, processor);
- }
- else {
- collectContextElements(dataContext, false, false, classes, processor);
- }
- return processor.getCollection().size() > 1;
- }
-
- public static void collectTestMembers(PsiElement[] psiElements,
- boolean checkAbstract,
- boolean checkIsTest,
- PsiElementProcessor.CollectElements<PsiElement> collectingProcessor) {
- for (PsiElement psiElement : psiElements) {
- if (psiElement instanceof PsiClassOwner) {
- final PsiClass[] classes = ((PsiClassOwner)psiElement).getClasses();
- for (PsiClass aClass : classes) {
- if ((!checkIsTest && aClass.hasModifierProperty(PsiModifier.PUBLIC) || checkIsTest && isTestClass(aClass)) &&
- !collectingProcessor.execute(aClass)) {
- return;
- }
- }
- } else if (psiElement instanceof PsiClass) {
- if ((!checkIsTest && ((PsiClass)psiElement).hasModifierProperty(PsiModifier.PUBLIC) || checkIsTest && isTestClass((PsiClass)psiElement)) &&
- !collectingProcessor.execute(psiElement)) {
- return;
- }
- } else if (psiElement instanceof PsiMethod) {
- if (checkIsTest && isTestMethod(checkAbstract, psiElement) && !collectingProcessor.execute(psiElement)) {
- return;
- }
- if (!checkIsTest) {
- final PsiClass containingClass = ((PsiMethod)psiElement).getContainingClass();
- if (containingClass != null && containingClass.hasModifierProperty(PsiModifier.PUBLIC) && !collectingProcessor.execute(psiElement)) {
- return;
- }
- }
- } else if (psiElement instanceof PsiDirectory) {
- final PsiPackage aPackage = JavaDirectoryService.getInstance().getPackage((PsiDirectory)psiElement);
- if (aPackage != null && !collectingProcessor.execute(aPackage)) {
- return;
- }
- }
- }
- }
-
- private static boolean collectContextElements(DataContext dataContext,
- boolean checkAbstract,
- boolean checkIsTest,
- LinkedHashSet<String> classes,
- PsiElementProcessor.CollectElements<PsiElement> processor) {
- PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
- if (elements != null) {
- collectTestMembers(elements, checkAbstract, checkIsTest, processor);
- for (PsiElement psiClass : processor.getCollection()) {
- classes.add(getQName(psiClass));
- }
- return true;
- }
- else {
- final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
- if (files != null) {
- Project project = CommonDataKeys.PROJECT.getData(dataContext);
- if (project != null) {
- final PsiManager psiManager = PsiManager.getInstance(project);
- for (VirtualFile file : files) {
- final PsiFile psiFile = psiManager.findFile(file);
- if (psiFile instanceof PsiClassOwner) {
- collectTestMembers(((PsiClassOwner)psiFile).getClasses(), checkAbstract, checkIsTest, processor);
- for (PsiElement psiMember : processor.getCollection()) {
- classes.add(((PsiClass)psiMember).getQualifiedName());
- }
- }
- }
- return true;
- }
- }
- }
- return false;
- }
-
- private static PsiElement[] collectLocationElements(LinkedHashSet<String> classes, DataContext dataContext) {
- final Location<?>[] locations = Location.DATA_KEYS.getData(dataContext);
- if (locations != null) {
- List<PsiElement> elements = new ArrayList<PsiElement>();
- for (Location<?> location : locations) {
- final PsiElement psiElement = location.getPsiElement();
- classes.add(getQName(psiElement, location));
- elements.add(psiElement);
- }
- return elements.toArray(new PsiElement[elements.size()]);
- }
- return null;
- }
-
- public static String getQName(PsiElement psiMember) {
- return getQName(psiMember, null);
- }
-
- public static String getQName(PsiElement psiMember, Location location) {
- if (psiMember instanceof PsiClass) {
- return ClassUtil.getJVMClassName((PsiClass)psiMember);
- }
- else if (psiMember instanceof PsiMember) {
- final PsiClass containingClass = location instanceof MethodLocation
- ? ((MethodLocation)location).getContainingClass()
- : location instanceof PsiMemberParameterizedLocation ? ((PsiMemberParameterizedLocation)location).getContainingClass()
- : ((PsiMember)psiMember).getContainingClass();
- assert containingClass != null;
- return ClassUtil.getJVMClassName(containingClass) + "," + ((PsiMember)psiMember).getName();
- } else if (psiMember instanceof PsiPackage) {
- return ((PsiPackage)psiMember).getQualifiedName();
- }
- assert false;
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java
deleted file mode 100644
index bbcce9b..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.intellij.execution.Location;
-import com.intellij.execution.junit.JUnitUtil;
-import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
-import com.intellij.execution.junit2.info.MethodLocation;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiMethod;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Iterator;
-
-/**
- * Copy of {@link org.jetbrains.plugins.gradle.execution.test.runner.TestRunnerUtils}.
- * <p/>
- * <p>Do not modify.
- */
-public class ProducerUtils {
- @Nullable
- public static Location<PsiMethod> getMethodLocation(@NotNull Location contextLocation) {
- Location<PsiMethod> methodLocation = getTestMethod(contextLocation);
- if (methodLocation == null) {
- return null;
- }
-
- if (contextLocation instanceof PsiMemberParameterizedLocation) {
- PsiClass containingClass =
- ((PsiMemberParameterizedLocation)contextLocation).getContainingClass();
- if (containingClass != null) {
- methodLocation = MethodLocation
- .elementInClass(methodLocation.getPsiElement(), containingClass);
- }
- }
- return methodLocation;
- }
-
- @Nullable
- public static Location<PsiMethod> getTestMethod(final Location<?> location) {
- for (Iterator<Location<PsiMethod>> iterator = location.getAncestors(PsiMethod.class, false);
- iterator.hasNext(); ) {
- final Location<PsiMethod> methodLocation = iterator.next();
- if (JUnitUtil.isTestMethod(methodLocation, false)) {
- return methodLocation;
- }
- }
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java b/blaze-java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java
deleted file mode 100644
index 0322bc0..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run.producers;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
-import com.intellij.psi.PsiAnnotation;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiMethod;
-import com.intellij.psi.PsiModifierList;
-
-import javax.annotation.Nullable;
-
-/**
- * Maps method and class annotations to our test size enumeration.
- */
-public class TestSizeAnnotationMap {
- private static ImmutableMap<String, TestIdeInfo.TestSize> ANNOTATION_TO_TEST_SIZE = ImmutableMap.<String, TestIdeInfo.TestSize>builder()
- .put("com.google.testing.testsize.SmallTest", TestIdeInfo.TestSize.SMALL)
- .put("com.google.testing.testsize.MediumTest", TestIdeInfo.TestSize.MEDIUM)
- .put("com.google.testing.testsize.LargeTest", TestIdeInfo.TestSize.LARGE)
- .put("com.google.testing.testsize.EnormousTest", TestIdeInfo.TestSize.ENORMOUS)
- .build();
-
- @Nullable
- public static TestIdeInfo.TestSize getTestSize(PsiMethod psiMethod) {
- PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations();
- TestIdeInfo.TestSize testSize = getTestSize(annotations);
- if (testSize != null) {
- return testSize;
- }
- return getTestSize(psiMethod.getContainingClass());
- }
-
- @Nullable
- public static TestIdeInfo.TestSize getTestSize(PsiClass psiClass) {
- PsiModifierList psiModifierList = psiClass.getModifierList();
- if (psiModifierList == null) {
- return null;
- }
- PsiAnnotation[] annotations = psiModifierList.getAnnotations();
- TestIdeInfo.TestSize testSize = getTestSize(annotations);
- if (testSize == null) {
- return null;
- }
- return testSize;
- }
-
- @Nullable
- private static TestIdeInfo.TestSize getTestSize(PsiAnnotation[] annotations) {
- for (PsiAnnotation annotation : annotations) {
- String qualifiedName = annotation.getQualifiedName();
- TestIdeInfo.TestSize testSize = ANNOTATION_TO_TEST_SIZE.get(qualifiedName);
- if (testSize != null) {
- return testSize;
- }
- }
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java b/blaze-java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
deleted file mode 100644
index ba7219c..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.section.Glob;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.intellij.openapi.extensions.ExtensionPointName;
-
-import java.util.Collection;
-
-/**
- * Augments the java importer
- */
-public interface BlazeJavaSyncAugmenter {
- ExtensionPointName<BlazeJavaSyncAugmenter> EP_NAME = ExtensionPointName.create("com.google.idea.blaze.java.JavaSyncAugmenter");
-
- /**
- * Adds any library filters. Useful if some libraries are supplied by this plugin in some other way, eg. via an SDK.
- */
- void addLibraryFilter(Glob.GlobSet excludedLibraries);
-
- /**
- * Called during the project structure phase to get additional libraries.
- */
- Collection<BlazeLibrary> getAdditionalLibraries(BlazeProjectData blazeProjectData);
-
- /**
- * Returns a collection of library names for libraries that are added by some framework
- * and shouldn't be removed during sync. Examples are typescript and dart support.
- */
- Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData);
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java b/blaze-java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
deleted file mode 100644
index 06e97e2..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.experiments.BoolExperiment;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.Glob;
-import com.google.idea.blaze.base.projectview.section.SectionParser;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PerformanceWarning;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.google.idea.blaze.java.projectview.ExcludeLibrarySection;
-import com.google.idea.blaze.java.projectview.ExcludedLibrarySection;
-import com.google.idea.blaze.java.projectview.JavaLanguageLevelSection;
-import com.google.idea.blaze.java.sync.importer.BlazeJavaWorkspaceImporter;
-import com.google.idea.blaze.java.sync.jdeps.JdepsFileReader;
-import com.google.idea.blaze.java.sync.jdeps.JdepsMap;
-import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
-import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.projectstructure.Jdks;
-import com.google.idea.blaze.java.sync.projectstructure.LibraryEditor;
-import com.google.idea.blaze.java.sync.projectstructure.SourceFolderEditor;
-import com.google.idea.blaze.java.sync.workingset.JavaWorkingSet;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleType;
-import com.intellij.openapi.module.StdModuleTypes;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.LanguageLevelProjectExtension;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
-import com.intellij.pom.java.LanguageLevel;
-import com.intellij.util.ui.UIUtil;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Sync support for Java.
- */
-public class BlazeJavaSyncPlugin extends BlazeSyncPlugin.Adapter {
- private static final BoolExperiment USE_WORKING_SET = new BoolExperiment("use.working.set", true);
- private static final Logger LOG = Logger.getInstance(BlazeJavaSyncPlugin.class);
- private final JdepsFileReader jdepsFileReader = new JdepsFileReader();
-
- @Nullable
- @Override
- public WorkspaceType getDefaultWorkspaceType() {
- return WorkspaceType.JAVA;
- }
-
- @Override
- public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- if (workspaceType == WorkspaceType.JAVA) {
- return ImmutableSet.of(LanguageClass.JAVA);
- }
- return ImmutableSet.of();
- }
-
- @Nullable
- @Override
- public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
- if (workspaceType == WorkspaceType.JAVA) {
- return StdModuleTypes.JAVA;
- }
- return null;
- }
-
- @Override
- public void updateSyncState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
- JavaWorkingSet javaWorkingSet = null;
- if (USE_WORKING_SET.getValue() && workingSet != null) {
- javaWorkingSet = new JavaWorkingSet(workspaceRoot, workingSet);
- }
-
- JdepsMap jdepsMap = jdepsFileReader.loadJdepsFiles(context, ruleMap, syncStateBuilder, previousSyncState);
-
- BlazeJavaWorkspaceImporter blazeJavaWorkspaceImporter = new BlazeJavaWorkspaceImporter(
- project,
- workspaceRoot,
- projectViewSet,
- ruleMap,
- jdepsMap,
- javaWorkingSet,
- new ArtifactLocationDecoder(blazeRoots, workspacePathResolver)
- );
- BlazeJavaImportResult importResult = Scope.push(context, (childContext) -> {
- childContext.push(new TimingScope("JavaWorkspaceImporter"));
- return blazeJavaWorkspaceImporter.importWorkspace(childContext);
- });
- Glob.GlobSet excludedLibraries = new Glob.GlobSet(
- ImmutableList.<Glob>builder()
- .addAll(projectViewSet.listItems(ExcludeLibrarySection.KEY))
- .addAll(projectViewSet.listItems(ExcludedLibrarySection.KEY))
- .build()
- );
- for (BlazeJavaSyncAugmenter syncAugmenter : BlazeJavaSyncAugmenter.EP_NAME.getExtensions()) {
- syncAugmenter.addLibraryFilter(excludedLibraries);
- }
- BlazeJavaSyncData syncData = new BlazeJavaSyncData(
- importResult,
- excludedLibraries,
- BlazeUserSettings.getInstance().getAttachSourcesByDefault()
- );
- syncStateBuilder.put(BlazeJavaSyncData.class, syncData);
- }
-
- @Override
- public void updateSdk(Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- if (!blazeProjectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.JAVA)) {
- return;
- }
- updateJdk(project, context, projectViewSet, blazeProjectData);
- }
-
- @Override
- public void updateContentEntries(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- Collection<ContentEntry> contentEntries) {
- if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.JAVA)) {
- return;
- }
- BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
- if (syncData == null) {
- return;
- }
-
- SourceFolderEditor.modifyContentEntries(
- syncData.importResult,
- contentEntries
- );
- }
-
- @Override
- public void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel) {
- BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
- if (syncData == null) {
- return;
- }
-
- @Nullable BlazeJavaSyncData oldSyncData = oldBlazeProjectData != null
- ? oldBlazeProjectData.syncState.get(BlazeJavaSyncData.class)
- : null;
-
- if (syncData.attachSourceJarsByDefault) {
- context.output(PrintOutput.output(
- "Attaching source jars by default. This may lead to significant increases in indexing time,"
- + " project opening time, and IDE memory usage. To turn off go to"
- + " Settings > Other Settings > Blaze."
- ));
- }
-
- List<BlazeLibrary> newLibraries = getLibraries(blazeProjectData, syncData);
- final List<BlazeLibrary> oldLibraries;
- if (oldSyncData != null && oldSyncData.attachSourceJarsByDefault == syncData.attachSourceJarsByDefault) {
- oldLibraries = getLibraries(oldBlazeProjectData, oldSyncData);
- } else {
- oldLibraries = ImmutableList.of();
- }
-
- LibraryEditor.updateProjectLibraries(
- project,
- context,
- blazeProjectData,
- newLibraries,
- oldLibraries
- );
-
- LibraryEditor.configureDependencies(
- project,
- context,
- workspaceModifiableModel,
- newLibraries
- );
- }
-
- private static List<BlazeLibrary> getLibraries(BlazeProjectData blazeProjectData,
- BlazeJavaSyncData syncData) {
- Glob.GlobSet excludedLibraries = syncData.excludedLibraries;
-
- List<BlazeLibrary> libraries = Lists.newArrayList();
- libraries.addAll(syncData.importResult.libraries.values());
- for (BlazeJavaSyncAugmenter syncAugmenter : BlazeJavaSyncAugmenter.EP_NAME.getExtensions()) {
- libraries.addAll(syncAugmenter.getAdditionalLibraries(blazeProjectData));
- }
- return libraries
- .stream()
- .filter(blazeLibrary -> !isExcluded(excludedLibraries, blazeLibrary.getLibraryArtifact()))
- .collect(Collectors.toList());
- }
-
- private static boolean isExcluded(Glob.GlobSet excludedLibraries, @Nullable LibraryArtifact libraryArtifact) {
- if (libraryArtifact == null) {
- return false;
- }
- ArtifactLocation jar = libraryArtifact.jar;
- ArtifactLocation runtimeJar = libraryArtifact.runtimeJar;
- return excludedLibraries.matches(jar.getRelativePath())
- || (runtimeJar != null && excludedLibraries.matches(runtimeJar.getRelativePath()));
- }
-
- private static void updateJdk(
- Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
-
- LanguageLevel javaLanguageLevel = JavaLanguageLevelHelper
- .getJavaLanguageLevel(projectViewSet, blazeProjectData, LanguageLevel.JDK_1_7);
-
- final Sdk sdk = Jdks.chooseOrCreateJavaSdk(javaLanguageLevel);
- if (sdk == null) {
- String msg = String.format(
- "Unable to find a JDK %1$s installed.\n", javaLanguageLevel.getPresentableText());
- msg += "After configuring a suitable JDK in the \"Project Structure\" dialog, "
- + "sync the project again.";
- IssueOutput.error(msg).submit(context);
- return;
- }
- setProjectSdkAndLanguageLevel(project, sdk, javaLanguageLevel);
- }
-
- private static void setProjectSdkAndLanguageLevel(
- final Project project,
- final Sdk sdk,
- final LanguageLevel javaLanguageLevel) {
- UIUtil.invokeAndWaitIfNeeded((Runnable)() -> ApplicationManager.getApplication().runWriteAction(() -> {
- ProjectRootManagerEx rootManager = ProjectRootManagerEx.getInstanceEx(project);
- rootManager.setProjectSdk(sdk);
- LanguageLevelProjectExtension ext = LanguageLevelProjectExtension.getInstance(project);
- ext.setLanguageLevel(javaLanguageLevel);
- }));
- }
-
- @Override
- public boolean validate(Project project,
- BlazeContext context,
- BlazeProjectData blazeProjectData) {
- BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
- if (syncData == null) {
- return true;
- }
- warnAboutDeployJars(context, syncData);
- return true;
- }
-
- @Override
- public Collection<SectionParser> getSections() {
- return ImmutableList.of(
- ExcludedLibrarySection.PARSER,
- ExcludeLibrarySection.PARSER,
- JavaLanguageLevelSection.PARSER
- );
- }
-
- @Override
- public boolean requiresResolveIdeArtifacts() {
- return true;
- }
-
- /**
- * Looks at your jars for anything that seems to be a deploy jar and
- * warns about it. This often turns out to be a duplicate copy of
- * all your application's code, so you don't want it in your project.
- */
- private static void warnAboutDeployJars(
- BlazeContext context,
- BlazeJavaSyncData syncData) {
- for (BlazeLibrary library : syncData.importResult.libraries.values()) {
- LibraryArtifact libraryArtifact = library.getLibraryArtifact();
- if (libraryArtifact == null) {
- continue;
- }
- ArtifactLocation artifactLocation = libraryArtifact.jar;
- if (artifactLocation.getRelativePath().endsWith("deploy.jar")
- || artifactLocation.getRelativePath().endsWith("deploy-ijar.jar")
- || artifactLocation.getRelativePath().endsWith("deploy-hjar.jar")) {
- context.output(new PerformanceWarning(
- "Performance warning: You have added a deploy jar as a library. "
- + "This can lead to poor indexing performance, and the debugger may "
- + "become confused and step into the deploy jar instead of your code. "
- + "Consider redoing the rule to not use deploy jars, exclude the target "
- + "from your .blazeproject, or exclude the library.\n"
- + "Library path: " + artifactLocation.getRelativePath()
- ));
- }
- }
- }
-
- @Override
- public Set<String> prefetchSrcFileExtensions() {
- return ImmutableSet.of("java");
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java b/blaze-java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
deleted file mode 100644
index 1120f41..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync;
-
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Multimap;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.PerformanceWarning;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Detects and reports duplicate sources
- */
-public class DuplicateSourceDetector {
- Multimap<ArtifactLocation, Label> artifacts = ArrayListMultimap.create();
-
- public void add(Label label, ArtifactLocation artifactLocation) {
- artifacts.put(artifactLocation, label);
- }
-
- static class Duplicate {
- final ArtifactLocation artifactLocation;
- final Collection<Label> labels;
- public Duplicate(ArtifactLocation artifactLocation, Collection<Label> labels) {
- this.artifactLocation = artifactLocation;
- this.labels = labels;
- }
- }
-
- public void reportDuplicates(BlazeContext context) {
- List<Duplicate> duplicates = Lists.newArrayList();
- for (ArtifactLocation key : artifacts.keySet()) {
- Collection<Label> labels = artifacts.get(key);
- if (labels.size() > 1) {
-
- // Workaround for aspect bug. Can be removed after the next blaze release, as of May 27 2016
- Set<Label> labelSet = Sets.newHashSet(labels);
- if (labelSet.size() > 1) {
- duplicates.add(new Duplicate(key, labelSet));
- }
- }
- }
-
- if (duplicates.isEmpty()) {
- return;
- }
-
- Collections.sort(duplicates, (lhs, rhs) -> lhs.artifactLocation.getRelativePath().compareTo(rhs.artifactLocation.getRelativePath()));
-
- context.output(new PerformanceWarning("Duplicate sources detected:"));
- for (Duplicate duplicate : duplicates) {
- ArtifactLocation artifactLocation = duplicate.artifactLocation;
- context.output(new PerformanceWarning(" Source: " + artifactLocation.getRelativePath()));
- context.output(new PerformanceWarning(" Consumed by rules:"));
- for (Label label : duplicate.labels) {
- context.output(new PerformanceWarning(" " + label));
- }
- context.output(new PerformanceWarning("")); // Newline
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/JavaLanguageLevelHelper.java b/blaze-java/src/com/google/idea/blaze/java/sync/JavaLanguageLevelHelper.java
deleted file mode 100644
index 8f6bfe4..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/JavaLanguageLevelHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync;
-
-import com.google.common.base.Strings;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.java.projectview.JavaLanguageLevelSection;
-import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.intellij.pom.java.LanguageLevel;
-
-/**
- * Called by sync plugins to determine the appropriate java language level.
- */
-public class JavaLanguageLevelHelper {
-
- public static LanguageLevel getJavaLanguageLevel(
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- LanguageLevel defaultLanguageLevel) {
-
- defaultLanguageLevel = getLanguageLevelFromToolchain(blazeProjectData, defaultLanguageLevel);
- return JavaLanguageLevelSection.getLanguageLevel(projectViewSet, defaultLanguageLevel);
- }
-
- private static LanguageLevel getLanguageLevelFromToolchain(BlazeProjectData blazeProjectData, LanguageLevel defaultLanguageLevel) {
- BlazeJavaSyncData blazeJavaSyncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
- if (blazeJavaSyncData != null) {
- String sourceVersion = blazeJavaSyncData.importResult.sourceVersion;
- if (!Strings.isNullOrEmpty(sourceVersion)) {
- switch (sourceVersion) {
- case "6":
- return LanguageLevel.JDK_1_6;
- case "7":
- return LanguageLevel.JDK_1_7;
- case "8":
- return LanguageLevel.JDK_1_8;
- case "9":
- return LanguageLevel.JDK_1_9;
- }
- }
- }
- return defaultLanguageLevel;
- }
-
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java b/blaze-java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java
deleted file mode 100644
index 9868352..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.importer;
-
-import com.google.common.collect.*;
-import com.google.idea.blaze.base.ideinfo.*;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.projectview.ImportRoots;
-import com.google.idea.blaze.base.sync.projectview.ProjectViewRuleImportFilter;
-import com.google.idea.blaze.base.sync.projectview.SourceTestConfig;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.java.sync.DuplicateSourceDetector;
-import com.google.idea.blaze.java.sync.jdeps.JdepsMap;
-import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
-import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-import com.google.idea.blaze.java.sync.source.SourceArtifact;
-import com.google.idea.blaze.java.sync.source.SourceDirectoryCalculator;
-import com.google.idea.blaze.java.sync.workingset.JavaWorkingSet;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Builds a BlazeWorkspace.
- */
-public final class BlazeJavaWorkspaceImporter {
- private static final Logger LOG = Logger.getInstance(BlazeJavaWorkspaceImporter.class);
-
- private final Project project;
- private final WorkspaceRoot workspaceRoot;
- private final ImportRoots importRoots;
- private final ImmutableMap<Label, RuleIdeInfo> ruleMap;
- private final SourceTestConfig sourceTestConfig;
- private final JdepsMap jdepsMap;
- @Nullable private final JavaWorkingSet workingSet;
- private final ArtifactLocationDecoder artifactLocationDecoder;
- private final ProjectViewRuleImportFilter importFilter;
- private final DuplicateSourceDetector duplicateSourceDetector = new DuplicateSourceDetector();
-
- public BlazeJavaWorkspaceImporter(
- Project project,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- JdepsMap jdepsMap,
- @Nullable JavaWorkingSet workingSet,
- ArtifactLocationDecoder artifactLocationDecoder) {
- this.project = project;
- this.workspaceRoot = workspaceRoot;
- this.importRoots = ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
- .add(projectViewSet)
- .build();
- this.ruleMap = ruleMap;
- this.jdepsMap = jdepsMap;
- this.workingSet = workingSet;
- this.artifactLocationDecoder = artifactLocationDecoder;
- this.importFilter = new ProjectViewRuleImportFilter(project, workspaceRoot, projectViewSet);
- this.sourceTestConfig = new SourceTestConfig(projectViewSet);
- }
-
- public BlazeJavaImportResult importWorkspace(BlazeContext context) {
- List<RuleIdeInfo> includedRules = ruleMap.values().stream()
- .filter(rule -> !importFilter.excludeTarget(rule))
- .collect(Collectors.toList());
-
- List<RuleIdeInfo> javaRules = includedRules.stream()
- .filter(rule -> rule.javaRuleIdeInfo != null)
- .collect(Collectors.toList());
-
- List<RuleIdeInfo> sourceRules = Lists.newArrayList();
- List<RuleIdeInfo> libraryRules = Lists.newArrayList();
- for (RuleIdeInfo rule : javaRules) {
- boolean importAsSource =
- importFilter.isSourceRule(rule)
- && canImportAsSource(rule)
- && !allSourcesGenerated(rule);
-
- if (importAsSource) {
- sourceRules.add(rule);
- } else {
- libraryRules.add(rule);
- }
- }
-
- List<RuleIdeInfo> protoLibraries = includedRules.stream()
- .filter(rule -> rule.kind == Kind.PROTO_LIBRARY)
- .collect(Collectors.toList());
-
- WorkspaceBuilder workspaceBuilder = new WorkspaceBuilder();
- for (RuleIdeInfo rule : sourceRules) {
- addRuleAsSource(workspaceBuilder, rule);
- }
-
- SourceDirectoryCalculator sourceDirectoryCalculator = new SourceDirectoryCalculator();
- ImmutableList<BlazeContentEntry> contentEntries = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- sourceTestConfig,
- artifactLocationDecoder,
- importRoots.rootDirectories(),
- workspaceBuilder.sourceArtifacts,
- workspaceBuilder.javaPackageManifests
- );
-
- int totalContentEntryCount = 0;
- for (BlazeContentEntry contentEntry : contentEntries) {
- totalContentEntryCount += contentEntry.sources.size();
- }
- context.output(PrintOutput.output("Java content entry count: " + totalContentEntryCount));
-
- ImmutableMap<LibraryKey, BlazeLibrary> libraries = buildLibraries(workspaceBuilder, ruleMap, libraryRules, protoLibraries);
-
- duplicateSourceDetector.reportDuplicates(context);
-
- String sourceVersion = findSourceVersion(ruleMap);
-
- return new BlazeJavaImportResult(
- contentEntries,
- libraries,
- ImmutableList.copyOf(workspaceBuilder.buildOutputJars
- .stream()
- .sorted()
- .collect(Collectors.toList())),
- ImmutableSet.copyOf(workspaceBuilder.addedSourceFiles),
- sourceVersion
- );
- }
-
- private boolean canImportAsSource(RuleIdeInfo rule) {
- return !rule.kindIsOneOf(Kind.JAVA_WRAP_CC, Kind.JAVA_IMPORT);
- }
-
- private boolean allSourcesGenerated(RuleIdeInfo rule) {
- return !rule.sources.isEmpty() && rule.sources.stream().allMatch(ArtifactLocation::isGenerated);
- }
-
- private ImmutableMap<LibraryKey, BlazeLibrary> buildLibraries(WorkspaceBuilder workspaceBuilder,
- Map<Label, RuleIdeInfo> ruleMap,
- List<RuleIdeInfo> libraryRules,
- List<RuleIdeInfo> protoLibraries) {
- // Build library maps
- Multimap<Label, LibraryArtifact> labelToLibrary = ArrayListMultimap.create();
- Map<String, LibraryArtifact> jdepsPathToLibrary = Maps.newHashMap();
- for (RuleIdeInfo rule : libraryRules) {
- JavaRuleIdeInfo javaRuleIdeInfo = rule.javaRuleIdeInfo;
- if (javaRuleIdeInfo == null) {
- continue;
- }
- Iterable<LibraryArtifact> libraries = Iterables.concat(javaRuleIdeInfo.jars, javaRuleIdeInfo.generatedJars);
- labelToLibrary.putAll(rule.label, libraries);
- for (LibraryArtifact libraryArtifact : libraries) {
- addLibraryToJdeps(jdepsPathToLibrary, libraryArtifact);
- }
- }
-
- // proto legacy jdeps support
- for (RuleIdeInfo rule : protoLibraries) {
- ProtoLibraryLegacyInfo protoLibraryLegacyInfo = rule.protoLibraryLegacyInfo;
- if (protoLibraryLegacyInfo == null) {
- continue;
- }
- for (LibraryArtifact libraryArtifact : Iterables.concat(protoLibraryLegacyInfo.jarsV1,
- protoLibraryLegacyInfo.jarsMutable,
- protoLibraryLegacyInfo.jarsImmutable)) {
- addLibraryToJdeps(jdepsPathToLibrary, libraryArtifact);
- }
- }
-
- // Collect jars from jdep references
- Set<LibraryArtifact> libraries = Sets.newHashSet();
- for (String jdepsPath : workspaceBuilder.jdeps) {
- LibraryArtifact libraryArtifact = jdepsPathToLibrary.get(jdepsPath);
- if (libraryArtifact != null) {
- libraries.add(libraryArtifact);
- }
- }
-
- // Collect jars referenced by direct deps from your working set
- for (Label deps : workspaceBuilder.directDeps) {
- libraries.addAll(labelToLibrary.get(deps));
- }
-
- // Collect legacy proto libraries from direct deps
- addProtoLegacyLibrariesFromDirectDeps(workspaceBuilder, ruleMap, libraries);
-
- // Collect generated jars from source rules
- libraries.addAll(workspaceBuilder.generatedJars);
-
- ImmutableMap.Builder<LibraryKey, BlazeLibrary> result = ImmutableMap.builder();
- for (LibraryArtifact libraryArtifact : libraries) {
- File jar = libraryArtifact.jar.getFile();
- LibraryKey key = LibraryKey.fromJarFile(jar);
- BlazeLibrary blazeLibrary = new BlazeLibrary(key, libraryArtifact);
- result.put(key, blazeLibrary);
- }
- return result.build();
- }
-
- private void addProtoLegacyLibrariesFromDirectDeps(WorkspaceBuilder workspaceBuilder,
- Map<Label, RuleIdeInfo> ruleMap,
- Set<LibraryArtifact> result) {
- List<Label> version1Roots = Lists.newArrayList();
- List<Label> immutableRoots = Lists.newArrayList();
- List<Label> mutableRoots = Lists.newArrayList();
- for (Label label : workspaceBuilder.directDeps) {
- RuleIdeInfo rule = ruleMap.get(label);
- if (rule == null) {
- continue;
- }
- ProtoLibraryLegacyInfo protoLibraryLegacyInfo = rule.protoLibraryLegacyInfo;
- if (protoLibraryLegacyInfo == null) {
- continue;
- }
- switch (protoLibraryLegacyInfo.apiFlavor) {
- case VERSION_1:
- version1Roots.add(label);
- break;
- case IMMUTABLE:
- immutableRoots.add(label);
- break;
- case MUTABLE:
- mutableRoots.add(label);
- break;
- case BOTH:
- mutableRoots.add(label);
- immutableRoots.add(label);
- break;
- default:
- // Can't happen
- break;
- }
- }
-
- addProtoLegacyLibrariesFromDirectDepsForFlavor(ruleMap, ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1, version1Roots, result);
- addProtoLegacyLibrariesFromDirectDepsForFlavor(ruleMap, ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE, immutableRoots, result);
- addProtoLegacyLibrariesFromDirectDepsForFlavor(ruleMap, ProtoLibraryLegacyInfo.ApiFlavor.MUTABLE, mutableRoots, result);
- }
-
- private void addProtoLegacyLibrariesFromDirectDepsForFlavor(Map<Label, RuleIdeInfo> ruleMap,
- ProtoLibraryLegacyInfo.ApiFlavor apiFlavor,
- List<Label> roots,
- Set<LibraryArtifact> result) {
- Set<Label> seen = Sets.newHashSet();
- while (!roots.isEmpty()) {
- Label label = roots.remove(roots.size() - 1);
- if (!seen.add(label)) {
- continue;
- }
- RuleIdeInfo rule = ruleMap.get(label);
- if (rule == null) {
- continue;
- }
- ProtoLibraryLegacyInfo protoLibraryLegacyInfo = rule.protoLibraryLegacyInfo;
- if (protoLibraryLegacyInfo == null) {
- continue;
- }
- switch (apiFlavor) {
- case VERSION_1:
- result.addAll(protoLibraryLegacyInfo.jarsV1);
- break;
- case MUTABLE:
- result.addAll(protoLibraryLegacyInfo.jarsMutable);
- break;
- case IMMUTABLE:
- result.addAll(protoLibraryLegacyInfo.jarsImmutable);
- break;
- default:
- // Can't happen
- break;
- }
-
- roots.addAll(rule.dependencies);
- }
- }
-
- private void addLibraryToJdeps(Map<String, LibraryArtifact> jdepsPathToLibrary, LibraryArtifact libraryArtifact) {
- ArtifactLocation jar = libraryArtifact.jar;
- jdepsPathToLibrary.put(jar.getExecutionRootRelativePath(), libraryArtifact);
- ArtifactLocation runtimeJar = libraryArtifact.runtimeJar;
- if (runtimeJar != null) {
- jdepsPathToLibrary.put(runtimeJar.getExecutionRootRelativePath(), libraryArtifact);
- }
- }
-
- private void addRuleAsSource(
- WorkspaceBuilder workspaceBuilder,
- RuleIdeInfo rule) {
- JavaRuleIdeInfo javaRuleIdeInfo = rule.javaRuleIdeInfo;
- if (javaRuleIdeInfo == null) {
- return;
- }
-
- Collection<String> jars = jdepsMap.getDependenciesForRule(rule.label);
- if (jars != null) {
- workspaceBuilder.jdeps.addAll(jars);
- }
-
- // Add all deps if this rule is in the current working set
- if (workingSet == null || workingSet.isRuleInWorkingSet(rule)) {
- workspaceBuilder.directDeps.addAll(rule.dependencies);
- }
-
- for (ArtifactLocation artifactLocation : rule.sources) {
- if (!artifactLocation.isGenerated()) {
- duplicateSourceDetector.add(rule.label, artifactLocation);
- workspaceBuilder.sourceArtifacts.add(new SourceArtifact(rule.label, artifactLocation));
- workspaceBuilder.addedSourceFiles.add(artifactLocation.getFile());
- }
- }
-
- ArtifactLocation manifest = javaRuleIdeInfo.packageManifest;
- if (manifest != null) {
- workspaceBuilder.javaPackageManifests.put(rule.label, manifest);
- }
- for (LibraryArtifact libraryArtifact : javaRuleIdeInfo.jars) {
- ArtifactLocation runtimeJar = libraryArtifact.runtimeJar;
- if (runtimeJar != null) {
- workspaceBuilder.buildOutputJars.add(runtimeJar.getFile());
- }
- }
- workspaceBuilder.generatedJars.addAll(javaRuleIdeInfo.generatedJars);
- }
-
- @Nullable
- private String findSourceVersion(ImmutableMap<Label, RuleIdeInfo> ruleMap) {
- for (RuleIdeInfo rule : ruleMap.values()) {
- if (rule.javaToolchainIdeInfo != null) {
- return rule.javaToolchainIdeInfo.sourceVersion;
- }
- }
- return null;
- }
-
- static class WorkspaceBuilder {
- Set<String> jdeps = Sets.newHashSet();
- Set<Label> directDeps = Sets.newHashSet();
- Set<File> addedSourceFiles = Sets.newHashSet();
- List<LibraryArtifact> generatedJars = Lists.newArrayList();
- List<File> buildOutputJars = Lists.newArrayList();
- List<SourceArtifact> sourceArtifacts = Lists.newArrayList();
- Map<Label, ArtifactLocation> javaPackageManifests = Maps.newHashMap();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/importer/LibraryBuilder.java b/blaze-java/src/com/google/idea/blaze/java/sync/importer/LibraryBuilder.java
deleted file mode 100644
index 0d660f5..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/importer/LibraryBuilder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.importer;
-
-import com.google.common.collect.*;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Manages libraries during the module import stage.
- */
-public class LibraryBuilder {
-
- private final Map<LibraryKey, BlazeLibrary> libraries = Maps.newHashMap();
- private final Multimap<Label, LibraryKey> labelToLibraryKeys = ArrayListMultimap.create();
- private final Map<String, LibraryKey> jdepsPathToLibraryKey = Maps.newHashMap();
- private final Set<LibraryKey> referencedLibraryKeys = Sets.newHashSet();
-
- void createLibraryForRule(Label label, LibraryArtifact libraryArtifact) {
- LibraryKey libraryKey = createLibrary(libraryArtifact);
- labelToLibraryKeys.put(label, libraryKey);
- }
-
- public void createLibraryForModule(LibraryArtifact libraryArtifact) {
- LibraryKey libraryKey = createLibrary(libraryArtifact);
- referencedLibraryKeys.add(libraryKey);
- }
-
- void referenceLibraryFromModule(Label label) {
- Collection<LibraryKey> libraryKeys = labelToLibraryKeys.get(label);
- referencedLibraryKeys.addAll(libraryKeys);
- }
-
- void referenceLibraryFromModule(String jdepsPath) {
- LibraryKey libraryKey = jdepsPathToLibraryKey.get(jdepsPath);
- if (libraryKey != null) {
- referencedLibraryKeys.add(libraryKey);
- }
- }
-
- private LibraryKey createLibrary(LibraryArtifact libraryArtifact) {
- File jar = libraryArtifact.jar.getFile();
- LibraryKey key = LibraryKey.fromJarFile(jar);
- BlazeLibrary library = new BlazeLibrary(key, libraryArtifact);
- addLibrary(key, library);
- return key;
- }
-
- private void addLibrary(LibraryKey key,
- BlazeLibrary library) {
- BlazeLibrary existingLibrary = libraries.putIfAbsent(key, library);
- existingLibrary = existingLibrary != null ? existingLibrary : library;
-
- LibraryArtifact libraryArtifact = existingLibrary.getLibraryArtifact();
-
- // Index the library by jar for jdeps support
- if (libraryArtifact != null) {
- ArtifactLocation jar = libraryArtifact.jar;
- jdepsPathToLibraryKey.put(jar.getExecutionRootRelativePath(), key);
-
- ArtifactLocation runtimeJar = libraryArtifact.runtimeJar;
- if (runtimeJar != null) {
- jdepsPathToLibraryKey.put(runtimeJar.getExecutionRootRelativePath(), key);
- }
- }
- }
-
- ImmutableMap<LibraryKey, BlazeLibrary> build() {
- ImmutableMap.Builder<LibraryKey, BlazeLibrary> result = ImmutableMap.builder();
- for (LibraryKey libraryKey : referencedLibraryKeys) {
- result.put(libraryKey, libraries.get(libraryKey));
- }
- return result.build();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/jdeps/JdepsFileReader.java b/blaze-java/src/com/google/idea/blaze/java/sync/jdeps/JdepsFileReader.java
deleted file mode 100644
index c7e1333..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/jdeps/JdepsFileReader.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.jdeps;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.async.FutureUtil;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.prefetch.PrefetchService;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.sync.filediff.FileDiffService;
-import com.google.repackaged.devtools.build.lib.view.proto.Deps;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import java.io.*;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Reads jdeps from the ide info result.
- */
-public class JdepsFileReader {
- private static final Logger LOG = Logger.getInstance(JdepsFileReader.class);
- private final FileDiffService fileDiffService = new FileDiffService();
-
- static class JdepsState implements Serializable {
- private static final long serialVersionUID = 2L;
- private FileDiffService.State fileState = null;
- private Map<File, Label> fileToLabelMap = Maps.newHashMap();
- private Map<Label, List<String>> labelToJdeps = Maps.newHashMap();
- }
-
- private static class Result {
- File file;
- Label label;
- List<String> dependencies;
- public Result(File file, Label label, List<String> dependencies) {
- this.file = file;
- this.label = label;
- this.dependencies = dependencies;
- }
- }
-
- /**
- * Loads any updated jdeps files since the last invocation of this method.
- */
- @Nullable
- public JdepsMap loadJdepsFiles(BlazeContext parentContext,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
- JdepsState oldState = previousSyncState != null ? previousSyncState.get(JdepsState.class) : null;
- JdepsState jdepsState = Scope.push(parentContext, (context) -> {
- context.push(new TimingScope("LoadJdepsFiles"));
- return doLoadJdepsFiles(context, oldState, ruleMap);
- });
- if (jdepsState == null) {
- return null;
- }
- syncStateBuilder.put(JdepsState.class, jdepsState);
- return label -> jdepsState.labelToJdeps.get(label);
- }
-
- private JdepsState doLoadJdepsFiles(BlazeContext context,
- @Nullable JdepsState oldState,
- ImmutableMap<Label, RuleIdeInfo> ruleMap) {
- JdepsState state = new JdepsState();
- if (oldState != null) {
- state.labelToJdeps = Maps.newHashMap(oldState.labelToJdeps);
- state.fileToLabelMap = Maps.newHashMap(oldState.fileToLabelMap);
- }
-
- List<File> files = Lists.newArrayList();
- for (RuleIdeInfo ruleIdeInfo : ruleMap.values()) {
- JavaRuleIdeInfo javaRuleIdeInfo = ruleIdeInfo.javaRuleIdeInfo;
- if (javaRuleIdeInfo != null) {
- ArtifactLocation jdepsFile = javaRuleIdeInfo.jdepsFile;
- if (jdepsFile != null) {
- files.add(jdepsFile.getFile());
- }
- }
- }
-
- List<File> updatedFiles = Lists.newArrayList();
- List<File> removedFiles = Lists.newArrayList();
- state.fileState = fileDiffService.updateFiles(oldState != null ? oldState.fileState : null, files, updatedFiles, removedFiles);
-
- ListenableFuture<?> fetchFuture = PrefetchService.getInstance().prefetchFiles(updatedFiles, true);
- if (!FutureUtil.waitForFuture(context, fetchFuture)
- .timed("FetchJdeps")
- .run()
- .success()) {
- return null;
- }
-
- for (File removedFile : removedFiles) {
- Label label = state.fileToLabelMap.remove(removedFile);
- if (label != null) {
- state.labelToJdeps.remove(label);
- }
- }
-
- AtomicLong totalSizeLoaded = new AtomicLong(0);
-
- List<ListenableFuture<Result>> futures = Lists.newArrayList();
- for (File updatedFile : updatedFiles) {
- futures.add(submit(() -> {
- totalSizeLoaded.addAndGet(updatedFile.length());
- try (InputStream inputStream = new FileInputStream(updatedFile)){
- Deps.Dependencies dependencies = Deps.Dependencies.parseFrom(inputStream);
- if (dependencies != null) {
- if (dependencies.hasRuleLabel()) {
- Label label = new Label(dependencies.getRuleLabel());
- List<String> dependencyStringList = Lists.newArrayList();
- for (Deps.Dependency dependency : dependencies.getDependencyList()) {
- dependencyStringList.add(dependency.getPath());
- }
- return new Result(updatedFile, label, dependencyStringList);
- }
- }
- } catch (FileNotFoundException e) {
- LOG.info("Could not open jdeps file: " + updatedFile);
- }
- return null;
- }));
- }
- try {
- for (Result result : Futures.allAsList(futures).get()) {
- if (result != null) {
- state.fileToLabelMap.put(result.file, result.label);
- state.labelToJdeps.put(result.label, result.dependencies);
- }
- }
- context.output(new PrintOutput(String.format(
- "Loaded %d jdeps files, total size %dkB", updatedFiles.size(), totalSizeLoaded.get() / 1024
- )));
- }
- catch (InterruptedException | ExecutionException e) {
- LOG.error(e);
- return null;
- }
- return state;
- }
-
- private static <T> ListenableFuture<T> submit(Callable<T> callable) {
- return BlazeExecutor.getInstance().submit(callable);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java b/blaze-java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java
deleted file mode 100644
index 9d7b301..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.jdeps;
-
-import com.google.idea.blaze.base.model.primitives.Label;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
-/**
- * Map of rule -> jdeps dependencies.
- */
-public interface JdepsMap {
- /**
- * For a given rule, returns workspace root relative paths of artifacts that
- * were used during compilation.
- *
- * It's not specified whether jars or ijars are used during compilation.
- *
- * If the rule doesn't have source or otherwise wasn't instrumented,
- * null is returned.
- */
- @Nullable
- List<String> getDependenciesForRule(@NotNull Label label);
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeContentEntry.java b/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeContentEntry.java
deleted file mode 100644
index ebb4d70..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeContentEntry.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.model;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Corresponds to an IntelliJ content entry.
- */
-@Immutable
-public class BlazeContentEntry implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public final File contentRoot;
- public final ImmutableList<BlazeSourceDirectory> sources;
-
- public BlazeContentEntry(File contentRoot,
- ImmutableList<BlazeSourceDirectory> sources) {
- this.contentRoot = contentRoot;
- this.sources = sources;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- BlazeContentEntry that = (BlazeContentEntry)o;
- return Objects.equal(contentRoot, that.contentRoot) &&
- Objects.equal(sources, that.sources);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(contentRoot, sources);
- }
-
- @Override
- public String toString() {
- return "BlazeContentEntry {\n"
- + " contentRoot: " + contentRoot + "\n"
- + " sources: " + sources + "\n"
- + '}';
- }
-
- public static Builder builder(String contentRoot) {
- return new Builder(new File(contentRoot));
- }
-
- public static Builder builder(File contentRoot) {
- return new Builder(contentRoot);
- }
-
- public static class Builder {
- File contentRoot;
- List<BlazeSourceDirectory> sources = Lists.newArrayList();
- public Builder(File contentRoot) {
- this.contentRoot = contentRoot;
- }
- public Builder addSource(BlazeSourceDirectory sourceDirectory) {
- this.sources.add(sourceDirectory);
- return this;
- }
- public BlazeContentEntry build() {
- Collections.sort(sources, BlazeSourceDirectory.COMPARATOR);
- return new BlazeContentEntry(contentRoot, ImmutableList.copyOf(sources));
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeJavaImportResult.java b/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeJavaImportResult.java
deleted file mode 100644
index ac43b94..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeJavaImportResult.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.model;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.Immutable;
-import java.io.File;
-import java.io.Serializable;
-
-/**
- * The result of a blaze import operation.
- */
-@Immutable
-public class BlazeJavaImportResult implements Serializable {
- private static final long serialVersionUID = 3L;
-
- public final ImmutableList<BlazeContentEntry> contentEntries;
- public final ImmutableMap<LibraryKey, BlazeLibrary> libraries;
- public final ImmutableCollection<File> buildOutputJars;
- public final ImmutableSet<File> javaSourceFiles;
- @Nullable public final String sourceVersion;
-
- public BlazeJavaImportResult(ImmutableList<BlazeContentEntry> contentEntries,
- ImmutableMap<LibraryKey, BlazeLibrary> libraries,
- ImmutableCollection<File> buildOutputJars,
- ImmutableSet<File> javaSourceFiles,
- @Nullable String sourceVersion) {
- this.contentEntries = contentEntries;
- this.libraries = libraries;
- this.buildOutputJars = buildOutputJars;
- this.javaSourceFiles = javaSourceFiles;
- this.sourceVersion = sourceVersion;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeJavaSyncData.java b/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeJavaSyncData.java
deleted file mode 100644
index 44367b9..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeJavaSyncData.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.model;
-
-import com.google.idea.blaze.base.projectview.section.Glob;
-
-import java.io.Serializable;
-
-/**
- * Sync data for the java plugin.
- */
-public class BlazeJavaSyncData implements Serializable {
- private static final long serialVersionUID = 2L;
-
- public final BlazeJavaImportResult importResult;
- public final Glob.GlobSet excludedLibraries;
- public final boolean attachSourceJarsByDefault;
-
- public BlazeJavaSyncData(BlazeJavaImportResult importResult,
- Glob.GlobSet excludedLibraries,
- boolean attachSourceJarsByDefault) {
- this.importResult = importResult;
- this.excludedLibraries = excludedLibraries;
- this.attachSourceJarsByDefault = attachSourceJarsByDefault;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeLibrary.java b/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeLibrary.java
deleted file mode 100644
index a656a1b..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeLibrary.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.model;
-
-import com.google.common.base.Objects;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.Collection;
-
-/**
- * An immutable reference to a .jar required by a rule. This class supports value semantics when
- * used as a key to a hash map.
- */
-@Immutable
-public final class BlazeLibrary implements Serializable {
- private static final long serialVersionUID = 6L;
-
- @NotNull
- private final LibraryKey key;
-
- @Nullable
- private final LibraryArtifact libraryArtifact;
-
- @Nullable
- private final Collection<File> sources;
-
- public BlazeLibrary(
- @NotNull LibraryKey key,
- @NotNull LibraryArtifact libraryArtifact) {
- this(key, libraryArtifact, null);
- }
-
- public BlazeLibrary(
- @NotNull LibraryKey key,
- @NotNull Collection<File> sources) {
- this(key, null, sources);
- }
-
- private BlazeLibrary(
- @NotNull LibraryKey key,
- @Nullable LibraryArtifact libraryArtifact,
- @Nullable Collection<File> sources) {
- this.key = key;
- this.libraryArtifact = libraryArtifact;
- this.sources = sources;
- }
-
- /**
- * Returns the library key.
- */
- @NotNull
- public LibraryKey getKey() {
- return key;
- }
-
- @Nullable
- public LibraryArtifact getLibraryArtifact() {
- return libraryArtifact;
- }
-
- @Nullable
- public Collection<File> getSources() {
- return sources;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(key, libraryArtifact, sources);
- }
-
- @Override
- public String toString() {
- return key.toString();
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof BlazeLibrary)) {
- return false;
- }
-
- BlazeLibrary that = (BlazeLibrary)other;
-
- return Objects.equal(key, that.key)
- && Objects.equal(libraryArtifact, that.libraryArtifact)
- && Objects.equal(sources, that.sources);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeSourceDirectory.java b/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeSourceDirectory.java
deleted file mode 100644
index f0b89d5..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/model/BlazeSourceDirectory.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.model;
-
-import com.google.common.base.Objects;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.Comparator;
-
-/**
- * A source directory.
- */
-@Immutable
-public final class BlazeSourceDirectory implements Serializable {
- private static final long serialVersionUID = 2L;
-
- public static final Comparator<BlazeSourceDirectory> COMPARATOR =
- (o1, o2) -> String.CASE_INSENSITIVE_ORDER.compare(
- o1.getDirectory().getPath(),
- o2.getDirectory().getPath());
-
- @NotNull
- private final File directory;
- private final boolean isTest;
- private final boolean isGenerated;
- private final boolean isResource;
- @NotNull
- private final String packagePrefix;
-
- public static class Builder {
- @NotNull private final File directory;
- @NotNull private String packagePrefix = "";
- private boolean isTest;
- private boolean isResource;
- private boolean isGenerated;
-
- private Builder(@NotNull File directory) {
- this.directory = directory;
- }
- public Builder setPackagePrefix(@NotNull String packagePrefix) {
- this.packagePrefix = packagePrefix;
- return this;
- }
- public Builder setTest(boolean isTest) {
- this.isTest = isTest;
- return this;
- }
- public Builder setResource(boolean isResource) {
- this.isResource = isResource;
- return this;
- }
- public Builder setGenerated(boolean isGenerated) {
- this.isGenerated = isGenerated;
- return this;
- }
-
- public BlazeSourceDirectory build() {
- return new BlazeSourceDirectory(directory, isTest, isResource, isGenerated, packagePrefix);
- }
- }
-
- @NotNull
- public static Builder builder(@NotNull String directory) {
- return new Builder(new File(directory));
- }
-
- @NotNull
- public static Builder builder(@NotNull File directory) {
- return new Builder(directory);
- }
-
- private BlazeSourceDirectory(
- @NotNull File directory,
- boolean isTest,
- boolean isResource,
- boolean isGenerated,
- @NotNull String packagePrefix) {
- this.directory = directory;
- this.isTest = isTest;
- this.isResource = isResource;
- this.isGenerated = isGenerated;
- this.packagePrefix = packagePrefix;
- }
-
- /**
- * Returns the full path name of the root of a source directory.
- */
- @NotNull
- public File getDirectory() {
- return directory;
- }
-
- /**
- * Returns {@code true} if the directory contains test sources.
- */
- public boolean getIsTest() {
- return isTest;
- }
-
- /**
- * Returns {@code true} if the directory contains resources.
- */
- public boolean getIsResource() {
- return isResource;
- }
-
- /**
- * Returns {@code true} if the directory contains generated files.
- */
- public boolean getIsGenerated() {
- return isGenerated;
- }
-
- /**
- * Returns the package prefix for the directory. If the directory is a source root, such as a
- * "src" directory, then this returns an empty string.
- */
- @NotNull
- public String getPackagePrefix() {
- return packagePrefix;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(
- directory,
- isTest,
- isResource,
- packagePrefix,
- isGenerated);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof BlazeSourceDirectory)) {
- return false;
- }
- BlazeSourceDirectory that = (BlazeSourceDirectory)other;
- return directory.equals(that.directory)
- && packagePrefix.equals(that.packagePrefix)
- && isResource == that.isResource
- && isTest == that.isTest
- && isGenerated == that.isGenerated;
- }
-
- @Override
- public String toString() {
- return "BlazeSourceDirectory {\n"
- + " directory: " + directory + "\n"
- + " isTest: " + isTest + "\n"
- + " isGenerated: " + isGenerated + "\n"
- + " isResource: " + isResource + "\n"
- + " packagePrefix: " + packagePrefix + "\n"
- + '}';
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/model/LibraryKey.java b/blaze-java/src/com/google/idea/blaze/java/sync/model/LibraryKey.java
deleted file mode 100644
index 1ab31b5..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/model/LibraryKey.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.model;
-
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.util.io.FileUtil;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.File;
-import java.io.Serializable;
-import java.util.Comparator;
-
-/**
- * Uniquely identifies a library as imported into IntellJ.
- */
-@Immutable
-public final class LibraryKey implements Serializable {
- public static final long serialVersionUID = 1L;
-
- public static final Comparator<LibraryKey> COMPARATOR = new Comparator<LibraryKey>() {
- @Override
- public int compare(LibraryKey o1, LibraryKey o2) {
- return String.CASE_INSENSITIVE_ORDER.compare(o1.name, o2.name);
- }
- };
-
- @NotNull
- private final String name;
-
- @NotNull
- public static LibraryKey fromJarFile(@NotNull File jarFile) {
- int parentHash = jarFile.getParent().hashCode();
- String name = FileUtil.getNameWithoutExtension(jarFile) + "_" + Integer.toHexString(parentHash);
- return new LibraryKey(name);
- }
-
- @NotNull
- public static LibraryKey forResourceLibrary() {
- return new LibraryKey("external_resources_library");
- }
-
- @NotNull
- public static LibraryKey fromIntelliJLibrary(@NotNull Library library) {
- String name = library.getName();
- if (name == null) {
- throw new IllegalArgumentException("Null library name");
- }
- return fromIntelliJLibraryName(name);
- }
-
- @NotNull
- public static LibraryKey fromIntelliJLibraryName(@NotNull String name) {
- return new LibraryKey(name);
- }
-
- LibraryKey(@NotNull String name) {
- this.name = name;
- }
-
- public String getIntelliJLibraryName() {
- return name;
- }
-
- @Override
- public String toString() {
- return name;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- LibraryKey that = (LibraryKey)o;
- return name.equals(that.name);
- }
-
- @Override
- public int hashCode() {
- return name.hashCode();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java b/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java
deleted file mode 100644
index c63b1dd..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.projectstructure;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.sync.sdk.DefaultSdkProvider;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.projectRoots.JavaSdk;
-import com.intellij.openapi.projectRoots.JavaSdkVersion;
-import com.intellij.openapi.projectRoots.ProjectJdkTable;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.pom.java.LanguageLevel;
-import com.intellij.util.SystemProperties;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-import static com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil.createAndAddSDK;
-import static com.intellij.openapi.util.io.FileUtil.notNullize;
-import static com.intellij.openapi.util.text.StringUtil.isNotEmpty;
-import static java.util.Collections.emptyList;
-
-/**
- * Utility methods related to IDEA JDKs.
- */
-public class Jdks {
- @NonNls
- private static final LanguageLevel DEFAULT_LANG_LEVEL = LanguageLevel.JDK_1_7;
-
- @Nullable
- public static Sdk chooseOrCreateJavaSdk(LanguageLevel langLevel) {
- for (Sdk sdk : ProjectJdkTable.getInstance().getAllJdks()) {
- if (isApplicableJdk(sdk, langLevel)) {
- return sdk;
- }
- }
- String jdkHomePath = null;
- for (DefaultSdkProvider defaultSdkProvider : DefaultSdkProvider.EP_NAME.getExtensions()) {
- File sdk = defaultSdkProvider.provideSdkForLanguage(LanguageClass.JAVA);
- if (sdk != null) {
- jdkHomePath = sdk.getPath();
- break;
- }
- }
-
- if (jdkHomePath == null) {
- jdkHomePath = getJdkHomePath(langLevel);
- }
-
- if (jdkHomePath == null) {
- return null;
- }
-
- return createJdk(jdkHomePath);
- }
-
- public static boolean isApplicableJdk(@NotNull Sdk jdk, @Nullable LanguageLevel langLevel) {
- if (!(jdk.getSdkType() instanceof JavaSdk)) {
- return false;
- }
- if (langLevel == null) {
- langLevel = DEFAULT_LANG_LEVEL;
- }
- JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk);
- if (version != null) {
- //noinspection TestOnlyProblems
- return hasMatchingLangLevel(version, langLevel);
- }
- return false;
- }
-
- @Nullable
- public static String getJdkHomePath(@NotNull LanguageLevel langLevel) {
- Collection<String> jdkHomePaths = new ArrayList<String>(JavaSdk.getInstance().suggestHomePaths());
- if (jdkHomePaths.isEmpty()) {
- return null;
- }
- // prefer jdk path of getJavaHome(), since we have to allow access to it in tests
- // see AndroidProjectDataServiceTest#testImportData()
- final List<String> list = new ArrayList<String>();
- String javaHome = SystemProperties.getJavaHome();
-
- if (javaHome != null && !javaHome.isEmpty()) {
- for (Iterator<String> it = jdkHomePaths.iterator(); it.hasNext(); ) {
- final String path = it.next();
-
- if (path != null && javaHome.startsWith(path)) {
- it.remove();
- list.add(path);
- }
- }
- }
- list.addAll(jdkHomePaths);
- return getBestJdkHomePath(list, langLevel);
-
- }
-
- @VisibleForTesting
- @Nullable
- static String getBestJdkHomePath(@NotNull Collection<String> jdkHomePaths, @NotNull LanguageLevel langLevel) {
- // Search for JDKs in both the suggest folder and all its sub folders.
- List<String> roots = Lists.newArrayList();
- for (String jdkHomePath : jdkHomePaths) {
- if (isNotEmpty(jdkHomePath)) {
- roots.add(jdkHomePath);
- roots.addAll(getChildrenPaths(jdkHomePath));
- }
- }
- return getBestJdk(roots, langLevel);
- }
-
- @NotNull
- private static List<String> getChildrenPaths(@NotNull String dirPath) {
- File dir = new File(dirPath);
- if (!dir.isDirectory()) {
- return emptyList();
- }
- List<String> childrenPaths = Lists.newArrayList();
- for (File child : notNullize(dir.listFiles())) {
- boolean directory = child.isDirectory();
- if (directory) {
- childrenPaths.add(child.getAbsolutePath());
- }
- }
- return childrenPaths;
- }
-
- @Nullable
- private static String getBestJdk(@NotNull List<String> jdkRoots, @NotNull LanguageLevel langLevel) {
- String bestJdk = null;
- for (String jdkRoot : jdkRoots) {
- if (JavaSdk.getInstance().isValidSdkHome(jdkRoot)) {
- if (bestJdk == null && hasMatchingLangLevel(jdkRoot, langLevel)) {
- bestJdk = jdkRoot;
- }
- else if (bestJdk != null) {
- bestJdk = selectJdk(bestJdk, jdkRoot, langLevel);
- }
- }
- }
- return bestJdk;
- }
-
- @Nullable
- private static String selectJdk(@NotNull String jdk1, @NotNull String jdk2, @NotNull LanguageLevel langLevel) {
- if (hasMatchingLangLevel(jdk1, langLevel)) {
- return jdk1;
- }
- if (hasMatchingLangLevel(jdk2, langLevel)) {
- return jdk2;
- }
- return null;
- }
-
- private static boolean hasMatchingLangLevel(@NotNull String jdkRoot, @NotNull LanguageLevel langLevel) {
- JavaSdkVersion version = getVersion(jdkRoot);
- return hasMatchingLangLevel(version, langLevel);
- }
-
- @VisibleForTesting
- static boolean hasMatchingLangLevel(@NotNull JavaSdkVersion jdkVersion, @NotNull LanguageLevel langLevel) {
- LanguageLevel max = jdkVersion.getMaxLanguageLevel();
- return max.isAtLeast(langLevel);
- }
-
- @NotNull
- private static JavaSdkVersion getVersion(@NotNull String jdkRoot) {
- String version = JavaSdk.getInstance().getVersionString(jdkRoot);
- if (version == null) {
- return JavaSdkVersion.JDK_1_0;
- }
- JavaSdkVersion sdkVersion = JavaSdk.getInstance().getVersion(version);
- return sdkVersion == null ? JavaSdkVersion.JDK_1_0 : sdkVersion;
- }
-
- @Nullable
- public static Sdk createJdk(@NotNull String jdkHomePath) {
- Sdk jdk = createAndAddSDK(jdkHomePath, JavaSdk.getInstance());
- if (jdk == null) {
- String msg = String.format("Unable to create JDK from path '%1$s'", jdkHomePath);
- Logger.getInstance(Jdks.class).error(msg);
- }
- return jdk;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/LibraryEditor.java b/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/LibraryEditor.java
deleted file mode 100644
index a454628..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/LibraryEditor.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.projectstructure;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.java.libraries.SourceJarManager;
-import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.OrderRootType;
-import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
-import com.intellij.openapi.roots.libraries.Library;
-import com.intellij.openapi.roots.libraries.LibraryTable;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.io.FileUtilRt;
-import com.intellij.openapi.vfs.StandardFileSystems;
-import com.intellij.openapi.vfs.VirtualFileManager;
-import com.intellij.util.io.URLUtil;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Edits IntelliJ libraries
- */
-public class LibraryEditor {
- private static final Logger LOG = Logger.getInstance(LibraryEditor.class);
-
- public static void updateProjectLibraries(Project project,
- BlazeContext context,
- BlazeProjectData blazeProjectData,
- Collection<BlazeLibrary> newLibraries,
- Collection<BlazeLibrary> oldLibraries) {
- Set<LibraryKey> intelliJLibraryState = Sets.newHashSet();
- for (Library library : ProjectLibraryTable.getInstance(project).getLibraries()) {
- String name = library.getName();
- if (name != null) {
- intelliJLibraryState.add(LibraryKey.fromIntelliJLibraryName(name));
- }
- }
- Collection<BlazeLibrary> librariesToUpdate = getUpdatedObjects(oldLibraries,
- newLibraries,
- intelliJLibraryState);
- if (oldLibraries.isEmpty()) {
- context.output(new PrintOutput(
- String.format(
- "Importing %d libraries",
- librariesToUpdate.size())));
- }
- else {
- String consoleMessage = String.format(
- "Total libraries: %d\n"
- + "Updating %d modified libraries",
- newLibraries.size(),
- librariesToUpdate.size());
- context.output(new PrintOutput(consoleMessage));
- }
-
- Set<String> externallyAddedLibraries = Sets.newHashSet();
- for (BlazeJavaSyncAugmenter syncAugmenter : BlazeJavaSyncAugmenter.EP_NAME.getExtensions()) {
- externallyAddedLibraries.addAll(syncAugmenter.getExternallyAddedLibraries(blazeProjectData));
- }
-
- LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
- LibraryTable.ModifiableModel libraryTableModel =
- libraryTable.getModifiableModel();
- try {
- boolean attachSourcesByDefault = BlazeUserSettings.getInstance().getAttachSourcesByDefault();
- SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
- for (BlazeLibrary library : librariesToUpdate) {
- boolean attachSources = attachSourcesByDefault || sourceJarManager.hasSourceJarAttached(library.getKey());
- updateLibrary(libraryTable, libraryTableModel, library, attachSources);
- }
-
- // Garbage collect unused libraries
- Set<LibraryKey> newLibraryKeys = newLibraries.stream().map(BlazeLibrary::getKey).collect(Collectors.toSet());
- for (LibraryKey libraryKey : intelliJLibraryState) {
- String libraryIntellijName = libraryKey.getIntelliJLibraryName();
- if (!newLibraryKeys.contains(libraryKey) && !externallyAddedLibraries.contains(libraryIntellijName)) {
- Library library = libraryTable.getLibraryByName(libraryIntellijName);
- if (library != null) {
- libraryTableModel.removeLibrary(library);
- }
- }
- }
- }
- finally {
- libraryTableModel.commit();
- }
- }
-
-
- public static void updateLibrary(
- LibraryTable libraryTable,
- LibraryTable.ModifiableModel libraryTableModel,
- BlazeLibrary blazeLibrary,
- boolean attachSourceJar) {
- String libraryName = blazeLibrary.getKey().getIntelliJLibraryName();
- Library library = libraryTable.getLibraryByName(libraryName);
- if (library != null) {
- libraryTableModel.removeLibrary(library);
- }
- library = libraryTableModel.createLibrary(libraryName);
-
- Library.ModifiableModel libraryModel = library.getModifiableModel();
- try {
- LibraryArtifact libraryArtifact = blazeLibrary.getLibraryArtifact();
- if (libraryArtifact != null) {
- libraryModel.addRoot(
- pathToUrl(libraryArtifact.jar.getFile()),
- OrderRootType.CLASSES
- );
- if (attachSourceJar && libraryArtifact.sourceJar != null) {
- libraryModel.addRoot(
- pathToUrl(libraryArtifact.sourceJar.getFile()),
- OrderRootType.SOURCES
- );
- }
- }
- if (blazeLibrary.getSources() != null) {
- for (File file : blazeLibrary.getSources()) {
- libraryModel.addRoot(
- pathToUrl(file),
- OrderRootType.SOURCES
- );
- }
- }
- }
- finally {
- libraryModel.commit();
- }
- }
-
- static Collection<BlazeLibrary> getUpdatedObjects(Collection<BlazeLibrary> oldObjects,
- Collection<BlazeLibrary> newObjects,
- Set<LibraryKey> intelliJState) {
- List<BlazeLibrary> result = Lists.newArrayList();
- Set<BlazeLibrary> oldObjectSet = Sets.newHashSet(oldObjects);
- for (BlazeLibrary value : newObjects) {
- LibraryKey key = value.getKey();
- if (!intelliJState.contains(key) || !oldObjectSet.contains(value)) {
- result.add(value);
- }
- }
- return result;
- }
-
- private static String pathToUrl(File path) {
- String name = path.getName();
- boolean isJarFile = FileUtilRt.extensionEquals(name, "jar") ||
- FileUtilRt.extensionEquals(name, "zip");
- // .jar files require an URL with "jar" protocol.
- String protocol = isJarFile
- ? StandardFileSystems.JAR_PROTOCOL
- : StandardFileSystems.FILE_PROTOCOL;
- String filePath = FileUtil.toSystemIndependentName(path.getPath());
- String url = VirtualFileManager.constructUrl(protocol, filePath);
- if (isJarFile) {
- url += URLUtil.JAR_SEPARATOR;
- }
- return url;
- }
-
- public static void configureDependencies(
- Project project,
- BlazeContext context,
- ModifiableRootModel modifiableRootModel,
- Collection<BlazeLibrary> libraries) {
- for (BlazeLibrary library : libraries) {
- updateLibraryDependency(modifiableRootModel, library.getKey());
- }
- }
-
- private static void updateLibraryDependency(
- ModifiableRootModel model,
- LibraryKey libraryKey) {
- LibraryTable libraryTable = ProjectLibraryTable.getInstance(model.getProject());
- Library library = libraryTable.getLibraryByName(libraryKey.getIntelliJLibraryName());
- if (library == null) {
- LOG.error("Library missing: " + libraryKey.getIntelliJLibraryName() + ". Please resync project to resolve.");
- return;
- }
- model.addLibraryEntry(library);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/SourceFolderEditor.java b/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/SourceFolderEditor.java
deleted file mode 100644
index a24d559..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/projectstructure/SourceFolderEditor.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.projectstructure;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
-import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
-import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.SourceFolder;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.VfsUtilCore;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.URLUtil;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.jps.model.JpsElement;
-import org.jetbrains.jps.model.java.JavaResourceRootType;
-import org.jetbrains.jps.model.java.JavaSourceRootProperties;
-import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Map;
-
-public class SourceFolderEditor {
- private static final Logger LOG = Logger.getInstance(SourceFolderEditor.class);
-
- public static void modifyContentEntries(
- BlazeJavaImportResult importResult,
- Collection<ContentEntry> contentEntries) {
-
- Map<File, BlazeContentEntry> contentEntryMap = Maps.newHashMap();
- for (BlazeContentEntry contentEntry : importResult.contentEntries) {
- contentEntryMap.put(contentEntry.contentRoot, contentEntry);
- }
-
- for (ContentEntry contentEntry : contentEntries) {
- VirtualFile virtualFile = contentEntry.getFile();
- if (virtualFile == null) {
- continue;
- }
-
- File contentRoot = new File(virtualFile.getPath());
- BlazeContentEntry javaContentEntry = contentEntryMap.get(contentRoot);
- if (javaContentEntry != null) {
- for (BlazeSourceDirectory sourceDirectory : javaContentEntry.sources) {
- addSourceFolderToContentEntry(
- contentEntry,
- sourceDirectory
- );
- }
- }
- }
- }
-
- private static void addSourceFolderToContentEntry(
- ContentEntry contentEntry,
- BlazeSourceDirectory sourceDirectory) {
- File sourceDir = sourceDirectory.getDirectory();
-
- // Create the source folder
- SourceFolder sourceFolder;
- if (sourceDirectory.getIsResource()) {
- JavaResourceRootType resourceRootType = sourceDirectory.getIsTest()
- ? JavaResourceRootType.TEST_RESOURCE
- : JavaResourceRootType.RESOURCE;
- sourceFolder = contentEntry.addSourceFolder(pathToUrl(sourceDir.getPath()),
- resourceRootType);
- }
- else {
- sourceFolder = contentEntry
- .addSourceFolder(pathToUrl(sourceDir.getPath()), sourceDirectory.getIsTest());
- }
- JpsModuleSourceRoot sourceRoot = sourceFolder.getJpsElement();
- JpsElement properties = sourceRoot.getProperties();
- if (properties instanceof JavaSourceRootProperties) {
- JavaSourceRootProperties rootProperties = (JavaSourceRootProperties)properties;
- if (sourceDirectory.getIsGenerated()) {
- rootProperties.setForGeneratedSources(true);
- }
- String packagePrefix = sourceDirectory.getPackagePrefix();
- if (!Strings.isNullOrEmpty(packagePrefix)) {
- rootProperties.setPackagePrefix(packagePrefix);
- }
- }
- }
-
- @NotNull
- private static String pathToUrl(@NotNull String filePath) {
- filePath = FileUtil.toSystemIndependentName(filePath);
- if (filePath.endsWith(".srcjar") || filePath.endsWith(".jar")) {
- return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR +
- filePath + URLUtil.JAR_SEPARATOR;
- }
- else if (filePath.contains("src.jar!")) {
- return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR +
- filePath;
- }
- else {
- return VfsUtilCore.pathToUrl(filePath);
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/FilePathJavaPackageReader.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/FilePathJavaPackageReader.java
deleted file mode 100644
index ba9f1f7..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/FilePathJavaPackageReader.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.util.PackagePrefixCalculator;
-
-/**
- * Gets the package from a java file by its file path alone (i.e. without opening the file).
- */
-public final class FilePathJavaPackageReader extends JavaPackageReader {
- @Override
- public String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact) {
- String directory = sourceArtifact.artifactLocation.getRelativePath();
- int i = directory.lastIndexOf('/');
- if (i >= 0) {
- directory = directory.substring(0, i);
- }
- return PackagePrefixCalculator.packagePrefixOf(new WorkspacePath(directory));
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/JavaPackageReader.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/JavaPackageReader.java
deleted file mode 100644
index 5cf63c3..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/JavaPackageReader.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.idea.blaze.base.scope.BlazeContext;
-
-import javax.annotation.Nullable;
-
-/**
- * Reads java packages from files.
- */
-public abstract class JavaPackageReader {
- @Nullable
- abstract String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact);
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java
deleted file mode 100644
index a9001f2..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.idea.blaze.base.io.InputStreamProvider;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import java.io.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Parse package string directly from java source
- */
-public class JavaSourcePackageReader extends JavaPackageReader {
-
- public static JavaSourcePackageReader getInstance() {
- return ServiceManager.getService(JavaSourcePackageReader.class);
- }
-
- private static final Logger LOG = Logger.getInstance(SourceDirectoryCalculator.class);
-
- private static final Pattern JAVA_PACKAGE_PATTERN =
- Pattern.compile("^\\s*package\\s+([\\w\\.]+);");
-
- @Override
- @Nullable
- public String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact) {
- if (sourceArtifact.artifactLocation.isGenerated()) {
- return null;
- }
- InputStreamProvider inputStreamProvider = InputStreamProvider.getInstance();
- File sourceFile = sourceArtifact.artifactLocation.getFile();
- try (InputStream javaInputStream = inputStreamProvider.getFile(sourceFile)) {
- BufferedReader javaReader = new BufferedReader(new InputStreamReader(javaInputStream));
- String javaLine;
-
- while ((javaLine = javaReader.readLine()) != null) {
- Matcher packageMatch = JAVA_PACKAGE_PATTERN.matcher(javaLine);
- if (packageMatch.find()) {
- return packageMatch.group(1);
- }
- }
- IssueOutput
- .warn("No package name string found in java source file: " + sourceFile)
- .inFile(sourceFile)
- .submit(context);
- return null;
- }
- catch (FileNotFoundException e) {
- IssueOutput
- .warn("No source file found for: " + sourceFile)
- .inFile(sourceFile)
- .submit(context);
- return null;
- }
- catch (IOException e) {
- LOG.error(e);
- return null;
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/ManifestFilePackageReader.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/ManifestFilePackageReader.java
deleted file mode 100644
index 71b1707..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/ManifestFilePackageReader.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.scope.BlazeContext;
-
-import javax.annotation.Nullable;
-import java.util.Map;
-
-public class ManifestFilePackageReader extends JavaPackageReader {
-
- private final Map<Label, Map<String, String>> manifestMap;
-
- public ManifestFilePackageReader(Map<Label, Map<String, String>> manifestMap) {
- this.manifestMap = manifestMap;
- }
-
- @Nullable
- @Override
- String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact) {
- Map<String, String> manifestMapForRule = manifestMap.get(sourceArtifact.originatingRule);
- if (manifestMapForRule != null) {
- return manifestMapForRule.get(sourceArtifact.artifactLocation.getFile().getPath());
- }
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java
deleted file mode 100644
index afa6ba7..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.idea.blaze.base.async.FutureUtil;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.io.InputStreamProvider;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.prefetch.PrefetchService;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.filediff.FileDiffService;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.JavaSourcePackage;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.PackageManifest;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-public class PackageManifestReader {
- private static final Logger LOG = Logger.getInstance(SourceDirectoryCalculator.class);
-
- public static PackageManifestReader getInstance() {
- return ServiceManager.getService(PackageManifestReader.class);
- }
-
- private FileDiffService fileDiffService = new FileDiffService();
- private FileDiffService.State fileDiffState;
-
- private Map<File, Label> fileToLabelMap = Maps.newHashMap();
- private final Map<Label, Map<String, String>> manifestMap = Maps.newConcurrentMap();
-
- /**
- * @return A map from java source absolute file path to declared package string.
- */
- public Map<Label, Map<String, String>> readPackageManifestFiles(
- BlazeContext context,
- ArtifactLocationDecoder decoder,
- Map<Label, ArtifactLocation> javaPackageManifests,
- ListeningExecutorService executorService) {
-
- Map<File, Label> fileToLabelMap = Maps.newHashMap();
- for (Map.Entry<Label, ArtifactLocation> entry : javaPackageManifests.entrySet()) {
- Label label = entry.getKey();
- File file = entry.getValue().getFile();
- fileToLabelMap.put(file, label);
- }
- List<File> updatedFiles = Lists.newArrayList();
- List<File> removedFiles = Lists.newArrayList();
- fileDiffState = fileDiffService.updateFiles(fileDiffState, fileToLabelMap.keySet(), updatedFiles, removedFiles);
-
- ListenableFuture<?> fetchFuture = PrefetchService.getInstance().prefetchFiles(updatedFiles, true);
- if (!FutureUtil.waitForFuture(context, fetchFuture)
- .timed("FetchPackageManifests")
- .run()
- .success()) {
- return null;
- }
-
- List<ListenableFuture<Void>> futures = Lists.newArrayList();
- for (File file : updatedFiles) {
- futures.add(executorService.submit(() -> {
- Map<String, String> manifest = parseManifestFile(decoder, file);
- manifestMap.put(fileToLabelMap.get(file), manifest);
- return null;
- }));
- }
- for (File file : removedFiles) {
- Label label = this.fileToLabelMap.get(file);
- if (label != null) {
- manifestMap.remove(label);
- }
- }
- this.fileToLabelMap = fileToLabelMap;
-
- try {
- Futures.allAsList(futures).get();
- } catch (ExecutionException | InterruptedException e) {
- LOG.error(e);
- throw new IllegalStateException("Could not read sources");
- }
- return manifestMap;
- }
-
- protected Map<String, String> parseManifestFile(ArtifactLocationDecoder decoder,
- File packageManifest) {
- Map<String, String> outputMap = Maps.newHashMap();
- InputStreamProvider inputStreamProvider = InputStreamProvider.getInstance();
-
- try (InputStream input = inputStreamProvider.getFile(packageManifest)) {
- try (BufferedInputStream bufferedInputStream = new BufferedInputStream(input)) {
- PackageManifest proto = PackageManifest.parseFrom(bufferedInputStream);
- for (JavaSourcePackage source : proto.getSourcesList()) {
- String absPath = getAbsolutePath(decoder, source);
- if (absPath != null) {
- outputMap.put(absPath, source.getPackageString());
- }
- }
- }
- return outputMap;
- }
- catch (IOException e) {
- LOG.error(e);
- return outputMap;
- }
- }
-
- /**
- * Returns null if the artifact location file can't be found,
- * presumably because it's been removed from the file system since the blaze build.
- */
- @Nullable
- private static String getAbsolutePath(ArtifactLocationDecoder decoder,
- JavaSourcePackage source) {
- if (!source.hasArtifactLocation()) {
- return source.getAbsolutePath();
- }
- ArtifactLocation location = decoder.decode(source.getArtifactLocation());
- if (location == null) {
- return null;
- }
- return location.getFile().getAbsolutePath();
- }
-
-}
-
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/SourceArtifact.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/SourceArtifact.java
deleted file mode 100644
index 4f9c877..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/SourceArtifact.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.model.primitives.Label;
-
-/**
- * Pairing of rule and source artifact.
- */
-public class SourceArtifact {
- public final Label originatingRule;
- public final ArtifactLocation artifactLocation;
-
- public SourceArtifact(Label originatingRule, ArtifactLocation artifactLocation) {
- this.originatingRule = originatingRule;
- this.artifactLocation = artifactLocation;
- }
-
- public static Builder builder(Label originatingRule) {
- return new Builder(originatingRule);
- }
-
- public static class Builder {
- Label originatingRule;
- ArtifactLocation artifactLocation;
-
- Builder(Label originatingRule) {
- this.originatingRule = originatingRule;
- }
-
- public Builder setArtifactLocation(ArtifactLocation artifactLocation) {
- this.artifactLocation = artifactLocation;
- return this;
- }
-
- public Builder setArtifactLocation(ArtifactLocation.Builder artifactLocation) {
- return setArtifactLocation(artifactLocation.build());
- }
-
- public SourceArtifact build() {
- return new SourceArtifact(originatingRule, artifactLocation);
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java b/blaze-java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java
deleted file mode 100644
index c312bbe..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.common.base.*;
-import com.google.common.base.Objects;
-import com.google.common.collect.*;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.idea.blaze.base.async.executor.TransientExecutor;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
-import com.google.idea.blaze.base.sync.projectview.SourceTestConfig;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.util.PackagePrefixCalculator;
-import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
-import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
-import com.intellij.openapi.diagnostic.Logger;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.*;
-import java.util.concurrent.ExecutionException;
-import java.util.stream.Collectors;
-
-/**
- * This is a utility class for calculating the java sources and their package prefixes given
- * a module and its Blaze {@link ArtifactLocation} list.
- */
-public final class SourceDirectoryCalculator {
-
- private static final Logger LOG = Logger.getInstance(SourceDirectoryCalculator.class);
-
- private static final Splitter PACKAGE_SPLITTER = Splitter.on('.');
- private static final Splitter PATH_SPLITTER = Splitter.on('/');
- private static final Joiner PACKAGE_JOINER = Joiner.on('.');
- private static final Joiner PATH_JOINER = Joiner.on('/');
-
- private static final Comparator<WorkspacePath> WORKSPACE_PATH_COMPARATOR =
- (o1, o2) -> o1.relativePath().compareTo(o2.relativePath());
-
- private static final JavaPackageReader generatedFileJavaPackageReader = new FilePathJavaPackageReader();
- private final ListeningExecutorService executorService = MoreExecutors.sameThreadExecutor();
- private final ListeningExecutorService packageReaderExecutorService = MoreExecutors.listeningDecorator(new TransientExecutor(16));
-
- public ImmutableList<BlazeContentEntry> calculateContentEntries(
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- SourceTestConfig sourceTestConfig,
- ArtifactLocationDecoder artifactLocationDecoder,
- Collection<WorkspacePath> rootDirectories,
- Collection<SourceArtifact> sources,
- Map<Label, ArtifactLocation> javaPackageManifests) {
-
- ManifestFilePackageReader manifestFilePackageReader = Scope.push(context, (childContext) -> {
- childContext.push(new TimingScope("ReadPackageManifests"));
- Map<Label, Map<String, String>> manifestMap = PackageManifestReader.getInstance().readPackageManifestFiles(
- childContext,
- artifactLocationDecoder,
- javaPackageManifests,
- packageReaderExecutorService
- );
- return new ManifestFilePackageReader(manifestMap);
- });
-
- final List<JavaPackageReader> javaPackageReaders = Lists.newArrayList(
- manifestFilePackageReader,
- JavaSourcePackageReader.getInstance(),
- generatedFileJavaPackageReader);
-
- Collection<SourceArtifact> nonGeneratedSources = filterGeneratedArtifacts(sources);
-
- // Sort artifacts and excludes into their respective workspace paths
- Multimap<WorkspacePath, SourceArtifact> sourcesUnderDirectoryRoot =
- sortArtifactLocationsByRootDirectory(context, rootDirectories, nonGeneratedSources);
-
- List<BlazeContentEntry> result = Lists.newArrayList();
- for (WorkspacePath workspacePath : rootDirectories) {
- File contentRoot = workspaceRoot.fileForPath(workspacePath);
- ImmutableList<BlazeSourceDirectory> sourceDirectories = calculateSourceDirectoriesForContentRoot(
- context,
- sourceTestConfig,
- workspaceRoot,
- workspacePath,
- sourcesUnderDirectoryRoot.get(workspacePath),
- javaPackageReaders
- );
- if (!sourceDirectories.isEmpty()) {
- result.add(new BlazeContentEntry(contentRoot, sourceDirectories));
- }
- }
- Collections.sort(result, (lhs, rhs) -> lhs.contentRoot.compareTo(rhs.contentRoot));
- return ImmutableList.copyOf(result);
- }
-
- private Collection<SourceArtifact> filterGeneratedArtifacts(Collection<SourceArtifact> artifactLocations) {
- return artifactLocations
- .stream()
- .filter(sourceArtifact -> sourceArtifact.artifactLocation.isSource())
- .collect(Collectors.toList());
- }
-
- private static Multimap<WorkspacePath, SourceArtifact> sortArtifactLocationsByRootDirectory(
- BlazeContext context,
- Collection<WorkspacePath> rootDirectories,
- Collection<SourceArtifact> sources) {
-
- Multimap<WorkspacePath, SourceArtifact> result = ArrayListMultimap.create();
-
- for (SourceArtifact sourceArtifact : sources) {
- WorkspacePath foundWorkspacePath = rootDirectories
- .stream()
- .filter(rootDirectory -> isUnderRootDirectory(rootDirectory, sourceArtifact.artifactLocation.getRelativePath()))
- .findFirst()
- .orElse(null);
-
- if (foundWorkspacePath != null) {
- result.put(foundWorkspacePath, sourceArtifact);
- }
- else if (sourceArtifact.artifactLocation.isSource()) {
- File sourceFile = sourceArtifact.artifactLocation.getFile();
- String message = String.format(
- "Did not add %s. You're probably using a java file from outside the workspace"
- + "that has been exported using export_files. Don't do that.", sourceFile);
- IssueOutput
- .warn(message)
- .inFile(sourceFile)
- .submit(context);
- }
- }
- return result;
- }
-
- private static boolean isUnderRootDirectory(WorkspacePath rootDirectory, String relativePath) {
- if (rootDirectory.isWorkspaceRoot()) {
- return true;
- }
- String rootDirectoryString = rootDirectory.toString();
- return relativePath.startsWith(rootDirectoryString)
- && (relativePath.length() == rootDirectoryString.length()
- || (relativePath.charAt(rootDirectoryString.length()) == '/'));
- }
-
- /**
- * Calculates all source directories for a single content root.
- */
- private ImmutableList<BlazeSourceDirectory> calculateSourceDirectoriesForContentRoot(
- BlazeContext context,
- SourceTestConfig sourceTestConfig,
- WorkspaceRoot workspaceRoot,
- WorkspacePath directoryRoot,
- Collection<SourceArtifact> sourceArtifacts,
- Collection<JavaPackageReader> javaPackageReaders) {
-
- // Split out java files
- List<SourceArtifact> javaArtifacts = Lists.newArrayList();
- for (SourceArtifact sourceArtifact : sourceArtifacts) {
- if (isJavaFile(sourceArtifact.artifactLocation)) {
- javaArtifacts.add(sourceArtifact);
- }
- }
-
- List<BlazeSourceDirectory> result = Lists.newArrayList();
-
- // Add java source directories
- calculateJavaSourceDirectories(
- context,
- workspaceRoot,
- directoryRoot,
- sourceTestConfig,
- javaArtifacts,
- javaPackageReaders,
- result
- );
-
- Collections.sort(result, BlazeSourceDirectory.COMPARATOR);
- return ImmutableList.copyOf(result);
- }
-
- /**
- * Adds the java source directories.
- */
- private void calculateJavaSourceDirectories(
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- WorkspacePath directoryRoot,
- SourceTestConfig sourceTestConfig,
- Collection<SourceArtifact> javaArtifacts,
- Collection<JavaPackageReader> javaPackageReaders,
- Collection<BlazeSourceDirectory> result) {
-
- List<SourceRoot> sourceRootsPerFile = Lists.newArrayList();
-
- // Get java sources
- List<ListenableFuture<SourceRoot>> sourceRootFutures = Lists.newArrayList();
- for (final SourceArtifact sourceArtifact : javaArtifacts) {
- ListenableFuture<SourceRoot> future = executorService.submit(() -> sourceRootForJavaSource(
- context,
- sourceArtifact,
- javaPackageReaders
- ));
- sourceRootFutures.add(future);
- }
- try {
- for (SourceRoot sourceRoot : Futures.allAsList(sourceRootFutures).get()) {
- if (sourceRoot != null) {
- sourceRootsPerFile.add(sourceRoot);
- }
- }
- }
- catch (ExecutionException | InterruptedException e) {
- LOG.error(e);
- throw new IllegalStateException("Could not read sources");
- }
-
- // Sort source roots into their respective directories
- Multimap<WorkspacePath, SourceRoot> sourceDirectoryToSourceRoots = HashMultimap.create();
- for (SourceRoot sourceRoot : sourceRootsPerFile) {
- sourceDirectoryToSourceRoots.put(sourceRoot.workspacePath, sourceRoot);
- }
-
- // Create a mapping from directory to package prefix
- Map<WorkspacePath, SourceRoot> workspacePathToCandidateRoot = Maps.newHashMap();
- for (WorkspacePath workspacePath : sourceDirectoryToSourceRoots.keySet()) {
- Collection<SourceRoot> sources = sourceDirectoryToSourceRoots.get(workspacePath);
- Multiset<String> packages = HashMultiset.create();
-
- for (SourceRoot source : sources) {
- packages.add(source.packagePrefix);
- }
-
- final String directoryPackagePrefix;
- // Common case -- all source files agree on a single package
- if (packages.elementSet().size() == 1) {
- directoryPackagePrefix = packages.elementSet().iterator().next();
- }
- else {
- directoryPackagePrefix = pickMostFrequentlyOccurring(packages);
- }
-
- // These properties must be the same for all files in the directory
- SourceRoot sourceFile = sources.iterator().next();
-
- SourceRoot candidateRoot = new SourceRoot(workspacePath, directoryPackagePrefix);
- workspacePathToCandidateRoot.put(workspacePath, candidateRoot);
- }
-
- // Add content entry base if it doesn't exist
- if (!workspacePathToCandidateRoot.containsKey(directoryRoot)) {
- SourceRoot candidateRoot = new SourceRoot(directoryRoot, PackagePrefixCalculator.packagePrefixOf(directoryRoot));
- workspacePathToCandidateRoot.put(directoryRoot, candidateRoot);
- }
-
- // Merge source roots
- // We have to do this in directory order to ensure we encounter roots before
- // their subdirectories
- Map<WorkspacePath, SourceRoot> mergedSourceRoots = Maps.newHashMap();
- List<WorkspacePath> sortedWorkspacePaths = Lists.newArrayList(workspacePathToCandidateRoot.keySet());
- Collections.sort(sortedWorkspacePaths, WORKSPACE_PATH_COMPARATOR);
- for (WorkspacePath workspacePath : sortedWorkspacePaths) {
- SourceRoot candidateRoot = workspacePathToCandidateRoot.get(workspacePath);
- SourceRoot bestNewRoot = candidateRoot;
- for (SourceRoot mergedSourceRoot : new CandidateRoots(directoryRoot, candidateRoot)) {
- SourceRoot existingSourceRoot = mergedSourceRoots.get(mergedSourceRoot.workspacePath);
- if (existingSourceRoot != null) {
- if (existingSourceRoot.packagePrefix.equals(mergedSourceRoot.packagePrefix)) {
- // Do not create new source root -- merge into preexisting source root
- // Since we already decided to establish one here, there is also
- // no need to go further up the tree
- bestNewRoot = null;
- }
- break;
- }
- bestNewRoot = mergedSourceRoot;
- }
-
- if (bestNewRoot != null) {
- mergedSourceRoots.put(bestNewRoot.workspacePath, bestNewRoot);
- }
- }
-
- // Add merged source roots
- for (SourceRoot sourceRoot : mergedSourceRoots.values()) {
- result.add(BlazeSourceDirectory.builder(workspaceRoot.fileForPath(sourceRoot.workspacePath))
- .setPackagePrefix(sourceRoot.packagePrefix)
- .setTest(sourceTestConfig.isTestSource(sourceRoot.workspacePath.relativePath()))
- .setGenerated(false)
- .build());
- }
- }
-
- private static <T> T pickMostFrequentlyOccurring(Multiset<T> set) {
- Preconditions.checkArgument(set.size() > 0);
-
- T best = null;
- int bestCount = 0;
-
- for (T candidate : set.elementSet()) {
- int candidateCount = set.count(candidate);
- if (candidateCount > bestCount) {
- best = candidate;
- bestCount = candidateCount;
- }
- }
- return best;
- }
-
- @Nullable
- private static SourceRoot sourceRootForJavaSource(
- BlazeContext context,
- SourceArtifact sourceArtifact,
- Collection<JavaPackageReader> javaPackageReaders) {
-
- File javaFile = sourceArtifact.artifactLocation.getFile();
-
- String declaredPackage = null;
- for (JavaPackageReader reader : javaPackageReaders) {
- declaredPackage = reader.getDeclaredPackageOfJavaFile(context, sourceArtifact);
- if (declaredPackage != null) {
- break;
- }
- }
- if (declaredPackage == null) {
- IssueOutput
- .warn("Failed to inspect the package name of java source file: " + javaFile)
- .inFile(javaFile)
- .submit(context);
- return null;
- }
- return new SourceRoot(
- new WorkspacePath(new File(sourceArtifact.artifactLocation.getRelativePath()).getParent()),
- declaredPackage
- );
- }
-
- static class SourceRoot {
- final WorkspacePath workspacePath;
- final String packagePrefix;
- public SourceRoot(WorkspacePath workspacePath, String packagePrefix) {
- this.workspacePath = workspacePath;
- this.packagePrefix = packagePrefix;
- }
- @Override
- public boolean equals(Object o) {
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- SourceRoot that = (SourceRoot)o;
- return Objects.equal(workspacePath, that.workspacePath)
- && Objects.equal(packagePrefix, that.packagePrefix);
- }
- @Override
- public int hashCode() {
- return Objects.hashCode(workspacePath, packagePrefix);
- }
-
- @Override
- public String toString() {
- return "SourceRoot {" + '\n'
- + " workspacePath: " + workspacePath + '\n'
- + " packagePrefix: " + packagePrefix + '\n'
- + '}';
- }
- }
-
- private static boolean isJavaFile(ArtifactLocation artifactLocation) {
- return artifactLocation.getRelativePath().endsWith(".java");
- }
-
- static class CandidateRoots implements Iterable<SourceRoot> {
- private static final List<String> EMPTY_LIST = ImmutableList.of();
-
- private final SourceRoot candidateRoot;
- private final WorkspacePath directoryRoot;
-
- CandidateRoots(
- WorkspacePath directoryRoot,
- SourceRoot candidateRoot) {
- this.directoryRoot = directoryRoot;
- this.candidateRoot = candidateRoot;
- }
-
- @Override
- public Iterator<SourceRoot> iterator() {
- return new CandidateRootIterator();
- }
-
- class CandidateRootIterator implements Iterator<SourceRoot> {
- private final List<String> packageComponents;
- private final List<String> pathComponents;
- private int packageIndex;
- private int pathIndex;
-
- CandidateRootIterator() {
- int directoryRootLength = directoryRoot.relativePath().length();
- String relativePath = candidateRoot.workspacePath.relativePath();
- final String sourcePathRelativeToModule;
- if (relativePath.length() > directoryRootLength) {
- if (directoryRootLength > 0) {
- sourcePathRelativeToModule = relativePath.substring(directoryRootLength + 1);
- } else {
- sourcePathRelativeToModule = relativePath;
- }
- } else {
- sourcePathRelativeToModule = "";
- }
-
- this.packageComponents = PACKAGE_SPLITTER.splitToList(candidateRoot.packagePrefix);
- this.pathComponents = !Strings.isNullOrEmpty(sourcePathRelativeToModule)
- ? PATH_SPLITTER.splitToList(sourcePathRelativeToModule) : EMPTY_LIST;
- this.packageIndex = packageComponents.size() - 1;
- this.pathIndex = pathComponents.size() - 1;
- }
-
- @Override
- public boolean hasNext() {
- return (packageIndex >= 0 && pathIndex >= 0 && packageComponents.get(packageIndex).equals(pathComponents.get(pathIndex)));
- }
-
- @Override
- public SourceRoot next() {
- String directoryRootRelativePath = PATH_JOINER.join(pathComponents.subList(0, pathIndex));
- final WorkspacePath workspacePath;
- if (directoryRootRelativePath.isEmpty()){
- workspacePath = directoryRoot;
- } else if (directoryRoot.isWorkspaceRoot()) {
- workspacePath = new WorkspacePath(directoryRootRelativePath);
- } else {
- workspacePath = new WorkspacePath(PATH_JOINER.join(directoryRoot.relativePath(), directoryRootRelativePath));
- }
-
- SourceRoot sourceRoot = new SourceRoot(
- workspacePath,
- PACKAGE_JOINER.join(packageComponents.subList(0, packageIndex))
- );
- --packageIndex;
- --pathIndex;
- return sourceRoot;
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/sync/workingset/JavaWorkingSet.java b/blaze-java/src/com/google/idea/blaze/java/sync/workingset/JavaWorkingSet.java
deleted file mode 100644
index f804eb3..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/sync/workingset/JavaWorkingSet.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.workingset;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-
-import java.util.Set;
-
-/**
- * Computes the working set of files of directories from source control.
- *
- * The working set is:
- * - All new untracked directories (git only)
- * - All modified BUILD files
- * - All modified java files
- *
- * A rule is considered part of the working set if any of the following is true:
- * - Its BUILD file is modified
- * - Its BUILD file is under a new directory
- * - Any of its java files are modified
- * - Any of its java files are under a new directory
- *
- * Rules in the working set get an expanded classpath of their direct deps,
- * i.e. they temporarily defeat classpath reduction.
- */
-public class JavaWorkingSet {
- private final Set<String> modifiedBuildFileRelativePaths;
- private final Set<String> modifiedJavaFileRelativePaths;
-
- public JavaWorkingSet(WorkspaceRoot workspaceRoot, WorkingSet workingSet) {
- Set<String> modifiedBuildFileRelativePaths = Sets.newHashSet();
- Set<String> modifiedJavaFileRelativePaths = Sets.newHashSet();
-
- for (WorkspacePath workspacePath : Iterables.concat(workingSet.addedFiles, workingSet.modifiedFiles)) {
- if (workspaceRoot.fileForPath(workspacePath).getName().equals("BUILD")) {
- modifiedBuildFileRelativePaths.add(workspacePath.relativePath());
- } else if (workspacePath.relativePath().endsWith(".java")){
- modifiedJavaFileRelativePaths.add(workspacePath.relativePath());
- }
- }
-
- this.modifiedBuildFileRelativePaths = modifiedBuildFileRelativePaths;
- this.modifiedJavaFileRelativePaths = modifiedJavaFileRelativePaths;
- }
-
- public boolean isRuleInWorkingSet(RuleIdeInfo ruleIdeInfo) {
- ArtifactLocation buildFile = ruleIdeInfo.buildFile;
- if (buildFile != null) {
- if (modifiedBuildFileRelativePaths.contains(buildFile.getRelativePath())) {
- return true;
- }
- }
-
- for (ArtifactLocation artifactLocation : ruleIdeInfo.sources) {
- if (isInWorkingSet(artifactLocation)) {
- return true;
- }
- }
- return false;
- }
-
- public boolean isInWorkingSet(ArtifactLocation artifactLocation) {
- return isInWorkingSet(artifactLocation.getRelativePath());
- }
-
- boolean isInWorkingSet(String relativePath) {
- return modifiedJavaFileRelativePaths.contains(relativePath);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java b/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
deleted file mode 100644
index dd61284..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.syncstatus;
-
-import com.intellij.ide.projectView.PresentationData;
-import com.intellij.ide.projectView.ProjectViewNode;
-import com.intellij.ide.projectView.ProjectViewNodeDecorator;
-import com.intellij.ide.projectView.impl.nodes.ClassTreeNode;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.packageDependencies.ui.PackageDependenciesNode;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiFile;
-import com.intellij.ui.ColoredTreeCellRenderer;
-import com.intellij.ui.SimpleTextAttributes;
-
-/**
- * Grays out any unreachable java classes.
- */
-public class BlazeJavaSyncStatusClassNodeDecorator implements ProjectViewNodeDecorator {
- @Override
- public void decorate(ProjectViewNode node, PresentationData data) {
- if (!(node instanceof ClassTreeNode)) {
- return;
- }
- PsiClass psiClass = ((ClassTreeNode)node).getPsiClass();
- if (psiClass == null) {
- return;
- }
- PsiFile psiFile = psiClass.getContainingFile();
- if (psiFile == null) {
- return;
- }
- VirtualFile virtualFile = psiFile.getVirtualFile();
- if (virtualFile == null) {
- return;
- }
-
- Project project = node.getProject();
- if (SyncStatusHelper.isUnsynced(project, virtualFile)) {
- data.clearText();
- data.addText(psiClass.getName(), SimpleTextAttributes.GRAY_ATTRIBUTES);
- data.addText(" (unsynced)", SimpleTextAttributes.GRAY_ATTRIBUTES);
- }
- }
-
- @Override
- public void decorate(PackageDependenciesNode node, ColoredTreeCellRenderer cellRenderer) {
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java b/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
deleted file mode 100644
index 0c9e188..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.syncstatus;
-
-import com.intellij.openapi.fileEditor.impl.EditorTabColorProvider;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.JBColor;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.awt.*;
-
-/**
- * Changes the color for unsynced files.
- */
-public class BlazeJavaSyncStatusEditorTabColorProvider implements EditorTabColorProvider {
- private static final JBColor UNSYNCED_COLOR = new JBColor(new Color(252, 234, 234), new Color(121, 105, 105));
-
- @Nullable
- @Override
- public Color getEditorTabColor(@NotNull Project project, @NotNull VirtualFile file) {
- if (file.getName().endsWith(".java") && SyncStatusHelper.isUnsynced(project, file)) {
- return UNSYNCED_COLOR;
- }
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java b/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java
deleted file mode 100644
index 642ed83..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.syncstatus;
-
-import com.intellij.openapi.fileEditor.impl.EditorTabTitleProvider;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * Changes the tab title for unsynced files.
- */
-public class BlazeJavaSyncStatusEditorTabTitleProvider implements EditorTabTitleProvider {
- @Nullable
- @Override
- public String getEditorTabTitle(Project project, VirtualFile file) {
- if (file.getName().endsWith("java") && SyncStatusHelper.isUnsynced(project, file)) {
- return file.getPresentableName() + " (unsynced)";
- }
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java b/blaze-java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java
deleted file mode 100644
index d2a3cf9..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.syncstatus;
-
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import java.io.File;
-
-class SyncStatusHelper {
- static boolean isUnsynced(Project project, VirtualFile virtualFile) {
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return false;
- }
- BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
- if (syncData == null) {
- return false;
- }
- if (!virtualFile.isInLocalFileSystem()) {
- return false;
- }
-
- File file = new File(virtualFile.getPath());
- return !syncData.importResult.javaSourceFiles.contains(file);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java b/blaze-java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
deleted file mode 100644
index f31a694..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.ui;
-
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.ui.BlazeProblemsView;
-import com.intellij.compiler.CompilerMessageImpl;
-import com.intellij.compiler.ProblemsView;
-import com.intellij.openapi.compiler.CompilerMessageCategory;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
-
-import java.util.UUID;
-
-public class BlazeIntelliJProblemsView implements BlazeProblemsView {
- private final Project project;
-
- private BlazeIntelliJProblemsView(Project project) {
- this.project = project;
- }
-
- @Override
- public void clearOldMessages(UUID sessionId) {
- ProblemsView.SERVICE.getInstance(project).clearOldMessages(null, sessionId);
- }
-
- @Override
- public void addMessage(IssueOutput issue, UUID sessionId) {
- VirtualFile virtualFile = issue.getFile() != null
- ? VfsUtil.findFileByIoFile(issue.getFile(), true /* refresh */)
- : null;
- CompilerMessageCategory category = issue.getCategory() == IssueOutput.Category.ERROR
- ? CompilerMessageCategory.ERROR
- : CompilerMessageCategory.WARNING;
- CompilerMessageImpl message = new CompilerMessageImpl(
- project,
- category,
- issue.getMessage(),
- virtualFile,
- issue.getLine(),
- issue.getColumn(),
- issue.getNavigatable()
- );
- ProblemsView.SERVICE.getInstance(project).addMessage(message, sessionId);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeImportJavaProjectWizard.java b/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeImportJavaProjectWizard.java
deleted file mode 100644
index b00047d..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeImportJavaProjectWizard.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard;
-
-import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.projectImport.ProjectImportProvider;
-
-final class BlazeImportJavaProjectWizard extends AddModuleWizard {
- public BlazeImportJavaProjectWizard(VirtualFile file, ProjectImportProvider provider) {
- super(null, file.getCanonicalPath(), provider);
- }
-
- @Override
- protected String getDimensionServiceKey() {
- return null; // No dimension service
- }
-
- public boolean runWizard() {
- return showAndGet();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeImportNewJavaProjectAction.java b/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeImportNewJavaProjectAction.java
deleted file mode 100644
index 5c3c49f..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeImportNewJavaProjectAction.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard;
-
-import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.wizard.BlazeImportFileChooser;
-import com.intellij.ide.impl.NewProjectUtil;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.projectImport.ProjectImportProvider;
-
-import javax.annotation.Nullable;
-import java.io.IOException;
-
-
-public class BlazeImportNewJavaProjectAction extends AnAction {
- private static final Logger LOG = Logger.getInstance(BlazeImportNewJavaProjectAction.class);
-
- public BlazeImportNewJavaProjectAction() {
- super("Import Project...");
- }
-
- @Override
- public void update(AnActionEvent e) {
- super.update(e);
- // this importer only supports importing blaze projects
- if (!BuildSystemProvider.isBuildSystemAvailable(BuildSystem.Blaze)) {
- e.getPresentation().setEnabledAndVisible(false);
- } else {
- e.getPresentation().setEnabledAndVisible(true);
- }
- }
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- try {
- BlazeImportJavaProjectWizard wizard = selectFileAndCreateWizard();
- if (wizard != null) {
- if (!wizard.runWizard()) {
- return;
- }
- //noinspection ConstantConditions
- NewProjectUtil.createFromWizard(wizard, null);
- }
- }
- catch (IOException | ConfigurationException exception) {
- handleImportException(e.getProject(), exception);
- }
- }
-
- @Nullable
- private BlazeImportJavaProjectWizard selectFileAndCreateWizard() throws IOException, ConfigurationException {
- VirtualFile fileToImport = BlazeImportFileChooser.getFileToImport();
- if (fileToImport == null) {
- return null;
- }
- return createImportWizard(fileToImport);
- }
-
- @Nullable
- protected BlazeImportJavaProjectWizard createImportWizard(VirtualFile file) throws IOException, ConfigurationException {
- ProjectImportProvider provider = createBlazeImportProvider();
- return new BlazeImportJavaProjectWizard(file, provider);
- }
-
- private static ProjectImportProvider createBlazeImportProvider() {
- BlazeNewJavaProjectImportBuilder builder = new BlazeNewJavaProjectImportBuilder();
- return new BlazeNewProjectImportProvider(builder);
- }
-
- private static void handleImportException(@Nullable Project project, Exception e) {
- String message = String.format("Project import failed: %s", e.getMessage());
- Messages.showErrorDialog(project, message, "Import Project");
- LOG.error(e);
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeNewJavaProjectImportBuilder.java b/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeNewJavaProjectImportBuilder.java
deleted file mode 100644
index 7378e4a..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeNewJavaProjectImportBuilder.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.wizard.BlazeNewProjectBuilder;
-import com.intellij.openapi.module.ModifiableModuleModel;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.JavaSdk;
-import com.intellij.openapi.projectRoots.SdkTypeId;
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
-import com.intellij.packaging.artifacts.ModifiableArtifactModel;
-import com.intellij.projectImport.ProjectImportBuilder;
-import icons.BlazeIcons;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.util.List;
-
-/**
- * Project builder for Blaze projects.
- */
-public class BlazeNewJavaProjectImportBuilder extends ProjectImportBuilder<BlazeProjectData> {
- private BlazeImportSettings importSettings;
- private ProjectView projectView;
-
- @NotNull
- @Override
- public String getName() {
- return "Blaze";
- }
-
- @Override
- public Icon getIcon() {
- return BlazeIcons.Blaze;
- }
-
- @Override
- public boolean isSuitableSdkType(SdkTypeId sdk) {
- return sdk == JavaSdk.getInstance();
- }
-
- @Override
- public List<BlazeProjectData> getList() {
- return ImmutableList.of();
- }
-
- @Override
- public boolean isMarked(BlazeProjectData element) {
- return true;
- }
-
- @Override
- public void setList(List<BlazeProjectData> gradleProjects) {
- }
-
- @Override
- public void setOpenProjectSettingsAfter(boolean on) {
- }
-
- @Override
- public List<Module> commit(final Project project,
- ModifiableModuleModel model,
- ModulesProvider modulesProvider,
- ModifiableArtifactModel artifactModel) {
- assert importSettings != null;
- assert projectView != null;
-
- return BlazeNewProjectBuilder.commit(project, importSettings, projectView);
- }
-
- public void setImportSettings(BlazeImportSettings importSettings) {
- this.importSettings = importSettings;
- }
-
- public void setProjectView(ProjectView projectView) {
- this.projectView = projectView;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeNewProjectImportProvider.java b/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeNewProjectImportProvider.java
deleted file mode 100644
index 2ac630c..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard/BlazeNewProjectImportProvider.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard;
-
-import com.google.idea.blaze.base.wizard.ImportSource;
-import com.intellij.ide.util.projectWizard.ModuleWizardStep;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.projectImport.ProjectImportProvider;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * The import provider for the Blaze plugin.
- */
-public class BlazeNewProjectImportProvider extends ProjectImportProvider {
-
- public BlazeNewProjectImportProvider(BlazeNewJavaProjectImportBuilder builder) {
- super(builder);
- }
-
- @Override
- protected boolean canImportFromFile(VirtualFile file) {
- return ImportSource.canImport(file);
- }
-
- @Nullable
- @Override
- public String getFileSample() {
- return "Workspace root, .blazeproject file, or BUILD file";
- }
-
- @Override
- public String getPathToBeImported(VirtualFile file) {
- return file.getCanonicalPath();
- }
-
- @Override
- public ModuleWizardStep[] createSteps(WizardContext context) {
- return new ModuleWizardStep[]{new SelectExternalProjectStep(context)};
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard/SelectExternalProjectStep.java b/blaze-java/src/com/google/idea/blaze/java/wizard/SelectExternalProjectStep.java
deleted file mode 100644
index 8d9ef36..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard/SelectExternalProjectStep.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard;
-
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard.BlazeProjectSettingsControl;
-import com.google.idea.blaze.base.wizard.ImportResults;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.projectImport.ProjectImportWizardStep;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-
-/**
- * Handles the following responsibilities:
- * <pre>
- * <ul>
- * <li>allows end user to define external system config file to import from;</li>
- * <li>processes the input and reacts accordingly - shows error message if the project is invalid or proceeds to the next screen;</li>
- * </ul>
- * </pre>
- *
- * @author Denis Zhdanov
- * @since 8/1/11 4:15 PM
- */
-public class SelectExternalProjectStep extends ProjectImportWizardStep {
-
- @NotNull
- private final JPanel component = new JPanel(new BorderLayout());
-
- @NotNull
- private final BlazeProjectSettingsControl control;
-
- private boolean settingsInitialised;
-
- public SelectExternalProjectStep(@NotNull WizardContext context) {
- super(context);
- control = new BlazeProjectSettingsControl(context.getDisposable());
- }
-
- @Override
- public JComponent getComponent() {
- return component;
- }
-
- @Override
- public void updateStep() {
- if (!settingsInitialised) {
- init();
- }
- }
-
- private void init() {
- BlazeNewJavaProjectImportBuilder builder = getBuilder();
- File fileToImport = new File(builder.getFileToImport());
- JPanel importControl = control.createComponent(fileToImport);
- this.component.add(importControl);
- settingsInitialised = true;
- }
-
- @Override
- public boolean validate() throws ConfigurationException {
- BlazeValidationResult validationResult = control.validate();
- if (validationResult.error != null) {
- throw new ConfigurationException(validationResult.error.getError());
- }
- return validationResult.success;
- }
-
- @Override
- public void updateDataModel() {
- ImportResults importResults = control.getResults();
-
- BlazeNewJavaProjectImportBuilder builder = getBuilder();
- WizardContext wizardContext = getWizardContext();
-
- builder.setImportSettings(importResults.importSettings);
- builder.setProjectView(importResults.projectView);
- wizardContext.setProjectName(importResults.projectName);
- wizardContext.setProjectFileDirectory(importResults.projectDataDirectory);
- }
-
- @Override
- @NotNull
- protected BlazeNewJavaProjectImportBuilder getBuilder() {
- BlazeNewJavaProjectImportBuilder builder =
- (BlazeNewJavaProjectImportBuilder)getWizardContext().getProjectBuilder();
- assert builder != null;
- return builder;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
deleted file mode 100644
index b88ba19..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.BlazeProjectCommitException;
-import com.google.idea.blaze.base.wizard2.ui.BlazeEditProjectViewControl;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.ide.wizard.CommitStepException;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.projectImport.ProjectImportWizardStep;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-
-/**
- * Shows the edit project view screen.
- */
-class BlazeEditProjectViewImportWizardStep extends ProjectImportWizardStep {
-
- private final JPanel component = new JPanel(new BorderLayout());
- private BlazeEditProjectViewControl control;
- private boolean settingsInitialised;
-
- public BlazeEditProjectViewImportWizardStep(@NotNull WizardContext context) {
- super(context);
- }
-
- @Override
- public JComponent getComponent() {
- return component;
- }
-
- @Override
- public void updateStep() {
- if (!settingsInitialised) {
- init();
- } else {
- control.update(getProjectBuilder());
- }
- }
-
- private void init() {
- control = new BlazeEditProjectViewControl(getProjectBuilder(), getWizardContext().getDisposable());
- this.component.add(control.getUiComponent());
- settingsInitialised = true;
- }
-
- @Override
- public boolean validate() throws ConfigurationException {
- BlazeValidationResult validationResult = control.validate();
- if (validationResult.error != null) {
- throw new ConfigurationException(validationResult.error.getError());
- }
- return validationResult.success;
- }
-
- @Override
- public void updateDataModel() {
- BlazeNewProjectBuilder builder = getProjectBuilder();
- control.updateBuilder(builder);
-
- WizardContext wizardContext = getWizardContext();
- wizardContext.setProjectName(builder.getProjectName());
- wizardContext.setProjectFileDirectory(builder.getProjectDataDirectory());
- }
-
- @Override
- public void onWizardFinished() throws CommitStepException {
- try {
- getProjectBuilder().commit();
- }
- catch (BlazeProjectCommitException e) {
- throw new CommitStepException(e.getMessage());
- }
- }
-
- @Override
- public String getHelpId() {
- return "docs/project-views.md";
- }
-
- private BlazeNewProjectBuilder getProjectBuilder() {
- BlazeProjectImportBuilder builder = (BlazeProjectImportBuilder)getWizardContext().getProjectBuilder();
- assert builder != null;
- return builder.builder();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeImportProjectAction.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeImportProjectAction.java
deleted file mode 100644
index ee3782d..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeImportProjectAction.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.idea.blaze.base.settings.Blaze;
-import com.intellij.ide.impl.NewProjectUtil;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-
-
-public class BlazeImportProjectAction extends AnAction {
- @Override
- public void actionPerformed(AnActionEvent e) {
- BlazeNewProjectWizard wizard = new BlazeNewProjectWizard(
- new BlazeNewProjectImportProvider(new BlazeProjectImportBuilder()));
- if (!wizard.showAndGet()) {
- return;
- }
- //noinspection ConstantConditions
- NewProjectUtil.createFromWizard(wizard, null);
- }
-
- @Override
- public void update(AnActionEvent e) {
- super.update(e);
- e.getPresentation().setText(String.format("Import %s Project...", Blaze.defaultBuildSystemName()));
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectImportProvider.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectImportProvider.java
deleted file mode 100644
index 5aa5683..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectImportProvider.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.intellij.ide.util.projectWizard.ModuleWizardStep;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.projectImport.ProjectImportProvider;
-
-/**
- * The import provider for the Blaze plugin.
- */
-class BlazeNewProjectImportProvider extends ProjectImportProvider {
-
- public BlazeNewProjectImportProvider(BlazeProjectImportBuilder builder) {
- super(builder);
- }
-
- @Override
- public ModuleWizardStep[] createSteps(WizardContext context) {
- return new ModuleWizardStep[]{
- new BlazeSelectWorkspaceImportWizardStep(context),
- new BlazeSelectBuildSystemBinaryStep(context),
- new BlazeSelectProjectViewImportWizardStep(context),
- new BlazeEditProjectViewImportWizardStep(context)
- };
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
deleted file mode 100644
index 22fb231..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.idea.blaze.base.help.BlazeHelpHandler;
-import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
-import com.intellij.projectImport.ProjectImportProvider;
-import org.jetbrains.annotations.Nullable;
-
-import java.awt.event.ActionListener;
-
-final class BlazeNewProjectWizard extends AddModuleWizard {
- public BlazeNewProjectWizard(ProjectImportProvider provider) {
- super(null, null, provider);
- }
-
- @Override
- protected String getDimensionServiceKey() {
- return null; // No dimension service
- }
-
- @Override
- protected void helpAction() {
- doHelpAction();
- }
-
- @Override
- protected void doHelpAction() {
- String helpId = getHelpID();
- BlazeHelpHandler helpHandler = BlazeHelpHandler.getInstance();
- if (helpId != null && helpHandler != null) {
- helpHandler.handleHelp(helpId);
- }
- }
-
- // Swallow the escape key
- @Nullable
- @Override
- protected ActionListener createCancelAction() {
- return null;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeProjectImportBuilder.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeProjectImportBuilder.java
deleted file mode 100644
index 5e02a22..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeProjectImportBuilder.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.intellij.openapi.module.ModifiableModuleModel;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.JavaSdk;
-import com.intellij.openapi.projectRoots.SdkTypeId;
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
-import com.intellij.packaging.artifacts.ModifiableArtifactModel;
-import com.intellij.projectImport.ProjectImportBuilder;
-import icons.BlazeIcons;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.util.List;
-
-/**
- * Wrapper around a {@link BlazeNewProjectBuilder} to fit into
- * IntelliJ's import framework.
- */
-class BlazeProjectImportBuilder extends ProjectImportBuilder<Void> {
- private BlazeNewProjectBuilder builder = new BlazeNewProjectBuilder();
-
- @NotNull
- @Override
- public String getName() {
- return Blaze.defaultBuildSystemName();
- }
-
- @Override
- public Icon getIcon() {
- return BlazeIcons.Blaze;
- }
-
- @Override
- public boolean isSuitableSdkType(SdkTypeId sdk) {
- return sdk == JavaSdk.getInstance();
- }
-
- @Override
- public List<Void> getList() {
- return ImmutableList.of();
- }
-
- @Override
- public boolean isMarked(Void element) {
- return true;
- }
-
- @Override
- public void setList(List<Void> gradleProjects) {
- }
-
- @Override
- public void setOpenProjectSettingsAfter(boolean on) {
- }
-
- @Override
- public List<Module> commit(final Project project,
- ModifiableModuleModel model,
- ModulesProvider modulesProvider,
- ModifiableArtifactModel artifactModel) {
- builder.commitToProject(project);
- return ImmutableList.of();
- }
-
- public BlazeNewProjectBuilder builder() {
- return builder;
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectBuildSystemBinaryStep.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectBuildSystemBinaryStep.java
deleted file mode 100644
index 940fc6c..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectBuildSystemBinaryStep.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.ui.SelectBazelBinaryControl;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.ide.wizard.CommitStepException;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.projectImport.ProjectImportWizardStep;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-
-class BlazeSelectBuildSystemBinaryStep extends ProjectImportWizardStep {
-
- private final JPanel component = new JPanel(new BorderLayout());
- private SelectBazelBinaryControl control;
- private boolean settingsInitialized = false;
-
- public BlazeSelectBuildSystemBinaryStep(@NotNull WizardContext context) {
- super(context);
- }
-
- @Override
- public boolean isStepVisible() {
- updateStep();
- if (control.builder.getBuildSystem() != BuildSystem.Bazel) {
- return false;
- }
- String currentBinaryPath = BlazeUserSettings.getInstance().getBazelBinaryPath();
- return currentBinaryPath == null;
- }
-
- @Override
- public JComponent getComponent() {
- return component;
- }
-
- @Override
- public void updateStep() {
- if (!settingsInitialized) {
- init();
- }
- }
-
- private void init() {
- control = new SelectBazelBinaryControl(getProjectBuilder());
- component.add(control.getUiComponent());
- settingsInitialized = true;
- }
-
- @Override
- public boolean validate() throws ConfigurationException {
- BlazeValidationResult result = control.validate();
- if (!result.success) {
- throw new ConfigurationException(result.error.getError());
- }
- return true;
- }
-
- @Override
- public void updateDataModel() {
- }
-
- @Override
- public void onWizardFinished() throws CommitStepException {
- control.commit();
- }
-
- private BlazeNewProjectBuilder getProjectBuilder() {
- BlazeProjectImportBuilder builder = (BlazeProjectImportBuilder)getWizardContext().getProjectBuilder();
- assert builder != null;
- return builder.builder();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectProjectViewImportWizardStep.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectProjectViewImportWizardStep.java
deleted file mode 100644
index 14ba13e..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectProjectViewImportWizardStep.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.ui.BlazeSelectProjectViewControl;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.ide.wizard.CommitStepException;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.projectImport.ProjectImportWizardStep;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-
-class BlazeSelectProjectViewImportWizardStep extends ProjectImportWizardStep {
-
- private final JPanel component = new JPanel(new BorderLayout());
- private BlazeSelectProjectViewControl control;
- private boolean settingsInitialised;
-
- public BlazeSelectProjectViewImportWizardStep(@NotNull WizardContext context) {
- super(context);
- }
-
- @Override
- public JComponent getComponent() {
- return component;
- }
-
- @Override
- public void updateStep() {
- if (!settingsInitialised) {
- init();
- } else {
- control.update(getProjectBuilder());
- }
- }
-
- private void init() {
- control = new BlazeSelectProjectViewControl(getProjectBuilder());
- this.component.add(control.getUiComponent());
- settingsInitialised = true;
- }
-
- @Override
- public boolean validate() throws ConfigurationException {
- BlazeValidationResult result = control.validate();
- if (!result.success) {
- throw new ConfigurationException(result.error.getError());
- }
- return true;
- }
-
- @Override
- public void updateDataModel() {
- control.updateBuilder(getProjectBuilder());
- }
-
- @Override
- public void onWizardFinished() throws CommitStepException {
- control.commit();
- }
-
- @Override
- public String getHelpId() {
- return "docs/project-views.md";
- }
-
- private BlazeNewProjectBuilder getProjectBuilder() {
- BlazeProjectImportBuilder builder = (BlazeProjectImportBuilder)getWizardContext().getProjectBuilder();
- assert builder != null;
- return builder.builder();
- }
-}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectWorkspaceImportWizardStep.java b/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectWorkspaceImportWizardStep.java
deleted file mode 100644
index 2923643..0000000
--- a/blaze-java/src/com/google/idea/blaze/java/wizard2/BlazeSelectWorkspaceImportWizardStep.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.wizard2;
-
-import com.google.idea.blaze.base.ui.BlazeValidationResult;
-import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
-import com.google.idea.blaze.base.wizard2.ui.BlazeSelectWorkspaceControl;
-import com.intellij.ide.util.projectWizard.WizardContext;
-import com.intellij.ide.wizard.CommitStepException;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.projectImport.ProjectImportWizardStep;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.*;
-
-class BlazeSelectWorkspaceImportWizardStep extends ProjectImportWizardStep {
-
- private final JPanel component = new JPanel(new BorderLayout());
- private BlazeSelectWorkspaceControl control;
- private boolean settingsInitialised;
-
- public BlazeSelectWorkspaceImportWizardStep(@NotNull WizardContext context) {
- super(context);
- }
-
- @Override
- public JComponent getComponent() {
- return component;
- }
-
- @Override
- public void updateStep() {
- if (!settingsInitialised) {
- init();
- }
- }
-
- private void init() {
- control = new BlazeSelectWorkspaceControl(getProjectBuilder());
- this.component.add(control.getUiComponent());
- settingsInitialised = true;
- }
-
- @Override
- public boolean validate() throws ConfigurationException {
- BlazeValidationResult result = control.validate();
- if (!result.success) {
- throw new ConfigurationException(result.error.getError());
- }
- return true;
- }
-
- @Override
- public void updateDataModel() {
- control.updateBuilder(getProjectBuilder());
- }
-
- @Override
- public void onWizardFinished() throws CommitStepException {
- control.commit();
- }
-
- @Override
- public String getHelpId() {
- return "docs/import-project.md";
- }
-
- private BlazeNewProjectBuilder getProjectBuilder() {
- BlazeProjectImportBuilder builder = (BlazeProjectImportBuilder)getWizardContext().getProjectBuilder();
- assert builder != null;
- return builder.builder();
- }
-}
diff --git a/blaze-java/tests/integrationtests/com/google/idea/blaze/java/lang/build/JavaClassRenameTest.java b/blaze-java/tests/integrationtests/com/google/idea/blaze/java/lang/build/JavaClassRenameTest.java
deleted file mode 100644
index b4f6d18..0000000
--- a/blaze-java/tests/integrationtests/com/google/idea/blaze/java/lang/build/JavaClassRenameTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.lang.build;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.intellij.psi.PsiJavaFile;
-import com.intellij.refactoring.rename.RenameProcessor;
-
-/**
- * Tests that BUILD file references are correctly updated when performing rename refactors.
- */
-public class JavaClassRenameTest extends BuildFileIntegrationTestCase {
-
- public void testRenameJavaClass() {
- PsiJavaFile javaFile = (PsiJavaFile) createPsiFile(
- "com/google/foo/JavaClass.java",
- "package com.google.foo;",
- "public class JavaClass {}");
-
- BuildFile buildFile = createBuildFile(
- "com/google/foo/BUILD",
- "java_library(name = \"ref2\", srcs = [\"JavaClass.java\"])");
-
- new RenameProcessor(getProject(), javaFile.getClasses()[0], "NewName", false, false).run();
-
- assertFileContents(
- buildFile,
- "java_library(name = \"ref2\", srcs = [\"NewName.java\"])");
- }
-
-}
diff --git a/blaze-java/tests/integrationtests/com/google/idea/blaze/java/lang/build/SafeDeleteTest.java b/blaze-java/tests/integrationtests/com/google/idea/blaze/java/lang/build/SafeDeleteTest.java
deleted file mode 100644
index ab9390f..0000000
--- a/blaze-java/tests/integrationtests/com/google/idea/blaze/java/lang/build/SafeDeleteTest.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.lang.build;
-
-import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
-import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
-import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.refactoring.BaseRefactoringProcessor;
-import com.intellij.refactoring.safeDelete.SafeDeleteHandler;
-
-/**
- * Tests for the safe delete action which aren't covered by existing tests.
- */
-public class SafeDeleteTest extends BuildFileIntegrationTestCase {
-
- public void testIndirectGlobReferencesNotIncluded() {
- PsiFile javaFile = createPsiFile(
- "com/google/Test.java",
- "package com.google;",
- "public class Test {}");
-
- PsiClass javaClass = PsiUtils.findFirstChildOfClassRecursive(javaFile, PsiClass.class);
-
- BuildFile buildFile = createBuildFile(
- "com/google/BUILD",
- "java_library(",
- " name = 'lib'",
- " srcs = glob(['*.java'])",
- ")");
-
- try {
- SafeDeleteHandler.invoke(getProject(), new PsiElement[] {javaClass}, true);
- } catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
- fail("Glob reference was incorrectly included");
- return;
- }
- }
-
- public void testDirectGlobReferencesIncluded() {
- PsiFile javaFile = createPsiFile(
- "com/google/Test.java",
- "package com.google;",
- "public class Test {}");
-
- PsiClass javaClass = PsiUtils.findFirstChildOfClassRecursive(javaFile, PsiClass.class);
-
- BuildFile buildFile = createBuildFile(
- "com/google/BUILD",
- "java_library(",
- " name = 'lib'",
- " srcs = glob(['Test.java'])",
- ")");
-
- try {
- SafeDeleteHandler.invoke(getProject(), new PsiElement[] {javaClass}, true);
- } catch (BaseRefactoringProcessor.ConflictsInTestsException expected) {
- return;
- }
- fail("Expected an unsafe usage to be found");
- }
-
-
-}
diff --git a/blaze-java/tests/integrationtests/com/google/idea/blaze/java/sync/JavaSyncTest.java b/blaze-java/tests/integrationtests/com/google/idea/blaze/java/sync/JavaSyncTest.java
deleted file mode 100644
index 52998b1..0000000
--- a/blaze-java/tests/integrationtests/com/google/idea/blaze/java/sync/JavaSyncTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.sync.BlazeSyncIntegrationTestCase;
-import com.google.idea.blaze.base.sync.BlazeSyncParams;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
-import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Java-specific sync integration tests.
- */
-public class JavaSyncTest extends BlazeSyncIntegrationTestCase {
-
- public void testJavaClassesPresentInClassPath() throws Exception {
- setProjectView(
- "directories:",
- " java/com/google",
- "targets:",
- " //java/com/google:lib",
- "workspace_type: java"
- );
-
- createWorkspaceFile(
- "java/com/google/ClassWithUniqueName1.java",
- "package com.google;",
- "public class ClassWithUniqueName1 {}"
- );
-
- createWorkspaceFile(
- "java/com/google/ClassWithUniqueName2.java",
- "package com.google;",
- "public class ClassWithUniqueName2 {}"
- );
-
- ImmutableMap<Label, RuleIdeInfo> ruleMap = RuleMapBuilder.builder()
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("java/com/google/BUILD"))
- .setLabel("//java/com/google:lib")
- .setKind("java_library")
- .addSource(sourceRoot("java/com/google/ClassWithUniqueName1.java"))
- .addSource(sourceRoot("java/com/google/ClassWithUniqueName2.java"))
- .setJavaInfo(JavaRuleIdeInfo.builder()))
- .build();
-
- setRuleMap(ruleMap);
-
- BlazeSyncParams syncParams = new BlazeSyncParams.Builder("Full Sync", BlazeSyncParams.SyncMode.FULL).build();
- runBlazeSync(syncParams);
-
- assertNoErrors();
-
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
- assertThat(blazeProjectData).isNotNull();
- assertThat(blazeProjectData.ruleMap).isEqualTo(ruleMap);
- assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
- .isEqualTo(WorkspaceType.JAVA);
-
- BlazeJavaSyncData javaSyncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
- List<BlazeContentEntry> contentEntries = javaSyncData.importResult.contentEntries;
- assertThat(contentEntries).hasSize(1);
-
- BlazeContentEntry contentEntry = contentEntries.get(0);
- assertThat(contentEntry.contentRoot.getPath()).isEqualTo(tempDirectory.getPath() + "/java/com/google");
- assertThat(contentEntry.sources).hasSize(1);
-
- BlazeSourceDirectory sourceDir = contentEntry.sources.get(0);
- assertThat(sourceDir.getPackagePrefix()).isEqualTo("com.google");
- assertThat(sourceDir.getDirectory().getPath()).isEqualTo(tempDirectory.getPath() + "/java/com/google");
- }
-
-}
diff --git a/blaze-java/tests/unittests/com/google/idea/blaze/java/run/BlazeCommandRunConfigurationTest.java b/blaze-java/tests/unittests/com/google/idea/blaze/java/run/BlazeCommandRunConfigurationTest.java
deleted file mode 100644
index 07a59b2..0000000
--- a/blaze-java/tests/unittests/com/google/idea/blaze/java/run/BlazeCommandRunConfigurationTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.java.run.BlazeCommandRunConfiguration.BlazeCommandRunConfigurationSettingsEditor;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
-import org.jdom.Element;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for {@link BlazeCommandRunConfiguration}.
- */
-@RunWith(JUnit4.class)
-public class BlazeCommandRunConfigurationTest extends BlazeTestCase {
- private static Label label;
- private static final BlazeCommandName COMMAND = BlazeCommandName.fromString("command");
- private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS = new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
-
- BlazeCommandRunConfigurationType type = new BlazeCommandRunConfigurationType();
- BlazeCommandRunConfiguration configuration;
-
-
- @Override
- protected void initTest(
- @NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
-
- applicationServices.register(ExperimentService.class, new MockExperimentService());
- projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
- BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
-
- configuration = type.getFactory().createTemplateConfiguration(project);
- label = new Label("//package:rule");
- }
-
- @Test
- public void readAndWriteShouldMatch() throws InvalidDataException, WriteExternalException {
- configuration.setTarget(label);
- configuration.setCommand(COMMAND);
- configuration.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- configuration.setExeFlags(ImmutableList.of("--exeFlag1"));
- Element element = new Element("test");
- configuration.writeExternal(element);
- BlazeCommandRunConfiguration readConfiguration =
- type.getFactory().createTemplateConfiguration(project);
- readConfiguration.readExternal(element);
- assertThat(readConfiguration.getTarget()).isEqualTo(label);
- assertThat(readConfiguration.getCommand()).isEqualTo(COMMAND);
- assertThat(readConfiguration.getAllBlazeFlags()).isEqualTo(ImmutableList.of("--flag1", "--flag2"));
- assertThat(readConfiguration.getAllExeFlags()).isEqualTo(ImmutableList.of("--exeFlag1"));
- }
-
- @Test
- public void readAndWriteShouldHandleNulls() throws InvalidDataException, WriteExternalException {
- Element element = new Element("test");
- configuration.writeExternal(element);
- BlazeCommandRunConfiguration readConfiguration =
- type.getFactory().createTemplateConfiguration(project);
- readConfiguration.readExternal(element);
- assertThat(readConfiguration.getTarget()).isEqualTo(configuration.getTarget());
- assertThat(readConfiguration.getCommand()).isEqualTo(configuration.getCommand());
- assertThat(readConfiguration.getAllBlazeFlags()).isEqualTo(configuration.getAllBlazeFlags());
- assertThat(readConfiguration.getAllExeFlags()).isEqualTo(configuration.getAllExeFlags());
- }
-
- @Test
- public void readShouldOmitEmptyFlags() throws InvalidDataException, WriteExternalException {
- configuration.setBlazeFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
- configuration.setExeFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
- Element element = new Element("test");
- configuration.writeExternal(element);
- BlazeCommandRunConfiguration readConfiguration =
- type.getFactory().createTemplateConfiguration(project);
- readConfiguration.readExternal(element);
- assertThat(readConfiguration.getAllBlazeFlags()).isEqualTo(ImmutableList.of("hi", "I'm", "Josh"));
- assertThat(readConfiguration.getAllExeFlags()).isEqualTo(ImmutableList.of("hi", "I'm", "Josh"));
- }
-
- @Test
- public void editorApplyToAndResetFromShouldHandleNulls() throws ConfigurationException {
- BlazeCommandRunConfigurationSettingsEditor editor =
- new BlazeCommandRunConfigurationSettingsEditor("Blaze");
- editor.resetFrom(configuration);
- BlazeCommandRunConfiguration readConfiguration =
- type.getFactory().createTemplateConfiguration(project);
- editor.applyEditorTo(readConfiguration);
- assertThat(readConfiguration.getTarget()).isEqualTo(configuration.getTarget());
- assertThat(readConfiguration.getCommand()).isEqualTo(configuration.getCommand());
- assertThat(readConfiguration.getAllBlazeFlags()).isEqualTo(configuration.getAllBlazeFlags());
- assertThat(readConfiguration.getAllExeFlags()).isEqualTo(configuration.getAllExeFlags());
-
- Disposer.dispose(editor);
- }
-
- @Test
- public void editorApplyToAndResetFromShouldMatch() throws ConfigurationException {
- BlazeCommandRunConfigurationSettingsEditor editor = new BlazeCommandRunConfigurationSettingsEditor("Blaze");
- configuration.setTarget(label);
- configuration.setCommand(COMMAND);
- configuration.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- configuration.setExeFlags(ImmutableList.of("--exeFlag1", "--exeFlag2"));
- editor.resetFrom(configuration);
-
- BlazeCommandRunConfiguration readConfiguration = type.getFactory().createTemplateConfiguration(project);
- editor.applyEditorTo(readConfiguration);
- assertThat(readConfiguration.getTarget()).isEqualTo(configuration.getTarget());
- assertThat(readConfiguration.getCommand()).isEqualTo(configuration.getCommand());
- assertThat(readConfiguration.getAllBlazeFlags()).isEqualTo(configuration.getAllBlazeFlags());
- assertThat(readConfiguration.getAllExeFlags()).isEqualTo(configuration.getAllExeFlags());
-
- Disposer.dispose(editor);
- }
-}
diff --git a/blaze-java/tests/unittests/com/google/idea/blaze/java/run/BlazeCommandRunProfileStateTest.java b/blaze-java/tests/unittests/com/google/idea/blaze/java/run/BlazeCommandRunProfileStateTest.java
deleted file mode 100644
index 03a0a7f..0000000
--- a/blaze-java/tests/unittests/com/google/idea/blaze/java/run/BlazeCommandRunProfileStateTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.run;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.command.BuildFlagsProvider;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.intellij.openapi.project.Project;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Tests for {@link BlazeCommandRunProfileState}.
- */
-@RunWith(JUnit4.class)
-public class BlazeCommandRunProfileStateTest extends BlazeTestCase {
-
- private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS = new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
-
- private BlazeCommandRunConfiguration configuration;
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
- BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
-
- configuration = new BlazeCommandRunConfigurationType().getFactory().createTemplateConfiguration(project);
-
- ExperimentService experimentService = new MockExperimentService();
- applicationServices.register(ExperimentService.class, experimentService);
- applicationServices.register(RuleFinder.class, new MockRuleFinder());
- applicationServices.register(BlazeUserSettings.class, new BlazeUserSettings());
- registerExtensionPoint(BuildFlagsProvider.EP_NAME, BuildFlagsProvider.class);
- }
-
- @Test
- public void flagsShouldBeAppendedIfPresent() {
- configuration.setTarget(new Label("//label:rule"));
- configuration.setCommand(BlazeCommandName.fromString("command"));
- configuration.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- assertThat(
- BlazeCommandRunProfileState.getBlazeCommand(project, configuration, ProjectViewSet.builder().build(), false /* debug */).toList())
- .isEqualTo(ImmutableList.of(
- "/usr/bin/blaze",
- "command",
- BlazeFlags.getToolTagFlag(),
- "--flag1",
- "--flag2",
- "--",
- "//label:rule"
- ));
- }
-
- @Test
- public void debugFlagShouldBeIncludedForJavaTest() {
- configuration.setTarget(new Label("//label:rule"));
- configuration.setCommand(BlazeCommandName.fromString("command"));
- assertThat(
- BlazeCommandRunProfileState.getBlazeCommand(project, configuration, ProjectViewSet.builder().build(), true /* debug */).toList())
- .isEqualTo(ImmutableList.of(
- "/usr/bin/blaze",
- "command",
- BlazeFlags.getToolTagFlag(),
- "--java_debug",
- "--",
- "//label:rule"
- ));
- }
-
- @Test
- public void debugFlagShouldBeIncludedForJavaBinary() {
- configuration.setTarget(new Label("//label:java_binary_rule"));
- configuration.setCommand(BlazeCommandName.fromString("command"));
- assertThat(
- BlazeCommandRunProfileState.getBlazeCommand(project, configuration, ProjectViewSet.builder().build(), true /* debug */).toList())
- .isEqualTo(ImmutableList.of(
- "/usr/bin/blaze",
- "command",
- BlazeFlags.getToolTagFlag(),
- "--",
- "//label:java_binary_rule",
- "--debug"
- ));
- }
-
- private static class MockRuleFinder extends RuleFinder {
- @Override
- public List<RuleIdeInfo> findRules(Project project, Predicate<RuleIdeInfo> predicate) {
- return null;
- }
-
- @Override
- public RuleIdeInfo ruleForTarget(Project project, final Label target) {
- RuleIdeInfo.Builder builder = RuleIdeInfo.builder().setLabel(target);
- if (target.ruleName().toString().equals("java_binary_rule")) {
- builder.setKind(Kind.JAVA_BINARY);
- } else {
- builder.setKind(Kind.JAVA_TEST);
- }
- return builder.build();
- }
- }
-}
diff --git a/blaze-java/tests/unittests/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporterTest.java b/blaze-java/tests/unittests/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporterTest.java
deleted file mode 100644
index 1393cb1..0000000
--- a/blaze-java/tests/unittests/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporterTest.java
+++ /dev/null
@@ -1,1146 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.importer;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.ideinfo.*;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.prefetch.MockPrefetchService;
-import com.google.idea.blaze.base.prefetch.PrefetchService;
-import com.google.idea.blaze.base.projectview.ProjectView;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.projectview.section.Glob;
-import com.google.idea.blaze.base.projectview.section.ListSection;
-import com.google.idea.blaze.base.projectview.section.sections.*;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ErrorCollector;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.google.idea.blaze.base.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.java.sync.jdeps.JdepsMap;
-import com.google.idea.blaze.java.sync.model.*;
-import com.google.idea.blaze.java.sync.source.JavaSourcePackageReader;
-import com.google.idea.blaze.java.sync.source.PackageManifestReader;
-import com.google.idea.blaze.java.sync.source.SourceArtifact;
-import com.google.idea.blaze.java.sync.workingset.JavaWorkingSet;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.junit.Test;
-
-import java.io.File;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.*;
-
-/**
- * Tests for BlazeJavaWorkspaceImporter
- */
-public class BlazeJavaWorkspaceImporterTest extends BlazeTestCase {
-
- private String FAKE_WORKSPACE_ROOT = "/root";
- private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File(FAKE_WORKSPACE_ROOT));
-
- private static final String FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT =
- "blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin";
-
- private static final String FAKE_GEN_ROOT =
- "/path/to/8093958afcfde6c33d08b621dfaa4e09/root/"
- + FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT;
-
- private static final ArtifactLocationDecoder FAKE_ARTIFACT_DECODER = new ArtifactLocationDecoder(
- new BlazeRoots(
- new File("/"),
- ImmutableList.of(),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen")
- ),
- null
- );
-
- private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS = new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
-
- private static class JdepsMock implements JdepsMap {
- Map<Label, List<String>> jdeps = Maps.newHashMap();
-
- @Nullable
- @Override
- public List<String> getDependenciesForRule(@NotNull Label label) {
- return jdeps.get(label);
- }
-
- JdepsMock put(Label label, List<String> values) {
- jdeps.put(label, values);
- return this;
- }
- }
-
- private BlazeContext context;
- private ErrorCollector errorCollector = new ErrorCollector();
- private final JdepsMock jdepsMap = new JdepsMock();
- private JavaWorkingSet workingSet = null;
- private MockExperimentService experimentService;
-
- @Override
- protected void initTest(@NotNull Container applicationServices, @NotNull Container projectServices) {
- experimentService = new MockExperimentService();
- applicationServices.register(ExperimentService.class, experimentService);
-
- BlazeExecutor blazeExecutor = new MockBlazeExecutor();
- applicationServices.register(BlazeExecutor.class, blazeExecutor);
- projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
- BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
-
- // will silently fall back to FilePathJavaPackageReader
- applicationServices.register(
- JavaSourcePackageReader.class,
- new JavaSourcePackageReader() {
- @Nullable
- @Override
- public String getDeclaredPackageOfJavaFile(@NotNull BlazeContext context, @NotNull SourceArtifact sourceArtifact) {
- return null;
- }
- }
- );
- applicationServices.register(PackageManifestReader.class, new PackageManifestReader());
- applicationServices.register(PrefetchService.class, new MockPrefetchService());
-
- context = new BlazeContext();
- context.addOutputSink(IssueOutput.class, errorCollector);
- }
-
- BlazeJavaImportResult importWorkspace(
- WorkspaceRoot workspaceRoot,
- RuleMapBuilder ruleMapBuilder,
- ProjectView projectView) {
-
- ProjectViewSet projectViewSet = ProjectViewSet.builder().add(projectView).build();
-
- BlazeJavaWorkspaceImporter blazeWorkspaceImporter = new BlazeJavaWorkspaceImporter(
- project,
- workspaceRoot,
- projectViewSet,
- ruleMapBuilder.build(),
- jdepsMap,
- workingSet,
- FAKE_ARTIFACT_DECODER
- );
-
- return blazeWorkspaceImporter.importWorkspace(context);
- }
-
- /**
- * Ensure an empty response results in an empty import result.
- */
- @Test
- public void testEmptyProject() {
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- RuleMapBuilder.builder(),
- ProjectView.builder().build()
- );
- errorCollector.assertNoIssues();
- assertTrue(result.contentEntries.isEmpty());
- }
-
- @Test
- public void testSingleModule() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example"))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug-ijar.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertEquals(1, result.buildOutputJars.size());
- File compilerOutputLib = result.buildOutputJars.iterator().next();
- assertNotNull(compilerOutputLib);
- assertTrue(compilerOutputLib.getPath().endsWith("example_debug.jar"));
-
- assertThat(result.contentEntries).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .build())
- .build()
- );
-
- assertThat(result.javaSourceFiles).containsExactly(
- sourceRoot("java/com/google/android/apps/example/MainActivity.java").getFile(),
- sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java").getFile()
- );
- }
-
- @Test
- public void testGeneratedLibrariesIncluded() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/example"))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/example:lib")
- .setBuildFile(sourceRoot("java/com/google/example/BUILD"))
- .setKind("java_library")
- .addSource(sourceRoot("java/com/google/example/Test.java"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/example/lib-ijar.jar"))
- .setRuntimeJar(genRoot("java/com/google/example/lib.jar")))
- .addGeneratedJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/example/lib-gen.jar"))
- .setRuntimeJar(genRoot("java/com/google/example/lib-gen.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- assertThat(result.libraries.values().stream().map(BlazeJavaWorkspaceImporterTest::libraryFileName).collect(Collectors.toList()))
- .containsExactly("lib-gen.jar");
- }
-
-
- /**
- * Imports two binaries and a library. Only one binary should pass the package filter.
- */
- @Test
- public void testImportFilter() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example"))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/android/libraries/example:example")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/libraries/example:example")
- .setBuildFile(sourceRoot("java/com/google/android/libraries/example/BUILD"))
- .setKind("android_library")
- .addSource(sourceRoot("java/com/google/android/libraries/example/SharedActivity.java"))
- .setAndroidInfo(
- AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/libraries/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/libraries/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.libraries.example"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/libraries/example/example.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/libraries/example/example.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/dontimport:example_debug")
- .setBuildFile(sourceRoot("java/com/dontimport/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/dontimport/MainActivity.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/dontimport/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/dontimport/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.dontimport"))
- .addDependency("//java/com/dontimport:sometarget")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/dontimport/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/dontimport/example_debug.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.contentEntries).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .build())
- .build()
- );
- assertThat(result.javaSourceFiles).containsExactly(
- sourceRoot("java/com/google/android/apps/example/MainActivity.java").getFile()
- );
- }
-
- /**
- * Import a project and its tests
- */
- @Test
- public void testProjectAndTests() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .put(ListSection.builder(TestSourceSection.KEY).add(new Glob("javatests/*")))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//javatests/com/google/android/apps/example:example")
- .setBuildFile(sourceRoot("javatests/com/google/android/apps/example/BUILD"))
- .setKind("android_test")
- .addSource(sourceRoot("javatests/com/google/android/apps/example/ExampleTests.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/android/apps/example:example_debug")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("javatests/com/google/android/apps/example/example.jar"))
- .setRuntimeJar(genRoot("javatests/com/google/android/apps/example/example.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.contentEntries).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .build())
- .build(),
- BlazeContentEntry.builder("/root/javatests/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/javatests/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .setTest(true)
- .build())
- .build()
- );
- }
-
- /**
- * Test library with a source jar
- */
- @Test
- public void testLibraryWithSourceJar() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(genRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//thirdparty/some/library:library")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/some/library:library")
- .setBuildFile(sourceRoot("/thirdparty/some/library/BUILD"))
- .setKind("java_import")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("thirdparty/some/library.jar"))
- .setRuntimeJar(genRoot("thirdparty/some/library.jar"))
- .setSourceJar(genRoot("thirdparty/some/library.srcjar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- BlazeLibrary library = findLibrary(result.libraries, "library.jar");
- assertNotNull(library);
- assertNotNull(library.getLibraryArtifact().sourceJar);
- }
-
- /**
- * Test a project with a java test rule
- */
- @Test
- public void testJavaTestRule() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .put(ListSection.builder(TestSourceSection.KEY).add(new Glob("javatests/*")))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/android/apps/example/example_debug.jar"))
- .setRuntimeJar(genRoot("java/com/google/android/apps/example/example_debug.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//javatests/com/google/android/apps/example:example")
- .setBuildFile(sourceRoot("javatests/com/google/android/apps/example/BUILD"))
- .setKind("java_test")
- .addSource(sourceRoot("javatests/com/google/android/apps/example/ExampleTests.java"))
- .addDependency("//java/com/google/android/apps/example:example_debug")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("javatests/com/google/android/apps/example/example.jar"))
- .setRuntimeJar(genRoot("javatests/com/google/android/apps/example/example.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.contentEntries).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .build())
- .build(),
- BlazeContentEntry.builder("/root/javatests/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/javatests/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .setTest(true)
- .build())
- .build()
- );
- }
-
-
- /*
- * Test that the non-android libraries can be imported.
- */
- @Test
- public void testNormalJavaLibraryPackage() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/library/something"))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/library/something:something")
- )
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/library/something:something")
- .setBuildFile(sourceRoot("java/com/google/library/something/BUILD"))
- .setKind("java_library")
- .addSource(sourceRoot("java/com/google/library/something/SomeJavaFile.java"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/library/something/something.jar"))
- .setRuntimeJar(genRoot("java/com/google/library/something/something.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.contentEntries).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google/android/apps/example")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/android/apps/example")
- .setPackagePrefix("com.google.android.apps.example")
- .build())
- .build(),
- BlazeContentEntry.builder("/root/java/com/google/library/something")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/library/something")
- .setPackagePrefix("com.google.library.something")
- .build())
- .build()
- );
- }
-
- @Test
- public void testImportTargetOutputTag() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("lib")))
- .add(DirectoryEntry.include(new WorkspacePath("lib2"))))
- .build();
-
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib:lib")
- .setBuildFile(sourceRoot("lib/BUILD"))
- .setKind("java_library")
- .addDependency("//lib2:lib2")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("lib/lib.jar"))
- .setRuntimeJar(genRoot("lib/lib.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib2:lib2")
- .setBuildFile(sourceRoot("lib2/BUILD"))
- .setKind("java_library")
- .addTag("intellij-import-target-output")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("lib2/lib2.jar"))
- .setRuntimeJar(genRoot("lib2/lib2.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
- errorCollector.assertNoIssues();
- assertEquals(1, result.libraries.size());
- }
-
- @Test
- public void testImportAsLibraryTagLegacy() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("lib")))
- .add(DirectoryEntry.include(new WorkspacePath("lib2"))))
- .build();
-
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib:lib")
- .setBuildFile(sourceRoot("lib/BUILD"))
- .setKind("java_library")
- .addDependency("//lib2:lib2")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("lib/lib.jar"))
- .setRuntimeJar(genRoot("lib/lib.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib2:lib2")
- .setBuildFile(sourceRoot("lib2/BUILD"))
- .setKind("java_library")
- .addTag("aswb-import-as-library")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("lib2/lib2.jar"))
- .setRuntimeJar(genRoot("lib2/lib2.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertEquals(1, result.libraries.size());
- }
-
- @Test
- public void testMultipleImportOfJarsGetMerged() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("lib"))))
- .build();
-
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib:libsource")
- .setBuildFile(sourceRoot("lib/BUILD"))
- .setKind("java_library")
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .addDependency("//lib:lib0")
- .addDependency("//lib:lib1"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib:lib0")
- .setBuildFile(sourceRoot("lib/BUILD"))
- .setKind("java_import")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(sourceRoot("lib/lib.jar"))
- .setRuntimeJar(sourceRoot("lib/lib.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//lib:lib1")
- .setBuildFile(sourceRoot("lib/BUILD"))
- .setKind("java_import")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(sourceRoot("lib/lib.jar"))
- .setRuntimeJar(sourceRoot("lib/lib.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
- errorCollector.assertNoIssues();
- assertEquals(1, result.libraries.size()); // The libraries were merged
- }
-
- @Test
- public void testRuleWithOnlyGeneratedSourcesIsAddedAsLibrary() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("import"))))
- .build();
-
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//import:lib")
- .setBuildFile(sourceRoot("import/BUILD"))
- .setKind("android_library")
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .addDependency("//import:import")
- .addDependency("//import:import_android"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//import:import")
- .setBuildFile(sourceRoot("import/BUILD"))
- .addSource(genRoot("import/GenSource.java"))
- .setKind("java_library")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("import/import.jar"))
- .setRuntimeJar(genRoot("import/import.jar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//import:import_android")
- .setBuildFile(sourceRoot("import/BUILD"))
- .addSource(genRoot("import/GenSource.java"))
- .setKind("android_library")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("import/import_android.jar"))
- .setRuntimeJar(genRoot("import/import_android.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(findLibrary(result.libraries, "import.jar")).isNotNull();
- assertThat(findLibrary(result.libraries, "import_android.jar")).isNotNull();
- }
-
- @Test
- public void testImportTargetOutput() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("import"))))
- .put(ListSection.builder(ImportTargetOutputSection.KEY)
- .add(new Label("//import:import")))
- .build();
-
- RuleMapBuilder response = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//import:lib")
- .setBuildFile(sourceRoot("import/BUILD"))
- .setKind("java_library")
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .addDependency("//import:import"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//import:import")
- .setBuildFile(sourceRoot("import/BUILD"))
- .setKind("java_import")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("import/import.jar"))
- .setRuntimeJar(genRoot("import/import.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- response,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.libraries).isNotEmpty();
- }
-
- private RuleMapBuilder ruleMapForJdepsSuite() {
- return RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .addSource(sourceRoot("java/com/google/android/apps/example/Test.java"))
- .setKind("java_library")
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .addDependency("//thirdparty/a:a"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/a:a")
- .setKind("java_library")
- .setBuildFile(sourceRoot("third_party/a/BUILD"))
- .addDependency("//thirdparty/b:b")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("thirdparty/a.jar"))
- .setRuntimeJar(genRoot("thirdparty/a.jar"))
- .setSourceJar(genRoot("thirdparty/a.srcjar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/b:b")
- .setKind("java_library")
- .setBuildFile(sourceRoot("third_party/b/BUILD"))
- .addDependency("//thirdparty/c:c")
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("thirdparty/b.jar"))
- .setRuntimeJar(genRoot("thirdparty/b.jar"))
- .setSourceJar(genRoot("thirdparty/b.srcjar")))))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/c:c")
- .setKind("java_library")
- .setBuildFile(sourceRoot("third_party/c/BUILD"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("thirdparty/c.jar"))
- .setRuntimeJar(genRoot("thirdparty/c.jar"))
- .setSourceJar(genRoot("thirdparty/c.srcjar")))));
- }
-
- @Test
- public void testLibraryDependenciesWithJdepsSet() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .build();
- RuleMapBuilder ruleMapBuilder = ruleMapForJdepsSuite();
- jdepsMap.put(new Label("//java/com/google/android/apps/example:example_debug"), Lists.newArrayList(
- jdepsPath("thirdparty/a.jar"),
- jdepsPath("thirdparty/c.jar"))
- );
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- assertThat(result.libraries.values().stream().map(BlazeJavaWorkspaceImporterTest::libraryFileName).collect(Collectors.toList()))
- .containsExactly("a.jar", "c.jar");
- }
-
- @Test
- public void testLibraryDependenciesWithJdepsReportingNothingShouldStillIncludeDirectDepsIfInWorkingSet() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .build();
- RuleMapBuilder ruleMapBuilder = ruleMapForJdepsSuite();
- workingSet = new JavaWorkingSet(workspaceRoot, new WorkingSet(
- ImmutableList.of(new WorkspacePath("java/com/google/android/apps/example/Test.java")),
- ImmutableList.of(),
- ImmutableList.of()
- ));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- assertThat(result.libraries.values().stream().map(BlazeJavaWorkspaceImporterTest::libraryFileName).collect(Collectors.toList()))
- .containsExactly("a.jar");
- }
-
- @Test
- public void testLibraryDependenciesWithJdepsReportingNothingShouldNotIncludeDirectDepsIfNotInWorkingSet() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/android/apps/example")))
- .add(DirectoryEntry.include(new WorkspacePath("javatests/com/google/android/apps/example"))))
- .build();
- RuleMapBuilder ruleMapBuilder = ruleMapForJdepsSuite();
- workingSet = new JavaWorkingSet(workspaceRoot, new WorkingSet(
- ImmutableList.of(),
- ImmutableList.of(),
- ImmutableList.of()
- ));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- assertThat(result.libraries.values().stream().map(BlazeJavaWorkspaceImporterTest::libraryFileName).collect(Collectors.toList()))
- .isEmpty();
- }
-
- /*
- * Test the exclude_target section
- */
- @Test
- public void testExcludeTarget() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY))
- .put(ListSection.builder(ExcludeTargetSection.KEY)
- .add(new Label("//java/com/google/android/apps/example:example_debug")))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/library/something:something")
- );
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.libraries).isEmpty();
- }
-
- /**
- * Test legacy proto_library jars, complete with overrides and everything.
- */
- @Test
- public void testLegacyProtoLibraryInfo() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath("java/com/google/example"))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/example:liba")
- .setBuildFile(sourceRoot("java/com/google/example/BUILD"))
- .setKind("java_library")
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .addDependency("//thirdparty/proto/a:a"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/example:libb")
- .setBuildFile(sourceRoot("java/com/google/example/BUILD"))
- .setKind("java_library")
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .addDependency("//thirdparty/proto/b:b"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/proto/a:a")
- .setBuildFile(sourceRoot("/thirdparty/a/BUILD"))
- .setKind("proto_library")
- .setProtoLibraryLegacyInfo(ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE)
- .addJarV1(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/a/liba-1-ijar.jar")))
- .addJarImmutable(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/a/liba-ijar.jar"))))
- .addDependency("//thirdparty/proto/b:b")
- .addDependency("//thirdparty/proto/c:c"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/proto/b:b")
- .setBuildFile(sourceRoot("/thirdparty/b/BUILD"))
- .setKind("proto_library")
- .setProtoLibraryLegacyInfo(ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1)
- .addJarV1(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/b/libb-ijar.jar")))
- .addJarImmutable(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/b/libb-2-ijar.jar"))))
- .addDependency("//thirdparty/proto/d:d"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/proto/c:c")
- .setBuildFile(sourceRoot("/thirdparty/c/BUILD"))
- .setKind("proto_library")
- .setProtoLibraryLegacyInfo(ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE)
- .addJarV1(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/c/libc-1-ijar.jar")))
- .addJarImmutable(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/c/libc-ijar.jar"))))
- .addDependency("//thirdparty/proto/d:d"))
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//thirdparty/proto/d:d")
- .setBuildFile(sourceRoot("/thirdparty/d/BUILD"))
- .setKind("proto_library")
- .setProtoLibraryLegacyInfo(ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1)
- .addJarV1(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/d/libd-ijar.jar")))
- .addJarImmutable(LibraryArtifact.builder().setJar(genRoot("thirdparty/proto/d/libd-2-ijar.jar")))));
-
- workingSet = new JavaWorkingSet(workspaceRoot, new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()));
-
- // First test - make sure that jdeps is working
- jdepsMap.put(new Label("//java/com/google/example:liba"), Lists.newArrayList(jdepsPath("thirdparty/proto/a/liba-ijar.jar")));
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
- assertThat(result.libraries).hasSize(1);
- assertThat(findLibrary(result.libraries, "liba-ijar.jar")).isNotNull();
-
-
- // Second test - put everything in the working set, which should expand to the full transitive closure
- workingSet = new JavaWorkingSet(workspaceRoot, new WorkingSet(
- ImmutableList.of(new WorkspacePath("java/com/google/example/BUILD")),
- ImmutableList.of(),
- ImmutableList.of()
- ));
-
- result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.libraries).hasSize(6);
- assertThat(findLibrary(result.libraries, "liba-ijar.jar")).isNotNull();
- assertThat(findLibrary(result.libraries, "libb-ijar.jar")).isNotNull();
- assertThat(findLibrary(result.libraries, "libb-2-ijar.jar")).isNotNull();
- assertThat(findLibrary(result.libraries, "libc-ijar.jar")).isNotNull();
- assertThat(findLibrary(result.libraries, "libd-ijar.jar")).isNotNull();
- assertThat(findLibrary(result.libraries, "libd-2-ijar.jar")).isNotNull();
- }
-
- /*
- * Test that the non-android libraries can be imported.
- */
- @Test
- public void testImporterWorksWithWorkspaceRootDirectoryIncluded() {
- ProjectView projectView = ProjectView.builder()
- .put(ListSection.builder(DirectorySection.KEY)
- .add(DirectoryEntry.include(new WorkspacePath(""))))
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/android/apps/example:example_debug")
- .setBuildFile(sourceRoot("java/com/google/android/apps/example/BUILD"))
- .setKind("android_binary")
- .addSource(sourceRoot("java/com/google/android/apps/example/MainActivity.java"))
- .addSource(sourceRoot("java/com/google/android/apps/example/subdir/SubdirHelper.java"))
- .setJavaInfo(JavaRuleIdeInfo.builder())
- .setAndroidInfo(AndroidRuleIdeInfo.builder()
- .setManifestFile(sourceRoot("java/com/google/android/apps/example/AndroidManifest.xml"))
- .addResource(sourceRoot("java/com/google/android/apps/example/res"))
- .setGenerateResourceClass(true)
- .setResourceJavaPackage("com.google.android.apps.example"))
- .addDependency("//java/com/google/library/something:something")
- )
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google/library/something:something")
- .setBuildFile(sourceRoot("java/com/google/library/something/BUILD"))
- .setKind("java_library")
- .addSource(sourceRoot("java/com/google/library/something/SomeJavaFile.java"))
- .setJavaInfo(JavaRuleIdeInfo.builder()
- .addJar(LibraryArtifact.builder()
- .setJar(genRoot("java/com/google/library/something/something.jar"))
- .setRuntimeJar(genRoot("java/com/google/library/something/something.jar")))));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- errorCollector.assertNoIssues();
-
- assertThat(result.contentEntries).containsExactly(
- BlazeContentEntry.builder("/root")
- .addSource(BlazeSourceDirectory.builder("/root")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java")
- .build())
- .build()
- );
- }
-
- @Test
- public void testLanguageLevelIsReadFromToolchain() {
- ProjectView projectView = ProjectView.builder()
- .build();
-
- RuleMapBuilder ruleMapBuilder = RuleMapBuilder.builder()
- .addRule(
- RuleIdeInfo.builder()
- .setLabel("//java/com/google:toolchain")
- .setBuildFile(sourceRoot("java/com/google/BUILD"))
- .setKind("java_toolchain")
- .setJavaToolchainIdeInfo(JavaToolchainIdeInfo.builder()
- .setSourceVersion("8")
- .setTargetVersion("8")));
-
- BlazeJavaImportResult result = importWorkspace(
- workspaceRoot,
- ruleMapBuilder,
- projectView
- );
- assertThat(result.sourceVersion).isEqualTo("8");
- }
-
- /* Utility methods */
-
- private static String libraryFileName(BlazeLibrary library) {
- return new File(library.getLibraryArtifact().jar.getRelativePath()).getName();
- }
-
- @Nullable
- private static BlazeLibrary findLibrary(Map<LibraryKey, BlazeLibrary> libraries, String libraryName) {
- for (BlazeLibrary library : libraries.values()) {
- if (library.getLibraryArtifact().jar.getFile().getPath().endsWith(libraryName)) {
- return library;
- }
- }
- return null;
- }
-
- private ArtifactLocation sourceRoot(String relativePath) {
- return ArtifactLocation.builder()
- .setRootPath(FAKE_WORKSPACE_ROOT)
- .setRelativePath(relativePath)
- .setIsSource(true)
- .build();
- }
-
- private static ArtifactLocation genRoot(String relativePath) {
- return ArtifactLocation.builder()
- .setRootPath(FAKE_GEN_ROOT)
- .setRootExecutionPathFragment(FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT)
- .setRelativePath(relativePath)
- .setIsSource(false)
- .build();
- }
-
- private static String jdepsPath(String relativePath) {
- return FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT + "/" + relativePath;
- }
-}
diff --git a/blaze-java/tests/unittests/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculatorTest.java b/blaze-java/tests/unittests/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculatorTest.java
deleted file mode 100644
index 2442f33..0000000
--- a/blaze-java/tests/unittests/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculatorTest.java
+++ /dev/null
@@ -1,1102 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.java.sync.source;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.idea.blaze.base.BlazeTestCase;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
-import com.google.idea.blaze.base.experiments.ExperimentService;
-import com.google.idea.blaze.base.experiments.MockExperimentService;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
-import com.google.idea.blaze.base.io.InputStreamProvider;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.prefetch.MockPrefetchService;
-import com.google.idea.blaze.base.prefetch.PrefetchService;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.ErrorCollector;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.sync.projectview.SourceTestConfig;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
-import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
-import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.JavaSourcePackage;
-import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.PackageManifest;
-import com.intellij.util.containers.HashMap;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.io.*;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Map;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-
-/**
- * Test cases for {@link SourceDirectoryCalculator}.
- */
-public class SourceDirectoryCalculatorTest extends BlazeTestCase {
-
- private static final ImmutableMap<Label, ArtifactLocation> NO_MANIFESTS = ImmutableMap.of();
- private static final Label LABEL = new Label("//fake:label");
-
- private MockInputStreamProvider mockInputStreamProvider;
- private SourceDirectoryCalculator sourceDirectoryCalculator;
-
- private BlazeContext context = new BlazeContext();
- private ErrorCollector issues = new ErrorCollector();
- private MockExperimentService experimentService;
-
- private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/root"));
- private ArtifactLocationDecoder decoder = new ArtifactLocationDecoder(
- new BlazeRoots(
- new File("/"),
- Lists.newArrayList(new File("/usr/local/code")),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen")
- ),
- null
- );
-
- final static class TestSourceImportConfig extends SourceTestConfig {
- final boolean isTest;
-
- public TestSourceImportConfig(boolean isTest) {
- super(ProjectViewSet.builder().build());
- this.isTest = isTest;
- }
-
- @Override
- public boolean isTestSource(String relativePath) {
- return isTest;
- }
- }
-
- @Override
- protected void initTest(
- @NotNull Container applicationServices,
- @NotNull Container projectServices) {
- super.initTest(applicationServices, projectServices);
-
- mockInputStreamProvider = new MockInputStreamProvider();
- applicationServices.register(
- InputStreamProvider.class,
- mockInputStreamProvider
- );
- applicationServices.register(JavaSourcePackageReader.class, new JavaSourcePackageReader());
- applicationServices.register(PackageManifestReader.class, new PackageManifestReader());
- applicationServices.register(FileAttributeProvider.class, new MockFileAttributeProvider());
-
- context.addOutputSink(IssueOutput.class, issues);
- sourceDirectoryCalculator = new SourceDirectoryCalculator();
-
- BlazeExecutor blazeExecutor = new MockBlazeExecutor();
- applicationServices.register(BlazeExecutor.class, blazeExecutor);
-
- experimentService = new MockExperimentService();
- applicationServices.register(ExperimentService.class, experimentService);
-
- applicationServices.register(PrefetchService.class, new MockPrefetchService());
- }
-
- @Test
- public void testWorkspacePathIsAddedWithoutSources() throws Exception {
- List<SourceArtifact> sourceArtifacts = ImmutableList.of();
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false /* isTest */),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google/app")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google/app")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/app")
- .setPackagePrefix("com.google.app")
- .build())
- .build()
- );
- }
-
- @Test
- public void testCalculatesPackageForSimpleCase() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .build()
- );
- issues.assertNoIssues();
- }
-
- @Test
- public void testSourcesToSourceDirectories_testReturnsTest() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(true),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .setTest(true)
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_multipleMatchingPackagesAreMerged() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}")
- .addFile("/root/java/com/google/subpackage/Bla.java",
- "package com.google.subpackage;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .build()
- );
- }
-
- @Test
- public void testMultipleDirectoriesAreMergedWithDirectoryRootAsWorkspaceRoot() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/idea/blaze/plugin/run/Run.java",
- "package com.google.idea.blaze.plugin.run;\n public class run {}")
- .addFile("/root/java/com/google/idea/blaze/plugin/sync/Sync.java",
- "package com.google.idea.blaze.plugin.sync;\n public class Sync {}")
- .addFile("/root/java/com/google/idea/blaze/plugin/Plugin.java",
- "package com.google.idea.blaze.plugin;\n public class Plugin {}")
- ;
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/idea/blaze/plugin/run/Run.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/idea/blaze/plugin/sync/Sync.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/idea/blaze/plugin/Plugin.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root")
- .addSource(BlazeSourceDirectory.builder("/root")
- .setPackagePrefix("")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java")
- .setPackagePrefix("")
- .build())
- .build()
- );
- }
-
- @Test
- public void testIncorrectPackageInMiddleOfTreeCausesMergePointHigherUp() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/idea/blaze/plugin/run/Run.java",
- "package com.google.idea.blaze.plugin.run;\n public class run {}")
- .addFile("/root/java/com/google/idea/blaze/plugin/sync/Sync.java",
- "package com.google.idea.blaze.plugin.sync;\n public class Sync {}")
- .addFile("/root/java/com/google/idea/blaze/Incorrect.java",
- "package com.google.idea.blaze.incorrect;\n public class Incorrect {}")
- ;
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/idea/blaze/plugin/run/Run.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/idea/blaze/plugin/sync/Sync.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/idea/blaze/Incorrect.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root")
- .addSource(BlazeSourceDirectory.builder("/root")
- .setPackagePrefix("")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/idea/blaze")
- .setPackagePrefix("com.google.idea.blaze.incorrect")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/idea/blaze/plugin")
- .setPackagePrefix("com.google.idea.blaze.plugin")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_multipleNonMatchingPackagesAreNotMerged() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}")
- .addFile("/root/java/com/google/subpackage/Bla.java",
- "package com.google.different;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
- .setPackagePrefix("com.google.different")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_childMatchesPathButParentDoesnt() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.facebook;\n public class Bla {}")
- .addFile("/root/java/com/google/subpackage/Bla.java",
- "package com.google.subpackage;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.facebook")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
- .setPackagePrefix("com.google.subpackage")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_orderIsIrrelevant() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}")
- .addFile("/root/java/com/google/subpackage/Bla.java",
- "package com.google.different;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
- .setPackagePrefix("com.google.different")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_packagesMatchPath() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_packagesDoNotMatchPath() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.facebook;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.facebook")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_completePackagePathMismatch() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/org/foo/Bla.java",
- "package com.facebook;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/org/foo/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/org")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/org")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/org")
- .setPackagePrefix("com.org")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/org/foo")
- .setPackagePrefix("com.facebook")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_sourcesOutsideOfModuleGeneratesIssue() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/facebook/Bla.java",
- "package com.facebook;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/facebook/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
-
- issues.assertIssueContaining("Did not add");
- }
-
- @Test
- public void testSourcesToSourceDirectories_generatedSourcesOutsideOfModuleGeneratesNoIssue() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/facebook/Bla.java",
- "package com.facebook;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/facebook/Bla.java")
- .setRootPath("/root")
- .setIsSource(false))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google/my")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- }
-
- @Test
- public void testSourcesToSourceDirectories_missingPackageDeclaration() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
-
- issues.assertIssueContaining("No package name string found");
- }
-
- @Test
- public void testCompetingPackageDeclarationPicksMajority() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Foo.java",
- "package com.google.different;\n public class Foo {}")
- .addFile("/root/java/com/google/Bla.java",
- "package com.google;\n public class Bla {}")
- .addFile("/root/java/com/google/Bla2.java",
- "package com.google;\n public class Bla2 {}")
- .addFile("/root/java/com/google/Bla3.java",
- "package com.google;\n public class Bla3 {}")
- ;
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla2.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla3.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Foo.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_packagesMatchPathButNotAtRoot() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/Bla.java",
- "package com.google.different;\n public class Bla {}")
- .addFile("/root/java/com/google/subpackage/Bla.java",
- "package com.google.subpackage;\n public class Bla {}")
- .addFile("/root/java/com/google/subpackage/subsubpackage/Bla.java",
- "package com.google.subpackage.subsubpackage;\n public class Bla {}")
- ;
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/subsubpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google.different")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
- .setPackagePrefix("com.google.subpackage")
- .build())
- .build()
- );
- }
-
- @Test
- public void testSourcesToSourceDirectories_multipleSubdirectoriesAreNotMerged() throws Exception {
- mockInputStreamProvider
- .addFile("/root/java/com/google/package0/Bla.java",
- "package com.google.packagewrong0;\n public class Bla {}")
- .addFile("/root/java/com/google/package1/Bla.java",
- "package com.google.packagewrong1;\n public class Bla {}");
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/package0/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/package1/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build()
- );
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- decoder,
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- NO_MANIFESTS
- );
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/package0")
- .setPackagePrefix("com.google.packagewrong0")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/package1")
- .setPackagePrefix("com.google.packagewrong1")
- .build())
- .build()
- );
- }
-
- @Test
- public void testOldFormatManifest() throws Exception {
- setOldFormatPackageManifest(
- "/root/java/com/test.manifest",
- ImmutableList.of("/root/java/com/google/Bla.java"),
- ImmutableList.of("com.google")
- );
- ImmutableMap<Label, ArtifactLocation> manifests = ImmutableMap.<Label, ArtifactLocation>builder()
- .put(LABEL, ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setRootPath("/root")
- .setIsSource(true)
- .build())
- .build();
- Map<Label, Map<String, String>> manifestMap = readPackageManifestFiles(manifests, getDecoder("/root"));
-
- assertThat(manifestMap.get(LABEL)).containsEntry(
- "/root/java/com/google/Bla.java",
- "com.google");
- }
-
- @Test
- public void testNewFormatManifest() throws Exception {
- setNewFormatPackageManifest(
- "/root/java/com/test.manifest",
- ImmutableList.of(
- PackageManifestOuterClass.ArtifactLocation.newBuilder()
- .setRelativePath("java/com/google/Bla.java")
- .setIsSource(true)
- .build()),
- ImmutableList.of("com.google")
- );
- ImmutableMap<Label, ArtifactLocation> manifests = ImmutableMap.<Label, ArtifactLocation>builder()
- .put(LABEL, ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setRootPath("/root")
- .setIsSource(true)
- .build())
- .build();
- Map<Label, Map<String, String>> manifestMap = readPackageManifestFiles(manifests, getDecoder("/root"));
-
- assertThat(manifestMap.get(LABEL)).containsEntry(
- "/root/java/com/google/Bla.java",
- "com.google");
- }
-
- @Test
- public void testManifestSingleFile() throws Exception {
- setPackageManifest(
- "/root",
- "/root/java/com/test.manifest",
- ImmutableList.of("java/com/google/Bla.java"),
- ImmutableList.of("com.google")
- );
- ImmutableMap<Label, ArtifactLocation> manifests = ImmutableMap.<Label, ArtifactLocation>builder()
- .put(LABEL, ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setRootPath("/root")
- .setIsSource(true)
- .build())
- .build();
- Map<Label, Map<String, String>> manifestMap = readPackageManifestFiles(manifests, getDecoder("/root"));
-
- assertThat(manifestMap.get(LABEL)).containsEntry(
- "/root/java/com/google/Bla.java",
- "com.google");
- }
-
- @Test
- public void testManifestRepeatedSources() throws Exception {
- setPackageManifest(
- "/root",
- "/root/java/com/test.manifest",
- ImmutableList.of("java/com/google/Bla.java",
- "java/com/google/Foo.java"),
- ImmutableList.of("com.google", "com.google.subpackage")
- );
- setPackageManifest(
- "/root",
- "/root/java/com/test2.manifest",
- ImmutableList.of("java/com/google/Bla.java",
- "java/com/google/other/Temp.java"),
- ImmutableList.of("com.google", "com.google.other")
- );
- ImmutableMap<Label, ArtifactLocation> manifests = ImmutableMap.<Label, ArtifactLocation>builder()
- .put(new Label("//a:a"), ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setRootPath("/root")
- .setIsSource(true)
- .build())
- .put(new Label("//b:b"), ArtifactLocation.builder()
- .setRelativePath("java/com/test2.manifest")
- .setRootPath("/root")
- .setIsSource(true)
- .build())
- .build();
- Map<Label, Map<String, String>> manifestMap = readPackageManifestFiles(manifests, getDecoder("/root"));
-
- assertThat(manifestMap).hasSize(2);
-
- assertThat(manifestMap.get(new Label("//a:a"))).containsEntry(
- "/root/java/com/google/Bla.java",
- "com.google");
- assertThat(manifestMap.get(new Label("//a:a"))).containsEntry(
- "/root/java/com/google/Foo.java",
- "com.google.subpackage");
- assertThat(manifestMap.get(new Label("//b:b"))).containsEntry(
- "/root/java/com/google/other/Temp.java",
- "com.google.other");
- }
-
- @Test
- public void testManifestMissingSourcesFallback() throws Exception {
- setPackageManifest(
- "/root",
- "/root/java/com/test.manifest",
- ImmutableList.of("java/com/google/Bla.java",
- "java/com/google/Foo.java"),
- ImmutableList.of("com.google", "com.google")
- );
-
- mockInputStreamProvider.addFile("/root/java/com/google/subpackage/Bla.java",
- "package com.google.different;\n public class Bla {}");
-
- ImmutableMap<Label, ArtifactLocation> manifests = ImmutableMap.<Label, ArtifactLocation>builder()
- .put(LABEL,
- ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setRootPath("/root")
- .setIsSource(true)
- .build())
- .build();
-
- List<SourceArtifact> sourceArtifacts = ImmutableList.of(
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/Foo.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build(),
- SourceArtifact.builder(LABEL)
- .setArtifactLocation(ArtifactLocation.builder()
- .setRelativePath("java/com/google/subpackage/Bla.java")
- .setRootPath("/root")
- .setIsSource(true))
- .build());
-
- ImmutableList<BlazeContentEntry> result = sourceDirectoryCalculator.calculateContentEntries(
- context,
- workspaceRoot,
- new TestSourceImportConfig(false),
- getDecoder("/root"),
- ImmutableList.of(new WorkspacePath("java/com/google")),
- sourceArtifacts,
- manifests
- );
-
- issues.assertNoIssues();
- assertThat(result).containsExactly(
- BlazeContentEntry.builder("/root/java/com/google")
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google")
- .setPackagePrefix("com.google")
- .build())
- .addSource(BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
- .setPackagePrefix("com.google.different")
- .build())
- .build()
- );
- }
-
- @Test
- public void testCandidateRootIterator() {
- WorkspacePath directoryRoot = new WorkspacePath("com/google");
- assertThat(new SourceDirectoryCalculator.CandidateRoots(directoryRoot, new SourceDirectoryCalculator.SourceRoot(
- new WorkspacePath("com/google/a/b/c"), "com.google.a.b.c"))
- ).containsExactly(
- new SourceDirectoryCalculator.SourceRoot(new WorkspacePath("com/google/a/b"), "com.google.a.b"),
- new SourceDirectoryCalculator.SourceRoot(new WorkspacePath("com/google/a"), "com.google.a"),
- new SourceDirectoryCalculator.SourceRoot(new WorkspacePath("com/google"), "com.google")
- ).inOrder();
- assertThat(new SourceDirectoryCalculator.CandidateRoots(directoryRoot, new SourceDirectoryCalculator.SourceRoot(
- new WorkspacePath("com/google/directory"), "com.google.different"))
- ).isEmpty();
- }
-
- private void setPackageManifest(String rootPath,
- String manifestPath,
- List<String> sourceRelativePaths,
- List<String> packages) {
- PackageManifest.Builder manifest = PackageManifest.newBuilder();
- for (int i = 0; i < sourceRelativePaths.size(); i++) {
- String sourceRelativePath = sourceRelativePaths.get(i);
- String absPath = Paths.get(rootPath, sourceRelativePath).toString();
- PackageManifestOuterClass.ArtifactLocation source = PackageManifestOuterClass.ArtifactLocation.newBuilder()
- .setRootPath(rootPath)
- .setRelativePath(sourceRelativePath)
- .setIsSource(true)
- .build();
- manifest.addSources(JavaSourcePackage.newBuilder()
- .setAbsolutePath(absPath)
- .setArtifactLocation(source)
- .setPackageString(packages.get(i)));
- }
- mockInputStreamProvider.addFile(manifestPath, manifest.build().toByteArray());
- }
-
- private void setOldFormatPackageManifest(String manifestPath, List<String> sourcePaths, List<String> packages) {
- PackageManifest.Builder manifest = PackageManifest.newBuilder();
- for (int i = 0; i < sourcePaths.size(); i++) {
- manifest.addSources(JavaSourcePackage.newBuilder()
- .setAbsolutePath(sourcePaths.get(i))
- .setPackageString(packages.get(i)));
- }
- mockInputStreamProvider.addFile(manifestPath, manifest.build().toByteArray());
- }
-
- private void setNewFormatPackageManifest(String manifestPath,
- List<PackageManifestOuterClass.ArtifactLocation> sources,
- List<String> packages) {
- PackageManifest.Builder manifest = PackageManifest.newBuilder();
- for (int i = 0; i < sources.size(); i++) {
- manifest.addSources(JavaSourcePackage.newBuilder()
- .setArtifactLocation(sources.get(i))
- .setPackageString(packages.get(i)));
- }
- mockInputStreamProvider.addFile(manifestPath, manifest.build().toByteArray());
- }
-
- private static ArtifactLocationDecoder getDecoder(String rootPath) {
- File root = new File(rootPath);
- WorkspaceRoot workspaceRoot = new WorkspaceRoot(root);
- BlazeRoots roots = new BlazeRoots(
- root,
- ImmutableList.of(root),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen")
- );
- return new ArtifactLocationDecoder(roots, new WorkspacePathResolverImpl(workspaceRoot, roots));
- }
-
- private static class MockInputStreamProvider implements InputStreamProvider {
-
- private final Map<String, InputStream> javaFiles = new HashMap<String, InputStream>();
-
- public MockInputStreamProvider addFile(String filePath, String javaSrc) {
- try {
- addFile(filePath, javaSrc.getBytes("UTF-8"));
- }
- catch (UnsupportedEncodingException e) {
- fail(e.getMessage());
- }
- return this;
- }
-
- public MockInputStreamProvider addFile(String filePath, byte[] contents) {
- javaFiles.put(filePath, new ByteArrayInputStream(contents));
- return this;
- }
-
- @Override
- public InputStream getFile(@NotNull File path) throws FileNotFoundException {
- final InputStream inputStream = javaFiles.get(path.getPath());
- if (inputStream == null) {
- throw new FileNotFoundException(
- path + " has not been mapped into MockInputStreamProvider.");
- }
- return inputStream;
- }
- }
-
- private Map<Label, Map<String, String>> readPackageManifestFiles(
- Map<Label, ArtifactLocation> manifests,
- ArtifactLocationDecoder decoder) {
- return PackageManifestReader.getInstance().readPackageManifestFiles(context, decoder, manifests, MoreExecutors.sameThreadExecutor());
- }
-
- static class MockFileAttributeProvider extends FileAttributeProvider {
- @Override
- public long getFileModifiedTime(@NotNull File file) {
- return 0;
- }
- }
-}
\ No newline at end of file
diff --git a/blaze-plugin-dev/BUILD b/blaze-plugin-dev/BUILD
deleted file mode 100644
index 0377443..0000000
--- a/blaze-plugin-dev/BUILD
+++ /dev/null
@@ -1,42 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-java_library(
- name = "blaze-plugin-dev",
- srcs = glob(["src/**/*.java"]),
- deps = [
- "//blaze-base",
- "//blaze-java",
- "//intellij-platform-sdk:devkit",
- "//intellij-platform-sdk:plugin_api",
- "//third_party:jsr305",
- ],
-)
-
-filegroup(
- name = "plugin_xml",
- srcs = ["src/META-INF/blaze-plugin-dev.xml"],
-)
-
-load(
- "//intellij_test:test_defs.bzl",
- "intellij_test",
-)
-
-intellij_test(
- name = "integration_tests",
- srcs = glob(["tests/integrationtests/**/*.java"]),
- integration_tests = True,
- required_plugins = "com.google.idea.blaze.ijwb",
- test_package_root = "com.google.idea.blaze.plugin",
- deps = [
- ":blaze-plugin-dev",
- "//blaze-base",
- "//blaze-base:integration_test_utils",
- "//blaze-base:unit_test_utils",
- "//ijwb:ijwb_bazel",
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//intellij_test:lib",
- "//third_party:jsr305",
- "//third_party:test_lib",
- ],
-)
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
deleted file mode 100644
index 29f2271..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin;
-
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Kind;
-
-/**
- * Utility methods for intellij_plugin blaze rules
- */
-public class IntellijPluginRule {
-
- public static final String RULE_TAG_IJ_PLUGIN = "intellij-plugin";
-
- public static boolean isPluginRule(RuleIdeInfo rule) {
- return rule.kindIsOneOf(Kind.JAVA_IMPORT) && rule.tags.contains(RULE_TAG_IJ_PLUGIN);
- }
-}
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java
deleted file mode 100644
index eff1164..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.run;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.command.BlazeCommandName;
-import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.run.BlazeRunConfiguration;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.google.idea.blaze.plugin.IntellijPluginRule;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.Executor;
-import com.intellij.execution.configurations.*;
-import com.intellij.execution.process.OSProcessHandler;
-import com.intellij.execution.process.ProcessAdapter;
-import com.intellij.execution.process.ProcessEvent;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.ide.plugins.IdeaPluginDescriptor;
-import com.intellij.ide.plugins.PluginManagerCore;
-import com.intellij.openapi.application.JetBrainsProtocolHandler;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.SettingsEditor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.ProjectJdkTable;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ProjectRootManager;
-import com.intellij.openapi.roots.ui.configuration.JdkComboBox;
-import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
-import com.intellij.openapi.ui.ComboBox;
-import com.intellij.openapi.ui.LabeledComponent;
-import com.intellij.openapi.util.BuildNumber;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.WriteExternalException;
-import com.intellij.ui.ListCellRendererWrapper;
-import com.intellij.ui.RawCommandLineEditor;
-import com.intellij.util.PlatformUtils;
-import com.intellij.util.execution.ParametersListUtil;
-import org.jdom.Element;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.awt.*;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * A run configuration that builds a plugin jar via blaze, copies it to the
- * SDK sandbox, then runs IJ with the plugin loaded.
- */
-public class BlazeIntellijPluginConfiguration extends LocatableConfigurationBase implements BlazeRunConfiguration, ModuleRunConfiguration {
-
- private static final String TARGET_TAG = "blaze-target";
- private static final String USER_BLAZE_FLAG_TAG = "blaze-user-flag";
- private static final String USER_EXE_FLAG_TAG = "blaze-user-exe-flag";
- private static final String SDK_ATTR = "blaze-plugin-sdk";
- private static final String VM_PARAMS_ATTR = "blaze-vm-params";
- private static final String PROGRAM_PARAMS_ATTR = "blaze-program-params";
-
- private final String buildSystem;
-
- @Nullable private Label target;
- private ImmutableList<String> blazeFlags = ImmutableList.of();
- private ImmutableList<String> exeFlags = ImmutableList.of();
- @Nullable private Sdk pluginSdk;
- @Nullable private String vmParameters;
- @Nullable private String programParameters;
-
- public BlazeIntellijPluginConfiguration(
- Project project,
- ConfigurationFactory factory,
- String name,
- @Nullable RuleIdeInfo initialRule) {
- super(project, factory, name);
- this.buildSystem = Blaze.buildSystemName(project);
- if (initialRule != null) {
- target = initialRule.label;
- }
- Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdk();
- if (IdeaJdkHelper.isIdeaJdk(projectSdk)) {
- pluginSdk = projectSdk;
- }
- }
-
- @Override
- @Nullable
- public Label getTarget() {
- return target;
- }
-
- public void setTarget(Label target) {
- this.target = target;
- }
-
- private File findPluginJar() throws ExecutionException {
- RuleIdeInfo rule = RuleFinder.getInstance().ruleForTarget(getProject(), getTarget());
- if (rule == null) {
- throw new ExecutionException(buildSystem + " rule '" + getTarget() + "' not imported during sync");
- }
- JavaRuleIdeInfo javaRuleIdeInfo = rule.javaRuleIdeInfo;
- if (javaRuleIdeInfo == null) {
- throw new ExecutionException(buildSystem + " rule '" + getTarget() + "' is not a valid intellij_plugin rule");
- }
- Collection<LibraryArtifact> jars = javaRuleIdeInfo.jars;
- if (javaRuleIdeInfo.jars.size() > 1) {
- throw new ExecutionException("Invalid IntelliJ plugin rule: it has multiple output jars");
- }
- LibraryArtifact artifact = jars.isEmpty() ? null : jars.iterator().next();
- if (artifact == null || artifact.runtimeJar == null) {
- throw new ExecutionException("No output plugin jar found for '" + getTarget() + "'");
- }
- return artifact.runtimeJar.getFile();
- }
-
- /**
- * Plugin jar has been previously created via blaze build. This method:
- * - copies jar to sandbox environment
- * - cracks open jar and finds plugin.xml (with ID, etc., needed for JVM args)
- * - sets up the SDK, etc. (use project SDK?)
- * - sets up the JVM, and returns a JavaCommandLineState
- */
- @Nullable
- @Override
- public RunProfileState getState(Executor executor, ExecutionEnvironment env) throws ExecutionException {
- final Sdk ideaJdk = pluginSdk;
- if (!IdeaJdkHelper.isIdeaJdk(ideaJdk)) {
- throw new ExecutionException("Choose an IntelliJ Platform Plugin SDK");
- }
- String sandboxHome = IdeaJdkHelper.getSandboxHome(ideaJdk);
- if (sandboxHome == null){
- throw new ExecutionException("No sandbox specified for IntelliJ Platform Plugin SDK");
- }
-
- try {
- sandboxHome = new File(sandboxHome).getCanonicalPath();
- }
- catch (IOException e) {
- throw new ExecutionException("No sandbox specified for IntelliJ Platform Plugin SDK");
- }
- final String canonicalSandbox = sandboxHome;
- final File pluginJar = findPluginJar();
- if (!pluginJar.exists()) {
- throw new ExecutionException("No plugin jar found. Did the " + buildSystem + " build fail?");
- }
- final File pluginJarDestination = new File(canonicalSandbox, "plugins/" + pluginJar.getName());
-
- // copy license from running instance of idea
- IdeaJdkHelper.copyIDEALicense(sandboxHome);
-
- final JavaCommandLineState state = new JavaCommandLineState(env) {
- @Override
- protected JavaParameters createJavaParameters() throws ExecutionException {
-
- // copy plugin jar to sandbox
- IdeaPluginDescriptor pluginDescriptor = PluginManagerCore.loadDescriptor(pluginJar, "plugin.xml");
- String buildNumber = IdeaJdkHelper.getBuildNumber(ideaJdk);
- if (PluginManagerCore.isIncompatible(pluginDescriptor, BuildNumber.fromString(buildNumber))) {
- throw new ExecutionException(
- String.format("Plugin SDK version '%s' is incompatible with this plugin (since: '%s', until: '%s')",
- buildNumber, pluginDescriptor.getSinceBuild(), pluginDescriptor.getUntilBuild()));
- }
-
- try {
- pluginJarDestination.getParentFile().mkdirs();
- Files.copy(pluginJar.toPath(), pluginJarDestination.toPath(), StandardCopyOption.REPLACE_EXISTING);
- }
- catch (IOException e) {
- throw new ExecutionException("Error copying plugin jar to sandbox", e);
- }
-
- final JavaParameters params = new JavaParameters();
-
- ParametersList vm = params.getVMParametersList();
-
- fillParameterList(vm, vmParameters);
- fillParameterList(params.getProgramParametersList(), programParameters);
-
- IntellijWithPluginClasspathHelper.addRequiredVmParams(params, ideaJdk);
-
- vm.defineProperty(JetBrainsProtocolHandler.REQUIRED_PLUGINS_KEY, pluginDescriptor.getPluginId().toString());
-
- if (!vm.hasProperty(PlatformUtils.PLATFORM_PREFIX_KEY) && buildNumber != null) {
- String prefix = IdeaJdkHelper.getPlatformPrefix(buildNumber);
- if (prefix != null) {
- vm.defineProperty(PlatformUtils.PLATFORM_PREFIX_KEY, prefix);
- }
- }
- return params;
- }
-
- @Override
- protected OSProcessHandler startProcess() throws ExecutionException {
- final OSProcessHandler handler = super.startProcess();
- handler.addProcessListener(new ProcessAdapter() {
- @Override
- public void processTerminated(ProcessEvent event) {
- pluginJarDestination.delete();
- }
- });
- return handler;
- }
- };
- return state;
- }
-
- private static void fillParameterList(ParametersList list, @Nullable String value) {
- if (value == null) return;
-
- for (String parameter : value.split(" ")) {
- if (parameter != null && parameter.length() > 0) {
- list.add(parameter);
- }
- }
- }
-
- @Override
- public Module[] getModules() {
- return Module.EMPTY_ARRAY;
- }
-
- @Override
- public void checkConfiguration() throws RuntimeConfigurationException {
- super.checkConfiguration();
-
- Label target = getTarget();
- if (target == null) {
- throw new RuntimeConfigurationError("Select a target to run");
- }
- RuleIdeInfo rule = RuleFinder.getInstance().ruleForTarget(getProject(), target);
- if (rule == null) {
- throw new RuntimeConfigurationError("The selected target does not exist.");
- }
- if (!IntellijPluginRule.isPluginRule(rule)) {
- throw new RuntimeConfigurationError(
- "The selected target is not an intellij_plugin");
- }
- if (!IdeaJdkHelper.isIdeaJdk(pluginSdk)) {
- throw new RuntimeConfigurationError("Select an IntelliJ Platform Plugin SDK");
- }
- }
-
- @Override
- public void readExternal(Element element) throws InvalidDataException {
- super.readExternal(element);
- // Target is persisted as a tag to permit multiple targets in the future.
- Element targetElement = element.getChild(TARGET_TAG);
- if (targetElement != null && !Strings.isNullOrEmpty(targetElement.getTextTrim())) {
- target = (Label) TargetExpression.fromString(targetElement.getTextTrim());
- }
- else {
- target = null;
- }
- blazeFlags = loadUserFlags(element, USER_BLAZE_FLAG_TAG);
- exeFlags = loadUserFlags(element, USER_EXE_FLAG_TAG);
-
- String sdkName = element.getAttributeValue(SDK_ATTR);
- if (!Strings.isNullOrEmpty(sdkName)) {
- pluginSdk = ProjectJdkTable.getInstance().findJdk(sdkName);
- }
- vmParameters = Strings.emptyToNull(element.getAttributeValue(VM_PARAMS_ATTR));
- programParameters = Strings.emptyToNull(element.getAttributeValue(PROGRAM_PARAMS_ATTR));
- }
-
- private static ImmutableList<String> loadUserFlags(Element root,String tag) {
- ImmutableList.Builder<String> flagsBuilder = ImmutableList.builder();
- for (Element e : root.getChildren(tag)) {
- String flag = e.getTextTrim();
- if (flag != null && !flag.isEmpty()) {
- flagsBuilder.add(flag);
- }
- }
- return flagsBuilder.build();
- }
-
- private static void saveUserFlags(Element root, List<String> flags, String tag) {
- for (String flag : flags) {
- Element child = new Element(tag);
- child.setText(flag);
- root.addContent(child);
- }
- }
-
- @Override
- public void writeExternal(Element element) throws WriteExternalException {
- super.writeExternal(element);
- if (target != null) {
- // Target is persisted as a tag to permit multiple targets in the future.
- Element targetElement = new Element(TARGET_TAG);
- targetElement.setText(target.toString());
- element.addContent(targetElement);
- }
- saveUserFlags(element, blazeFlags, USER_BLAZE_FLAG_TAG);
- saveUserFlags(element, exeFlags, USER_EXE_FLAG_TAG);
- if (pluginSdk != null) {
- element.setAttribute(SDK_ATTR, pluginSdk.getName());
- }
- if (vmParameters != null) {
- element.setAttribute(VM_PARAMS_ATTR, vmParameters);
- }
- if (programParameters != null) {
- element.setAttribute(PROGRAM_PARAMS_ATTR, programParameters);
- }
- }
-
- @Override
- public BlazeIntellijPluginConfiguration clone() {
- final BlazeIntellijPluginConfiguration configuration = (BlazeIntellijPluginConfiguration) super.clone();
- configuration.target = target;
- configuration.blazeFlags = blazeFlags;
- configuration.exeFlags = exeFlags;
- configuration.pluginSdk = pluginSdk;
- configuration.vmParameters = vmParameters;
- configuration.programParameters = programParameters;
- return configuration;
- }
-
- protected BlazeCommand buildBlazeCommand(Project project, ProjectViewSet projectViewSet) {
- BlazeCommand.Builder command = BlazeCommand.builder(Blaze.getBuildSystem(getProject()), BlazeCommandName.BUILD)
- .addTargets(getTarget())
- .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
- .addBlazeFlags(blazeFlags)
- .addExeFlags(exeFlags)
- ;
- return command.build();
- }
-
- @Override
- public BlazeIntellijPluginConfigurationSettingsEditor getConfigurationEditor() {
- List<RuleIdeInfo> javaRules = RuleFinder.getInstance().findRules(getProject(), IntellijPluginRule::isPluginRule);
- List<Label> javaLabels = Lists.newArrayList();
- for (RuleIdeInfo rule : javaRules) {
- javaLabels.add(rule.label);
- }
- return new BlazeIntellijPluginConfigurationSettingsEditor(buildSystem, javaLabels);
- }
-
- @Override
- @Nullable
- public String suggestedName() {
- Label target = getTarget();
- if (target == null) {
- return null;
- }
- return target.ruleName().toString();
- }
-
- @VisibleForTesting
- static class BlazeIntellijPluginConfigurationSettingsEditor extends SettingsEditor<BlazeIntellijPluginConfiguration> {
- private final String buildSystemName;
- private final ComboBox targetCombo;
- private final JTextArea blazeFlagsField = new JTextArea(5, 0);
- private final JTextArea exeFlagsField = new JTextArea(5, 0);
- private final JdkComboBox sdkCombo;
- private final LabeledComponent<RawCommandLineEditor> vmParameters = new LabeledComponent<>();
- private final LabeledComponent<RawCommandLineEditor> programParameters = new LabeledComponent<>();
-
- public BlazeIntellijPluginConfigurationSettingsEditor(String buildSystemName, List<Label> javaLabels) {
- this.buildSystemName = buildSystemName;
- targetCombo = new ComboBox(new DefaultComboBoxModel(Ordering.usingToString().sortedCopy(javaLabels).toArray()));
- targetCombo.setRenderer(new ListCellRendererWrapper<Label>() {
- @Override
- public void customize(JList list, @Nullable Label value, int index, boolean selected, boolean hasFocus) {
- setText(value == null ? null : value.toString());
- }
- });
-
- ProjectSdksModel sdksModel = new ProjectSdksModel();
- sdksModel.reset(null);
- sdkCombo = new JdkComboBox(sdksModel, IdeaJdkHelper::isIdeaJdkType);
- }
-
- @VisibleForTesting
- @Override
- public void resetEditorFrom(BlazeIntellijPluginConfiguration s) {
- targetCombo.setSelectedItem(s.getTarget());
- blazeFlagsField.setText(ParametersListUtil.join(s.blazeFlags));
- exeFlagsField.setText(ParametersListUtil.join(s.exeFlags));
- if (s.pluginSdk != null) {
- sdkCombo.setSelectedJdk(s.pluginSdk);
- } else {
- s.pluginSdk = sdkCombo.getSelectedJdk();
- }
- if (s.vmParameters != null) {
- vmParameters.getComponent().setText(s.vmParameters);
- }
- if (s.programParameters != null) {
- programParameters.getComponent().setText(s.programParameters);
- }
- }
-
- @VisibleForTesting
- @Override
- public void applyEditorTo(BlazeIntellijPluginConfiguration s) throws ConfigurationException {
- try {
- s.target = (Label)targetCombo.getSelectedItem();
- }
- catch (ClassCastException e) {
- throw new ConfigurationException("Invalid label specified.");
- }
- s.blazeFlags = ImmutableList.copyOf(ParametersListUtil.parse(Strings.nullToEmpty(blazeFlagsField.getText())));
- s.exeFlags = ImmutableList.copyOf(ParametersListUtil.parse(Strings.nullToEmpty(exeFlagsField.getText())));
- s.pluginSdk = sdkCombo.getSelectedJdk();
- s.vmParameters = vmParameters.getComponent().getText();
- s.programParameters = programParameters.getComponent().getText();
- }
-
- @Override
- protected JComponent createEditor() {
- vmParameters.setText("VM options:");
- vmParameters.setComponent(new RawCommandLineEditor());
- vmParameters.getComponent().setDialogCaption(vmParameters.getRawText());
- vmParameters.setLabelLocation(BorderLayout.WEST);
-
- programParameters.setText("Program arguments");
- programParameters.setComponent(new RawCommandLineEditor());
- programParameters.getComponent().setDialogCaption(programParameters.getRawText());
- programParameters.setLabelLocation(BorderLayout.WEST);
-
- return UiUtil.createBox(
- new JLabel("Target:"),
- targetCombo,
- new JLabel("Plugin SDK"),
- sdkCombo,
- vmParameters.getLabel(),
- vmParameters.getComponent(),
- programParameters.getLabel(),
- programParameters.getComponent(),
- new JLabel(buildSystemName + " flags:"),
- blazeFlagsField,
- new JLabel("Executable flags:"),
- exeFlagsField
- );
- }
- }
-}
-
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfigurationType.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfigurationType.java
deleted file mode 100644
index 0b8356f..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfigurationType.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.run;
-
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
-import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.plugin.IntellijPluginRule;
-import com.intellij.execution.BeforeRunTask;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.RunnerAndConfigurationSettings;
-import com.intellij.execution.configurations.ConfigurationFactory;
-import com.intellij.execution.configurations.ConfigurationType;
-import com.intellij.execution.configurations.ConfigurationTypeUtil;
-import com.intellij.icons.AllIcons;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Key;
-
-import javax.swing.*;
-
-/**
- * A type for run configurations that build an IntelliJ plugin jar via blaze,
- * then load them in an IntelliJ application
- */
-public class BlazeIntellijPluginConfigurationType implements ConfigurationType {
-
- private final BlazeIntellijPluginConfigurationFactory factory = new BlazeIntellijPluginConfigurationFactory(this);
-
- public static class BlazeIntellijPluginRuleConfigurationFactory implements BlazeRuleConfigurationFactory {
- @Override
- public boolean handlesRule(WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule) {
- return workspaceLanguageSettings.isWorkspaceType(WorkspaceType.INTELLIJ_PLUGIN)
- && IntellijPluginRule.isPluginRule(rule);
- }
-
- @Override
- public RunnerAndConfigurationSettings createForRule(RunManager runManager, RuleIdeInfo rule) {
- return getInstance().factory.createForRule(runManager, rule);
- }
- }
-
- public static class BlazeIntellijPluginConfigurationFactory extends ConfigurationFactory {
-
- protected BlazeIntellijPluginConfigurationFactory(ConfigurationType type) {
- super(type);
- }
-
- @Override
- public boolean isApplicable(Project project) {
- return Blaze.isBlazeProject(project);
- }
-
- @Override
- public BlazeIntellijPluginConfiguration createTemplateConfiguration(Project project) {
- return new BlazeIntellijPluginConfiguration(
- project,
- this,
- "Unnamed",
- RuleFinder.getInstance().findFirstRule(project, IntellijPluginRule::isPluginRule)
- );
- }
-
- @Override
- public void configureBeforeRunTaskDefaults(
- Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
- task.setEnabled(providerID.equals(BuildPluginBeforeRunTaskProvider.ID));
- }
-
- public RunnerAndConfigurationSettings createForRule(RunManager runManager, RuleIdeInfo rule) {
- final RunnerAndConfigurationSettings settings =
- runManager.createRunConfiguration(rule.label.toString(), this);
- final BlazeIntellijPluginConfiguration configuration =
- (BlazeIntellijPluginConfiguration) settings.getConfiguration();
- configuration.setTarget(rule.label);
- return settings;
- }
-
- @Override
- public boolean isConfigurationSingletonByDefault() {
- return true;
- }
- }
-
- public static BlazeIntellijPluginConfigurationType getInstance() {
- return ConfigurationTypeUtil.findConfigurationType(BlazeIntellijPluginConfigurationType.class);
- }
-
- @Override
- public String getDisplayName() {
- return Blaze.defaultBuildSystemName() + " IntelliJ Plugin";
- }
-
- @Override
- public String getConfigurationTypeDescription() {
- return "Configuration for launching an IntelliJ plugin in a sandbox environment.";
- }
-
- @Override
- public Icon getIcon() {
- return AllIcons.Nodes.Plugin;
- }
-
- @Override
- public String getId() {
- return "BlazeIntellijPluginConfigurationType";
- }
-
- @Override
- public BlazeIntellijPluginConfigurationFactory[] getConfigurationFactories() {
- return new BlazeIntellijPluginConfigurationFactory[] {factory};
- }
-
- public BlazeIntellijPluginConfigurationFactory getFactory() {
- return factory;
- }
-
-}
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java
deleted file mode 100644
index 216621c..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.run;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.idea.blaze.base.async.executor.BlazeExecutor;
-import com.google.idea.blaze.base.async.process.ExternalTask;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.idea.blaze.base.experiments.ExperimentScope;
-import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
-import com.google.idea.blaze.base.metrics.Action;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewManager;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.ScopedTask;
-import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
-import com.google.idea.blaze.base.scope.scopes.IssuesScope;
-import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.BlazeUserSettings;
-import com.google.idea.blaze.base.util.SaveUtil;
-import com.intellij.execution.BeforeRunTask;
-import com.intellij.execution.BeforeRunTaskProvider;
-import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.actionSystem.DataContext;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import icons.BlazeIcons;
-
-import javax.annotation.Nullable;
-import javax.swing.*;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-
-/**
- * Builds the intellij_plugin jar via 'blaze build', for Blaze Intellij Plugin run configurations
- */
-public final class BuildPluginBeforeRunTaskProvider extends BeforeRunTaskProvider<BuildPluginBeforeRunTaskProvider.Task> {
- public static final Key<Task> ID = Key.create("Blaze.Intellij.Plugin.BeforeRunTask");
-
- public static class Task extends BeforeRunTask<Task> {
- private Task() {
- super(ID);
- setEnabled(true);
- }
- }
-
- private final Project project;
-
- public BuildPluginBeforeRunTaskProvider(Project project) {
- this.project = project;
- }
-
- @Override
- public Icon getIcon() {
- return BlazeIcons.Blaze;
- }
-
- @Override
- public Icon getTaskIcon(Task task) {
- return BlazeIcons.Blaze;
- }
-
- @Override
- public boolean isConfigurable() {
- return false;
- }
-
- @Override
- public boolean configureTask(RunConfiguration runConfiguration, Task task) {
- return false;
- }
-
- @Override
- public Key<Task> getId() {
- return ID;
- }
-
- @Override
- public String getName() {
- return taskName();
- }
-
- @Override
- public String getDescription(Task task) {
- return taskName();
- }
-
- private String taskName() {
- return Blaze.buildSystemName(project) + " build plugin before-run task";
- }
-
- @Override
- public final boolean canExecuteTask(RunConfiguration configuration, Task task) {
- return isValidConfiguration(configuration);
- }
-
- @Nullable
- @Override
- public Task createTask(RunConfiguration runConfiguration) {
- if (isValidConfiguration(runConfiguration)) {
- return new Task();
- }
- return null;
- }
-
- private static boolean isValidConfiguration(RunConfiguration runConfiguration) {
- return runConfiguration instanceof BlazeIntellijPluginConfiguration;
- }
-
- @Override
- public final boolean executeTask(
- final DataContext dataContext,
- final RunConfiguration configuration,
- final ExecutionEnvironment env,
- Task task) {
- if (!canExecuteTask(configuration, task)) {
- return false;
- }
- boolean suppressConsole = BlazeUserSettings.getInstance().getSuppressConsoleForRunAction();
- return Scope.root(context -> {
- context
- .push(new ExperimentScope())
- .push(new IssuesScope(project))
- .push(new BlazeConsoleScope.Builder(project).setSuppressConsole(suppressConsole).build())
- ;
-
- final ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- IssueOutput.error("Could not load project view. Please resync project").submit(context);
- return false;
- }
-
- final ScopedTask buildTask = new ScopedTask(context) {
- @Override
- protected void execute(BlazeContext context) {
- BlazeIntellijPluginConfiguration config = (BlazeIntellijPluginConfiguration) configuration;
- BlazeCommand command = config.buildBlazeCommand(project, projectViewSet);
- if (command == null || context.hasErrors() || context.isCancelled()) {
- return;
- }
- SaveUtil.saveAllFiles();
- WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- int retVal = ExternalTask.builder(workspaceRoot, command)
- .context(context)
- .stderr(LineProcessingOutputStream.of(new IssueOutputLineProcessor(project, context, workspaceRoot)))
- .build()
- .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
- if (retVal != 0) {
- context.setHasError();
- }
- LocalFileSystem.getInstance().refresh(true);
- }
- };
-
- ListenableFuture<Void> buildFuture = BlazeExecutor.submitTask(
- project,
- "Executing blaze build for IntelliJ plugin jar",
- buildTask
- );
-
- try {
- Futures.get(buildFuture, ExecutionException.class);
- }
- catch (ExecutionException e) {
- context.setHasError();
- }
- catch (CancellationException e) {
- context.setCancelled();
- }
-
- if (context.hasErrors() || context.isCancelled()) {
- return false;
- }
- return true;
- });
- }
-
-}
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/IdeaJdkHelper.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/IdeaJdkHelper.java
deleted file mode 100644
index 3b9b152..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/IdeaJdkHelper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.run;
-
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.projectRoots.SdkTypeId;
-import org.jetbrains.idea.devkit.projectRoots.IdeaJdk;
-import org.jetbrains.idea.devkit.projectRoots.IntelliJPlatformProduct;
-import org.jetbrains.idea.devkit.projectRoots.Sandbox;
-import org.jetbrains.idea.devkit.run.IdeaLicenseHelper;
-
-import javax.annotation.Nullable;
-
-/**
- * Contains all dependencies on devkit (not included in plugin SDK)
- */
-public class IdeaJdkHelper {
-
- public static boolean isIdeaJdk(@Nullable Sdk sdk) {
- return sdk != null && isIdeaJdkType(sdk.getSdkType());
- }
-
- public static boolean isIdeaJdkType(SdkTypeId type) {
- // return IdeaJdk.getInstance().equals(type);
-
- // gross hack: SdkType.findInstance uses Class object equality, and for IJwB
- // there are currently two copies of devkit classes...
- return type.getName().equals("IDEA JDK");
- }
-
- @Nullable
- public static String getBuildNumber(Sdk sdk) {
- return IdeaJdk.getBuildNumber(sdk.getHomePath());
- }
-
- public static void copyIDEALicense(final String sandboxHome) {
- IdeaLicenseHelper.copyIDEALicense(sandboxHome);
- }
-
- /**
- * @throws RuntimeException if input Sdk is not an IdeaJdk
- */
- public static String getSandboxHome(Sdk sdk) {
- if (!isIdeaJdk(sdk))
- throw new RuntimeException("Invalid SDK type: " + sdk.getSdkType());
- return ((Sandbox) sdk.getSdkAdditionalData()).getSandboxHome();
- }
-
- @Nullable
- public static String getPlatformPrefix(String buildNumber) {
- return IntelliJPlatformProduct.fromBuildNumber(buildNumber).getPlatformPrefix();
- }
-
-}
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/IntellijWithPluginClasspathHelper.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/IntellijWithPluginClasspathHelper.java
deleted file mode 100644
index 7d88630..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/run/IntellijWithPluginClasspathHelper.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.run;
-
-import com.google.common.collect.Lists;
-import com.intellij.execution.configurations.JavaParameters;
-import com.intellij.execution.configurations.ParametersList;
-import com.intellij.openapi.projectRoots.JavaSdkType;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.util.PathsList;
-import org.jetbrains.annotations.NonNls;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Boilerplate for running an IJ application with an additional plugin,
- * copied from org.jetbrains.idea.devkit.run.PluginRunConfiguration
- */
-public class IntellijWithPluginClasspathHelper {
-
- private static final List<String> IJ_LIBRARIES = Lists.newArrayList(
- "log4j.jar",
- "trove4j.jar",
- "openapi.jar",
- "util.jar",
- "extensions.jar",
- "bootstrap.jar",
- "idea.jar",
- "idea_rt.jar"
- );
-
- private static void addIntellijLibraries(JavaParameters params,
- Sdk ideaJdk) {
- @NonNls String libPath = ideaJdk.getHomePath() + File.separator + "lib";
- PathsList list = params.getClassPath();
- for (String lib : IJ_LIBRARIES) {
- list.addFirst(libPath + File.separator + lib);
- }
- list.addFirst(((JavaSdkType) ideaJdk.getSdkType()).getToolsPath(ideaJdk));
- }
-
- public static void addRequiredVmParams(JavaParameters params,
- Sdk ideaJdk) {
- String canonicalSandbox = IdeaJdkHelper.getSandboxHome(ideaJdk);
- ParametersList vm = params.getVMParametersList();
-
- @NonNls String libPath = ideaJdk.getHomePath() + File.separator + "lib";
- vm.add("-Xbootclasspath/a:" + libPath + File.separator + "boot.jar");
-
- vm.defineProperty("idea.config.path", canonicalSandbox + File.separator + "config");
- vm.defineProperty("idea.system.path", canonicalSandbox + File.separator + "system");
- vm.defineProperty("idea.plugins.path", canonicalSandbox + File.separator + "plugins");
- vm.defineProperty("idea.classpath.index.enabled", "false");
-
- if (SystemInfo.isMac) {
- vm.defineProperty("idea.smooth.progress", "false");
- vm.defineProperty("apple.laf.useScreenMenuBar", "true");
- }
-
- if (SystemInfo.isXWindow) {
- if (!vm.hasProperty("sun.awt.disablegrab")) {
- vm.defineProperty("sun.awt.disablegrab", "true"); // See http://devnet.jetbrains.net/docs/DOC-1142
- }
- }
-
- params.setWorkingDirectory(ideaJdk.getHomePath() + File.separator + "bin" + File.separator);
- params.setJdk(ideaJdk);
-
- addIntellijLibraries(params, ideaJdk);
-
- params.setMainClass("com.intellij.idea.Main");
- }
-}
diff --git a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/sync/IntellijPluginSyncPlugin.java b/blaze-plugin-dev/src/com/google/idea/blaze/plugin/sync/IntellijPluginSyncPlugin.java
deleted file mode 100644
index bf3d14b..0000000
--- a/blaze-plugin-dev/src/com/google/idea/blaze/plugin/sync/IntellijPluginSyncPlugin.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.sync;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.java.sync.JavaLanguageLevelHelper;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.module.ModuleType;
-import com.intellij.openapi.module.StdModuleTypes;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.LanguageLevelProjectExtension;
-import com.intellij.pom.java.LanguageLevel;
-import com.intellij.util.ui.UIUtil;
-
-import javax.annotation.Nullable;
-import java.util.Set;
-
-/**
- * Development environment support for intellij plugin projects.
- * Prevents the project SDK being reset during sync
- */
-public class IntellijPluginSyncPlugin extends BlazeSyncPlugin.Adapter {
-
- @Nullable
- @Override
- public WorkspaceType getDefaultWorkspaceType() {
- return WorkspaceType.INTELLIJ_PLUGIN;
- }
-
- @Nullable
- @Override
- public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
- if (workspaceType == WorkspaceType.INTELLIJ_PLUGIN) {
- return StdModuleTypes.JAVA;
- }
- return null;
- }
-
- @Override
- public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- if (workspaceType == WorkspaceType.INTELLIJ_PLUGIN) {
- return ImmutableSet.of(LanguageClass.JAVA);
- }
- return ImmutableSet.of();
- }
-
- @Override
- public void updateSdk(Project project,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData) {
- if (!blazeProjectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.INTELLIJ_PLUGIN)) {
- return;
- }
-
- LanguageLevel javaLanguageLevel = JavaLanguageLevelHelper
- .getJavaLanguageLevel(projectViewSet, blazeProjectData, LanguageLevel.JDK_1_7);
-
- // Leave the SDK, but set the language level
- UIUtil.invokeAndWaitIfNeeded((Runnable)() -> ApplicationManager.getApplication().runWriteAction(() -> {
- LanguageLevelProjectExtension ext = LanguageLevelProjectExtension.getInstance(project);
- ext.setLanguageLevel(javaLanguageLevel);
- }));
- }
-}
diff --git a/blaze-plugin-dev/tests/integrationtests/com/google/idea/blaze/plugin/sync/PluginDevSyncTest.java b/blaze-plugin-dev/tests/integrationtests/com/google/idea/blaze/plugin/sync/PluginDevSyncTest.java
deleted file mode 100644
index 941947b..0000000
--- a/blaze-plugin-dev/tests/integrationtests/com/google/idea/blaze/plugin/sync/PluginDevSyncTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.plugin.sync;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.sync.BlazeSyncIntegrationTestCase;
-import com.google.idea.blaze.base.sync.actions.IncrementalSyncProjectAction;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.plugin.run.BlazeIntellijPluginConfiguration;
-import com.intellij.execution.RunManager;
-import com.intellij.execution.configurations.RunConfiguration;
-
-import java.util.List;
-
-import static com.google.common.truth.Truth.assertThat;
-
-/**
- * Plugin-dev specific sync integration test.
- */
-public class PluginDevSyncTest extends BlazeSyncIntegrationTestCase {
-
- public void ignore_testRunConfigurationCreatedDuringSync() throws Exception {
- setProjectView(
- "directories:",
- " java/com/google",
- "targets:",
- " //java/com/google:lib",
- " //java/com/google:plugin",
- "workspace_type: intellij_plugin"
- );
-
- createFile(
- "java/com/google/ClassWithUniqueName1.java",
- "package com.google;",
- "public class ClassWithUniqueName1 {}"
- );
-
- createFile(
- "java/com/google/ClassWithUniqueName2.java",
- "package com.google;",
- "public class ClassWithUniqueName2 {}"
- );
-
- ImmutableMap<Label, RuleIdeInfo> ruleMap = RuleMapBuilder.builder()
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("java/com/google/BUILD"))
- .setLabel("//java/com/google:lib")
- .setKind("java_library")
- .addSource(sourceRoot("java/com/google/ClassWithUniqueName1.java"))
- .addSource(sourceRoot("java/com/google/ClassWithUniqueName2.java")))
- .addRule(RuleIdeInfo.builder()
- .setBuildFile(sourceRoot("java/com/google/BUILD"))
- .setLabel("//java/com/google:plugin")
- .setKind("java_import")
- .addTag("intellij-plugin")
- )
- .build();
-
- setRuleMap(ruleMap);
-
- runBlazeSync(IncrementalSyncProjectAction.manualSyncParams);
-
- assertNoErrors();
-
- BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
- assertThat(blazeProjectData).isNotNull();
- assertThat(blazeProjectData.ruleMap).isEqualTo(ruleMap);
- assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
- .isEqualTo(WorkspaceType.INTELLIJ_PLUGIN);
-
- List<RunConfiguration> runConfigs = RunManager.getInstance(getProject()).getAllConfigurationsList();
- assertThat(runConfigs).hasSize(1);
- assertThat(runConfigs.get(0)).isInstanceOf(BlazeIntellijPluginConfiguration.class);
- }
-
-}
diff --git a/build_defs/BUILD b/build_defs/BUILD
index 47e9af1..0988550 100644
--- a/build_defs/BUILD
+++ b/build_defs/BUILD
@@ -1 +1,5 @@
-package(default_visibility=["//visibility:public"])
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+exports_files(["LICENSE"])
diff --git a/build_defs/build_defs.bzl b/build_defs/build_defs.bzl
index ada1bb5..974b857 100644
--- a/build_defs/build_defs.bzl
+++ b/build_defs/build_defs.bzl
@@ -1,65 +1,136 @@
-# Copyright 2016 The Bazel Authors. All rights reserved.
-#
-# 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.
-
-""" Description: Custom build macros for plugin.xml handling """
-#
+"""Custom build macros for plugin.xml handling.
+"""
load("//build_defs/shared:build_defs.bzl",
"merged_plugin_xml_impl",
"stamped_plugin_xml_impl",
- "intellij_plugin_impl")
+ "product_build_txt_impl",
+ "intellij_plugin_impl",
+ "plugin_bundle_impl")
-def merged_plugin_xml(name, srcs):
- """Merges N plugin.xml files together
- """
- merged_plugin_xml_impl(
- name = name,
- srcs = srcs,
- merge_tool = "//build_defs/shared:merge_xml",
- )
+def merged_plugin_xml(name, srcs, **kwargs):
+ """Merges N plugin.xml files together."""
+ merged_plugin_xml_impl(
+ name = name,
+ srcs = srcs,
+ merge_tool = "//build_defs/shared:merge_xml",
+ **kwargs)
-def stamped_plugin_xml(name, plugin_xml,
+def stamped_plugin_xml(name,
+ plugin_xml,
+ plugin_id=None,
+ plugin_name=None,
stamp_since_build=False,
stamp_until_build=False,
+ include_product_code_in_stamp=False,
version_file=None,
changelog_file=None,
- include_product_code_in_stamp=False):
- """Stamps a plugin xml file with the IJ build number.
- stamp_since_build -- Add build number to idea-version since-build.
- stamp_until_build -- Add build number to idea-version until-build.
- version_file -- A file with the version number to be included.
- changelog_file -- A file with changelog to be included.
- include_product_code_in_stamp -- Whether the product code (eg. "IC")
- is included in since-build and until-build.
- """
- stamped_plugin_xml_impl(
- name = name,
- build_txt = "//intellij-platform-sdk:build_number",
- stamp_tool = "//build_defs/shared:stamp_plugin_xml",
- plugin_xml = plugin_xml,
- stamp_since_build = stamp_since_build,
- version_file = version_file,
- changelog_file = changelog_file,
- include_product_code_in_stamp = include_product_code_in_stamp
- )
+ **kwargs):
+ """Stamps a plugin xml file with the IJ build number.
-def intellij_plugin(name, plugin_xml, deps):
- """ Creates an intellij plugin from the given deps and plugin.xml """
- intellij_plugin_impl(
- name = name,
- plugin_xml = plugin_xml,
- zip_tool = "//tools/zip",
- deps = deps,
- )
+ Args:
+ name: name of this target
+ plugin_xml: target plugin_xml to stamp
+ plugin_id: the plugin ID to stamp
+ plugin_name: the plugin name to stamp
+ stamp_since_build: Add build number to idea-version since-build.
+ stamp_until_build: Add build number to idea-version until-build.
+ include_product_code_in_stamp: Whether the product code (eg. "IC")
+ is included in since-build and until-build.
+ version_file: A file with the version number to be included.
+ changelog_file: A file with changelog to be included.
+ **kwargs: Any additional arguments to pass to the final target.
+ """
+ stamped_plugin_xml_impl(
+ name = name,
+ application_info_jar = "//intellij_platform_sdk:application_info_jar",
+ application_info_name = "//intellij_platform_sdk:application_info_name",
+ plugin_id = plugin_id,
+ plugin_name = plugin_name,
+ stamp_tool = "//build_defs/shared:stamp_plugin_xml",
+ plugin_xml = plugin_xml,
+ stamp_since_build = stamp_since_build,
+ stamp_until_build = stamp_until_build,
+ include_product_code_in_stamp = include_product_code_in_stamp,
+ version_file = version_file,
+ changelog_file = changelog_file,
+ **kwargs)
+def product_build_txt(name, **kwargs):
+ """Produces a product-build.txt file with the build number."""
+ product_build_txt_impl(
+ name = name,
+ application_info_jar = "//intellij_platform_sdk:application_info_jar",
+ application_info_name = "//intellij_platform_sdk:application_info_name",
+ product_build_txt_tool = "//build_defs/shared:product_build_txt",
+ **kwargs)
+
+
+def intellij_plugin(name, plugin_xml, deps, meta_inf_files=[], **kwargs):
+ """Creates an intellij plugin from the given deps and plugin.xml."""
+ intellij_plugin_impl(
+ name = name,
+ plugin_xml = plugin_xml,
+ zip_tool = "//third_party:zip",
+ deps = deps,
+ meta_inf_files = meta_inf_files,
+ **kwargs)
+
+def repackage_jar(name, src_rule, out,
+ rules = [
+ "com.google.common.** com.google.repackaged.common.@1",
+ "com.google.gson.** com.google.repackaged.gson.@1",
+ "com.google.protobuf.** com.google.repackaged.protobuf.@1",
+ "com.google.thirdparty.** com.google.repackaged.thirdparty.@1",
+ ], **kwargs):
+ """Repackages classes in a jar, to avoid collisions in the classpath.
+
+ Args:
+ name: the name of this target
+ src_rule: a java_binary label with the create_executable attribute set to 0
+ out: the output jarfile
+ rules: the rules to apply in the repackaging
+ Only repackage some of com.google.** from proto_deps.jar.
+ We do not repackage:
+ - com.google.net.** because that has JNI files which use
+ FindClass(JNIEnv *, const char *) with hard-coded native string
+ literals that jarjar doesn't rewrite.
+ - com.google.errorprone packages (rewriting will throw off blaze build).
+ **kwargs: Any additional arguments to pass to the final target.
+ """
+ repackage_tool = "@jarjar//jar"
+ deploy_jar = "{src_rule}_deploy.jar".format(src_rule=src_rule)
+ script_lines = []
+ script_lines.append("echo >> /tmp/repackaged_rule.txt")
+ for rule in rules:
+ script_lines.append("echo 'rule {rule}' >> /tmp/repackaged_rule.txt;".format(rule=rule))
+ script_lines.append(" ".join([
+ "$(location {repackage_tool})",
+ "process /tmp/repackaged_rule.txt",
+ "$(location {deploy_jar})",
+ "$@",
+ ]).format(
+ repackage_tool = repackage_tool,
+ deploy_jar = deploy_jar,
+ ))
+ genrule_name = name + "_gen"
+ native.genrule(
+ name = genrule_name,
+ srcs = [deploy_jar],
+ outs = [out],
+ tools = [repackage_tool],
+ cmd = "\n".join(script_lines),
+ )
+ native.java_import(
+ name = name,
+ jars = [out],
+ **kwargs)
+
+def plugin_bundle(name, plugins):
+ """Communicates to IJwB a set of plugins which should be loaded together in a run configuration.
+
+ Args:
+ name: the name of this target
+ plugins: the 'intellij_plugin' targets to be bundled
+ """
+ plugin_bundle_impl(name, plugins)
diff --git a/build_defs/shared/BUILD b/build_defs/shared/BUILD
index 60a6eaf..bb4815c 100644
--- a/build_defs/shared/BUILD
+++ b/build_defs/shared/BUILD
@@ -4,6 +4,8 @@
package(default_visibility = ["//visibility:public"])
+licenses(["notice"]) # Apache 2.0
+
py_binary(
name = "merge_xml",
srcs = ["merge_xml.py"],
@@ -13,3 +15,8 @@
name = "stamp_plugin_xml",
srcs = ["stamp_plugin_xml.py"],
)
+
+py_binary(
+ name = "product_build_txt",
+ srcs = ["product_build_txt.py"],
+)
diff --git a/build_defs/shared/build_defs.bzl b/build_defs/shared/build_defs.bzl
index 4d5712b..5c282ee 100644
--- a/build_defs/shared/build_defs.bzl
+++ b/build_defs/shared/build_defs.bzl
@@ -1,21 +1,7 @@
-# Copyright 2016 The Bazel Authors. All rights reserved.
-#
-# 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.
-
"""Custom build macros for IntelliJ plugin handling.
"""
-def merged_plugin_xml_impl(name, srcs, merge_tool):
+def merged_plugin_xml_impl(name, srcs, merge_tool, **kwargs):
"""Merges N plugin.xml files together."""
native.genrule(
name = name,
@@ -25,43 +11,58 @@
merge_tool=merge_tool,
),
tools = [merge_tool],
- )
+ **kwargs)
def _optstr(name, value):
return ("--" + name) if value else ""
def stamped_plugin_xml_impl(name,
plugin_xml,
- build_txt,
+ application_info_jar,
+ application_info_name,
stamp_tool,
+ plugin_id = None,
+ plugin_name = None,
stamp_since_build=False,
stamp_until_build=False,
+ include_product_code_in_stamp=False,
version_file=None,
changelog_file=None,
- include_product_code_in_stamp=False):
+ **kwargs):
"""Stamps a plugin xml file with the IJ build number.
Args:
- name: name of this rule
+ name: name of this target
plugin_xml: target plugin_xml to stamp
- build_txt: the file containing the build number
+ application_info_jar: the jar containing the application info
+ application_info_name: a file with the name of the application info
stamp_tool: the tool to use to stamp the version
+ plugin_id: the plugin ID to stamp
+ plugin_name: the plugin name to stamp
stamp_since_build: Add build number to idea-version since-build.
stamp_until_build: Add build number to idea-version until-build.
- version_file: A file with the version number to be included.
- changelog_file: A file with the changelog to be included.
include_product_code_in_stamp: Whether the product code (eg. "IC")
is included in since-build and until-build.
+ version_file: A file with the version number to be included.
+ changelog_file: A file with the changelog to be included.
+ **kwargs: Any additional arguments to pass to the final target.
"""
args = [
"./$(location {stamp_tool})",
"--plugin_xml=$(location {plugin_xml})",
- "--build_txt=$(location {build_txt})",
+ "--application_info_jar=$(location {application_info_jar})",
+ "--application_info_name=$(location {application_info_name})",
"{stamp_since_build}",
"{stamp_until_build}",
"{include_product_code_in_stamp}",
]
- srcs = [plugin_xml, build_txt]
+ srcs = [plugin_xml, application_info_jar, application_info_name]
+
+ if plugin_id:
+ args.append("--plugin_id=%s" % plugin_id)
+
+ if plugin_name:
+ args.append("--plugin_name='%s'" % plugin_name)
if version_file:
args.append("--version_file=$(location {version_file})")
@@ -72,19 +73,20 @@
srcs.append(changelog_file)
cmd = " ".join(args).format(
- plugin_xml=plugin_xml,
- build_txt=build_txt,
- stamp_tool=stamp_tool,
- stamp_since_build=_optstr("stamp_since_build",
- stamp_since_build),
- stamp_until_build=_optstr("stamp_until_build",
- stamp_until_build),
- version_file=version_file,
- changelog_file=changelog_file,
- include_product_code_in_stamp=_optstr(
- "include_product_code_in_stamp",
- include_product_code_in_stamp)
- ) + "> $@"
+ plugin_xml=plugin_xml,
+ application_info_jar=application_info_jar,
+ application_info_name=application_info_name,
+ stamp_tool=stamp_tool,
+ stamp_since_build=_optstr("stamp_since_build",
+ stamp_since_build),
+ stamp_until_build=_optstr("stamp_until_build",
+ stamp_until_build),
+ include_product_code_in_stamp=_optstr(
+ "include_product_code_in_stamp",
+ include_product_code_in_stamp),
+ version_file=version_file,
+ changelog_file=changelog_file,
+ ) + "> $@"
native.genrule(
name = name,
@@ -92,9 +94,46 @@
outs = [name + ".xml"],
cmd = cmd,
tools = [stamp_tool],
- )
+ **kwargs)
-def intellij_plugin_impl(name, plugin_xml, zip_tool, deps):
+def product_build_txt_impl(name,
+ product_build_txt_tool,
+ application_info_jar,
+ application_info_name,
+ **kwargs):
+ """Produces a product-build.txt file with the build number.
+
+ Args:
+ name: name of this target
+ product_build_txt_tool: the product build tool
+ application_info_jar: the jar containing the application info
+ application_info_name: a file with the name of the application info
+ **kwargs: Any additional arguments to pass to the final target.
+ """
+ args = [
+ "./$(location {product_build_txt_tool})",
+ "--application_info_jar=$(location {application_info_jar})",
+ "--application_info_name=$(location {application_info_name})",
+ ]
+ cmd = " ".join(args).format(
+ application_info_jar=application_info_jar,
+ application_info_name=application_info_name,
+ product_build_txt_tool=product_build_txt_tool,
+ ) + "> $@"
+ native.genrule(
+ name = name,
+ srcs = [application_info_jar, application_info_name],
+ outs = ["product-build.txt"],
+ cmd = cmd,
+ tools = [product_build_txt_tool],
+ **kwargs)
+
+def intellij_plugin_impl(name,
+ deps,
+ plugin_xml,
+ zip_tool,
+ meta_inf_files=[],
+ **kwargs):
"""Creates an intellij plugin from the given deps and plugin.xml."""
binary_name = name + "_binary"
deploy_jar = binary_name + "_deploy.jar"
@@ -103,22 +142,34 @@
runtime_deps = deps,
create_executable = 0,
)
+ cmd = [
+ "cp $(location {deploy_jar}) $@".format(deploy_jar=deploy_jar),
+ "chmod +w $@",
+ "mkdir -p META-INF",
+ "cp $(location {plugin_xml}) META-INF/plugin.xml".format(plugin_xml=plugin_xml),
+ "$(location {zip_tool}) -u $@ META-INF/plugin.xml >/dev/null".format(zip_tool=zip_tool),
+ ]
+ srcs = [
+ plugin_xml,
+ deploy_jar,
+ ]
+
+ for meta_inf_file in meta_inf_files:
+ cmd.append("cp $(location {meta_inf_file}) META-INF/$$(basename $(location {meta_inf_file}))".format(
+ meta_inf_file=meta_inf_file,
+ ))
+ cmd.append("$(location {zip_tool}) -u $@ META-INF/$$(basename $(location {meta_inf_file})) >/dev/null".format(
+ zip_tool=zip_tool,
+ meta_inf_file=meta_inf_file,
+ ))
+ srcs.append(meta_inf_file)
+
native.genrule(
name = name + "_genrule",
- srcs = [plugin_xml, deploy_jar],
+ srcs = srcs,
tools = [zip_tool],
outs = [name + ".jar"],
- cmd = " ; ".join([
- "cp $(location {deploy_jar}) $@",
- "chmod +w $@",
- "mkdir -p META-INF",
- "cp $(location {plugin_xml}) META-INF/plugin.xml",
- "$(location {zip_tool}) -u $@ META-INF/plugin.xml >/dev/null",
- ]).format(
- deploy_jar=deploy_jar,
- plugin_xml=plugin_xml,
- zip_tool=zip_tool,
- ),
+ cmd = " ; ".join(cmd),
)
# included (with tag) as a hack so that IJwB can recognize this is an intellij plugin
@@ -126,6 +177,17 @@
name = name,
jars = [name + ".jar"],
tags = ["intellij-plugin"],
- visibility = ["//visibility:public"],
- )
+ **kwargs)
+def plugin_bundle_impl(name, plugins):
+ """Communicates to IJwB a set of plugins which should be loaded together in a run configuration.
+
+ Args:
+ name: the name of this target
+ plugins: the 'intellij_plugin' targets to be bundled
+ """
+ native.java_library(
+ name = name,
+ exports = plugins,
+ tags = ["intellij-plugin-bundle"],
+ )
diff --git a/build_defs/shared/merge_xml.py b/build_defs/shared/merge_xml.py
index d7332f6..b5840e6 100755
--- a/build_defs/shared/merge_xml.py
+++ b/build_defs/shared/merge_xml.py
@@ -1,17 +1,3 @@
-# Copyright 2016 The Bazel Authors. All rights reserved.
-#
-# 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.
-
"""Merges multiple xml files with the same top element tags into a single file.
"""
@@ -35,9 +21,9 @@
file_dom = parse(filepath)
if file_dom.documentElement.tagName != tree.documentElement.tagName:
- raise RuntimeError("Incompatible top-level tags: '%s' vs. '%s'"
- % (file_dom.documentElement.tagName,
- tree.documentElement.tagName))
+ raise RuntimeError("Incompatible top-level tags: '%s' vs. '%s'" %
+ (file_dom.documentElement.tagName,
+ tree.documentElement.tagName))
for node in file_dom.documentElement.childNodes:
tree.documentElement.appendChild(tree.importNode(node, True))
diff --git a/build_defs/shared/product_build_txt.py b/build_defs/shared/product_build_txt.py
new file mode 100755
index 0000000..f7ac953
--- /dev/null
+++ b/build_defs/shared/product_build_txt.py
@@ -0,0 +1,72 @@
+"""Produces a product-build.txt with the product build."""
+
+import argparse
+import re
+from xml.dom.minidom import parseString
+import zipfile
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument(
+ "--application_info_jar",
+ help="The jar file containing the application info xml",
+ required=True,)
+parser.add_argument(
+ "--application_info_name",
+ help="A .txt file containing the application info xml name",
+ required=True,)
+
+
+def _parse_build_number(build_number):
+ """Parses the build number.
+
+ Args:
+ build_number: The build number as text.
+ Returns:
+ build_number, build_number_without_product_code.
+ Raises:
+ ValueError: if the build number is invalid.
+ """
+ match = re.match(r"^([A-Z]+-)?([0-9]+)(\.[0-9]+)?", build_number)
+ if match is None:
+ raise ValueError("Invalid build number: " + build_number)
+
+ build_number = match.group(1) + match.group(2) + match.group(3)
+ build_number_without_product_code = match.group(2) + match.group(3)
+ return build_number, build_number_without_product_code
+
+
+def main():
+
+ args = parser.parse_args()
+
+ with open(args.application_info_name) as f:
+ application_info_name = f.read().strip()
+
+ with zipfile.ZipFile(args.application_info_jar, "r") as zf:
+ try:
+ data = zf.read(application_info_name)
+ except:
+ raise ValueError("Could not read application info file: " +
+ application_info_name)
+ component = parseString(data)
+
+ build_elements = component.getElementsByTagName("build")
+ if not build_elements:
+ raise ValueError("Could not find <build> element.")
+ if len(build_elements) > 1:
+ raise ValueError("Ambiguous <build> element.")
+ build_element = build_elements[0]
+ attrs = build_element.attributes
+ build_number_attr = attrs.get("number")
+
+ if not build_number_attr:
+ raise ValueError("Could not find build number in application info")
+
+ build_number, _ = _parse_build_number(build_number_attr.value)
+
+ print build_number
+
+
+if __name__ == "__main__":
+ main()
diff --git a/build_defs/shared/stamp_plugin_xml.py b/build_defs/shared/stamp_plugin_xml.py
index 96c384a..b4fdfb6 100755
--- a/build_defs/shared/stamp_plugin_xml.py
+++ b/build_defs/shared/stamp_plugin_xml.py
@@ -1,22 +1,10 @@
-# Copyright 2016 The Bazel Authors. All rights reserved.
-#
-# 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.
-
"""Stamps a plugin xml with build information."""
import argparse
import re
from xml.dom.minidom import parse
+from xml.dom.minidom import parseString
+import zipfile
parser = argparse.ArgumentParser()
@@ -26,8 +14,13 @@
required=True,
)
parser.add_argument(
- "--build_txt",
- help="The build.txt file containing the build number, e.g. IC-144.1818",
+ "--application_info_jar",
+ help="The jar file containing the application info xml",
+ required=True,
+)
+parser.add_argument(
+ "--application_info_name",
+ help="A .txt file containing the application info xml name",
required=True,
)
parser.add_argument(
@@ -41,6 +34,14 @@
help="Stamp until-build with the build number",
)
parser.add_argument(
+ "--plugin_id",
+ help="plugin ID to stamp into the plugin.xml",
+)
+parser.add_argument(
+ "--plugin_name",
+ help="plugin name to stamp into the plugin.xml",
+)
+parser.add_argument(
"--version_file",
help="Version file to stamp into the plugin.xml",
)
@@ -54,11 +55,30 @@
help="Include the product code in the stamp",
)
+
def _read_changelog(changelog_file):
- """Reads the changelog and transforms it into trivial HTML"""
+ """Reads the changelog and transforms it into trivial HTML."""
with open(changelog_file) as f:
- lines = ["<p>" + line + "</p>" for line in f.readlines()]
- return "\n".join(lines)
+ return "\n".join("<p>" + line + "</p>" for line in f.readlines())
+
+
+def _parse_build_number(build_number):
+ """Parses the build number.
+
+ Args:
+ build_number: The build number as text.
+ Returns:
+ build_number, build_number_without_product_code.
+ Raises:
+ ValueError: if the build number is invalid.
+ """
+ match = re.match(r"^([A-Z]+-)?([0-9]+)(\.[0-9]+)?", build_number)
+ if match is None:
+ raise ValueError("Invalid build number: " + build_number)
+
+ build_number = match.group(1) + match.group(2) + match.group(3)
+ build_number_without_product_code = match.group(2) + match.group(3)
+ return build_number, build_number_without_product_code
def main():
@@ -67,20 +87,40 @@
dom = parse(args.plugin_xml)
- with open(args.build_txt) as f:
- build_number = f.read()
+ with open(args.application_info_name) as f:
+ application_info_name = f.read().strip()
+
+ with zipfile.ZipFile(args.application_info_jar, "r") as zf:
+ try:
+ data = zf.read(application_info_name)
+ except:
+ raise ValueError("Could not read application info file: " +
+ application_info_name)
+ component = parseString(data)
+
+ build_elements = component.getElementsByTagName("build")
+ if not build_elements:
+ raise ValueError("Could not find <build> element.")
+ if len(build_elements) > 1:
+ raise ValueError("Ambiguous <build> element.")
+ build_element = build_elements[0]
+
+ attrs = build_element.attributes
+ if attrs.has_key("apiVersion"):
+ api_version_attr = attrs.get("apiVersion")
+ else:
+ api_version_attr = attrs.get("number")
+
+ if not api_version_attr:
+ raise ValueError("Could not find api version in application info")
+
+ api_version, api_version_without_product_code = _parse_build_number(
+ api_version_attr.value)
new_elements = []
idea_plugin = dom.documentElement
- match = re.match(r"^([A-Z]+-)?([0-9]+)(\.[0-9]+)?", build_number)
- if match is None:
- raise ValueError("Invalid build number: " + build_number)
-
- build_number = match.group(1) + match.group(2) + match.group(3)
- build_number_without_product_code = match.group(2) + match.group(3)
-
version_element = None
version_elements = idea_plugin.getElementsByTagName("version")
if len(version_elements) > 1:
@@ -103,9 +143,9 @@
if idea_plugin.getElementsByTagName("idea-version"):
raise ValueError("idea-version element already present")
- idea_version_build_element = (build_number
+ idea_version_build_element = (api_version
if args.include_product_code_in_stamp else
- build_number_without_product_code)
+ api_version_without_product_code)
idea_version_element = dom.createElement("idea-version")
new_elements.append(idea_version_element)
@@ -121,10 +161,27 @@
if idea_plugin.getElementsByTagName("change-notes"):
raise ValueError("change-notes element already in plugin.xml")
changelog_element = dom.createElement("change-notes")
- changelog_text = dom.createCDATASection(_read_changelog(args.changelog_file))
- changelog_element.appendChild(changelog_text)
+ changelog_text = _read_changelog(args.changelog_file)
+ changelog_cdata = dom.createCDATASection(changelog_text)
+ changelog_element.appendChild(changelog_cdata)
new_elements.append(changelog_element)
+ if args.plugin_id:
+ if idea_plugin.getElementsByTagName("id"):
+ raise ValueError("id element already in plugin.xml")
+ id_element = dom.createElement("id")
+ new_elements.append(id_element)
+ id_text = dom.createTextNode(args.plugin_id)
+ id_element.appendChild(id_text)
+
+ if args.plugin_name:
+ if idea_plugin.getElementsByTagName("name"):
+ raise ValueError("name element already in plugin.xml")
+ name_element = dom.createElement("name")
+ new_elements.append(name_element)
+ name_text = dom.createTextNode(args.plugin_name)
+ name_element.appendChild(name_text)
+
for new_element in new_elements:
idea_plugin.appendChild(new_element)
diff --git a/common/experiments/BUILD b/common/experiments/BUILD
new file mode 100644
index 0000000..b15de1f
--- /dev/null
+++ b/common/experiments/BUILD
@@ -0,0 +1,39 @@
+licenses(["notice"]) # Apache 2.0
+
+java_library(
+ name = "experiments",
+ srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//intellij_platform_sdk:plugin_api",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+java_library(
+ name = "unit_test_utils",
+ testonly = 1,
+ srcs = glob(["tests/utils/unit/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ ":experiments",
+ "//intellij_platform_sdk:plugin_api",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+load(
+ "//intellij_test:test_defs.bzl",
+ "intellij_unit_test_suite",
+)
+
+intellij_unit_test_suite(
+ name = "unit_tests",
+ srcs = glob(["tests/unittests/**/*.java"]),
+ test_package_root = "com.google.idea.common.experiments",
+ deps = [
+ ":experiments",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@junit//jar",
+ ],
+)
diff --git a/common/experiments/src/com/google/idea/common/experiments/BoolExperiment.java b/common/experiments/src/com/google/idea/common/experiments/BoolExperiment.java
new file mode 100644
index 0000000..b07019a
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/BoolExperiment.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+/** Boolean-valued experiment. */
+public class BoolExperiment extends Experiment {
+ private final boolean defaultValue;
+
+ public BoolExperiment(String key, boolean defaultValue) {
+ super(key);
+ this.defaultValue = defaultValue;
+ }
+
+ public boolean getValue() {
+ return ExperimentService.getInstance().getExperiment(key, defaultValue);
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/DevOverride.java b/common/experiments/src/com/google/idea/common/experiments/DevOverride.java
new file mode 100644
index 0000000..5f3b4ce
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/DevOverride.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+/** Developer override for string experiments. */
+public class DevOverride extends Experiment {
+ private final String defaultValue;
+
+ public DevOverride(String key, String defaultValue) {
+ super(key);
+ this.defaultValue = defaultValue;
+ }
+
+ public String getValue() {
+ return ExperimentService.getInstance().getExperimentString(key, defaultValue);
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/DeveloperFlag.java b/common/experiments/src/com/google/idea/common/experiments/DeveloperFlag.java
new file mode 100644
index 0000000..04e3790
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/DeveloperFlag.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+/**
+ * This is an experiment that always defaults to off. Use to document that this is for devs only.
+ */
+public class DeveloperFlag extends BoolExperiment {
+ public DeveloperFlag(String key) {
+ super(key, false);
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/Experiment.java b/common/experiments/src/com/google/idea/common/experiments/Experiment.java
new file mode 100644
index 0000000..135dee5
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/Experiment.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+/** Experiment class. */
+public abstract class Experiment {
+ protected final String key;
+
+ Experiment(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return key;
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/ExperimentLoader.java b/common/experiments/src/com/google/idea/common/experiments/ExperimentLoader.java
new file mode 100644
index 0000000..a051872
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/ExperimentLoader.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import java.util.Map;
+
+interface ExperimentLoader {
+
+ /**
+ * Load the map of experiment names to values. Experiment names must be hashed from their
+ * canonical value with SHA-512.
+ *
+ * @see HashingExperimentLoader
+ */
+ Map<String, String> getExperiments();
+
+ void initialize();
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/ExperimentService.java b/common/experiments/src/com/google/idea/common/experiments/ExperimentService.java
new file mode 100644
index 0000000..ebf3b4a
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/ExperimentService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import com.intellij.openapi.application.ApplicationManager;
+import javax.annotation.Nullable;
+
+/** Reads experiments. */
+public interface ExperimentService {
+
+ static ExperimentService getInstance() {
+ return ApplicationManager.getApplication().getComponent(ExperimentService.class);
+ }
+
+ /** Returns an experiment if it exists, else defaultValue */
+ boolean getExperiment(String key, boolean defaultValue);
+
+ /** Returns a string-valued experiment if it exists, else defaultValue. */
+ @Nullable
+ String getExperimentString(String key, @Nullable String defaultValue);
+
+ /** Returns an int-valued experiment if it exists, else defaultValue. */
+ int getExperimentInt(String key, int defaultValue);
+
+ /** Starts an experiment scope. During an experiment scope, experiments won't be reloaded. */
+ void startExperimentScope();
+
+ /** Ends an experiment scope. */
+ void endExperimentScope();
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/ExperimentServiceImpl.java b/common/experiments/src/com/google/idea/common/experiments/ExperimentServiceImpl.java
new file mode 100644
index 0000000..6b908c1
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/ExperimentServiceImpl.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import static com.google.idea.common.experiments.ExperimentsUtil.hashExperimentName;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.SystemProperties;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * An experiment service that delegates to {@link ExperimentLoader ExperimentLoaders}, in a specific
+ * order.
+ *
+ * <p>It will check system properties first, then an experiment file in the user's home directory,
+ * then finally all files specified by the system property blaze.experiments.file.
+ */
+public class ExperimentServiceImpl extends ApplicationComponent.Adapter
+ implements ExperimentService {
+ private static final Logger logger = Logger.getInstance(ExperimentServiceImpl.class);
+
+ private static final String USER_EXPERIMENT_OVERRIDES_FILE =
+ SystemProperties.getUserHome() + File.separator + ".intellij-experiments";
+
+ private final List<ExperimentLoader> services;
+ private Map<String, String> experiments;
+ private int experimentScopeCounter = 0;
+
+ public ExperimentServiceImpl(String pluginName) {
+ this(
+ new SystemPropertyExperimentLoader(),
+ new FileExperimentLoader(USER_EXPERIMENT_OVERRIDES_FILE),
+ new WebExperimentLoader(pluginName));
+ }
+
+ @VisibleForTesting
+ ExperimentServiceImpl(ExperimentLoader... loaders) {
+ services = ImmutableList.copyOf(loaders);
+ }
+
+ @Override
+ public void initComponent() {
+ services.forEach(ExperimentLoader::initialize);
+ }
+
+ @Override
+ public boolean getExperiment(String key, boolean defaultValue) {
+ String property = getExperiment(key);
+ return property != null ? property.equals("1") : defaultValue;
+ }
+
+ @Override
+ public String getExperimentString(String key, @Nullable String defaultValue) {
+ String property = getExperiment(key);
+ return property != null ? property : defaultValue;
+ }
+
+ @Override
+ public int getExperimentInt(String key, int defaultValue) {
+ String property = getExperiment(key);
+ try {
+ return property != null ? Integer.parseInt(property) : defaultValue;
+ } catch (NumberFormatException e) {
+ logger.warn("Could not parse int for experiment: " + key, e);
+ return defaultValue;
+ }
+ }
+
+ @Override
+ public synchronized void startExperimentScope() {
+ if (++experimentScopeCounter > 0) {
+ experiments = getAllExperiments();
+ }
+ }
+
+ @Override
+ public synchronized void endExperimentScope() {
+ if (--experimentScopeCounter <= 0) {
+ logger.assertTrue(experimentScopeCounter == 0);
+ experiments = null;
+ }
+ }
+
+ private Map<String, String> getAllExperiments() {
+ Map<String, String> experiments = this.experiments;
+ if (experiments != null) {
+ return experiments;
+ } else {
+ return services
+ .stream()
+ .flatMap(service -> service.getExperiments().entrySet().stream())
+ .collect(
+ Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (first, second) -> first));
+ }
+ }
+
+ private String getExperiment(String key) {
+ return getAllExperiments().get(hashExperimentName(key));
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/ExperimentsUtil.java b/common/experiments/src/com/google/idea/common/experiments/ExperimentsUtil.java
new file mode 100644
index 0000000..30820f7
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/ExperimentsUtil.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hashing;
+import java.nio.charset.StandardCharsets;
+
+final class ExperimentsUtil {
+
+ private static final HashFunction HASHER = Hashing.sha512();
+
+ private ExperimentsUtil() {}
+
+ static String hashExperimentName(String name) {
+ return HASHER.hashString(name, StandardCharsets.UTF_8).toString();
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/FileExperimentLoader.java b/common/experiments/src/com/google/idea/common/experiments/FileExperimentLoader.java
new file mode 100644
index 0000000..d913f70
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/FileExperimentLoader.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import com.google.common.collect.ImmutableMap;
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+
+/** Reads experiments from a property file. */
+final class FileExperimentLoader extends HashingExperimentLoader {
+
+ private static final Logger logger = Logger.getInstance(FileExperimentLoader.class);
+
+ private final String filename;
+ private Map<String, String> experiments = ImmutableMap.of();
+ private FileTime lastModified = FileTime.fromMillis(0);
+
+ FileExperimentLoader(String filename) {
+ this.filename = filename;
+ }
+
+ @SuppressWarnings("unchecked") // Properties is Map<Object, Object>, we cast to strings
+ @Override
+ Map<String, String> getUnhashedExperiments() {
+ Properties properties = new Properties();
+
+ File file = new File(filename);
+ if (!file.exists()) {
+ experiments = ImmutableMap.of();
+ return experiments;
+ }
+
+ try {
+ FileTime lastModified =
+ Files.readAttributes(file.toPath(), BasicFileAttributes.class).lastModifiedTime();
+ if (Objects.equals(lastModified, this.lastModified)) {
+ return experiments;
+ }
+
+ try (InputStream fis = new FileInputStream(filename);
+ BufferedInputStream bis = new BufferedInputStream(fis)) {
+ properties.load(bis);
+ experiments = ImmutableMap.copyOf((Map) properties);
+ this.lastModified = lastModified;
+ }
+ } catch (IOException e) {
+ logger.warn("Could not load experiments from file: " + filename, e);
+ }
+
+ return experiments;
+ }
+
+ @Override
+ public void initialize() {
+ // Reads the file into memory.
+ getUnhashedExperiments();
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/HashingExperimentLoader.java b/common/experiments/src/com/google/idea/common/experiments/HashingExperimentLoader.java
new file mode 100644
index 0000000..cab45c9
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/HashingExperimentLoader.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import static com.google.idea.common.experiments.ExperimentsUtil.hashExperimentName;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * An experiment loader that handles hashing the experiment names, for sources that store the data
+ * unhashed.
+ */
+abstract class HashingExperimentLoader implements ExperimentLoader {
+
+ @Override
+ public Map<String, String> getExperiments() {
+ return getUnhashedExperiments()
+ .entrySet()
+ .stream()
+ .collect(Collectors.toMap(e -> hashExperimentName(e.getKey()), Map.Entry::getValue));
+ }
+
+ abstract Map<String, String> getUnhashedExperiments();
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/IntExperiment.java b/common/experiments/src/com/google/idea/common/experiments/IntExperiment.java
new file mode 100644
index 0000000..15eaebd
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/IntExperiment.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+/** Integer valued experiment. */
+public class IntExperiment extends Experiment {
+ private final int defaultValue;
+
+ public IntExperiment(String key, int defaultValue) {
+ super(key);
+ this.defaultValue = defaultValue;
+ }
+
+ public int getValue() {
+ return ExperimentService.getInstance().getExperimentInt(key, defaultValue);
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/SerializationUtil.java b/common/experiments/src/com/google/idea/common/experiments/SerializationUtil.java
new file mode 100644
index 0000000..53cd842
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/SerializationUtil.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import com.intellij.CommonBundle;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Utils for serialization. */
+final class SerializationUtil {
+
+ private SerializationUtil() {}
+
+ static void saveToDisk(File file, Serializable serializable) throws IOException {
+ ensureExists(file.getParentFile());
+ try (FileOutputStream fos = new FileOutputStream(file);
+ ObjectOutputStream oos = new ObjectOutputStream(fos)) {
+ oos.writeObject(serializable);
+ }
+ }
+
+ @Nullable
+ static Object loadFromDisk(File file) throws IOException {
+ if (!file.exists()) {
+ return null;
+ }
+ try (FileInputStream fis = new FileInputStream(file);
+ ObjectInputStream ois = new ObjectInputStream(fis)) {
+ return ois.readObject();
+ } catch (ClassNotFoundException e) {
+ throw new IOException(e);
+ }
+ }
+
+ private static void ensureExists(File dir) throws IOException {
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new IOException(
+ CommonBundle.message("exception.directory.can.not.create", dir.getPath()));
+ }
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/StringExperiment.java b/common/experiments/src/com/google/idea/common/experiments/StringExperiment.java
new file mode 100644
index 0000000..0fcd903
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/StringExperiment.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import javax.annotation.Nullable;
+
+/** String-valued experiment. */
+public class StringExperiment extends Experiment {
+
+ public StringExperiment(String key) {
+ super(key);
+ }
+
+ @Nullable
+ public String getValue() {
+ return ExperimentService.getInstance().getExperimentString(key, null);
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/SystemPropertyExperimentLoader.java b/common/experiments/src/com/google/idea/common/experiments/SystemPropertyExperimentLoader.java
new file mode 100644
index 0000000..96ebeba
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/SystemPropertyExperimentLoader.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+final class SystemPropertyExperimentLoader extends HashingExperimentLoader {
+ private static final String BLAZE_EXPERIMENT_OVERRIDE = "blaze.experiment.";
+
+ @Override
+ public Map<String, String> getUnhashedExperiments() {
+ return System.getProperties()
+ .stringPropertyNames()
+ .stream()
+ .filter(name -> name.startsWith(BLAZE_EXPERIMENT_OVERRIDE))
+ .collect(
+ Collectors.toMap(
+ name -> name.substring(BLAZE_EXPERIMENT_OVERRIDE.length()), System::getProperty));
+ }
+
+ @Override
+ public void initialize() {
+ // Nothing to do.
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/WebExperimentLoader.java b/common/experiments/src/com/google/idea/common/experiments/WebExperimentLoader.java
new file mode 100644
index 0000000..0f27c15
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/WebExperimentLoader.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import java.util.Map;
+
+final class WebExperimentLoader implements ExperimentLoader {
+
+ private final WebExperimentSyncer syncer;
+
+ WebExperimentLoader(String pluginName) {
+ syncer = new WebExperimentSyncer(pluginName);
+ }
+
+ @Override
+ public Map<String, String> getExperiments() {
+ return syncer.getExperimentValues();
+ }
+
+ @Override
+ public void initialize() {
+
+ syncer.initialize();
+ }
+}
diff --git a/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java b/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java
new file mode 100644
index 0000000..464a62d
--- /dev/null
+++ b/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListenableScheduledFuture;
+import com.google.common.util.concurrent.ListeningScheduledExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.concurrency.AppExecutorUtil;
+import com.intellij.util.io.HttpRequests;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.jetbrains.io.JsonReaderEx;
+
+/**
+ * A singleton class that retrieves the experiments from the experiments service</a>.
+ *
+ * <p>The first time {@link #getExperimentValues()} is called, fresh data will be retrieved in the
+ * current thread. Thereafter, data will be retrieved every 5 minutes in a background thread. If
+ * there is a failure retrieving data, new attempts will be made every minute.
+ */
+final class WebExperimentSyncer {
+
+ private static final Logger logger = Logger.getInstance(WebExperimentSyncer.class);
+
+ private static final String DEFAULT_EXPERIMENT_URL =
+ "https://intellij-experiments.appspot.com/api/experiments/";
+ private static final String EXPERIMENTS_URL_PROPERTY = "intellij.experiments.url";
+
+ private static final int SUCESSFUL_DOWNLOAD_DELAY_MINUTES = 5;
+ private static final int DOWNLOAD_FAILURE_DELAY_MINUTES = 1;
+
+ private final File cacheFile;
+ private final String pluginName;
+
+ // null indicates no fetch attempt has been made. After the first attempt, this will always be a
+ // (possibly empty) map.
+ private Map<String, String> experimentValues = null;
+
+ private final ListeningScheduledExecutorService executor =
+ MoreExecutors.listeningDecorator(AppExecutorUtil.getAppScheduledExecutorService());
+
+ WebExperimentSyncer(String pluginName) {
+ this.pluginName = pluginName;
+ cacheFile =
+ Paths.get(PathManager.getSystemPath(), "blaze", pluginName + ".experiments.cache.dat")
+ .toFile();
+ }
+
+ /**
+ * Get the last-retrieved set of experiment values.
+ *
+ * <p>The first time this method is called, an attempt to retrieve the values will take place.
+ * Thereafter, the values will be retrieved every five minutes on a background thread and this
+ * method will return the most recent successfully retrieved values.
+ */
+ synchronized Map<String, String> getExperimentValues() {
+ if (experimentValues == null) {
+ initialize();
+ }
+
+ return experimentValues;
+ }
+
+ private synchronized void setExperimentValues(HashMap<String, String> experimentValues) {
+ this.experimentValues = experimentValues;
+ saveCache(experimentValues);
+ }
+
+ /** Fetch and process the experiments on the current thread. */
+ void initialize() {
+ experimentValues = loadCache();
+ ListenableFuture<String> response = executor.submit(new WebExperimentsDownloader());
+ response.addListener(
+ new WebExperimentsResultProcessor(response), MoreExecutors.sameThreadExecutor());
+ }
+
+ private void scheduleNextRefresh(boolean refreshWasSuccessful) {
+ int delayInMinutes =
+ refreshWasSuccessful ? SUCESSFUL_DOWNLOAD_DELAY_MINUTES : DOWNLOAD_FAILURE_DELAY_MINUTES;
+ ListenableScheduledFuture<String> refreshResults =
+ executor.schedule(new WebExperimentsDownloader(), delayInMinutes, TimeUnit.MINUTES);
+ refreshResults.addListener(
+ new WebExperimentsResultProcessor(refreshResults), MoreExecutors.sameThreadExecutor());
+ }
+
+ private class WebExperimentsDownloader implements Callable<String> {
+
+ @Override
+ public String call() throws Exception {
+ logger.debug("About to fetch experiments.");
+ return HttpRequests.request(
+ System.getProperty(EXPERIMENTS_URL_PROPERTY, DEFAULT_EXPERIMENT_URL) + pluginName)
+ .readString(null /* progress indicator */);
+ }
+ }
+
+ private class WebExperimentsResultProcessor implements Runnable {
+
+ private final Future<String> resultFuture;
+
+ private WebExperimentsResultProcessor(Future<String> resultFuture) {
+ this.resultFuture = resultFuture;
+ }
+
+ @Override
+ public void run() {
+ logger.debug("Experiments fetched. Processing results.");
+ try {
+ HashMap<String, String> mapBuilder = Maps.newHashMap();
+ String result = resultFuture.get();
+ try (JsonReaderEx reader = new JsonReaderEx(result)) {
+ reader.beginObject();
+ while (reader.hasNext()) {
+ String experimentName = reader.nextName();
+ String experimentValue = reader.nextString();
+ mapBuilder.put(experimentName, experimentValue);
+ }
+ }
+ setExperimentValues(mapBuilder);
+
+ logger.debug("Successfully fetched experiments: " + getExperimentValues());
+ scheduleNextRefresh(true /* refreshWasSuccessful */);
+ } catch (InterruptedException | ExecutionException | RuntimeException e) {
+ logger.debug("Error fetching experiments", e);
+ scheduleNextRefresh(false /* refreshWasSuccessful */);
+ }
+ }
+ }
+
+ private void saveCache(HashMap<String, String> experiments) {
+ try {
+ SerializationUtil.saveToDisk(cacheFile, experiments);
+ } catch (IOException e) {
+ logger.warn("Could not save experiments cache to disk: " + cacheFile);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<String, String> loadCache() {
+ try {
+ Map<String, String> loaded = (Map<String, String>) SerializationUtil.loadFromDisk(cacheFile);
+ return loaded != null ? loaded : ImmutableMap.of();
+ } catch (IOException e) {
+ // This is normal, we might be offline and have never loaded the cache.
+ logger.info("Could not load experiments file: " + cacheFile);
+ }
+ return ImmutableMap.of();
+ }
+}
diff --git a/common/experiments/tests/unittests/com/google/idea/common/experiments/ExperimentServiceImplTest.java b/common/experiments/tests/unittests/com/google/idea/common/experiments/ExperimentServiceImplTest.java
new file mode 100644
index 0000000..cd33e99
--- /dev/null
+++ b/common/experiments/tests/unittests/com/google/idea/common/experiments/ExperimentServiceImplTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.truth.Truth.assertThat;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link ExperimentServiceImpl}. */
+@RunWith(JUnit4.class)
+public class ExperimentServiceImplTest {
+
+ @Test
+ public void testBooleanPropertyTrue() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(new MapExperimentLoader("test.property", "1"));
+ assertThat(experimentService.getExperiment("test.property", false)).isTrue();
+ }
+
+ @Test
+ public void testBooleanPropertyFalse() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(new MapExperimentLoader("test.property", "0"));
+ assertThat(experimentService.getExperiment("test.property", true)).isFalse();
+ }
+
+ @Test
+ public void testBooleanPropertyReturnsDefaultWhenMissing() {
+ ExperimentService experimentService = new ExperimentServiceImpl(new MapExperimentLoader());
+ assertThat(experimentService.getExperiment("test.notthere", true)).isTrue();
+ }
+
+ @Test
+ public void testStringProperty() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(new MapExperimentLoader("test.property", "hi"));
+ assertThat(experimentService.getExperimentString("test.property", null)).isEqualTo("hi");
+ }
+
+ @Test
+ public void testStringPropertyReturnsDefaultWhenMissing() {
+ ExperimentService experimentService = new ExperimentServiceImpl(new MapExperimentLoader());
+ assertThat(experimentService.getExperimentString("test.property", "bye")).isEqualTo("bye");
+ }
+
+ @Test
+ public void testFirstLoaderOverridesSecond() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(
+ new MapExperimentLoader("test.property", "1"),
+ new MapExperimentLoader("test.property", "0"));
+ assertThat(experimentService.getExperiment("test.property", false)).isTrue();
+ }
+
+ @Test
+ public void testOnlyInSecondLoader() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(
+ new MapExperimentLoader(), new MapExperimentLoader("test.property", "1"));
+ assertThat(experimentService.getExperiment("test.property", false)).isTrue();
+ }
+
+ @Test
+ public void testIntProperty() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(new MapExperimentLoader("test.property", "10"));
+ assertThat(experimentService.getExperimentInt("test.property", 0)).isEqualTo(10);
+ }
+
+ @Test
+ public void testIntPropertyDefaultValue() {
+ ExperimentService experimentService = new ExperimentServiceImpl(new MapExperimentLoader());
+ assertThat(experimentService.getExperimentInt("test.property", 100)).isEqualTo(100);
+ }
+
+ @Test
+ public void testIntPropertyThatDoesntParseReturnsDefaultValue() {
+ ExperimentService experimentService =
+ new ExperimentServiceImpl(new MapExperimentLoader("test.property", "hello"));
+ assertThat(experimentService.getExperimentInt("test.property", 111)).isEqualTo(111);
+ }
+
+ @Test
+ public void testDataIsReloadedWhenNotInAScope() throws Exception {
+ MapExperimentLoader experimentLoader = new MapExperimentLoader();
+ ExperimentService experimentService = new ExperimentServiceImpl(experimentLoader);
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ experimentLoader.map.put("test.property", "hello");
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("hello");
+ }
+
+ @Test
+ public void testDataIsFrozenWheninAScope() throws Exception {
+ MapExperimentLoader experimentLoader = new MapExperimentLoader();
+ ExperimentService experimentService = new ExperimentServiceImpl(experimentLoader);
+ experimentService.startExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ experimentLoader.map.put("test.property", "hello");
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ }
+
+ @Test
+ public void testDataIsReloadedAgainWhenLeavingAScope() throws Exception {
+ MapExperimentLoader experimentLoader = new MapExperimentLoader();
+ ExperimentService experimentService = new ExperimentServiceImpl(experimentLoader);
+ experimentService.startExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ experimentLoader.map.put("test.property", "hello");
+ experimentService.endExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("hello");
+ }
+
+ @Test
+ public void testEnterTwoScopesButOnlyLeaveOne() throws Exception {
+ MapExperimentLoader experimentLoader = new MapExperimentLoader();
+ ExperimentService experimentService = new ExperimentServiceImpl(experimentLoader);
+ experimentService.startExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ experimentService.startExperimentScope();
+ experimentService.endExperimentScope();
+ experimentLoader.map.put("test.property", "hello");
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ }
+
+ @Test
+ public void testEnterAndLeaveTwoScopes() throws Exception {
+ MapExperimentLoader experimentLoader = new MapExperimentLoader();
+ ExperimentService experimentService = new ExperimentServiceImpl(experimentLoader);
+ experimentService.startExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("default");
+ experimentService.startExperimentScope();
+ experimentService.endExperimentScope();
+ experimentService.endExperimentScope();
+ experimentLoader.map.put("test.property", "hello");
+ assertThat(experimentService.getExperimentString("test.property", "default"))
+ .isEqualTo("hello");
+ }
+
+ @Test
+ public void testLeaveAndEnterRefreshes() throws Exception {
+ MapExperimentLoader experimentLoader = new MapExperimentLoader();
+ experimentLoader.map.put("test.property", "one");
+ ExperimentService experimentService = new ExperimentServiceImpl(experimentLoader);
+ experimentService.startExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default")).isEqualTo("one");
+ experimentLoader.map.put("test.property", "two");
+ experimentService.endExperimentScope();
+ experimentService.startExperimentScope();
+ assertThat(experimentService.getExperimentString("test.property", "default")).isEqualTo("two");
+ }
+
+ private static class MapExperimentLoader extends HashingExperimentLoader {
+
+ private final Map<String, String> map;
+
+ private MapExperimentLoader(String... keysAndValues) {
+ checkState(keysAndValues.length % 2 == 0);
+ map = new HashMap<>();
+ for (int i = 0; i < keysAndValues.length; i += 2) {
+ map.put(keysAndValues[i], keysAndValues[i + 1]);
+ }
+ }
+
+ @Override
+ public Map<String, String> getUnhashedExperiments() {
+ return map;
+ }
+
+ @Override
+ public void initialize() {}
+ }
+}
diff --git a/common/experiments/tests/unittests/com/google/idea/common/experiments/SystemPropertyExperimentLoaderTest.java b/common/experiments/tests/unittests/com/google/idea/common/experiments/SystemPropertyExperimentLoaderTest.java
new file mode 100644
index 0000000..2b3aace
--- /dev/null
+++ b/common/experiments/tests/unittests/com/google/idea/common/experiments/SystemPropertyExperimentLoaderTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.idea.common.experiments.ExperimentsUtil.hashExperimentName;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for the system property experiment loader. */
+@RunWith(JUnit4.class)
+public class SystemPropertyExperimentLoaderTest {
+
+ private static final String EXPERIMENT = "test.foo";
+ private static final String PROPERTY = "blaze.experiment.test.foo";
+ private static final String VALUE = "true";
+
+ @Before
+ public void setUp() {
+ System.setProperty(PROPERTY, VALUE);
+ }
+
+ @After
+ public void tearDown() {
+ System.clearProperty(PROPERTY);
+ }
+
+ @Test
+ public void testGetExperiment() {
+ ExperimentLoader loader = new SystemPropertyExperimentLoader();
+ assertThat(loader.getExperiments().get(hashExperimentName(EXPERIMENT))).isEqualTo(VALUE);
+ }
+}
diff --git a/common/experiments/tests/utils/unit/com/google/idea/common/experiments/MockExperimentService.java b/common/experiments/tests/utils/unit/com/google/idea/common/experiments/MockExperimentService.java
new file mode 100644
index 0000000..c144c70
--- /dev/null
+++ b/common/experiments/tests/utils/unit/com/google/idea/common/experiments/MockExperimentService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.common.experiments;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+/** Used for tests. */
+public class MockExperimentService implements ExperimentService {
+
+ private Map<String, Object> experiments = new HashMap<>();
+
+ @Override
+ public void startExperimentScope() {}
+
+ @Override
+ public void endExperimentScope() {}
+
+ public void setExperiment(BoolExperiment experiment, boolean value) {
+ experiments.put(experiment.getKey(), value);
+ }
+
+ @Override
+ public boolean getExperiment(String key, boolean defaultValue) {
+ if (experiments.containsKey(key)) {
+ return (Boolean) experiments.get(key);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ @Nullable
+ public String getExperimentString(String key, @Nullable String defaultValue) {
+ if (experiments.containsKey(key)) {
+ return (String) experiments.get(key);
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public int getExperimentInt(String key, int defaultValue) {
+ if (experiments.containsKey(key)) {
+ return (Integer) experiments.get(key);
+ }
+ return defaultValue;
+ }
+}
diff --git a/cpp/BUILD b/cpp/BUILD
new file mode 100644
index 0000000..8b23007
--- /dev/null
+++ b/cpp/BUILD
@@ -0,0 +1,56 @@
+licenses(["notice"]) # Apache 2.0
+
+java_library(
+ name = "cpp",
+ srcs = glob(
+ ["src/**/*.java"],
+ exclude = [
+ "src/com/google/idea/blaze/cpp/versioned/**",
+ ],
+ ) + select({
+ "//intellij_platform_sdk:android-studio-latest": [":api_v145_sources"],
+ "//conditions:default": [":api_v162_sources"],
+ }),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//intellij_platform_sdk:plugin_api",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+filegroup(
+ name = "plugin_xml",
+ srcs = ["src/META-INF/blaze-cpp.xml"],
+ visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "api_v145_sources",
+ srcs = glob(["src/com/google/idea/blaze/cpp/versioned/v145/**"]),
+ visibility = ["//visibility:private"],
+)
+
+filegroup(
+ name = "api_v162_sources",
+ srcs = glob(["src/com/google/idea/blaze/cpp/versioned/v162/**"]),
+ visibility = ["//visibility:private"],
+)
+
+load(
+ "//intellij_test:test_defs.bzl",
+ "intellij_unit_test_suite",
+)
+
+intellij_unit_test_suite(
+ name = "unit_tests",
+ srcs = glob(["tests/unittests/**/*.java"]),
+ test_package_root = "com.google.idea.blaze.cpp",
+ deps = [
+ ":cpp",
+ "//base:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
diff --git a/cpp/src/META-INF/blaze-cpp.xml b/cpp/src/META-INF/blaze-cpp.xml
new file mode 100644
index 0000000..1cb99ea
--- /dev/null
+++ b/cpp/src/META-INF/blaze-cpp.xml
@@ -0,0 +1,32 @@
+<!--
+ ~ Copyright 2016 The Bazel Authors. All rights reserved.
+ ~
+ ~ 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.
+ -->
+<idea-plugin>
+ <depends>com.intellij.modules.cidr.lang</depends>
+ <depends>com.intellij.modules.cidr.debugger</depends>
+
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncPlugin implementation="com.google.idea.blaze.cpp.BlazeCSyncPlugin"/>
+ <PrefetchFileSource implementation="com.google.idea.blaze.cpp.CPrefetchFileSource"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="cidr.lang">
+ <languageKindHelper implementation="com.google.idea.blaze.cpp.BlazeLanguageKindCalculatorHelper"/>
+ <autoImportHelper implementation="com.google.idea.blaze.cpp.BlazeCppAutoImportHelper"/>
+ </extensions>
+ <extensions defaultExtensionNs="com.intellij">
+ <projectService serviceImplementation="com.google.idea.blaze.cpp.BlazeCWorkspace"/>
+ </extensions>
+</idea-plugin>
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
new file mode 100644
index 0000000..c066fc4
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.jetbrains.cidr.lang.workspace.OCWorkspace;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+final class BlazeCSyncPlugin extends BlazeSyncPlugin.Adapter {
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ if (workspaceType == WorkspaceType.C) {
+ return ImmutableSet.of(LanguageClass.C);
+ }
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
+ if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C)) {
+ return;
+ }
+
+ Scope.push(
+ context,
+ childContext -> {
+ childContext.push(new TimingScope("Setup C Workspace"));
+
+ OCWorkspace workspace = OCWorkspaceManager.getWorkspace(project);
+ if (workspace instanceof BlazeCWorkspace) {
+ BlazeCWorkspace blazeCWorkspace = (BlazeCWorkspace) workspace;
+ blazeCWorkspace.update(childContext, blazeProjectData);
+ }
+ });
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
new file mode 100644
index 0000000..84fc646
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.symbols.OCSymbol;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import com.jetbrains.cidr.lang.workspace.OCWorkspace;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceModificationTrackers;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Main entry point for C/CPP configuration data. */
+public final class BlazeCWorkspace implements OCWorkspace {
+ private static final Logger LOG = Logger.getInstance(BlazeCWorkspace.class);
+
+ @Nullable private final Project project;
+ @Nullable private final OCWorkspaceModificationTrackers modTrackers;
+
+ @Nullable private BlazeConfigurationResolver configurationResolver;
+
+ private BlazeCWorkspace(Project project) {
+ if (Blaze.isBlazeProject(project)) {
+ this.project = project;
+ this.modTrackers = new OCWorkspaceModificationTrackers(project);
+ this.configurationResolver = new BlazeConfigurationResolver(project);
+ } else {
+ this.project = null;
+ this.modTrackers = null;
+ }
+ }
+
+ public static BlazeCWorkspace getInstance(Project project) {
+ return ServiceManager.getService(project, BlazeCWorkspace.class);
+ }
+
+ public void update(BlazeContext context, BlazeProjectData blazeProjectData) {
+ LOG.assertTrue(project != null);
+ LOG.assertTrue(modTrackers != null);
+ LOG.assertTrue(configurationResolver != null);
+
+ long start = System.currentTimeMillis();
+ // Non-incremental update to our c configurations.
+ configurationResolver.update(context, blazeProjectData);
+ long end = System.currentTimeMillis();
+
+ LOG.info(String.format("Blaze OCWorkspace update took: %d ms", (end - start)));
+
+ ApplicationManager.getApplication()
+ .runReadAction(
+ () -> {
+ if (project.isDisposed()) {
+ return;
+ }
+
+ // TODO(salguarnieri) Avoid bumping all of these trackers; figure out what has changed
+ modTrackers.getProjectFilesListTracker().incModificationCount();
+ modTrackers.getSourceFilesListTracker().incModificationCount();
+ modTrackers.getBuildConfigurationChangesTracker().incModificationCount();
+ modTrackers.getBuildSettingsChangesTracker().incModificationCount();
+ });
+ }
+
+ @Override
+ public Collection<VirtualFile> getLibraryFilesToBuildSymbols() {
+ // This method should return all the header files themselves, not the head file directories.
+ // (And not header files in the project; just the ones in the SDK and in any dependencies)
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean areFromSameProject(@Nullable VirtualFile a, @Nullable VirtualFile b) {
+ return false;
+ }
+
+ @Override
+ public boolean areFromSamePackage(@Nullable VirtualFile a, @Nullable VirtualFile b) {
+ return false;
+ }
+
+ @Override
+ public boolean isInSDK(@Nullable VirtualFile file) {
+ return false;
+ }
+
+ @Override
+ public boolean isFromWrongSDK(OCSymbol symbol, @Nullable VirtualFile contextFile) {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public OCResolveConfiguration getSelectedResolveConfiguration() {
+ return null;
+ }
+
+ @Override
+ public OCWorkspaceModificationTrackers getModificationTrackers() {
+ LOG.assertTrue(modTrackers != null);
+ return modTrackers;
+ }
+
+ @Override
+ public List<? extends OCResolveConfiguration> getConfigurations() {
+ return configurationResolver == null
+ ? ImmutableList.of()
+ : configurationResolver.getAllConfigurations();
+ }
+
+ @Override
+ public List<? extends OCResolveConfiguration> getConfigurationsForFile(
+ @Nullable VirtualFile sourceFile) {
+ if (sourceFile == null || !sourceFile.isValid() || configurationResolver == null) {
+ return ImmutableList.of();
+ }
+ OCResolveConfiguration config = configurationResolver.getConfigurationForFile(sourceFile);
+ return config == null ? ImmutableList.of() : ImmutableList.of(config);
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
new file mode 100644
index 0000000..28eba21
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.cidr.lang.preprocessor.OCInclusionContext;
+import com.jetbrains.cidr.lang.preprocessor.OCInclusionContextUtil;
+import com.jetbrains.cidr.lang.workspace.compiler.CidrCompilerResult;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerMacros;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
+import com.jetbrains.cidr.toolchains.CompilerInfoCache;
+import java.util.Map;
+
+final class BlazeCompilerMacros extends OCCompilerMacros {
+ private final CompilerInfoCache compilerInfoCache;
+ private final ImmutableCollection<String> globalDefines;
+ private final ImmutableMap<String, String> globalFeatures;
+ private final OCCompilerSettings compilerSettings;
+ private final Project project;
+
+ public BlazeCompilerMacros(
+ Project project,
+ CompilerInfoCache compilerInfoCache,
+ OCCompilerSettings compilerSettings,
+ ImmutableCollection<String> defines,
+ ImmutableMap<String, String> features) {
+ this.project = project;
+ this.compilerInfoCache = compilerInfoCache;
+ this.compilerSettings = compilerSettings;
+ this.globalDefines = defines;
+ this.globalFeatures = features;
+ }
+
+ @Override
+ protected void fillFileMacros(OCInclusionContext context, PsiFile sourceFile) {
+ // Get the default compiler info for this file.
+ VirtualFile vf = OCInclusionContextUtil.getVirtualFile(sourceFile);
+ CidrCompilerResult<CompilerInfoCache.Entry> compilerInfoProvider =
+ compilerInfoCache.getCompilerInfoCache(
+ project, compilerSettings, context.getLanguageKind(), vf);
+ CompilerInfoCache.Entry compilerInfo = compilerInfoProvider.getResult();
+
+ // Combine the info we got from Blaze with the info we get from IntelliJ's methods.
+ ImmutableSet.Builder<String> allDefinesBuilder = ImmutableSet.builder();
+ // IntelliJ expects a string of "#define [VAR_NAME]\n#define [VAR_NAME2]\n..."
+ for (String globalDefine : globalDefines) {
+ allDefinesBuilder.add("#define " + globalDefine);
+ }
+ if (compilerInfo != null) {
+ String[] split = compilerInfo.defines.split("\n");
+ for (String s : split) {
+ allDefinesBuilder.add(s);
+ }
+ }
+ final String allDefines = Joiner.on("\n").join(allDefinesBuilder.build());
+
+ Map<String, String> allFeatures = Maps.newHashMap();
+ allFeatures.putAll(globalFeatures);
+ if (compilerInfo != null) {
+ allFeatures.putAll(compilerInfo.features);
+ }
+
+ fillSubstitutions(context, allDefines);
+ enableClangFeatures(context, allFeatures);
+ enableClangExtensions(context, allFeatures);
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
new file mode 100644
index 0000000..966b37c
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
+import com.jetbrains.cidr.lang.toolchains.CidrSwitchBuilder;
+import com.jetbrains.cidr.lang.toolchains.CidrToolEnvironment;
+import com.jetbrains.cidr.lang.toolchains.DefaultCidrToolEnvironment;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerKind;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
+import java.io.File;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+final class BlazeCompilerSettings extends OCCompilerSettings {
+ private final CidrToolEnvironment toolEnvironment = new DefaultCidrToolEnvironment();
+
+ private final Project project;
+ @Nullable private final File cCompiler;
+ @Nullable private final File cppCompiler;
+ private final CidrCompilerSwitches cCompilerSwitches;
+ private final CidrCompilerSwitches cppCompilerSwitches;
+
+ BlazeCompilerSettings(
+ Project project,
+ @Nullable File cCompiler,
+ @Nullable File cppCompiler,
+ ImmutableList<String> cFlags,
+ ImmutableList<String> cppFlags) {
+ this.project = project;
+ this.cCompiler = cCompiler;
+ this.cppCompiler = cppCompiler;
+ this.cCompilerSwitches = getCompilerSwitches(cFlags);
+ this.cppCompilerSwitches = getCompilerSwitches(cppFlags);
+ }
+
+ @Override
+ public OCCompilerKind getCompiler(OCLanguageKind languageKind) {
+ return null;
+ }
+
+ @Override
+ public File getCompilerExecutable(OCLanguageKind lang) {
+ if (lang == OCLanguageKind.C) {
+ return cCompiler;
+ } else if (lang == OCLanguageKind.CPP) {
+ return cppCompiler;
+ }
+ // We don't support objective c/c++.
+ return null;
+ }
+
+ @Override
+ public File getCompilerWorkingDir() {
+ return WorkspaceRoot.fromProject(project).directory();
+ }
+
+ @Override
+ public CidrToolEnvironment getEnvironment() {
+ return toolEnvironment;
+ }
+
+ @Override
+ public CidrCompilerSwitches getCompilerSwitches(
+ OCLanguageKind lang, @Nullable VirtualFile sourceFile) {
+ if (lang == OCLanguageKind.C) {
+ return cCompilerSwitches;
+ }
+ if (lang == OCLanguageKind.CPP) {
+ return cppCompilerSwitches;
+ }
+ return new CidrSwitchBuilder().build();
+ }
+
+ private static CidrCompilerSwitches getCompilerSwitches(List<String> allCompilerFlags) {
+ // Explanation of hack:
+ // - this list of switches is currently only used in one place -- GCCCompiler.tryRunGCC.
+ // - list is written to an argument file, whitespace-separated, then passed as a @file arg to
+ // clang.
+ // In this context, escaped whitespace within a single arg is not handled.
+ // Currently, the only way (short of using reflection) to ensure unescaped whitespace
+ // is to have CidrSwitchBuilder treat whitespace as a delimiter between args.
+ allCompilerFlags =
+ allCompilerFlags
+ .stream()
+ .map(flag -> flag.replace("\\ ", " "))
+ .collect(Collectors.toList());
+
+ return new CidrSwitchBuilder()
+ .addAll(Joiner.on(" ").join(allCompilerFlags), CidrSwitchBuilder.Format.FILE_ARGS)
+ .build();
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java b/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
new file mode 100644
index 0000000..925f873
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.ScopedFunction;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
+
+final class BlazeConfigurationResolver {
+ private static final class MapEntry {
+ public final Label label;
+ public final BlazeResolveConfiguration configuration;
+
+ public MapEntry(Label label, BlazeResolveConfiguration configuration) {
+ this.label = label;
+ this.configuration = configuration;
+ }
+ }
+
+ private static final Logger LOG = Logger.getInstance(BlazeConfigurationResolver.class);
+ private final Project project;
+
+ private ImmutableMap<Label, BlazeResolveConfiguration> resolveConfigurations = ImmutableMap.of();
+
+ public BlazeConfigurationResolver(Project project) {
+ this.project = project;
+ }
+
+ public void update(BlazeContext context, BlazeProjectData blazeProjectData) {
+ WorkspacePathResolver workspacePathResolver = blazeProjectData.workspacePathResolver;
+ ImmutableMap<Label, CToolchainIdeInfo> toolchainLookupMap =
+ BlazeResolveConfiguration.buildToolchainLookupMap(
+ context, blazeProjectData.ruleMap, blazeProjectData.reverseDependencies);
+ resolveConfigurations =
+ buildBlazeConfigurationMap(
+ context, blazeProjectData, toolchainLookupMap, workspacePathResolver);
+ }
+
+ private ImmutableMap<Label, BlazeResolveConfiguration> buildBlazeConfigurationMap(
+ BlazeContext parentContext,
+ BlazeProjectData blazeProjectData,
+ ImmutableMap<Label, CToolchainIdeInfo> toolchainLookupMap,
+ WorkspacePathResolver workspacePathResolver) {
+ // Type specification needed to avoid incorrect type inference during command line build.
+ return Scope.push(
+ parentContext,
+ (ScopedFunction<ImmutableMap<Label, BlazeResolveConfiguration>>)
+ context -> {
+ context.push(new TimingScope("Build C configuration map"));
+
+ ConcurrentMap<CToolchainIdeInfo, File> compilerWrapperCache = Maps.newConcurrentMap();
+ List<ListenableFuture<MapEntry>> mapEntryFutures = Lists.newArrayList();
+
+ for (RuleIdeInfo rule : blazeProjectData.ruleMap.rules()) {
+ if (rule.kind.getLanguageClass() == LanguageClass.C) {
+ ListenableFuture<MapEntry> future =
+ submit(
+ () ->
+ createResolveConfiguration(
+ rule,
+ toolchainLookupMap,
+ compilerWrapperCache,
+ workspacePathResolver,
+ blazeProjectData));
+ mapEntryFutures.add(future);
+ }
+ }
+
+ ImmutableMap.Builder<Label, BlazeResolveConfiguration> newResolveConfigurations =
+ ImmutableMap.builder();
+ List<MapEntry> mapEntries;
+ try {
+ mapEntries = Futures.allAsList(mapEntryFutures).get();
+ } catch (InterruptedException | ExecutionException e) {
+ Thread.currentThread().interrupt();
+ LOG.warn("Could not build C resolve configurations", e);
+ context.setCancelled();
+ return ImmutableMap.of();
+ }
+
+ for (MapEntry mapEntry : mapEntries) {
+ // Skip over labels that don't have C configuration data.
+ if (mapEntry != null) {
+ newResolveConfigurations.put(mapEntry.label, mapEntry.configuration);
+ }
+ }
+ return newResolveConfigurations.build();
+ });
+ }
+
+ private static ListenableFuture<MapEntry> submit(Callable<MapEntry> callable) {
+ return BlazeExecutor.getInstance().submit(callable);
+ }
+
+ @Nullable
+ private MapEntry createResolveConfiguration(
+ RuleIdeInfo rule,
+ ImmutableMap<Label, CToolchainIdeInfo> toolchainLookupMap,
+ ConcurrentMap<CToolchainIdeInfo, File> compilerWrapperCache,
+ WorkspacePathResolver workspacePathResolver,
+ BlazeProjectData blazeProjectData) {
+ Label label = rule.label;
+ LOG.info("Resolving " + label.toString());
+ CToolchainIdeInfo toolchainIdeInfo = toolchainLookupMap.get(label);
+ if (toolchainIdeInfo != null) {
+ File compilerWrapper =
+ findOrCreateCompilerWrapperScript(
+ compilerWrapperCache, toolchainIdeInfo, workspacePathResolver, rule.label);
+ if (compilerWrapper != null) {
+ BlazeResolveConfiguration config =
+ BlazeResolveConfiguration.createConfigurationForTarget(
+ project,
+ workspacePathResolver,
+ blazeProjectData.ruleMap.get(label),
+ toolchainIdeInfo,
+ compilerWrapper);
+ if (config != null) {
+ return new MapEntry(label, config);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static File findOrCreateCompilerWrapperScript(
+ Map<CToolchainIdeInfo, File> compilerWrapperCache,
+ CToolchainIdeInfo toolchainIdeInfo,
+ WorkspacePathResolver workspacePathResolver,
+ Label label) {
+ File compilerWrapper = compilerWrapperCache.get(toolchainIdeInfo);
+ if (compilerWrapper == null) {
+ File cppExecutable = toolchainIdeInfo.cppExecutable.getAbsoluteOrRelativeFile();
+ if (cppExecutable != null && !cppExecutable.isAbsolute()) {
+ cppExecutable = workspacePathResolver.resolveToFile(cppExecutable.getPath());
+ }
+ if (cppExecutable == null) {
+ String errorMessage =
+ String.format(
+ "Unable to find compiler executable: %s for rule %s",
+ toolchainIdeInfo.cppExecutable.toString(), label.toString());
+ LOG.warn(errorMessage);
+ compilerWrapper = null;
+ } else {
+ compilerWrapper = createCompilerExecutableWrapper(cppExecutable);
+ if (compilerWrapper != null) {
+ compilerWrapperCache.put(toolchainIdeInfo, compilerWrapper);
+ }
+ }
+ }
+ return compilerWrapper;
+ }
+
+ /**
+ * Create a wrapper script that transforms the CLion compiler invocation into a safe invocation of
+ * the compiler script that blaze uses.
+ *
+ * <p>CLion passes arguments to the compiler in an arguments file. The c toolchain compiler
+ * wrapper script doesn't handle arguments files, so we need to move the compiler arguments from
+ * the file to the command line.
+ *
+ * @param blazeCompilerExecutableFile blaze compiler wrapper
+ * @return The wrapper script that CLion can call.
+ */
+ @Nullable
+ private static File createCompilerExecutableWrapper(File blazeCompilerExecutableFile) {
+ try {
+ File blazeCompilerWrapper =
+ FileUtil.createTempFile("blaze_compiler", ".sh", true /* deleteOnExit */);
+ if (!blazeCompilerWrapper.setExecutable(true)) {
+ return null;
+ }
+ ImmutableList<String> compilerWrapperScriptLines =
+ ImmutableList.of(
+ "#!/bin/bash",
+ "",
+ "# The c toolchain compiler wrapper script doesn't handle arguments files, so we",
+ "# need to move the compiler arguments from the file to the command line.",
+ "",
+ "if [ $# -ne 2 ]; then",
+ " echo \"Usage: $0 @arg-file compile-file\"",
+ " exit 2;",
+ "fi",
+ "",
+ "if [[ $1 != @* ]]; then",
+ " echo \"Usage: $0 @arg-file compile-file\"",
+ " exit 3;",
+ "fi",
+ "",
+ " # Remove the @ before the arguments file path",
+ "ARG_FILE=${1#@}",
+ "# The actual compiler wrapper script we get from blaze",
+ "EXE=" + blazeCompilerExecutableFile.getPath(),
+ "# Read in the arguments file so we can pass the arguments on the command line.",
+ "ARGS=`cat $ARG_FILE`",
+ "$EXE $ARGS $2");
+
+ try (PrintWriter pw = new PrintWriter(blazeCompilerWrapper)) {
+ compilerWrapperScriptLines.forEach(pw::println);
+ }
+ return blazeCompilerWrapper;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ @Nullable
+ public OCResolveConfiguration getConfigurationForFile(VirtualFile sourceFile) {
+ SourceToRuleMap sourceToRuleMap = SourceToRuleMap.getInstance(project);
+ List<Label> targetsForSourceFile =
+ Lists.newArrayList(
+ sourceToRuleMap.getTargetsForSourceFile(VfsUtilCore.virtualToIoFile(sourceFile)));
+ if (targetsForSourceFile.isEmpty()) {
+ return null;
+ }
+
+ // If a source file is in two different targets,
+ // we can't possibly show how it will be interpreted in both contexts at the same time
+ // in the IDE, so just pick the first target after we sort.
+ targetsForSourceFile.sort((o1, o2) -> o1.toString().compareTo(o2.toString()));
+ Label target = Iterables.getFirst(targetsForSourceFile, null);
+ assert (target != null);
+
+ return resolveConfigurations.get(target);
+ }
+
+ public List<? extends OCResolveConfiguration> getAllConfigurations() {
+ return ImmutableList.copyOf(resolveConfigurations.values());
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCppAutoImportHelper.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCppAutoImportHelper.java
new file mode 100644
index 0000000..4a63ee9
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCppAutoImportHelper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.util.Processor;
+import com.jetbrains.cidr.lang.autoImport.OCDefaultAutoImportHelper;
+import com.jetbrains.cidr.lang.workspace.OCResolveRootAndConfiguration;
+import com.jetbrains.cidr.lang.workspace.headerRoots.IncludedHeadersRoot;
+import javax.annotation.Nullable;
+
+/**
+ * CLion's auto-import suggestions result in include paths relative to the current file (CPP-7593).
+ * Instead, we want paths relative to the header search root (e.g. the relevant blaze/bazel package
+ * path). Presumably this will be fixed in a future CLwB release, but in the meantime, fix it
+ * ourselves.
+ */
+public class BlazeCppAutoImportHelper extends OCDefaultAutoImportHelper {
+
+ @Override
+ public boolean supports(OCResolveRootAndConfiguration rootAndConfiguration) {
+ return rootAndConfiguration.getConfiguration()
+ instanceof com.google.idea.blaze.cpp.BlazeResolveConfiguration;
+ }
+
+ /**
+ * Search in project header roots only. All other cases are covered by CLion's default
+ * implementation.
+ */
+ @Override
+ public boolean processPathSpecificationToInclude(
+ Project project,
+ @Nullable VirtualFile targetFile,
+ final VirtualFile fileToImport,
+ OCResolveRootAndConfiguration rootAndConfiguration,
+ Processor<ImportSpecification> processor) {
+ String name = fileToImport.getName();
+ String path = fileToImport.getPath();
+
+ VirtualFile targetFileParent = targetFile != null ? targetFile.getParent() : null;
+
+ if (targetFileParent != null && targetFileParent.equals(fileToImport.getParent())) {
+ if (!processor.process(
+ new ImportSpecification(name, ImportSpecification.Kind.PROJECT_HEADER))) {
+ return false;
+ }
+ }
+
+ for (PsiFileSystemItem root : rootAndConfiguration.getProjectHeadersRoots().getRoots()) {
+ if (!(root instanceof IncludedHeadersRoot)) {
+ continue;
+ }
+ VirtualFile rootBase = root.getVirtualFile();
+ String relativePath = VfsUtilCore.getRelativePath(fileToImport, rootBase);
+ if (relativePath == null) {
+ continue;
+ }
+ if (!processor.process(
+ new ImportSpecification(relativePath, ImportSpecification.Kind.PROJECT_HEADER))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeLanguageKindCalculatorHelper.java b/cpp/src/com/google/idea/blaze/cpp/BlazeLanguageKindCalculatorHelper.java
new file mode 100644
index 0000000..254c94a
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeLanguageKindCalculatorHelper.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.workspace.OCLanguageKindCalculatorHelper;
+import javax.annotation.Nullable;
+
+final class BlazeLanguageKindCalculatorHelper implements OCLanguageKindCalculatorHelper {
+ @Nullable
+ @Override
+ public OCLanguageKind getSpecifiedLanguage(Project project, VirtualFile file) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public OCLanguageKind getLanguageByExtension(Project project, String name) {
+ if (Blaze.isBlazeProject(project)) {
+ String extension = FileUtilRt.getExtension(name);
+ if (extension.equalsIgnoreCase("c")) {
+ return OCLanguageKind.C;
+ }
+ if (extension.equalsIgnoreCase("cc")) {
+ return OCLanguageKind.CPP;
+ }
+ }
+ return null;
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfigurationTemporaryBase.java b/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfigurationTemporaryBase.java
new file mode 100644
index 0000000..a710707
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfigurationTemporaryBase.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.ideinfo.CRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.UserDataHolderBase;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCFileTypeHelpers;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.preprocessor.OCImportGraph;
+import com.jetbrains.cidr.lang.workspace.OCLanguageKindCalculator;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import com.jetbrains.cidr.lang.workspace.OCResolveRootAndConfiguration;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceUtil;
+import com.jetbrains.cidr.lang.workspace.compiler.CidrCompilerResult;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerMacros;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
+import com.jetbrains.cidr.lang.workspace.headerRoots.HeaderRoots;
+import com.jetbrains.cidr.lang.workspace.headerRoots.HeadersSearchRoot;
+import com.jetbrains.cidr.lang.workspace.headerRoots.IncludedHeadersRoot;
+import com.jetbrains.cidr.toolchains.CompilerInfoCache;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/**
+ * This is a temporary base class to deal with API changes between v145 (Android Studio) and v162
+ * (CLion). Once Android Studio's API has caught up, the features in versioned/v162 can be merged,
+ * this class be renamed BlazeResolveConfiguration, and it can be made final.
+ */
+abstract class BlazeResolveConfigurationTemporaryBase extends UserDataHolderBase
+ implements OCResolveConfiguration {
+
+ public static final Logger LOG = Logger.getInstance(BlazeResolveConfiguration.class);
+
+ private final WorkspacePathResolver workspacePathResolver;
+
+ /* project, label are protected instead of private just so v145 can access */
+ protected final Project project;
+ protected final Label label;
+
+ private final ImmutableList<HeadersSearchRoot> cLibraryIncludeRoots;
+ private final ImmutableList<HeadersSearchRoot> cppLibraryIncludeRoots;
+ private final HeaderRoots projectIncludeRoots;
+
+ private final CompilerInfoCache compilerInfoCache;
+ private final BlazeCompilerMacros compilerMacros;
+ private final BlazeCompilerSettings compilerSettings;
+
+ @Nullable
+ public static BlazeResolveConfiguration createConfigurationForTarget(
+ Project project,
+ WorkspacePathResolver workspacePathResolver,
+ RuleIdeInfo ruleIdeInfo,
+ CToolchainIdeInfo toolchainIdeInfo,
+ File compilerWrapper) {
+ CRuleIdeInfo cRuleIdeInfo = ruleIdeInfo.cRuleIdeInfo;
+ if (cRuleIdeInfo == null) {
+ return null;
+ }
+
+ ImmutableSet.Builder<ExecutionRootPath> systemIncludesBuilder = ImmutableSet.builder();
+ systemIncludesBuilder.addAll(cRuleIdeInfo.transitiveSystemIncludeDirectories);
+ systemIncludesBuilder.addAll(toolchainIdeInfo.builtInIncludeDirectories);
+ systemIncludesBuilder.addAll(toolchainIdeInfo.unfilteredToolchainSystemIncludes);
+
+ ImmutableSet.Builder<ExecutionRootPath> userIncludesBuilder = ImmutableSet.builder();
+ userIncludesBuilder.addAll(cRuleIdeInfo.transitiveIncludeDirectories);
+
+ ImmutableSet.Builder<ExecutionRootPath> userQuoteIncludesBuilder = ImmutableSet.builder();
+ userQuoteIncludesBuilder.addAll(cRuleIdeInfo.transitiveQuoteIncludeDirectories);
+
+ ImmutableList.Builder<String> cFlagsBuilder = ImmutableList.builder();
+ cFlagsBuilder.addAll(toolchainIdeInfo.baseCompilerOptions);
+ cFlagsBuilder.addAll(toolchainIdeInfo.cCompilerOptions);
+ cFlagsBuilder.addAll(toolchainIdeInfo.unfilteredCompilerOptions);
+
+ ImmutableList.Builder<String> cppFlagsBuilder = ImmutableList.builder();
+ cppFlagsBuilder.addAll(toolchainIdeInfo.baseCompilerOptions);
+ cppFlagsBuilder.addAll(toolchainIdeInfo.cppCompilerOptions);
+ cppFlagsBuilder.addAll(toolchainIdeInfo.unfilteredCompilerOptions);
+
+ ImmutableMap<String, String> features = ImmutableMap.of();
+
+ return new BlazeResolveConfiguration(
+ project,
+ workspacePathResolver,
+ ruleIdeInfo.label,
+ systemIncludesBuilder.build(),
+ systemIncludesBuilder.build(),
+ userQuoteIncludesBuilder.build(),
+ userIncludesBuilder.build(),
+ userIncludesBuilder.build(),
+ cRuleIdeInfo.transitiveDefines,
+ features,
+ compilerWrapper,
+ compilerWrapper,
+ cFlagsBuilder.build(),
+ cppFlagsBuilder.build());
+ }
+
+ public static ImmutableMap<Label, CToolchainIdeInfo> buildToolchainLookupMap(
+ BlazeContext context, RuleMap ruleMap, ImmutableMultimap<Label, Label> reverseDependencies) {
+ return Scope.push(
+ context,
+ childContext -> {
+ childContext.push(new TimingScope("Build toolchain lookup map"));
+
+ List<Label> seeds = Lists.newArrayList();
+ for (RuleIdeInfo rule : ruleMap.rules()) {
+ Label label = rule.label;
+ CToolchainIdeInfo cToolchainIdeInfo = rule.cToolchainIdeInfo;
+ if (cToolchainIdeInfo != null) {
+ seeds.add(label);
+ }
+ }
+
+ Map<Label, CToolchainIdeInfo> lookupTable = Maps.newHashMap();
+ for (Label seed : seeds) {
+ CToolchainIdeInfo toolchainInfo = ruleMap.get(seed).cToolchainIdeInfo;
+ LOG.assertTrue(toolchainInfo != null);
+ List<Label> worklist = Lists.newArrayList(reverseDependencies.get(seed));
+ while (!worklist.isEmpty()) {
+ // We should never see a label depend on two different toolchains.
+ Label l = worklist.remove(0);
+ CToolchainIdeInfo previousValue = lookupTable.putIfAbsent(l, toolchainInfo);
+ // Don't propagate the toolchain twice.
+ if (previousValue == null) {
+ worklist.addAll(reverseDependencies.get(l));
+ } else {
+ LOG.assertTrue(previousValue.equals(toolchainInfo));
+ }
+ }
+ }
+ return ImmutableMap.copyOf(lookupTable);
+ });
+ }
+
+ public BlazeResolveConfigurationTemporaryBase(
+ Project project,
+ WorkspacePathResolver workspacePathResolver,
+ Label label,
+ ImmutableCollection<ExecutionRootPath> cSystemIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cppSystemIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> quoteIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cppIncludeDirs,
+ ImmutableCollection<String> defines,
+ ImmutableMap<String, String> features,
+ File cCompilerExecutable,
+ File cppCompilerExecutable,
+ ImmutableList<String> cCompilerFlags,
+ ImmutableList<String> cppCompilerFlags) {
+ this.workspacePathResolver = workspacePathResolver;
+ this.project = project;
+ this.label = label;
+
+ ImmutableList.Builder<HeadersSearchRoot> cIncludeRootsBuilder = ImmutableList.builder();
+ collectHeaderRoots(cIncludeRootsBuilder, cIncludeDirs, true /* isUserHeader */);
+ collectHeaderRoots(cIncludeRootsBuilder, cSystemIncludeDirs, false /* isUserHeader */);
+ this.cLibraryIncludeRoots = cIncludeRootsBuilder.build();
+
+ ImmutableList.Builder<HeadersSearchRoot> cppIncludeRootsBuilder = ImmutableList.builder();
+ collectHeaderRoots(cppIncludeRootsBuilder, cppIncludeDirs, true /* isUserHeader */);
+ collectHeaderRoots(cppIncludeRootsBuilder, cppSystemIncludeDirs, false /* isUserHeader */);
+ this.cppLibraryIncludeRoots = cppIncludeRootsBuilder.build();
+
+ ImmutableList.Builder<HeadersSearchRoot> quoteIncludeRootsBuilder = ImmutableList.builder();
+ collectHeaderRoots(quoteIncludeRootsBuilder, quoteIncludeDirs, true /* isUserHeader */);
+ this.projectIncludeRoots = new HeaderRoots(quoteIncludeRootsBuilder.build());
+
+ this.compilerSettings =
+ new BlazeCompilerSettings(
+ project, cCompilerExecutable, cppCompilerExecutable, cCompilerFlags, cppCompilerFlags);
+
+ this.compilerInfoCache = new CompilerInfoCache();
+ this.compilerMacros =
+ new BlazeCompilerMacros(project, compilerInfoCache, compilerSettings, defines, features);
+ }
+
+ @Override
+ public Project getProject() {
+ return project;
+ }
+
+ @Override
+ public String getDisplayName(boolean shorten) {
+ return label.toString();
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getPrecompiledHeader() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public OCLanguageKind getDeclaredLanguageKind(VirtualFile sourceOrHeaderFile) {
+ String fileName = sourceOrHeaderFile.getName();
+ if (OCFileTypeHelpers.isSourceFile(fileName)) {
+ return getLanguageKind(sourceOrHeaderFile);
+ }
+
+ if (OCFileTypeHelpers.isHeaderFile(fileName)) {
+ return getLanguageKind(getSourceFileForHeaderFile(sourceOrHeaderFile));
+ }
+
+ return null;
+ }
+
+ private OCLanguageKind getLanguageKind(@Nullable VirtualFile sourceFile) {
+ OCLanguageKind kind = OCLanguageKindCalculator.tryFileTypeAndExtension(project, sourceFile);
+ return kind != null ? kind : getMaximumLanguageKind();
+ }
+
+ @Nullable
+ private VirtualFile getSourceFileForHeaderFile(VirtualFile headerFile) {
+ ArrayList<VirtualFile> roots =
+ new ArrayList<>(OCImportGraph.getAllHeaderRoots(project, headerFile));
+
+ final String headerNameWithoutExtension = headerFile.getNameWithoutExtension();
+ for (VirtualFile root : roots) {
+ if (root.getNameWithoutExtension().equals(headerNameWithoutExtension)) {
+ return root;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public OCLanguageKind getPrecompiledLanguageKind() {
+ return getMaximumLanguageKind();
+ }
+
+ @Override
+ public OCLanguageKind getMaximumLanguageKind() {
+ return OCLanguageKind.CPP;
+ }
+
+ @Override
+ public HeaderRoots getProjectHeadersRoots() {
+ return projectIncludeRoots;
+ }
+
+ @Override
+ public HeaderRoots getLibraryHeadersRoots(OCResolveRootAndConfiguration headerContext) {
+ OCLanguageKind languageKind = headerContext.getKind();
+ VirtualFile sourceFile = headerContext.getRootFile();
+ if (languageKind == null) {
+ languageKind = getLanguageKind(sourceFile);
+ }
+
+ ImmutableSet.Builder<HeadersSearchRoot> roots = ImmutableSet.builder();
+ if (languageKind == OCLanguageKind.C) {
+ roots.addAll(cLibraryIncludeRoots);
+ } else {
+ roots.addAll(cppLibraryIncludeRoots);
+ }
+
+ CidrCompilerResult<CompilerInfoCache.Entry> compilerInfoCacheHolder =
+ compilerInfoCache.getCompilerInfoCache(project, compilerSettings, languageKind, sourceFile);
+ CompilerInfoCache.Entry compilerInfo = compilerInfoCacheHolder.getResult();
+ if (compilerInfo != null) {
+ roots.addAll(compilerInfo.headerSearchPaths);
+ }
+ return new HeaderRoots(roots.build().asList());
+ }
+
+ private void collectHeaderRoots(
+ ImmutableList.Builder<HeadersSearchRoot> roots,
+ ImmutableCollection<ExecutionRootPath> paths,
+ boolean isUserHeader) {
+ for (ExecutionRootPath executionRootPath : paths) {
+ ImmutableList<File> possibleDirectories =
+ workspacePathResolver.resolveToIncludeDirectories(executionRootPath);
+ for (File f : possibleDirectories) {
+ VirtualFile vf = getVirtualFile(f);
+ if (vf == null) {
+ LOG.debug(
+ String.format(
+ "Header root %s could not be converted to a virtual file", f.getAbsolutePath()));
+ } else {
+ roots.add(new IncludedHeadersRoot(project, vf, false /* recursive */, isUserHeader));
+ }
+ }
+ }
+ }
+
+ @Nullable
+ private static VirtualFile getVirtualFile(File file) {
+ LocalFileSystem fileSystem = LocalFileSystem.getInstance();
+ VirtualFile vf = fileSystem.findFileByPathIfCached(file.getPath());
+ if (vf == null) {
+ vf = fileSystem.findFileByIoFile(file);
+ }
+ return vf;
+ }
+
+ @Override
+ public OCCompilerMacros getCompilerMacros() {
+ return compilerMacros;
+ }
+
+ @Override
+ public OCCompilerSettings getCompilerSettings() {
+ return compilerSettings;
+ }
+
+ @Nullable
+ @Override
+ public Object getIndexingCluster() {
+ return null;
+ }
+
+ @Override
+ public int compareTo(OCResolveConfiguration other) {
+ return OCWorkspaceUtil.compareConfigurations(this, other);
+ }
+
+ @Override
+ public int hashCode() {
+ // There should only be one configuration per label.
+ return Objects.hash(label);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof BlazeResolveConfiguration)) {
+ return false;
+ }
+
+ BlazeResolveConfiguration that = (BlazeResolveConfiguration) obj;
+ return compareTo(that) == 0;
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java b/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java
new file mode 100644
index 0000000..ff0b0ed
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.prefetch.PrefetchFileSource;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Set;
+
+/** Causes C files to become prefetched. */
+public class CPrefetchFileSource implements PrefetchFileSource {
+ @Override
+ public void addFilesToPrefetch(
+ Project project, BlazeProjectData blazeProjectData, Collection<File> files) {}
+
+ @Override
+ public Set<String> prefetchSrcFileExtensions() {
+ return ImmutableSet.of("c", "cc", "cpp", "h", "hh", "hpp");
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/versioned/v145/BlazeResolveConfiguration.java b/cpp/src/com/google/idea/blaze/cpp/versioned/v145/BlazeResolveConfiguration.java
new file mode 100644
index 0000000..7704f4f
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/versioned/v145/BlazeResolveConfiguration.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.execution.CidrBuildTarget;
+import com.jetbrains.cidr.execution.CidrBuildTargetWithConfigurations;
+import com.jetbrains.cidr.execution.CidrTargetHolder;
+import java.io.File;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+final class BlazeResolveConfiguration extends BlazeResolveConfigurationTemporaryBase
+ implements CidrTargetHolder {
+
+ public BlazeResolveConfiguration(
+ Project project,
+ WorkspacePathResolver workspacePathResolver,
+ Label label,
+ ImmutableCollection<ExecutionRootPath> cSystemIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cppSystemIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> quoteIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cppIncludeDirs,
+ ImmutableCollection<String> defines,
+ ImmutableMap<String, String> features,
+ File cCompilerExecutable,
+ File cppCompilerExecutable,
+ ImmutableList<String> cCompilerFlags,
+ ImmutableList<String> cppCompilerFlags) {
+ super(
+ project,
+ workspacePathResolver,
+ label,
+ cSystemIncludeDirs,
+ cppSystemIncludeDirs,
+ quoteIncludeDirs,
+ cIncludeDirs,
+ cppIncludeDirs,
+ defines,
+ features,
+ cCompilerExecutable,
+ cppCompilerExecutable,
+ cCompilerFlags,
+ cppCompilerFlags);
+ }
+
+ /** Workaround for b/30301958. TODO: Remove this once we move to CLion 162.1531.1 or later */
+ @Override
+ public CidrBuildTarget getTarget() {
+ return new CidrBuildTargetWithConfigurations() {
+ @Override
+ public String getName() {
+ return label.toString();
+ }
+
+ @Override
+ public String getProjectName() {
+ return project.getName();
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return null;
+ }
+
+ @Override
+ public boolean isExecutable() {
+ return false;
+ }
+
+ @Override
+ public List getBuildConfigurations() {
+ return ImmutableList.of();
+ }
+ };
+ }
+}
diff --git a/cpp/src/com/google/idea/blaze/cpp/versioned/v162/BlazeResolveConfiguration.java b/cpp/src/com/google/idea/blaze/cpp/versioned/v162/BlazeResolveConfiguration.java
new file mode 100644
index 0000000..c5c5e86
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/versioned/v162/BlazeResolveConfiguration.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.modulemap.ModuleMapModules;
+import java.io.File;
+import org.jetbrains.annotations.NotNull;
+
+final class BlazeResolveConfiguration extends BlazeResolveConfigurationTemporaryBase {
+
+ public BlazeResolveConfiguration(
+ Project project,
+ WorkspacePathResolver workspacePathResolver,
+ Label label,
+ ImmutableCollection<ExecutionRootPath> cSystemIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cppSystemIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> quoteIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cIncludeDirs,
+ ImmutableCollection<ExecutionRootPath> cppIncludeDirs,
+ ImmutableCollection<String> defines,
+ ImmutableMap<String, String> features,
+ File cCompilerExecutable,
+ File cppCompilerExecutable,
+ ImmutableList<String> cCompilerFlags,
+ ImmutableList<String> cppCompilerFlags) {
+ super(
+ project,
+ workspacePathResolver,
+ label,
+ cSystemIncludeDirs,
+ cppSystemIncludeDirs,
+ quoteIncludeDirs,
+ cIncludeDirs,
+ cppIncludeDirs,
+ defines,
+ features,
+ cCompilerExecutable,
+ cppCompilerExecutable,
+ cCompilerFlags,
+ cppCompilerFlags);
+ }
+
+ @NotNull
+ @Override
+ public ModuleMapModules getModules() {
+ return ModuleMapModules.Companion.getEMPTY();
+ }
+}
diff --git a/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java b/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
new file mode 100644
index 0000000..317d838
--- /dev/null
+++ b/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.cpp;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
+import java.io.File;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeCompilerSettings}. */
+@RunWith(JUnit4.class)
+public class BlazeCompilerSettingsTest extends BlazeTestCase {
+
+ @Test
+ public void testCompilerSwitchesSimple() {
+ File cppExe = new File("bin/cpp");
+ ImmutableList<String> cFlags = ImmutableList.of("-fast", "-slow");
+ BlazeCompilerSettings settings =
+ new BlazeCompilerSettings(getProject(), cppExe, cppExe, cFlags, cFlags);
+
+ CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
+ List<String> commandLineArgs = compilerSwitches.getFileArgs();
+ assertThat(commandLineArgs).containsExactly("-fast", "-slow");
+ }
+
+ @Test
+ public void testCompilerSwitchesWithUnescapedSpaces() {
+ File cppExe = new File("bin/cpp");
+ ImmutableList<String> cFlags = ImmutableList.of("-f ast", "-slo w");
+ BlazeCompilerSettings settings =
+ new BlazeCompilerSettings(getProject(), cppExe, cppExe, cFlags, cFlags);
+
+ CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
+ List<String> fileArgs = compilerSwitches.getFileArgs();
+ assertThat(fileArgs).containsExactly("-f", "ast", "-slo", "w");
+ }
+
+ @Test
+ public void testCompilerSwitchesWithEscapedSpaces() {
+ File cppExe = new File("bin/cpp");
+ ImmutableList<String> cFlags = ImmutableList.of("-f\\ ast", "-slo\\ w");
+ BlazeCompilerSettings settings =
+ new BlazeCompilerSettings(getProject(), cppExe, cppExe, cFlags, cFlags);
+
+ CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
+ List<String> fileArgs = compilerSwitches.getFileArgs();
+ assertThat(fileArgs).containsExactly("-f", "ast", "-slo", "w");
+ }
+
+ @Test
+ public void testCompilerSwitchesWithUnescapedAndEscapedSpaces() {
+ File cppExe = new File("bin/cpp");
+ ImmutableList<String> cFlags = ImmutableList.of("-f ast", "-slo\\ w");
+ BlazeCompilerSettings settings =
+ new BlazeCompilerSettings(getProject(), cppExe, cppExe, cFlags, cFlags);
+
+ CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
+ List<String> fileArgs = compilerSwitches.getFileArgs();
+ assertThat(fileArgs).containsExactly("-f", "ast", "-slo", "w");
+ }
+}
diff --git a/ijwb/.bazelproject b/ijwb/.bazelproject
index 3dc3303..f066e1b 100644
--- a/ijwb/.bazelproject
+++ b/ijwb/.bazelproject
@@ -1,6 +1,7 @@
directories:
.
-aswb
+ -aswb-google3
-clwb
-blaze-cpp
diff --git a/ijwb/BUILD b/ijwb/BUILD
index c681b39..fdc10ee 100644
--- a/ijwb/BUILD
+++ b/ijwb/BUILD
@@ -2,25 +2,28 @@
# Description: Builds ijwb
#
+licenses(["notice"]) # Apache 2.0
+
load(
"//build_defs:build_defs.bzl",
+ "intellij_plugin",
"merged_plugin_xml",
"stamped_plugin_xml",
- "intellij_plugin",
)
merged_plugin_xml(
name = "merged_plugin_xml_common",
srcs = [
"src/META-INF/ijwb.xml",
- "//blaze-base:plugin_xml",
- "//blaze-java:plugin_xml",
- "//blaze-plugin-dev:plugin_xml",
+ "//base:plugin_xml",
+ "//java:plugin_xml",
+ "//plugin_dev:plugin_xml",
],
+ visibility = ["//visibility:public"],
)
merged_plugin_xml(
- name = "merged_plugin_xml_bazel",
+ name = "merged_plugin_xml",
srcs = [
"src/META-INF/ijwb_bazel.xml",
":merged_plugin_xml_common",
@@ -28,9 +31,11 @@
)
stamped_plugin_xml(
- name = "stamped_plugin_xml_bazel",
+ name = "stamped_plugin_xml",
include_product_code_in_stamp = True,
- plugin_xml = ":merged_plugin_xml_bazel",
+ plugin_id = "com.google.idea.bazel.ijwb",
+ plugin_name = "IntelliJ with Bazel",
+ plugin_xml = ":merged_plugin_xml",
stamp_since_build = True,
version_file = "//:version",
)
@@ -38,20 +43,21 @@
java_library(
name = "ijwb_lib",
srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
exports = [
- "//blaze-plugin-dev",
+ "//plugin_dev",
],
deps = [
- "//blaze-base",
- "//blaze-java",
- "//intellij-platform-sdk:plugin_api",
- "//third_party:jsr305",
+ "//base",
+ "//intellij_platform_sdk:plugin_api",
+ "//java",
+ "@jsr305_annotations//jar",
],
)
intellij_plugin(
name = "ijwb_bazel",
- plugin_xml = ":stamped_plugin_xml_bazel",
+ plugin_xml = ":stamped_plugin_xml",
deps = [
":ijwb_lib",
],
diff --git a/ijwb/plugin/META-INF/.gitignore b/ijwb/plugin/META-INF/.gitignore
new file mode 100644
index 0000000..3a1130b
--- /dev/null
+++ b/ijwb/plugin/META-INF/.gitignore
@@ -0,0 +1 @@
+plugin.xml
\ No newline at end of file
diff --git a/ijwb/src/META-INF/ijwb.xml b/ijwb/src/META-INF/ijwb.xml
index 988e14e..b5fcb39 100644
--- a/ijwb/src/META-INF/ijwb.xml
+++ b/ijwb/src/META-INF/ijwb.xml
@@ -14,7 +14,6 @@
~ limitations under the License.
-->
<idea-plugin>
- <id>com.google.idea.blaze.ijwb</id>
<vendor>Google</vendor>
<extensions defaultExtensionNs="com.intellij">
diff --git a/ijwb/src/META-INF/ijwb_bazel.xml b/ijwb/src/META-INF/ijwb_bazel.xml
index a258cab..2068ad9 100644
--- a/ijwb/src/META-INF/ijwb_bazel.xml
+++ b/ijwb/src/META-INF/ijwb_bazel.xml
@@ -15,10 +15,25 @@
-->
<idea-plugin>
- <name>IntelliJ with Bazel</name>
-
<description>
- Provides the ability to import Bazel Java projects in IntelliJ.
+ <![CDATA[
+ <a href="http://bazel.io">Bazel</a> support for IntelliJ.
+
+ Features:
+ <ul>
+ <li>Import BUILD files into the IDE.</li>
+ <li>BUILD file custom language support.</li>
+ <li>Support for blaze run configurations for certain rule classes.</li>
+ </ul>
+
+ Usage instructions at <a href="http://ij.bazel.io">ij.bazel.io</a>
+ ]]>
</description>
+ <application-components>
+ <component>
+ <implementation-class>com.google.idea.blaze.ijwb.plugin.MigrateBazelPluginDependency</implementation-class>
+ </component>
+ </application-components>
+
</idea-plugin>
\ No newline at end of file
diff --git a/ijwb/src/META-INF/ijwb_blaze.xml b/ijwb/src/META-INF/ijwb_blaze.xml
deleted file mode 100644
index eaef611..0000000
--- a/ijwb/src/META-INF/ijwb_blaze.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ~ Copyright 2016 The Bazel Authors. All rights reserved.
- ~
- ~ 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.
- -->
-<idea-plugin>
-
- <name>IntelliJ with Blaze</name>
-
- <description>
- Provides the ability to import Blaze Java projects in IntelliJ.
- </description>
-
-</idea-plugin>
\ No newline at end of file
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteImportResult.java b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteImportResult.java
deleted file mode 100644
index 05c2b10..0000000
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteImportResult.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.ijwb.android;
-
-import com.google.common.collect.ImmutableCollection;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.Serializable;
-
-/**
- * The result of a blaze import operation.
- */
-@Immutable
-public class BlazeAndroidLiteImportResult implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public final ImmutableCollection<BlazeLibrary> libraries;
-
- public BlazeAndroidLiteImportResult(
- ImmutableCollection<BlazeLibrary> libraries) {
- this.libraries = libraries;
- }
-}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteJavaSyncAugmenter.java b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteJavaSyncAugmenter.java
index fabfb7d..0d864b8 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteJavaSyncAugmenter.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteJavaSyncAugmenter.java
@@ -15,34 +15,40 @@
*/
package com.google.idea.blaze.ijwb.android;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
import java.util.Collection;
-/**
- * Augments the java sync process with Android lite support.
- */
-public class BlazeAndroidLiteJavaSyncAugmenter implements BlazeJavaSyncAugmenter {
+/** Augments the java sync process with Android lite support. */
+public class BlazeAndroidLiteJavaSyncAugmenter extends BlazeJavaSyncAugmenter.Adapter {
@Override
- public void addLibraryFilter(Glob.GlobSet excludedLibraries) {
+ public boolean isActive(WorkspaceLanguageSettings workspaceLanguageSettings) {
+ return workspaceLanguageSettings.isLanguageActive(LanguageClass.ANDROID);
}
@Override
- public Collection<BlazeLibrary> getAdditionalLibraries(BlazeProjectData blazeProjectData) {
- BlazeAndroidLiteSyncData syncData = blazeProjectData.syncState.get(BlazeAndroidLiteSyncData.class);
- if (syncData == null) {
- return ImmutableList.of();
+ public void addJarsForSourceRule(
+ RuleIdeInfo rule, Collection<BlazeJarLibrary> jars, Collection<BlazeJarLibrary> genJars) {
+ AndroidRuleIdeInfo androidRuleIdeInfo = rule.androidRuleIdeInfo;
+ if (androidRuleIdeInfo == null) {
+ return;
}
- return syncData.importResult.libraries;
- }
- @Override
- public Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData) {
- return ImmutableList.of();
+ // Add R.java jars
+ LibraryArtifact resourceJar = androidRuleIdeInfo.resourceJar;
+ if (resourceJar != null) {
+ jars.add(new BlazeJarLibrary(resourceJar, rule.label));
+ }
+
+ LibraryArtifact idlJar = androidRuleIdeInfo.idlJar;
+ if (idlJar != null) {
+ genJars.add(new BlazeJarLibrary(idlJar, rule.label));
+ }
}
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncData.java b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncData.java
deleted file mode 100644
index b510f05..0000000
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncData.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.ijwb.android;
-
-import javax.annotation.concurrent.Immutable;
-import java.io.Serializable;
-
-/**
- * Sync data for the Android lite plugin.
- */
-@Immutable
-public class BlazeAndroidLiteSyncData implements Serializable {
- private static final long serialVersionUID = 1L;
-
- public final BlazeAndroidLiteImportResult importResult;
-
- public BlazeAndroidLiteSyncData(BlazeAndroidLiteImportResult importResult) {
- this.importResult = importResult;
- }
-}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPlugin.java b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPlugin.java
index a799d7e..4a9612d 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPlugin.java
@@ -15,34 +15,14 @@
*/
package com.google.idea.blaze.ijwb.android;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.SyncState;
-import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.model.primitives.WorkspaceType;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.scope.Scope;
-import com.google.idea.blaze.base.scope.scopes.TimingScope;
import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.google.idea.blaze.base.sync.workspace.WorkingSet;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.project.Project;
-
-import javax.annotation.Nullable;
-import java.io.File;
import java.util.Set;
-/**
- * Rudimentary support for android in IntelliJ.
- */
+/** Rudimentary support for android in IntelliJ. */
public class BlazeAndroidLiteSyncPlugin extends BlazeSyncPlugin.Adapter {
-
@Override
public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
switch (workspaceType) {
@@ -53,36 +33,4 @@
return ImmutableSet.of();
}
}
-
- @Override
- public void updateSyncState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
- if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.ANDROID)) {
- return;
- }
-
- BlazeAndroidLiteWorkspaceImporter workspaceImporter = new BlazeAndroidLiteWorkspaceImporter(
- project,
- workspaceRoot,
- context,
- projectViewSet,
- ruleMap
- );
- BlazeAndroidLiteImportResult importResult = Scope.push(context, childContext -> {
- childContext.push(new TimingScope("AndroidLiteWorkspaceImporter"));
- return workspaceImporter.importWorkspace();
- });
- BlazeAndroidLiteSyncData syncData = new BlazeAndroidLiteSyncData(importResult);
- syncStateBuilder.put(BlazeAndroidLiteSyncData.class, syncData);
- }
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteWorkspaceImporter.java b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteWorkspaceImporter.java
deleted file mode 100644
index c5fd4eb..0000000
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteWorkspaceImporter.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * 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 com.google.idea.blaze.ijwb.android;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
-import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
-import com.google.idea.blaze.base.scope.BlazeContext;
-import com.google.idea.blaze.base.sync.projectview.ProjectViewRuleImportFilter;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-import com.google.idea.blaze.java.sync.model.LibraryKey;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Builds a BlazeWorkspace.
- */
-public final class BlazeAndroidLiteWorkspaceImporter {
- private static final Logger LOG = Logger.getInstance(BlazeAndroidLiteWorkspaceImporter.class);
-
- private final Project project;
- private final BlazeContext context;
- private final ImmutableMap<Label, RuleIdeInfo> ruleMap;
- private final ProjectViewRuleImportFilter importFilter;
-
- public BlazeAndroidLiteWorkspaceImporter(
- Project project,
- WorkspaceRoot workspaceRoot,
- BlazeContext context,
- ProjectViewSet projectViewSet,
- ImmutableMap<Label, RuleIdeInfo> ruleMap) {
- this.project = project;
- this.context = context;
- this.ruleMap = ruleMap;
- this.importFilter = new ProjectViewRuleImportFilter(project, workspaceRoot, projectViewSet);
- }
-
- public BlazeAndroidLiteImportResult importWorkspace() {
- List<RuleIdeInfo> rules = ruleMap.values()
- .stream()
- .filter(importFilter::isSourceRule)
- .filter(rule -> rule.kind.getLanguageClass() == LanguageClass.ANDROID)
- .filter(rule -> !importFilter.excludeTarget(rule))
- .collect(Collectors.toList());
-
- WorkspaceBuilder workspaceBuilder = new WorkspaceBuilder();
-
- for (RuleIdeInfo rule : rules) {
- addRuleAsSource(
- workspaceBuilder,
- rule
- );
- }
-
- return new BlazeAndroidLiteImportResult(
- workspaceBuilder.libraries.build()
- );
- }
-
- private void addRuleAsSource(
- WorkspaceBuilder workspaceBuilder,
- RuleIdeInfo rule) {
-
- AndroidRuleIdeInfo androidRuleIdeInfo = rule.androidRuleIdeInfo;
- if (androidRuleIdeInfo != null) {
- // Add R.java jars
- LibraryArtifact resourceJar = androidRuleIdeInfo.resourceJar;
- if (resourceJar != null) {
- BlazeLibrary library1 = new BlazeLibrary(LibraryKey.fromJarFile(resourceJar.jar.getFile()), resourceJar);
- workspaceBuilder.libraries.add(library1);
- }
-
- LibraryArtifact idlJar = androidRuleIdeInfo.idlJar;
- if (idlJar != null) {
- BlazeLibrary library = new BlazeLibrary(LibraryKey.fromJarFile(idlJar.jar.getFile()), idlJar);
- workspaceBuilder.libraries.add(library);
- }
- }
- }
-
- static class WorkspaceBuilder {
- ImmutableList.Builder<BlazeLibrary> libraries = ImmutableList.builder();
- }
-}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartJavaSyncAugmenter.java b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartJavaSyncAugmenter.java
index 0de1f96..98f0f65 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartJavaSyncAugmenter.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartJavaSyncAugmenter.java
@@ -18,30 +18,19 @@
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-
import java.util.Collection;
-/**
- * Prevents garbage collection of the Dart SDK library.
- */
-public class BlazeDartJavaSyncAugmenter implements BlazeJavaSyncAugmenter {
+/** Prevents garbage collection of the Dart SDK library. */
+public class BlazeDartJavaSyncAugmenter extends BlazeJavaSyncAugmenter.Adapter {
@Override
- public void addLibraryFilter(Glob.GlobSet excludedLibraries) {
- }
-
- @Override
- public Collection<BlazeLibrary> getAdditionalLibraries(BlazeProjectData blazeProjectData) {
- return ImmutableList.of();
+ public boolean isActive(WorkspaceLanguageSettings workspaceLanguageSettings) {
+ return workspaceLanguageSettings.isLanguageActive(LanguageClass.DART);
}
@Override
public Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData) {
- if (blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.DART)) {
- return ImmutableList.of(BlazeDartSyncPlugin.DART_SDK_LIBRARY_NAME);
- }
- return ImmutableList.of();
+ return ImmutableList.of(BlazeDartSyncPlugin.DART_SDK_LIBRARY_NAME);
}
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPlugin.java b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPlugin.java
index 81fbf2b..d9245cd 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPlugin.java
@@ -31,13 +31,10 @@
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.impl.libraries.ApplicationLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
-
-import javax.annotation.Nullable;
import java.util.Set;
+import javax.annotation.Nullable;
-/**
- * Supports dart.
- */
+/** Supports dart. */
public class BlazeDartSyncPlugin extends BlazeSyncPlugin.Adapter {
static final String DART_SDK_LIBRARY_NAME = "Dart SDK";
@@ -49,36 +46,40 @@
}
@Override
- public void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel) {
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.DART)) {
return;
}
- Library dartSdkLibrary = ApplicationLibraryTable.getApplicationTable().getLibraryByName(DART_SDK_LIBRARY_NAME);
+ Library dartSdkLibrary =
+ ApplicationLibraryTable.getApplicationTable().getLibraryByName(DART_SDK_LIBRARY_NAME);
if (dartSdkLibrary != null) {
if (workspaceModifiableModel.findLibraryOrderEntry(dartSdkLibrary) == null) {
workspaceModifiableModel.addLibraryEntry(dartSdkLibrary);
}
} else {
- IssueOutput
- .error("Dart language support is requested, but the Dart SDK was not found. "
- + "You must manually enable Dart support from File > Settings > Languages & Frameworks > Dart.")
- .submit(context);
+ IssueOutput.error(
+ "Dart language support is requested, but the Dart SDK was not found. "
+ + "You must manually enable Dart support from "
+ + "File > Settings > Languages & Frameworks > Dart.")
+ .submit(context);
}
}
@Override
- public boolean validateProjectView(BlazeContext context,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings) {
+ public boolean validateProjectView(
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.DART)) {
return true;
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.java b/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.java
index 33a94ec..617b9a7 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.java
@@ -19,9 +19,7 @@
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.extensions.PluginId;
-/**
- * IDE and plugin checks.
- */
+/** IDE and plugin checks. */
public class IdeCheck {
public static boolean isPluginEnabled(String pluginIdString) {
PluginId pluginId = PluginId.getId(pluginIdString);
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPlugin.java b/ijwb/src/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPlugin.java
index b41596e..282a249 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPlugin.java
@@ -33,14 +33,11 @@
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PlatformUtils;
-
-import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Set;
+import javax.annotation.Nullable;
-/**
- * Allows people to use a javascript-only workspace.
- */
+/** Allows people to use a javascript-only workspace. */
public class BlazeJavascriptSyncPlugin extends BlazeSyncPlugin.Adapter {
@Nullable
@@ -58,12 +55,13 @@
}
@Override
- public void updateContentEntries(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- Collection<ContentEntry> contentEntries) {
+ public void updateContentEntries(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<ContentEntry> contentEntries) {
if (!blazeProjectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.JAVASCRIPT)) {
return;
}
@@ -84,9 +82,10 @@
}
@Override
- public boolean validateProjectView(BlazeContext context,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings) {
+ public boolean validateProjectView(
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.JAVASCRIPT)) {
return true;
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/plugin/IjwbPluginId.java b/ijwb/src/com/google/idea/blaze/ijwb/plugin/IjwbPluginId.java
index bfaba31..a1187f6 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/plugin/IjwbPluginId.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/plugin/IjwbPluginId.java
@@ -15,17 +15,23 @@
*/
package com.google.idea.blaze.ijwb.plugin;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.plugin.BlazePluginId;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-/**
- * IJwB plugin configuration information.
- */
+/** IJwB plugin configuration information. */
public class IjwbPluginId implements BlazePluginId {
- private static final String PLUGIN_ID = "com.google.idea.blaze.ijwb"; // Please keep up-to-date with plugin.xml
+ // Please keep these up-to-date with plugin xmls
+ static final String BLAZE_PLUGIN_ID = "com.google.idea.blaze.ijwb";
+ static final String BAZEL_PLUGIN_ID = "com.google.idea.bazel.ijwb";
@Override
public String getPluginId() {
- return PLUGIN_ID;
+ BuildSystem type = BuildSystemProvider.defaultBuildSystem().buildSystem();
+ if (type == BuildSystem.Blaze) {
+ return BLAZE_PLUGIN_ID;
+ }
+ return BAZEL_PLUGIN_ID;
}
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/plugin/MigrateBazelPluginDependency.java b/ijwb/src/com/google/idea/blaze/ijwb/plugin/MigrateBazelPluginDependency.java
new file mode 100644
index 0000000..4231e03
--- /dev/null
+++ b/ijwb/src/com/google/idea/blaze/ijwb/plugin/MigrateBazelPluginDependency.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.ijwb.plugin;
+
+import com.google.idea.blaze.base.plugin.dependency.PluginDependencyHelper;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.project.ProjectManagerAdapter;
+
+/**
+ * Temporary migration code following the IntelliJ-with-Bazel plugin ID change. We can't prevent an
+ * initial, spurious error that a required plugin is missing, however this will at least prevent the
+ * error on subsequent project loads.
+ */
+public class MigrateBazelPluginDependency extends ApplicationComponent.Adapter {
+
+ @Override
+ public void initComponent() {
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.addProjectManagerListener(
+ new ProjectManagerAdapter() {
+ @Override
+ public void projectOpened(Project project) {
+ if (Blaze.isBlazeProject(project)
+ && Blaze.getBuildSystem(project) == BuildSystem.Bazel) {
+ PluginDependencyHelper.removeDependencyOnOldPlugin(
+ project, IjwbPluginId.BLAZE_PLUGIN_ID);
+ }
+ }
+ });
+ }
+}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptJavaSyncAugmenter.java b/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptJavaSyncAugmenter.java
index 251b04d..a39c63e 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptJavaSyncAugmenter.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptJavaSyncAugmenter.java
@@ -18,30 +18,19 @@
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
-import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
-import com.google.idea.blaze.java.sync.model.BlazeLibrary;
-
import java.util.Collection;
-/**
- * Prevents garbage collection of "tsconfig$roots"
- */
-public class BlazeTypescriptJavaSyncAugmenter implements BlazeJavaSyncAugmenter {
+/** Prevents garbage collection of "tsconfig$roots" */
+public class BlazeTypescriptJavaSyncAugmenter extends BlazeJavaSyncAugmenter.Adapter {
@Override
- public void addLibraryFilter(Glob.GlobSet excludedLibraries) {
- }
-
- @Override
- public Collection<BlazeLibrary> getAdditionalLibraries(BlazeProjectData blazeProjectData) {
- return ImmutableList.of();
+ public boolean isActive(WorkspaceLanguageSettings workspaceLanguageSettings) {
+ return workspaceLanguageSettings.isLanguageActive(LanguageClass.TYPESCRIPT);
}
@Override
public Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData) {
- if (blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.TYPESCRIPT)) {
- return ImmutableList.of(BlazeTypescriptSyncPlugin.TSCONFIG_LIBRARY_NAME);
- }
- return ImmutableList.of();
+ return ImmutableList.of(BlazeTypescriptSyncPlugin.TSCONFIG_LIBRARY_NAME);
}
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPlugin.java b/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPlugin.java
index 7e5c3e7..3659a42 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPlugin.java
@@ -16,16 +16,15 @@
package com.google.idea.blaze.ijwb.typescript;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.idea.blaze.base.async.process.ExternalTask;
import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
import com.google.idea.blaze.base.command.BlazeCommand;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
-import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
import com.google.idea.blaze.base.model.SyncState;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
@@ -36,7 +35,7 @@
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.Scope;
import com.google.idea.blaze.base.scope.output.IssueOutput;
-import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
import com.google.idea.blaze.base.scope.scopes.TimingScope;
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
@@ -44,23 +43,17 @@
import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
import com.google.idea.blaze.base.sync.workspace.WorkingSet;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.util.PlatformUtils;
-
-import java.io.File;
import java.util.Collection;
import java.util.Set;
-
import javax.annotation.Nullable;
-/**
- * Supports typescript.
- */
+/** Supports typescript. */
public class BlazeTypescriptSyncPlugin extends BlazeSyncPlugin.Adapter {
static final String TSCONFIG_LIBRARY_NAME = "tsconfig$roots";
@@ -71,66 +64,73 @@
}
@Override
- public void updateSyncState(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
- @Nullable WorkingSet workingSet,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<Label, RuleIdeInfo> ruleMap,
- @Deprecated @Nullable File androidPlatformDirectory,
- SyncState.Builder syncStateBuilder,
- @Nullable SyncState previousSyncState) {
+ public void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {
if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.TYPESCRIPT)) {
return;
}
- Label tsConfig = projectViewSet.getSectionValue(TsConfigRuleSection.KEY);
+ Label tsConfig = projectViewSet.getScalarValue(TsConfigRuleSection.KEY);
if (tsConfig == null) {
invalidProjectViewError(context);
return;
}
- Scope.push(context, (childContext) -> {
- childContext.push(new TimingScope("TsConfig"));
- childContext.output(PrintOutput.output("Updating tsconfig..."));
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("TsConfig"));
+ childContext.output(new StatusOutput("Updating tsconfig..."));
- BlazeCommand command = BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.RUN)
- .addTargets(tsConfig)
- .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
- .build();
+ BlazeCommand command =
+ BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.RUN)
+ .addTargets(tsConfig)
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
+ .build();
- int retVal = ExternalTask.builder(workspaceRoot, command)
- .context(childContext)
- .stderr(LineProcessingOutputStream.of(
- new IssueOutputLineProcessor(project, childContext, workspaceRoot)
- ))
- .build()
- .run();
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command)
+ .context(childContext)
+ .stderr(
+ LineProcessingOutputStream.of(
+ new IssueOutputLineProcessor(project, childContext, workspaceRoot)))
+ .build()
+ .run();
- if (retVal != 0) {
- childContext.setHasError();
- }
- });
+ if (retVal != 0) {
+ childContext.setHasError();
+ }
+ });
}
@Override
- public void updateProjectStructure(Project project,
- BlazeContext context,
- WorkspaceRoot workspaceRoot,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- @Nullable BlazeProjectData oldBlazeProjectData,
- ModuleEditor moduleEditor,
- Module workspaceModule,
- ModifiableRootModel workspaceModifiableModel) {
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.TYPESCRIPT)) {
return;
}
- Library tsConfigLibrary = ProjectLibraryTable.getInstance(project).getLibraryByName(TSCONFIG_LIBRARY_NAME);
+ Library tsConfigLibrary =
+ ProjectLibraryTable.getInstance(project).getLibraryByName(TSCONFIG_LIBRARY_NAME);
if (tsConfigLibrary != null) {
if (workspaceModifiableModel.findLibraryOrderEntry(tsConfigLibrary) == null) {
workspaceModifiableModel.addLibraryEntry(tsConfigLibrary);
@@ -139,9 +139,10 @@
}
@Override
- public boolean validateProjectView(BlazeContext context,
- ProjectViewSet projectViewSet,
- WorkspaceLanguageSettings workspaceLanguageSettings) {
+ public boolean validateProjectView(
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
boolean typescriptActive = workspaceLanguageSettings.isLanguageActive(LanguageClass.TYPESCRIPT);
if (typescriptActive && !PlatformUtils.isIdeaUltimate()) {
@@ -150,7 +151,7 @@
}
// Must have either both typescript and ts_config_rule or neither
- Label tsConfig = projectViewSet.getSectionValue(TsConfigRuleSection.KEY);
+ Label tsConfig = projectViewSet.getScalarValue(TsConfigRuleSection.KEY);
if (typescriptActive ^ (tsConfig != null)) {
invalidProjectViewError(context);
return false;
@@ -160,9 +161,10 @@
}
private void invalidProjectViewError(BlazeContext context) {
- IssueOutput
- .error("For Typescript support you must add both additional_languages: typescript and the ts_config_rule attribute.")
- .submit(context);
+ IssueOutput.error(
+ "For Typescript support you must add both additional_languages: "
+ + "typescript and the ts_config_rule attribute.")
+ .submit(context);
}
@Override
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRuleSection.java b/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRuleSection.java
index ea476fd..aa3caff 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRuleSection.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRuleSection.java
@@ -24,13 +24,10 @@
import com.google.idea.blaze.base.projectview.section.SectionKey;
import com.google.idea.blaze.base.projectview.section.SectionParser;
import com.google.idea.blaze.base.ui.BlazeValidationError;
-
-import javax.annotation.Nullable;
import java.util.List;
+import javax.annotation.Nullable;
-/**
- * Points to the ts_config rule.
- */
+/** Points to the ts_config rule. */
public class TsConfigRuleSection {
public static final SectionKey<Label, ScalarSection<Label>> KEY = SectionKey.of("ts_config_rule");
public static final SectionParser PARSER = new TsConfigRuleSectionParser();
diff --git a/intellij-platform-sdk/BUILD b/intellij-platform-sdk/BUILD
deleted file mode 100644
index 617aa82..0000000
--- a/intellij-platform-sdk/BUILD
+++ /dev/null
@@ -1,100 +0,0 @@
-#
-# Description: IntelliJ plugin SDKs required to build the plugin jars.
-#
-
-config_setting(
- name = "intellij-latest",
- values = {
- "define": "ij_product=intellij-latest",
- },
-)
-
-config_setting(
- name = "clion-latest",
- values = {
- "define": "ij_product=clion-latest",
- },
-)
-
-config_setting(
- name = "android-studio-latest",
- values = {
- "define": "ij_product=android-studio-latest",
- },
-)
-
-java_library(
- name = "plugin_api_internal",
- exports = select({
- ":intellij-latest": ["@intellij_latest//:plugin_api"],
- ":clion-latest": ["@clion_latest//:plugin_api"],
- ":android-studio-latest": ["//intellij-platform-sdk/AI-145.971.21:plugin_api"],
- "//conditions:default": ["@intellij_latest//:plugin_api"],
- }),
-)
-
-# The outward facing plugin api
-java_library(
- name = "plugin_api",
- neverlink = 1,
- visibility = ["//visibility:public"],
- exports = [":plugin_api_internal"],
-)
-
-# for tests, we need the IJ API at runtime,
-# so can't use the neverlink rule
-java_library(
- name = "plugin_api_for_tests",
- testonly = 1,
- visibility = ["//visibility:public"],
- exports = [":plugin_api_internal"],
-)
-
-# The dev kit is only for IntelliJ since you only develop plugins in Java.
-java_library(
- name = "devkit",
- neverlink = 1,
- visibility = ["//visibility:public"],
- exports = select({
- ":intellij-latest": ["@intellij_latest//:devkit"],
- "//conditions:default": ["@intellij_latest//:devkit"],
- }),
-)
-
-filegroup(
- name = "build_number",
- srcs = select({
- ":intellij-latest": ["@intellij_latest//:build_number"],
- ":clion-latest": ["@clion_latest//:build_number"],
- ":android-studio-latest": ["//intellij-platform-sdk/AI-145.971.21:build_number"],
- "//conditions:default": ["@intellij_latest//:build_number"],
- }),
- visibility = ["//visibility:public"],
-)
-
-# Plugins bundled with the SDK which are required for compilation and/or integration tests
-java_library(
- name = "bundled_plugins_internal",
- exports = select({
- ":intellij-latest": ["@intellij_latest//:bundled_plugins"],
- ":clion-latest": ["@clion_latest//:bundled_plugins"],
- ":android-studio-latest": ["//intellij-platform-sdk/AI-145.971.21:bundled_plugins"],
- "//conditions:default": ["@intellij_latest//:bundled_plugins"],
- }),
-)
-
-java_library(
- name = "bundled_plugins",
- neverlink = 1,
- visibility = ["//visibility:public"],
- exports = [":bundled_plugins_internal"],
-)
-
-# for tests, we include the bundled plugins at runtime,
-# so can't use the neverlink rule
-java_library(
- name = "bundled_plugins_for_tests",
- testonly = 1,
- visibility = ["//visibility:public"],
- exports = [":bundled_plugins_internal"],
-)
diff --git a/intellij_platform_sdk/BUILD b/intellij_platform_sdk/BUILD
new file mode 100644
index 0000000..a733a02
--- /dev/null
+++ b/intellij_platform_sdk/BUILD
@@ -0,0 +1,104 @@
+#
+# Description: IntelliJ plugin SDKs required to build the plugin jars.
+#
+
+package(default_visibility = ["//visibility:public"])
+
+config_setting(
+ name = "intellij-latest",
+ values = {
+ "define": "ij_product=intellij-latest",
+ },
+)
+
+config_setting(
+ name = "clion-latest",
+ values = {
+ "define": "ij_product=clion-latest",
+ },
+)
+
+config_setting(
+ name = "android-studio-latest",
+ values = {
+ "define": "ij_product=android-studio-latest",
+ },
+)
+
+java_library(
+ name = "plugin_api_internal",
+ visibility = ["//visibility:private"],
+ exports = select({
+ ":intellij-latest": ["@intellij_latest//:plugin_api"],
+ ":clion-latest": ["@clion_latest//:plugin_api"],
+ ":android-studio-latest": [
+ "@android_studio_latest//:plugin_api",
+ "@android_studio_latest//:android_plugin",
+ ],
+ "//conditions:default": ["@intellij_latest//:plugin_api"],
+ }),
+)
+
+# The outward facing plugin api
+java_library(
+ name = "plugin_api",
+ neverlink = 1,
+ exports = [":plugin_api_internal"],
+)
+
+# for tests, we need the IJ API at runtime,
+# so can't use the neverlink rule
+java_library(
+ name = "plugin_api_for_tests",
+ testonly = 1,
+ exports = [
+ ":plugin_api_internal",
+ "@mockito//jar",
+ "@objenesis//jar",
+ "@truth//jar",
+ ],
+)
+
+# The dev kit is only for IntelliJ since you only develop plugins in Java.
+java_library(
+ name = "devkit",
+ neverlink = 1,
+ exports = select({
+ ":intellij-latest": ["@intellij_latest//:devkit"],
+ ":android-studio-latest": [],
+ ":clion-latest": [],
+ "//conditions:default": ["@intellij_latest//:devkit"],
+ }),
+)
+
+# Bundled plugins required by integration tests
+java_library(
+ name = "bundled_plugins",
+ testonly = 1,
+ runtime_deps = select({
+ ":intellij-latest": ["@intellij_latest//:bundled_plugins"],
+ ":clion-latest": ["@clion_latest//:bundled_plugins"],
+ ":android-studio-latest": ["@android_studio_latest//:bundled_plugins"],
+ "//conditions:default": ["@intellij_latest//:bundled_plugins"],
+ }),
+)
+
+filegroup(
+ name = "application_info_jar",
+ srcs = select({
+ ":intellij-latest": ["@intellij_latest//:application_info_jar"],
+ ":clion-latest": ["@clion_latest//:application_info_jar"],
+ ":android-studio-latest": ["@android_studio_latest//:application_info_jar"],
+ "//conditions:default": ["@intellij_latest//:application_info_jar"],
+ }),
+)
+
+filegroup(
+ name = "application_info_name",
+ srcs = select({
+ ":intellij-latest": ["intellij_application_info_name.txt"],
+ ":clion-latest": ["clion_application_info_name.txt"],
+ ":android-studio-latest": ["android_studio_application_info_name.txt"],
+ "//conditions:default": ["intellij_application_info_name.txt"],
+ }),
+)
diff --git a/intellij_platform_sdk/BUILD.android_studio b/intellij_platform_sdk/BUILD.android_studio
new file mode 100644
index 0000000..7a4839a
--- /dev/null
+++ b/intellij_platform_sdk/BUILD.android_studio
@@ -0,0 +1,40 @@
+# Description:
+#
+# Plugin source jars for Android Studio, accessed remotely.
+
+package(default_visibility = ["//visibility:public"])
+
+java_import(
+ name = "plugin_api",
+ jars = glob([
+ "android-studio/lib/*.jar",
+ ]),
+ tags = ["intellij-provided-by-sdk"],
+)
+
+java_import(
+ name = "android_plugin",
+ jars = glob([
+ "android-studio/plugins/android/lib/*.jar",
+ "android-studio/plugins/android-ndk/lib/*.jar",
+ ]),
+)
+
+# The plugins required by ASwB. We need to include them
+# when running integration tests.
+java_import(
+ name = "bundled_plugins",
+ jars = glob([
+ "android-studio/plugins/gradle/lib/*.jar",
+ "android-studio/plugins/Groovy/lib/*.jar",
+ "android-studio/plugins/java-i18n/lib/*.jar",
+ "android-studio/plugins/junit/lib/*.jar",
+ "android-studio/plugins/properties/lib/*.jar",
+ ]),
+ tags = ["intellij-provided-by-sdk"],
+)
+
+filegroup(
+ name = "application_info_jar",
+ srcs = ["android-studio/lib/resources.jar"],
+)
diff --git a/intellij_platform_sdk/BUILD.clion b/intellij_platform_sdk/BUILD.clion
new file mode 100644
index 0000000..c32194f
--- /dev/null
+++ b/intellij_platform_sdk/BUILD.clion
@@ -0,0 +1,24 @@
+# Description:
+#
+# Plugin source jars for CLion, accessed remotely.
+
+package(default_visibility = ["//visibility:public"])
+
+java_import(
+ name = "plugin_api",
+ jars = glob(["clion-*/lib/*.jar"]),
+ tags = ["intellij-provided-by-sdk"],
+)
+
+# The plugins required by CLwB. Presumably there will be some, when we write
+# some integration tests.
+java_import(
+ name = "bundled_plugins",
+ jars = [],
+ tags = ["intellij-provided-by-sdk"],
+)
+
+filegroup(
+ name = "application_info_jar",
+ srcs = glob(["clion-*/lib/clion.jar"]),
+)
\ No newline at end of file
diff --git a/intellij_platform_sdk/BUILD.idea b/intellij_platform_sdk/BUILD.idea
new file mode 100644
index 0000000..251b620
--- /dev/null
+++ b/intellij_platform_sdk/BUILD.idea
@@ -0,0 +1,34 @@
+# Description:
+#
+# Plugin source jars for IntelliJ CE, accessed remotely.
+
+package(default_visibility = ["//visibility:public"])
+
+java_import(
+ name = "plugin_api",
+ jars = glob(["idea-IC-*/lib/*.jar"]),
+ tags = ["intellij-provided-by-sdk"],
+)
+
+java_import(
+ name = "devkit",
+ jars = glob(["idea-IC-*/plugins/devkit/lib/devkit.jar"]),
+)
+
+# The plugins required by IJwB. We need to include them
+# when running integration tests.
+java_import(
+ name = "bundled_plugins",
+ jars = glob([
+ "idea-IC-*/plugins/devkit/lib/*.jar",
+ "idea-IC-*/plugins/java-i18n/lib/*.jar",
+ "idea-IC-*/plugins/junit/lib/*.jar",
+ "idea-IC-*/plugins/properties/lib/*.jar",
+ ]),
+ tags = ["intellij-provided-by-sdk"],
+)
+
+filegroup(
+ name = "application_info_jar",
+ srcs = glob(["idea-IC-*/lib/resources.jar"]),
+)
diff --git a/intellij_platform_sdk/android_studio_application_info_name.txt b/intellij_platform_sdk/android_studio_application_info_name.txt
new file mode 100644
index 0000000..d962cc0
--- /dev/null
+++ b/intellij_platform_sdk/android_studio_application_info_name.txt
@@ -0,0 +1 @@
+idea/AndroidStudioApplicationInfo.xml
diff --git a/intellij_platform_sdk/clion_application_info_name.txt b/intellij_platform_sdk/clion_application_info_name.txt
new file mode 100644
index 0000000..0cf4569
--- /dev/null
+++ b/intellij_platform_sdk/clion_application_info_name.txt
@@ -0,0 +1 @@
+idea/CLionApplicationInfo.xml
diff --git a/intellij_platform_sdk/intellij_application_info_name.txt b/intellij_platform_sdk/intellij_application_info_name.txt
new file mode 100644
index 0000000..687d0ea
--- /dev/null
+++ b/intellij_platform_sdk/intellij_application_info_name.txt
@@ -0,0 +1 @@
+idea/IdeaApplicationInfo.xml
diff --git a/intellij_test/BUILD b/intellij_test/BUILD
index cfd25b4..8b2600e 100644
--- a/intellij_test/BUILD
+++ b/intellij_test/BUILD
@@ -4,12 +4,15 @@
package(default_visibility = ["//visibility:public"])
+licenses(["notice"]) # Apache 2.0
+
java_library(
name = "lib",
+ testonly = 1,
srcs = glob(["src/**/*.java"]),
deps = [
- "//intellij-platform-sdk:plugin_api_for_tests",
- "//third_party:jsr305",
- "//third_party:test_lib",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
],
)
diff --git a/intellij_test/src/com/google/idea/blaze/base/BlazeTestSystemProperties.java b/intellij_test/src/com/google/idea/blaze/base/BlazeTestSystemProperties.java
index 2a19f58..c8a3351 100644
--- a/intellij_test/src/com/google/idea/blaze/base/BlazeTestSystemProperties.java
+++ b/intellij_test/src/com/google/idea/blaze/base/BlazeTestSystemProperties.java
@@ -17,33 +17,28 @@
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
-
+import com.intellij.openapi.application.Application;
+import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import com.intellij.util.PlatformUtils;
-
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.List;
+import javax.annotation.Nullable;
-/**
- * Test utilities specific to running in a blaze/bazel environment.
- */
+/** Test utilities specific to running in a blaze/bazel environment. */
public class BlazeTestSystemProperties {
- /**
- * The absolute path to the runfiles directory.
- */
+ /** The absolute path to the runfiles directory. */
private static final String RUNFILES_PATH = getUserValue("TEST_SRCDIR");
public static boolean isRunThroughBlaze() {
return System.getenv("JAVA_RUNFILES") != null;
}
- /**
- * Sets up the necessary system properties for running IntelliJ tests via blaze/bazel.
- */
+ /** Sets up the necessary system properties for running IntelliJ tests via blaze/bazel. */
public static void configureSystemProperties() throws IOException {
if (!isRunThroughBlaze()) {
return;
@@ -56,11 +51,18 @@
setIfEmpty(PlatformUtils.PLATFORM_PREFIX_KEY, "Idea");
setIfEmpty("idea.classpath.index.enabled", "false");
+ // Tests fail if they access files outside of the project roots and other system directories.
+ // Ensure runfiles and platform api are whitelisted.
VfsRootAccess.allowRootAccess(RUNFILES_PATH);
+ String platformApi = getPlatformApiPath();
+ if (platformApi != null) {
+ VfsRootAccess.allowRootAccess(platformApi);
+ }
List<String> pluginJars = Lists.newArrayList();
try {
- Enumeration<URL> urls = BlazeTestSystemProperties.class.getClassLoader().getResources("META-INF/plugin.xml");
+ Enumeration<URL> urls =
+ BlazeTestSystemProperties.class.getClassLoader().getResources("META-INF/plugin.xml");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
addArchiveFile(url, pluginJars);
@@ -73,6 +75,17 @@
setIfEmpty("idea.plugins.path", Joiner.on(File.pathSeparator).join(pluginJars));
}
+ @Nullable
+ private static String getPlatformApiPath() {
+ String platformJar = PathManager.getJarPathForClass(Application.class);
+ if (platformJar == null) {
+ return null;
+ }
+ File jarFile = new File(platformJar).getAbsoluteFile();
+ File libDir = jarFile.getParentFile();
+ return libDir != null ? libDir.getParent() : null;
+ }
+
private static void addArchiveFile(URL url, List<String> files) {
if ("jar".equals(url.getProtocol())) {
String path = url.getPath();
@@ -100,8 +113,8 @@
/**
* Gets directory that should be used for all files created during testing.
*
- * <p>This method will return a directory that's common to all tests run
- * within the same <i>build target</i>.
+ * <p>This method will return a directory that's common to all tests run within the same <i>build
+ * target</i>.
*
* @return standard file, for example the File representing "/tmp/zogjones/foo_unittest/".
*/
@@ -134,9 +147,8 @@
}
/**
- * Returns the value for system property <code>name</code>, or if that is
- * not found the value of the user's environment variable <code>name</code>.
- * If neither is found, null is returned.
+ * Returns the value for system property <code>name</code>, or if that is not found the value of
+ * the user's environment variable <code>name</code>. If neither is found, null is returned.
*
* @param name the name of property to get
* @return the value of the property or null if it is not found
@@ -148,5 +160,4 @@
}
return propValue;
}
-
}
diff --git a/intellij_test/src/com/google/idea/blaze/base/suite/TestAggregator.java b/intellij_test/src/com/google/idea/blaze/base/suite/TestAggregator.java
index af80f29..dbae268 100644
--- a/intellij_test/src/com/google/idea/blaze/base/suite/TestAggregator.java
+++ b/intellij_test/src/com/google/idea/blaze/base/suite/TestAggregator.java
@@ -27,5 +27,4 @@
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
-public @interface TestAggregator {
-}
+public @interface TestAggregator {}
diff --git a/intellij_test/src/com/google/idea/blaze/base/suite/TestAll.java b/intellij_test/src/com/google/idea/blaze/base/suite/TestAll.java
index fbd2a21..b40fafe 100644
--- a/intellij_test/src/com/google/idea/blaze/base/suite/TestAll.java
+++ b/intellij_test/src/com/google/idea/blaze/base/suite/TestAll.java
@@ -23,13 +23,6 @@
import com.intellij.testFramework.TestLoggerFactory;
import com.intellij.testFramework.TestRunnerUtil;
import com.intellij.util.ArrayUtil;
-
-import junit.framework.JUnit4TestAdapter;
-import junit.framework.Test;
-import junit.framework.TestCase;
-import junit.framework.TestResult;
-import junit.framework.TestSuite;
-
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
@@ -39,12 +32,14 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
-
import javax.annotation.Nullable;
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
-/**
- * A cut-down version of {@link com.intellij.TestAll} which supports test classes inside jars.
- */
+/** A cut-down version of {@link com.intellij.TestAll} which supports test classes inside jars. */
@TestAggregator
public class TestAll implements Test {
@@ -58,7 +53,8 @@
this(packageRoot, getClassRoots());
}
- public TestAll(String packageRoot, String... classRoots) throws IOException, ClassNotFoundException {
+ public TestAll(String packageRoot, String... classRoots)
+ throws IOException, ClassNotFoundException {
testCaseLoader = new TestCaseLoader("");
fillTestCases(testCaseLoader, packageRoot, classRoots);
}
@@ -66,7 +62,7 @@
public static String[] getClassRoots() {
final ClassLoader loader = TestAll.class.getClassLoader();
if (loader instanceof URLClassLoader) {
- return getClassRoots(((URLClassLoader)loader).getURLs());
+ return getClassRoots(((URLClassLoader) loader).getURLs());
}
final Class<? extends ClassLoader> loaderClass = loader.getClass();
if (loaderClass.getName().equals("com.intellij.util.lang.UrlClassLoader")) {
@@ -75,6 +71,7 @@
final List<URL> urls = (List<URL>) declaredMethod.invoke(loader);
return getClassRoots(urls.toArray(new URL[urls.size()]));
} catch (Throwable ignore) {
+ // Do nothing
}
}
return System.getProperty("java.class.path").split(File.pathSeparator);
@@ -82,16 +79,17 @@
private static String[] getClassRoots(URL[] urls) {
return Arrays.stream(urls)
- .map(VfsUtilCore::convertFromUrl)
- .map(VfsUtilCore::urlToPath)
- .toArray(String[]::new);
+ .map(VfsUtilCore::convertFromUrl)
+ .map(VfsUtilCore::urlToPath)
+ .toArray(String[]::new);
}
private static boolean isIntellijPlatformJar(String classRoot) {
return classRoot.contains("intellij-platform-sdk");
}
- public static void fillTestCases(TestCaseLoader testCaseLoader, String packageRoot, String... classRoots) throws IOException {
+ public static void fillTestCases(
+ TestCaseLoader testCaseLoader, String packageRoot, String... classRoots) throws IOException {
long before = System.currentTimeMillis();
for (String classRoot : classRoots) {
if (isIntellijPlatformJar(classRoot)) {
@@ -103,7 +101,8 @@
testCaseLoader.loadTestCases(classRootFile.getName(), classes);
int newCount = testCaseLoader.getClasses().size();
if (newCount != oldCount) {
- System.out.println("Loaded " + (newCount - oldCount) + " tests from class root " + classRoot);
+ System.out.println(
+ "Loaded " + (newCount - oldCount) + " tests from class root " + classRoot);
}
}
@@ -112,8 +111,12 @@
}
long after = System.currentTimeMillis();
- String message = "Number of test classes found: " + testCaseLoader.getClasses().size()
- + " time to load: " + (after - before) / 1000 + "s.";
+ String message =
+ "Number of test classes found: "
+ + testCaseLoader.getClasses().size()
+ + " time to load: "
+ + (after - before) / 1000
+ + "s.";
System.out.println(message);
log(message);
}
@@ -122,7 +125,7 @@
public int countTestCases() {
int count = 0;
for (Object aClass : testCaseLoader.getClasses()) {
- Test test = getTest((Class)aClass);
+ Test test = getTest((Class) aClass);
if (test != null) {
count += test.countTestCases();
}
@@ -175,30 +178,29 @@
}
final int[] testsCount = {0};
- TestSuite suite = new TestSuite(testCaseClass) {
- @Override
- public void addTest(Test test) {
- if (!(test instanceof TestCase)) {
- doAddTest(test);
- }
- else {
- String name = ((TestCase)test).getName();
- if ("warning".equals(name)) {
- return; // Mute TestSuite's "no tests found" warning
+ TestSuite suite =
+ new TestSuite(testCaseClass) {
+ @Override
+ public void addTest(Test test) {
+ if (!(test instanceof TestCase)) {
+ doAddTest(test);
+ } else {
+ String name = ((TestCase) test).getName();
+ if ("warning".equals(name)) {
+ return; // Mute TestSuite's "no tests found" warning
+ }
+ doAddTest(test);
+ }
}
- doAddTest(test);
- }
- }
- private void doAddTest(Test test) {
- testsCount[0]++;
- super.addTest(test);
- }
- };
+ private void doAddTest(Test test) {
+ testsCount[0]++;
+ super.addTest(test);
+ }
+ };
return testsCount[0] > 0 ? suite : null;
- }
- catch (Throwable t) {
+ } catch (Throwable t) {
System.err.println("Failed to load test: " + testCaseClass.getName());
t.printStackTrace(System.err);
return null;
@@ -209,8 +211,7 @@
private static Method safeFindMethod(Class<?> klass, String name) {
try {
return klass.getMethod(name);
- }
- catch (NoSuchMethodException e) {
+ } catch (NoSuchMethodException e) {
return null;
}
}
@@ -218,5 +219,4 @@
private static void log(String message) {
TeamCityLogger.info(message);
}
-
}
diff --git a/intellij_test/src/com/google/idea/blaze/base/suite/TestClassFinder.java b/intellij_test/src/com/google/idea/blaze/base/suite/TestClassFinder.java
index 8df1ed3..40633ed 100644
--- a/intellij_test/src/com/google/idea/blaze/base/suite/TestClassFinder.java
+++ b/intellij_test/src/com/google/idea/blaze/base/suite/TestClassFinder.java
@@ -18,7 +18,6 @@
import com.google.common.collect.Sets;
import com.intellij.ClassFinder;
import com.intellij.openapi.util.text.StringUtil;
-
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
@@ -26,18 +25,15 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-/**
- * Finds all valid test classes inside a given directory or jar.
- */
+/** Finds all valid test classes inside a given directory or jar. */
@TestAggregator
public class TestClassFinder {
private static final String CLASS_EXTENSION = ".class";
- /**
- * Returns all top-level test classes underneath the specified classpath and package roots.
- */
- public static SortedSet<String> findTestClasses(File classRootFile, String packageRoot) throws IOException {
+ /** Returns all top-level test classes underneath the specified classpath and package roots. */
+ public static SortedSet<String> findTestClasses(File classRootFile, String packageRoot)
+ throws IOException {
if (isJar(classRootFile.getPath())) {
return findTestClassesInJar(classRootFile, packageRoot);
}
@@ -45,7 +41,8 @@
return Sets.newTreeSet(finder.getClasses());
}
- private static SortedSet<String> findTestClassesInJar(File classPathRoot, String packageRoot) throws IOException {
+ private static SortedSet<String> findTestClassesInJar(File classPathRoot, String packageRoot)
+ throws IOException {
packageRoot = packageRoot.replace('.', File.separatorChar);
SortedSet<String> classNames = Sets.newTreeSet();
ZipFile zipFile = new ZipFile(classPathRoot.getPath());
@@ -55,7 +52,9 @@
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
String entryName = entries.nextElement().getName();
- if (entryName.endsWith(CLASS_EXTENSION) && isTopLevelClass(entryName) && entryName.startsWith(packageRoot)) {
+ if (entryName.endsWith(CLASS_EXTENSION)
+ && isTopLevelClass(entryName)
+ && entryName.startsWith(packageRoot)) {
classNames.add(getClassName(entryName));
}
}
@@ -70,9 +69,7 @@
return fileName.indexOf('$') < 0;
}
- /**
- * Given the absolute path of a class file, return the class name.
- */
+ /** Given the absolute path of a class file, return the class name. */
private static String getClassName(String className) {
return StringUtil.trimEnd(className, CLASS_EXTENSION).replace(File.separatorChar, '.');
}
diff --git a/intellij_test/src/com/google/idea/blaze/base/suite/TestSuiteBuilder.java b/intellij_test/src/com/google/idea/blaze/base/suite/TestSuiteBuilder.java
index 78c384c..9d918a1 100644
--- a/intellij_test/src/com/google/idea/blaze/base/suite/TestSuiteBuilder.java
+++ b/intellij_test/src/com/google/idea/blaze/base/suite/TestSuiteBuilder.java
@@ -17,11 +17,14 @@
import com.google.common.base.Strings;
import com.google.idea.blaze.base.BlazeTestSystemProperties;
-
import junit.framework.Test;
import junit.framework.TestSuite;
+import org.junit.runner.RunWith;
+import org.junit.runners.AllTests;
+/** Simple JUnit3 style test suite builder. */
@TestAggregator
+@RunWith(AllTests.class)
public class TestSuiteBuilder {
public static Test suite() throws Throwable {
@@ -34,5 +37,4 @@
suite.addTest(new TestAll(packageRoot));
return suite;
}
-
}
diff --git a/intellij_test/test_defs.bzl b/intellij_test/test_defs.bzl
index 72029a8..52205c4 100644
--- a/intellij_test/test_defs.bzl
+++ b/intellij_test/test_defs.bzl
@@ -1,55 +1,101 @@
-# Copyright 2016 The Bazel Authors. All rights reserved.
-#
-# 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.
-
"""Custom rule for creating IntelliJ plugin tests.
"""
-# The JVM flags common to all test rules
-JVM_FLAGS_FOR_TESTS = [
- "-Didea.classpath.index.enabled=false",
- "-Djava.awt.headless=true",
-]
+def intellij_unit_test_suite(name, srcs, test_package_root, **kwargs):
+ """Creates a java_test rule comprising all valid test classes in the specified srcs.
-def intellij_test(name,
- srcs,
- test_package_root,
- deps,
- platform_prefix="Idea",
- required_plugins=None,
- integration_tests=False):
- """Creates a java_test rule comprising all valid test classes
- in the specified srcs.
+ Args:
+ name: name of this rule.
+ srcs: the test classes.
+ test_package_root: only tests under this package root will be run.
+ **kwargs: Any other args to be passed to the java_test.
+ """
+ test_srcs = [test for test in srcs if test.endswith("Test.java")]
+ test_classes = [_get_test_class(test_src, test_package_root) for test_src in test_srcs]
+ suite_class_name = name + "TestSuite"
+ suite_class = test_package_root + "." + suite_class_name
+ _generate_test_suite(
+ name = suite_class_name,
+ test_package_root = test_package_root,
+ test_classes = test_classes,
+ )
+ native.java_test(
+ name = name,
+ srcs = srcs + [suite_class_name],
+ test_class = suite_class,
+ **kwargs)
+
+def _generate_test_suite(name, test_package_root, test_classes):
+ """Generates a JUnit test suite pulling in all the referenced classes."""
+ lines = []
+ lines.append("package %s;" % test_package_root)
+ lines.append("")
+ lines.append("import org.junit.runner.RunWith;")
+ lines.append("import org.junit.runners.Suite;")
+ lines.append("")
+ for test_class in test_classes:
+ lines.append("import %s;" % test_class)
+ lines.append("")
+ lines.append("@RunWith(Suite.class)")
+ lines.append("@Suite.SuiteClasses({")
+ for test_class in test_classes:
+ lines.append(" %s.class," % test_class.split(".")[-1])
+ lines.append("})")
+ lines.append("class %s {}" % name)
+
+ contents = "\\n".join(lines)
+ native.genrule(
+ name = name,
+ cmd = "printf '%s' > $@" % contents,
+ outs = [name + ".java"],
+ )
+
+
+def _get_test_class(test_src, test_package_root):
+ """Returns the test class of the source relative to the given root."""
+ temp = test_src[:-5]
+ temp = temp.replace("/", ".")
+ i = temp.rfind(test_package_root)
+ if i < 0:
+ fail("Test source '%s' not under package root '%s'" % (test_src, test_package_root))
+ test_class = temp[i:]
+ return test_class
+
+def intellij_integration_test_suite(
+ name,
+ srcs,
+ test_package_root,
+ deps,
+ runtime_deps = [],
+ platform_prefix="Idea",
+ required_plugins=None,
+ **kwargs):
+ """Creates a java_test rule comprising all valid test classes in the specified srcs.
Args:
name: name of this rule.
srcs: the test classes.
test_package_root: only tests under this package root will be run.
deps: the required deps.
- plugin_jar: a target building the plugin to be tested. This will be added to the classpath.
+ runtime_deps: the required runtime_deps.
platform_prefix: Specifies the JetBrains product these tests are run against. Examples are
'Idea' (IJ CE), 'idea' (IJ UE), 'CLion', 'AndroidStudio'. See
com.intellij.util.PlatformUtils for other options.
required_plugins: optional comma-separated list of plugin IDs. Integration tests will fail if
these plugins aren't loaded at runtime.
- integration_tests: if true, bundled IJ core plugins will be added to the classpath.
+ **kwargs: Any other args to be passed to the java_test.
"""
- if integration_tests:
- deps.append("//intellij-platform-sdk:bundled_plugins")
+ runtime_deps = list(runtime_deps)
+ runtime_deps.extend([
+ "//intellij_test:lib",
+ "//intellij_platform_sdk:bundled_plugins",
+ "//third_party:jdk8_tools",
+ ])
-
- jvm_flags = JVM_FLAGS_FOR_TESTS + [
+ jvm_flags = [
+ "-Didea.classpath.index.enabled=false",
+ "-Djava.awt.headless=true",
"-Didea.platform.prefix=" + platform_prefix,
"-Didea.test.package.root=" + test_package_root,
]
@@ -61,7 +107,8 @@
name = name,
srcs = srcs,
deps = deps,
- size = "medium" if integration_tests else "small",
+ runtime_deps = runtime_deps,
+ size = "medium",
jvm_flags = jvm_flags,
test_class = "com.google.idea.blaze.base.suite.TestSuiteBuilder",
- )
\ No newline at end of file
+ **kwargs)
diff --git a/java/BUILD b/java/BUILD
new file mode 100644
index 0000000..4ba94eb
--- /dev/null
+++ b/java/BUILD
@@ -0,0 +1,93 @@
+licenses(["notice"]) # Apache 2.0
+
+java_library(
+ name = "java",
+ srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//common/experiments",
+ "//intellij_platform_sdk:plugin_api",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+filegroup(
+ name = "plugin_xml",
+ srcs = ["src/META-INF/blaze-java.xml"],
+ visibility = ["//visibility:public"],
+)
+
+load(
+ "//build_defs:build_defs.bzl",
+ "merged_plugin_xml",
+ "stamped_plugin_xml",
+ "intellij_plugin",
+)
+
+merged_plugin_xml(
+ name = "merged_plugin_xml",
+ srcs = [
+ "//base:plugin_xml",
+ ] + [
+ ":plugin_xml",
+ ],
+)
+
+stamped_plugin_xml(
+ name = "java_plugin_xml",
+ plugin_id = "com.google.idea.blaze.java",
+ plugin_name = "com.google.idea.blaze.java",
+ plugin_xml = "merged_plugin_xml",
+)
+
+intellij_plugin(
+ name = "java_integration_test_plugin",
+ testonly = 1,
+ plugin_xml = ":java_plugin_xml",
+ deps = [
+ ":java",
+ ],
+)
+
+load(
+ "//intellij_test:test_defs.bzl",
+ "intellij_integration_test_suite",
+ "intellij_unit_test_suite",
+)
+
+intellij_unit_test_suite(
+ name = "unit_tests",
+ srcs = glob(["tests/unittests/**/*.java"]),
+ test_package_root = "com.google.idea.blaze.java",
+ deps = [
+ ":java",
+ "//base",
+ "//base:unit_test_utils",
+ "//common/experiments",
+ "//common/experiments:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//proto_deps",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
+
+intellij_integration_test_suite(
+ name = "integration_tests",
+ srcs = glob(["tests/integrationtests/**/*.java"]),
+ required_plugins = "com.google.idea.blaze.java",
+ test_package_root = "com.google.idea.blaze.java",
+ runtime_deps = [
+ ":java_integration_test_plugin",
+ ],
+ deps = [
+ ":java",
+ "//base",
+ "//base:integration_test_utils",
+ "//base:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@jsr305_annotations//jar",
+ ],
+)
diff --git a/java/src/META-INF/blaze-java.xml b/java/src/META-INF/blaze-java.xml
new file mode 100644
index 0000000..321e5e4
--- /dev/null
+++ b/java/src/META-INF/blaze-java.xml
@@ -0,0 +1,96 @@
+<!--
+ ~ Copyright 2016 The Bazel Authors. All rights reserved.
+ ~
+ ~ 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.
+ -->
+<idea-plugin>
+ <depends>com.intellij.modules.java</depends>
+ <depends>JUnit</depends>
+
+ <actions>
+ <action class="com.google.idea.blaze.java.libraries.ExcludeLibraryAction"
+ id="Blaze.ExcludeLibraryAction"
+ icon="BlazeIcons.Blaze"
+ text="Exclude Library and Resync">
+ <add-to-group group-id="Blaze.ProjectViewPopupMenu"/>
+ </action>
+ <action class="com.google.idea.blaze.java.libraries.AttachSourceJarAction"
+ id="Blaze.AttachSourceJarAction"
+ icon="BlazeIcons.Blaze"
+ text="Attach Source Jar">
+ <add-to-group group-id="Blaze.ProjectViewPopupMenu"/>
+ </action>
+ <action class="com.google.idea.blaze.java.libraries.AddLibraryRuleDirectoryToProjectViewAction"
+ id="Blaze.AddLibraryRuleDirectoryToProjectView"
+ icon="BlazeIcons.Blaze"
+ text="Add Library Rule Directory To Project View">
+ <add-to-group group-id="Blaze.ProjectViewPopupMenu"/>
+ </action>
+
+ <!-- IntelliJ specific actions -->
+
+ <action id="Blaze.ImportProject2" class="com.google.idea.blaze.java.wizard2.BlazeImportProjectAction" icon="BlazeIcons.Blaze">
+ <add-to-group group-id="WelcomeScreen.QuickStart" />
+ <add-to-group group-id="OpenProjectGroup" relative-to-action="ImportProject" anchor="after"/>
+ </action>
+
+ <!-- End IntelliJ specific actions -->
+
+ </actions>
+
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncPlugin implementation="com.google.idea.blaze.java.sync.BlazeJavaSyncPlugin"/>
+ <PsiFileProvider implementation="com.google.idea.blaze.java.psi.JavaPsiFileProvider" />
+ <BlazeCommandRunConfigurationHandlerProvider implementation="com.google.idea.blaze.java.run.BlazeJavaRunConfigurationHandlerProvider"/>
+ <RuleConfigurationFactory implementation="com.google.idea.blaze.java.run.BlazeJavaRuleConfigurationFactory"/>
+ <RuleConfigurationFactory implementation="com.google.idea.blaze.java.run.BlazeJavaTestRuleConfigurationFactory"/>
+ <BlazeUserSettingsContributor implementation="com.google.idea.blaze.java.settings.BlazeJavaUserSettingsContributor$BlazeJavaUserSettingsProvider"/>
+ <FileCache implementation="com.google.idea.blaze.java.libraries.JarCache$FileCacheAdapter"/>
+ <PrefetchFileSource implementation="com.google.idea.blaze.java.sync.JavaPrefetchFileSource"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.java.run.producers.BlazeJavaMainClassRunConfigurationProducer"
+ order="first"/>
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.java.run.producers.BlazeJavaTestClassConfigurationProducer"
+ order="first"/>
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.java.run.producers.BlazeJavaTestMethodConfigurationProducer"
+ order="first"/>
+ <projectViewNodeDecorator implementation="com.google.idea.blaze.java.syncstatus.BlazeJavaSyncStatusClassNodeDecorator"/>
+ <editorTabColorProvider implementation="com.google.idea.blaze.java.syncstatus.BlazeJavaSyncStatusEditorTabColorProvider"/>
+ <editorTabTitleProvider implementation="com.google.idea.blaze.java.syncstatus.BlazeJavaSyncStatusEditorTabTitleProvider"/>
+ <applicationService serviceInterface="com.google.idea.blaze.java.sync.source.JavaSourcePackageReader"
+ serviceImplementation="com.google.idea.blaze.java.sync.source.JavaSourcePackageReader"/>
+ <applicationService serviceInterface="com.google.idea.blaze.java.sync.source.PackageManifestReader"
+ serviceImplementation="com.google.idea.blaze.java.sync.source.PackageManifestReader"/>
+ <programRunner implementation="com.google.idea.blaze.java.run.BlazeJavaDebuggerRunner"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.ui.BlazeProblemsView"
+ serviceImplementation="com.google.idea.blaze.java.ui.BlazeIntelliJProblemsView"/>
+ <projectService serviceImplementation="com.google.idea.blaze.java.libraries.SourceJarManager"/>
+ <refactoring.safeDeleteProcessor id="build_file_safe_delete" order="before javaProcessor"
+ implementation="com.google.idea.blaze.java.lang.build.BuildFileSafeDeleteProcessor"/>
+ <projectService serviceImplementation="com.google.idea.blaze.java.libraries.JarCache"/>
+
+ <attachSourcesProvider implementation="com.google.idea.blaze.java.libraries.AddLibraryRuleDirectoryToProjectViewAttachSourcesProvider"/>
+ <attachSourcesProvider implementation="com.google.idea.blaze.java.libraries.BlazeAttachSourceProvider"/>
+ <applicationService serviceImplementation="com.google.idea.blaze.java.settings.BlazeJavaUserSettings"/>
+ </extensions>
+
+ <extensionPoints>
+ <extensionPoint qualifiedName="com.google.idea.blaze.java.JavaSyncAugmenter"
+ interface="com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter"/>
+ </extensionPoints>
+</idea-plugin>
diff --git a/java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java b/java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java
new file mode 100644
index 0000000..390ce7b
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.lang.build;
+
+import com.google.idea.blaze.base.lang.buildfile.references.GlobReference;
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
+import com.google.idea.blaze.base.lang.buildfile.search.ResolveUtil;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor;
+import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo;
+import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteUsageInfo;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.util.IncorrectOperationException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Removes glob references which don't refer directly to the item(s) being deleted (b/28979434)
+ * (e.g. indirect references from glob([*.java])).
+ *
+ * <p>Runs before JavaSafeDeleteProcessor, and delegates to it, removing indirect glob references.
+ * Only the first valid SafeDeleteProcessorDelegate is used in almost all cases*, so this class
+ * effectively replaces JavaSafeDeleteProcessor (*in the situations where all processors are used,
+ * this class has no effect).
+ */
+public class BuildFileSafeDeleteProcessor extends JavaSafeDeleteProcessor {
+
+ /**
+ * Delegates to JavaSafeDeleteProcessor, then removes indirect glob references which we don't want
+ * to block safe delete.
+ */
+ @Nullable
+ @Override
+ public NonCodeUsageSearchInfo findUsages(
+ @NotNull PsiElement element,
+ @NotNull PsiElement[] allElementsToDelete,
+ @NotNull List<UsageInfo> result) {
+ NonCodeUsageSearchInfo superResult = super.findUsages(element, allElementsToDelete, result);
+ Iterator<UsageInfo> iter = result.iterator();
+ while (iter.hasNext()) {
+ if (ignoreUsage(iter.next())) {
+ iter.remove();
+ }
+ }
+ return superResult;
+ }
+
+ /**
+ * We keep globs which reference the file directly (i.e. without wildcards), and remove all
+ * indirect references for the purposes of the 'safe delete' action.
+ */
+ private static boolean ignoreUsage(UsageInfo usage) {
+ if (usage.getReference() instanceof GlobReference && usage instanceof SafeDeleteUsageInfo) {
+ PsiElement referencedElement = ((SafeDeleteUsageInfo) usage).getReferencedElement();
+ PsiFileSystemItem file = ResolveUtil.asFileSystemItemSearch(referencedElement);
+ String relativePath = getBlazePackageRelativePathToFile(file);
+ if (relativePath == null) {
+ return false;
+ }
+ return !((GlobReference) usage.getReference())
+ .matchesDirectly(relativePath, file.isDirectory());
+ }
+ return false;
+ }
+
+ @Nullable
+ private static String getBlazePackageRelativePathToFile(@Nullable PsiFileSystemItem file) {
+ if (file == null) {
+ return null;
+ }
+ BlazePackage containingPackage = BlazePackage.getContainingPackage(file);
+ if (containingPackage == null) {
+ return null;
+ }
+ return containingPackage.getRelativePathToChild(file.getVirtualFile());
+ }
+
+ @Override
+ public boolean handlesElement(PsiElement element) {
+ return super.handlesElement(element);
+ }
+
+ @Nullable
+ @Override
+ public Collection<? extends PsiElement> getElementsToSearch(
+ @NotNull PsiElement element,
+ @Nullable Module module,
+ @NotNull Collection<PsiElement> allElementsToDelete) {
+ return super.getElementsToSearch(element, module, allElementsToDelete);
+ }
+
+ @Nullable
+ @Override
+ public Collection<PsiElement> getAdditionalElementsToDelete(
+ @NotNull PsiElement element,
+ @NotNull Collection<PsiElement> allElementsToDelete,
+ boolean askUser) {
+ return super.getAdditionalElementsToDelete(element, allElementsToDelete, askUser);
+ }
+
+ @Nullable
+ @Override
+ public Collection<String> findConflicts(
+ @NotNull PsiElement element, @NotNull PsiElement[] allElementsToDelete) {
+ return super.findConflicts(element, allElementsToDelete);
+ }
+
+ @Nullable
+ @Override
+ public UsageInfo[] preprocessUsages(Project project, UsageInfo[] usages) {
+ return usages;
+ }
+
+ @Override
+ public void prepareForDeletion(PsiElement element) throws IncorrectOperationException {}
+
+ @Override
+ public boolean isToSearchInComments(PsiElement element) {
+ return super.isToSearchInComments(element);
+ }
+
+ @Override
+ public void setToSearchInComments(PsiElement element, boolean enabled) {
+ super.setToSearchInComments(element, enabled);
+ }
+
+ @Override
+ public boolean isToSearchForTextOccurrences(PsiElement element) {
+ return super.isToSearchForTextOccurrences(element);
+ }
+
+ @Override
+ public void setToSearchForTextOccurrences(PsiElement element, boolean enabled) {
+ super.setToSearchForTextOccurrences(element, enabled);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/AddLibraryRuleDirectoryToProjectViewAction.java b/java/src/com/google/idea/blaze/java/libraries/AddLibraryRuleDirectoryToProjectViewAction.java
new file mode 100644
index 0000000..ac34691
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/AddLibraryRuleDirectoryToProjectViewAction.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.projectview.ProjectViewEdit;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.io.FileUtil;
+import java.io.File;
+import java.util.List;
+import java.util.Set;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class AddLibraryRuleDirectoryToProjectViewAction extends BlazeAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ assert project != null;
+ Library library = LibraryActionHelper.findLibraryForAction(e);
+ if (library != null) {
+ addDirectoriesToProjectView(project, ImmutableList.of(library));
+ }
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ boolean visible = false;
+ boolean enabled = false;
+ Project project = e.getProject();
+ if (project != null) {
+ Library library = LibraryActionHelper.findLibraryForAction(e);
+ if (library != null) {
+ visible = true;
+ if (getDirectoryToAddForLibrary(project, library) != null) {
+ enabled = true;
+ }
+ }
+ }
+ presentation.setVisible(visible);
+ presentation.setEnabled(enabled);
+ }
+
+ @Nullable
+ static WorkspacePath getDirectoryToAddForLibrary(Project project, Library library) {
+ BlazeJarLibrary blazeLibrary =
+ LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
+ if (blazeLibrary == null) {
+ return null;
+ }
+ Label originatingRule = blazeLibrary.originatingRule;
+ if (originatingRule == null) {
+ return null;
+ }
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return null;
+ }
+ RuleIdeInfo rule = blazeProjectData.ruleMap.get(originatingRule);
+ if (rule == null) {
+ return null;
+ }
+ // To start with, we whitelist only library rules
+ // It makes no sense to add directories for java_imports and the like
+ if (!rule.kind.isOneOf(Kind.JAVA_LIBRARY, Kind.ANDROID_LIBRARY)) {
+ return null;
+ }
+ if (rule.buildFile == null) {
+ return null;
+ }
+ File buildFile = new File(rule.buildFile.getRelativePath());
+ WorkspacePath workspacePath = new WorkspacePath(buildFile.getParent());
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return null;
+ }
+ boolean exists =
+ projectViewSet
+ .listItems(DirectorySection.KEY)
+ .stream()
+ .anyMatch(
+ entry ->
+ FileUtil.isAncestor(
+ entry.directory.relativePath(), workspacePath.relativePath(), false));
+ if (exists) {
+ return null;
+ }
+ return workspacePath;
+ }
+
+ static void addDirectoriesToProjectView(Project project, List<Library> libraries) {
+ Set<WorkspacePath> workspacePaths = Sets.newHashSet();
+ for (Library library : libraries) {
+ WorkspacePath workspacePath = getDirectoryToAddForLibrary(project, library);
+ if (workspacePath != null) {
+ workspacePaths.add(workspacePath);
+ }
+ }
+ ProjectViewEdit edit =
+ ProjectViewEdit.editLocalProjectView(
+ project,
+ builder -> {
+ ListSection<DirectoryEntry> existingSection = builder.getLast(DirectorySection.KEY);
+ ListSection.Builder<DirectoryEntry> directoryBuilder =
+ ListSection.update(DirectorySection.KEY, existingSection);
+ for (WorkspacePath workspacePath : workspacePaths) {
+ directoryBuilder.add(new DirectoryEntry(workspacePath, true));
+ }
+ builder.replace(existingSection, directoryBuilder);
+ return true;
+ });
+ if (edit == null) {
+ Messages.showErrorDialog(
+ "Could not modify project view. Check for errors in your project view and try again",
+ "Error");
+ return;
+ }
+ edit.apply();
+ BlazeSyncManager.getInstance(project)
+ .requestProjectSync(
+ new BlazeSyncParams.Builder("Adding Library", BlazeSyncParams.SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build());
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/AddLibraryRuleDirectoryToProjectViewAttachSourcesProvider.java b/java/src/com/google/idea/blaze/java/libraries/AddLibraryRuleDirectoryToProjectViewAttachSourcesProvider.java
new file mode 100644
index 0000000..03aaf3b
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/AddLibraryRuleDirectoryToProjectViewAttachSourcesProvider.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.codeInsight.AttachSourcesProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.LibraryOrderEntry;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.util.ActionCallback;
+import com.intellij.psi.PsiFile;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** @author Sergey Evdokimov */
+public class AddLibraryRuleDirectoryToProjectViewAttachSourcesProvider
+ implements AttachSourcesProvider {
+
+ @NotNull
+ @Override
+ public Collection<AttachSourcesAction> getActions(
+ List<LibraryOrderEntry> orderEntries, final PsiFile psiFile) {
+ Project project = psiFile.getProject();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return ImmutableList.of();
+ }
+
+ List<Library> librariesToAttachSourceTo = Lists.newArrayList();
+ for (LibraryOrderEntry orderEntry : orderEntries) {
+ Library library = orderEntry.getLibrary();
+ WorkspacePath workspacePath =
+ AddLibraryRuleDirectoryToProjectViewAction.getDirectoryToAddForLibrary(project, library);
+ if (workspacePath == null) {
+ continue;
+ }
+ librariesToAttachSourceTo.add(library);
+ }
+
+ if (librariesToAttachSourceTo.isEmpty()) {
+ return ImmutableList.of();
+ }
+
+ return ImmutableList.of(
+ new AttachSourcesAction() {
+ @Override
+ public String getName() {
+ return "Add Source Directories To Project View";
+ }
+
+ @Override
+ public String getBusyText() {
+ return "Adding directories...";
+ }
+
+ @Override
+ public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
+ AddLibraryRuleDirectoryToProjectViewAction.addDirectoriesToProjectView(
+ project, librariesToAttachSourceTo);
+ return ActionCallback.DONE;
+ }
+ });
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/AttachSourceJarAction.java b/java/src/com/google/idea/blaze/java/libraries/AttachSourceJarAction.java
new file mode 100644
index 0000000..ca216ac
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/AttachSourceJarAction.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.projectstructure.LibraryEditor;
+import com.intellij.CommonBundle;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.ui.Messages;
+import org.jetbrains.annotations.NotNull;
+
+class AttachSourceJarAction extends BlazeAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ assert project != null;
+ Library library = LibraryActionHelper.findLibraryForAction(e);
+ if (library != null) {
+ BlazeJarLibrary blazeLibrary =
+ LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
+ if (blazeLibrary == null) {
+ Messages.showErrorDialog(
+ project, "Could not find this library in the project.", CommonBundle.getErrorTitle());
+ return;
+ }
+
+ final LibraryArtifact libraryArtifact = blazeLibrary.libraryArtifact;
+ if (libraryArtifact.sourceJar == null) {
+ return;
+ }
+ SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
+ boolean attachSourceJar = !sourceJarManager.hasSourceJarAttached(blazeLibrary.key);
+ sourceJarManager.setHasSourceJarAttached(blazeLibrary.key, attachSourceJar);
+
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
+ LibraryTable.ModifiableModel libraryTableModel = libraryTable.getModifiableModel();
+ LibraryEditor.updateLibrary(project, libraryTable, libraryTableModel, blazeLibrary);
+ libraryTableModel.commit();
+ });
+ }
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ String text = "Attach Source Jar";
+ boolean visible = false;
+ boolean enabled = false;
+ Project project = e.getProject();
+ if (project != null) {
+ Library library = LibraryActionHelper.findLibraryForAction(e);
+ if (library != null) {
+ visible = true;
+
+ BlazeJarLibrary blazeLibrary =
+ LibraryActionHelper.findLibraryFromIntellijLibrary(e.getProject(), library);
+ if (blazeLibrary != null && blazeLibrary.libraryArtifact.sourceJar != null) {
+ enabled = true;
+ if (SourceJarManager.getInstance(project).hasSourceJarAttached(blazeLibrary.key)) {
+ text = "Detach Source Jar";
+ }
+ }
+ }
+ }
+ presentation.setVisible(visible);
+ presentation.setEnabled(enabled);
+ presentation.setText(text);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/BlazeAttachSourceProvider.java b/java/src/com/google/idea/blaze/java/libraries/BlazeAttachSourceProvider.java
new file mode 100644
index 0000000..b70ba2f
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/BlazeAttachSourceProvider.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.settings.BlazeJavaUserSettings;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.google.idea.blaze.java.sync.projectstructure.LibraryEditor;
+import com.intellij.codeInsight.AttachSourcesProvider;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.LibraryOrderEntry;
+import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.util.ActionCallback;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.ui.UIUtil;
+import java.util.Collection;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** @author Sergey Evdokimov */
+public class BlazeAttachSourceProvider implements AttachSourcesProvider {
+ private static final Logger LOG = Logger.getInstance(BlazeAttachSourceProvider.class);
+
+ @NotNull
+ @Override
+ public Collection<AttachSourcesAction> getActions(
+ List<LibraryOrderEntry> orderEntries, final PsiFile psiFile) {
+ Project project = psiFile.getProject();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return ImmutableList.of();
+ }
+
+ List<BlazeLibrary> librariesToAttachSourceTo = Lists.newArrayList();
+ for (LibraryOrderEntry orderEntry : orderEntries) {
+ Library library = orderEntry.getLibrary();
+ if (library == null) {
+ continue;
+ }
+ LibraryKey libraryKey = LibraryKey.fromIntelliJLibrary(library);
+ if (SourceJarManager.getInstance(project).hasSourceJarAttached(libraryKey)) {
+ continue;
+ }
+ BlazeJarLibrary blazeLibrary =
+ LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
+ if (blazeLibrary == null) {
+ continue;
+ }
+ LibraryArtifact libraryArtifact = blazeLibrary.libraryArtifact;
+ ArtifactLocation artifactLocation = libraryArtifact.sourceJar;
+ if (artifactLocation == null) {
+ continue;
+ }
+ librariesToAttachSourceTo.add(blazeLibrary);
+ }
+
+ if (librariesToAttachSourceTo.isEmpty()) {
+ return ImmutableList.of();
+ }
+
+ /**
+ * Semi-hack: When sources are requested and we have them, we attach them automatically if the
+ * corresponding user setting is active.
+ */
+ if (BlazeJavaUserSettings.getInstance().getAttachSourcesOnDemand()) {
+ UIUtil.invokeLaterIfNeeded(
+ () -> {
+ attachSources(project, librariesToAttachSourceTo);
+ });
+ return ImmutableList.of();
+ }
+
+ return ImmutableList.of(
+ new AttachSourcesAction() {
+ @Override
+ public String getName() {
+ return "Attach Blaze Source Jars";
+ }
+
+ @Override
+ public String getBusyText() {
+ return "Attaching source jars...";
+ }
+
+ @Override
+ public ActionCallback perform(List<LibraryOrderEntry> orderEntriesContainingFile) {
+ attachSources(project, librariesToAttachSourceTo);
+ return ActionCallback.DONE;
+ }
+ });
+ }
+
+ static void attachSources(Project project, Collection<BlazeLibrary> librariesToAttachSourceTo) {
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
+ LibraryTable.ModifiableModel libraryTableModel = libraryTable.getModifiableModel();
+ for (BlazeLibrary blazeLibrary : librariesToAttachSourceTo) {
+ // Make sure we don't do it twice
+ if (SourceJarManager.getInstance(project).hasSourceJarAttached(blazeLibrary.key)) {
+ continue;
+ }
+ SourceJarManager.getInstance(project)
+ .setHasSourceJarAttached(blazeLibrary.key, true);
+ LibraryEditor.updateLibrary(project, libraryTable, libraryTableModel, blazeLibrary);
+ }
+ libraryTableModel.commit();
+ });
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/ExcludeLibraryAction.java b/java/src/com/google/idea/blaze/java/libraries/ExcludeLibraryAction.java
new file mode 100644
index 0000000..8d2776e
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/ExcludeLibraryAction.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.idea.blaze.base.actions.BlazeAction;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.projectview.ProjectViewEdit;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.java.projectview.ExcludeLibrarySection;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.intellij.CommonBundle;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.ui.Messages;
+import org.jetbrains.annotations.NotNull;
+
+class ExcludeLibraryAction extends BlazeAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ Project project = e.getProject();
+ assert project != null;
+ Library library = LibraryActionHelper.findLibraryForAction(e);
+ if (library != null) {
+ BlazeJarLibrary blazeLibrary =
+ LibraryActionHelper.findLibraryFromIntellijLibrary(project, library);
+ if (blazeLibrary == null) {
+ Messages.showErrorDialog(
+ project, "Could not find this library in the project.", CommonBundle.getErrorTitle());
+ return;
+ }
+
+ final LibraryArtifact libraryArtifact = blazeLibrary.libraryArtifact;
+ final String path = libraryArtifact.jarForIntellijLibrary().getRelativePath();
+
+ ProjectViewEdit edit =
+ ProjectViewEdit.editLocalProjectView(
+ project,
+ builder -> {
+ ListSection<Glob> existingSection = builder.getLast(ExcludeLibrarySection.KEY);
+ builder.replace(
+ existingSection,
+ ListSection.update(ExcludeLibrarySection.KEY, existingSection)
+ .add(new Glob(path)));
+ return true;
+ });
+ if (edit == null) {
+ Messages.showErrorDialog(
+ "Could not modify project view. Check for errors in your project view and try again",
+ "Error");
+ return;
+ }
+ edit.apply();
+
+ BlazeSyncManager.getInstance(project)
+ .requestProjectSync(
+ new BlazeSyncParams.Builder("Sync", BlazeSyncParams.SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .addWorkingSet(BlazeUserSettings.getInstance().getExpandSyncToWorkingSet())
+ .build());
+ }
+ }
+
+ @Override
+ protected void doUpdate(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ boolean enabled = LibraryActionHelper.findLibraryForAction(e) != null;
+ presentation.setVisible(enabled);
+ presentation.setEnabled(enabled);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/JarCache.java b/java/src/com/google/idea/blaze/java/libraries/JarCache.java
new file mode 100644
index 0000000..33b5cad
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/JarCache.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.filecache.FileCache;
+import com.google.idea.blaze.base.filecache.FileDiffer;
+import com.google.idea.blaze.base.io.FileSizeScanner;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.prefetch.FetchExecutor;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.google.idea.blaze.java.settings.BlazeJavaUserSettings;
+import com.google.idea.blaze.java.sync.BlazeLibraryCollector;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** Local cache of the jars referenced by the project. */
+public class JarCache {
+ private static final Logger LOG = Logger.getInstance(JarCache.class);
+ public static final BoolExperiment ENABLE_JAR_CACHE =
+ new BoolExperiment("enable.jar.cache", true);
+
+ private final Project project;
+ private final BlazeImportSettings importSettings;
+ private final File cacheDir;
+ private boolean enabled;
+ @Nullable private BiMap<File, String> sourceFileToCacheKey = null;
+
+ public static JarCache getInstance(Project project) {
+ return ServiceManager.getService(project, JarCache.class);
+ }
+
+ public JarCache(Project project) {
+ this.project = project;
+ this.importSettings = BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ this.cacheDir = getCacheDir();
+ }
+
+ public void onSync(
+ BlazeContext context, BlazeProjectData projectData, BlazeSyncParams.SyncMode syncMode) {
+ Collection<BlazeLibrary> libraries = BlazeLibraryCollector.getLibraries(projectData);
+ boolean fullRefresh = syncMode == BlazeSyncParams.SyncMode.FULL;
+ boolean enabled = updateEnabled();
+
+ if (!enabled || fullRefresh) {
+ clearCache();
+ }
+ if (!enabled) {
+ return;
+ }
+
+ boolean attachAllSourceJars = BlazeJavaUserSettings.getInstance().getAttachSourcesByDefault();
+ SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
+
+ List<BlazeJarLibrary> jarLibraries =
+ libraries
+ .stream()
+ .filter(library -> library instanceof BlazeJarLibrary)
+ .map(library -> (BlazeJarLibrary) library)
+ .collect(Collectors.toList());
+
+ BiMap<File, String> sourceFileToCacheKey = HashBiMap.create(jarLibraries.size());
+ for (BlazeJarLibrary library : jarLibraries) {
+ File jarFile = library.libraryArtifact.jarForIntellijLibrary().getFile();
+ sourceFileToCacheKey.put(jarFile, cacheKeyForJar(jarFile));
+
+ boolean attachSourceJar =
+ attachAllSourceJars || sourceJarManager.hasSourceJarAttached(library.key);
+ if (attachSourceJar && library.libraryArtifact.sourceJar != null) {
+ File srcJarFile = library.libraryArtifact.sourceJar.getFile();
+ sourceFileToCacheKey.put(srcJarFile, cacheKeyForSourceJar(srcJarFile));
+ }
+ }
+
+ this.sourceFileToCacheKey = sourceFileToCacheKey;
+ refresh(context, true);
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ private boolean updateEnabled() {
+ this.enabled =
+ BlazeJavaUserSettings.getInstance().getUseJarCache()
+ && ENABLE_JAR_CACHE.getValue()
+ && !ApplicationManager.getApplication().isUnitTestMode();
+ return enabled;
+ }
+
+ /** Refreshes any updated files in the cache. Does not add or removes any files */
+ public void refresh() {
+ refresh(null, false);
+ }
+
+ private void refresh(@Nullable BlazeContext context, boolean removeMissingFiles) {
+ if (!enabled || sourceFileToCacheKey == null) {
+ return;
+ }
+
+ // Ensure the cache dir exists
+ if (!cacheDir.exists()) {
+ if (!cacheDir.mkdirs()) {
+ LOG.error("Could not create jar cache directory");
+ return;
+ }
+ }
+
+ // Discover state of source jars
+ ImmutableMap<File, Long> sourceFileTimestamps =
+ FileDiffer.readFileState(sourceFileToCacheKey.keySet());
+ if (sourceFileTimestamps == null) {
+ return;
+ }
+ ImmutableMap.Builder<String, Long> sourceFileCacheKeyToTimestamp = ImmutableMap.builder();
+ for (Map.Entry<File, Long> entry : sourceFileTimestamps.entrySet()) {
+ String cacheKey = sourceFileToCacheKey.get(entry.getKey());
+ sourceFileCacheKeyToTimestamp.put(cacheKey, entry.getValue());
+ }
+
+ // Discover current on-disk cache state
+ File[] cacheFiles = cacheDir.listFiles();
+ assert cacheFiles != null;
+ ImmutableMap<File, Long> cacheFileTimestamps =
+ FileDiffer.readFileState(Lists.newArrayList(cacheFiles));
+ if (cacheFileTimestamps == null) {
+ return;
+ }
+ ImmutableMap.Builder<String, Long> cachedFileCacheKeyToTimestamp = ImmutableMap.builder();
+ for (Map.Entry<File, Long> entry : cacheFileTimestamps.entrySet()) {
+ String cacheKey = entry.getKey().getName(); // Cache key == file name
+ cachedFileCacheKeyToTimestamp.put(cacheKey, entry.getValue());
+ }
+
+ List<String> updatedFiles = Lists.newArrayList();
+ List<String> removedFiles = Lists.newArrayList();
+ FileDiffer.diffState(
+ cachedFileCacheKeyToTimestamp.build(),
+ sourceFileCacheKeyToTimestamp.build(),
+ updatedFiles,
+ removedFiles);
+
+ ListeningExecutorService executor = FetchExecutor.EXECUTOR;
+ List<ListenableFuture<?>> futures = Lists.newArrayList();
+ Map<String, File> cacheKeyToSourceFile = sourceFileToCacheKey.inverse();
+ for (String cacheKey : updatedFiles) {
+ File sourceFile = cacheKeyToSourceFile.get(cacheKey);
+ File cacheFile = cacheFileForKey(cacheKey);
+ futures.add(
+ executor.submit(
+ () -> {
+ try {
+ Files.copy(
+ Paths.get(sourceFile.getPath()),
+ Paths.get(cacheFile.getPath()),
+ StandardCopyOption.REPLACE_EXISTING,
+ StandardCopyOption.COPY_ATTRIBUTES);
+ } catch (IOException e) {
+ LOG.warn(e);
+ }
+ }));
+ }
+
+ if (removeMissingFiles) {
+ for (String cacheKey : removedFiles) {
+ File cacheFile = cacheFileForKey(cacheKey);
+ futures.add(
+ executor.submit(
+ () -> {
+ try {
+ Files.deleteIfExists(Paths.get(cacheFile.getPath()));
+ } catch (IOException e) {
+ LOG.warn(e);
+ }
+ }));
+ }
+ }
+
+ try {
+ Futures.allAsList(futures).get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ LOG.warn(e);
+ } catch (ExecutionException e) {
+ LOG.error(e);
+ }
+ if (context != null && updatedFiles.size() > 0) {
+ context.output(PrintOutput.log(String.format("Copied %d jars", updatedFiles.size())));
+ }
+ if (context != null && removedFiles.size() > 0 && removeMissingFiles) {
+ context.output(PrintOutput.log(String.format("Removed %d jars", removedFiles.size())));
+ }
+ if (context != null) {
+ try {
+ File[] finalCacheFiles = cacheDir.listFiles();
+ assert finalCacheFiles != null;
+ ImmutableMap<File, Long> cacheFileSizes =
+ FileSizeScanner.readFilesizes(Lists.newArrayList(finalCacheFiles));
+ Long total =
+ cacheFileSizes.values().stream().reduce((size1, size2) -> size1 + size2).orElse(0L);
+ context.output(
+ PrintOutput.log(
+ String.format(
+ "Total Jar Cache size: %d kB (%d files)",
+ total / 1024, finalCacheFiles.length)));
+ } catch (Exception e) {
+ LOG.warn("Could not determine cache size", e);
+ }
+ }
+ }
+
+ private void clearCache() {
+ if (cacheDir.exists()) {
+ File[] cacheFiles = cacheDir.listFiles();
+ if (cacheFiles != null) {
+ FileUtil.asyncDelete(Lists.newArrayList(cacheFiles));
+ }
+ }
+ sourceFileToCacheKey = null;
+ }
+
+ /** Gets the cached file for a jar. If it doesn't exist, we return the file from the library. */
+ public File getCachedJar(BlazeJarLibrary library) {
+ File file = library.libraryArtifact.jarForIntellijLibrary().getFile();
+ if (!enabled || sourceFileToCacheKey == null) {
+ return file;
+ }
+ String cacheKey = sourceFileToCacheKey.get(file);
+ if (cacheKey == null) {
+ return file;
+ }
+ return cacheFileForKey(cacheKey);
+ }
+
+ /** Gets the cached file for a source jar. */
+ @Nullable
+ public File getCachedSourceJar(BlazeJarLibrary library) {
+ if (library.libraryArtifact.sourceJar == null) {
+ return null;
+ }
+ File file = library.libraryArtifact.sourceJar.getFile();
+ if (!enabled || sourceFileToCacheKey == null) {
+ return file;
+ }
+ String cacheKey = sourceFileToCacheKey.get(file);
+ if (cacheKey == null) {
+ return file;
+ }
+ return cacheFileForKey(cacheKey);
+ }
+
+ private static String cacheKeyInternal(File jar) {
+ int parentHash = jar.getParent().hashCode();
+ return FileUtil.getNameWithoutExtension(jar) + "_" + Integer.toHexString(parentHash);
+ }
+
+ private static String cacheKeyForJar(File jar) {
+ return cacheKeyInternal(jar) + ".jar";
+ }
+
+ private static String cacheKeyForSourceJar(File srcjar) {
+ return cacheKeyInternal(srcjar) + "-src.jar";
+ }
+
+ private File cacheFileForKey(String key) {
+ return new File(cacheDir, key);
+ }
+
+ private File getCacheDir() {
+ return new File(BlazeDataStorage.getProjectDataDir(importSettings), "libraries");
+ }
+
+ static class FileCacheAdapter implements FileCache {
+ @Override
+ public String getName() {
+ return "Jar Cache";
+ }
+
+ @Override
+ public void onSync(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData projectData,
+ BlazeSyncParams.SyncMode syncMode) {
+ getInstance(project).onSync(context, projectData, syncMode);
+ }
+
+ @Override
+ public void refreshFiles(Project project) {
+ getInstance(project).refresh();
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java b/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
new file mode 100644
index 0000000..3b3132c
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.intellij.ide.projectView.impl.nodes.NamedLibraryElementNode;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.pom.Navigatable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+class LibraryActionHelper {
+
+ static BlazeJarLibrary findLibraryFromIntellijLibrary(Project project, Library library) {
+ LibraryKey libraryKey = LibraryKey.fromIntelliJLibrary(library);
+ BlazeProjectData projectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (projectData == null) {
+ return null;
+ }
+ BlazeJavaSyncData syncData = projectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ Messages.showErrorDialog(project, "Project isn't synced. Please resync project.", "Error");
+ return null;
+ }
+
+ BlazeLibrary blazeLibrary = syncData.importResult.libraries.get(libraryKey);
+ if (!(blazeLibrary instanceof BlazeJarLibrary)) {
+ return null;
+ }
+ return (BlazeJarLibrary) blazeLibrary;
+ }
+
+ @Nullable
+ public static Library findLibraryForAction(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ if (project != null) {
+ NamedLibraryElementNode node = findLibraryNode(e.getDataContext());
+ if (node != null) {
+ String libraryName = node.getName();
+ if (StringUtil.isNotEmpty(libraryName)) {
+ LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
+ return libraryTable.getLibraryByName(libraryName);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static NamedLibraryElementNode findLibraryNode(@NotNull DataContext dataContext) {
+ Navigatable[] navigatables = CommonDataKeys.NAVIGATABLE_ARRAY.getData(dataContext);
+ if (navigatables != null && navigatables.length == 1) {
+ Navigatable navigatable = navigatables[0];
+ if (navigatable instanceof NamedLibraryElementNode) {
+ return (NamedLibraryElementNode) navigatable;
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/libraries/SourceJarManager.java b/java/src/com/google/idea/blaze/java/libraries/SourceJarManager.java
new file mode 100644
index 0000000..10ea861
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/libraries/SourceJarManager.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.libraries;
+
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.components.StoragePathMacros;
+import com.intellij.openapi.project.Project;
+import java.util.Set;
+import org.jdom.Element;
+
+/** Keeps track of which libraries have source jars attached. */
+@State(name = "BlazeSourceJarManager", storages = @Storage(StoragePathMacros.WORKSPACE_FILE))
+public class SourceJarManager implements PersistentStateComponent<Element> {
+ private Set<LibraryKey> librariesWithSourceJarsAttached = Sets.newHashSet();
+
+ public static SourceJarManager getInstance(Project project) {
+ return ServiceManager.getService(project, SourceJarManager.class);
+ }
+
+ public boolean hasSourceJarAttached(LibraryKey libraryKey) {
+ return librariesWithSourceJarsAttached.contains(libraryKey);
+ }
+
+ public void setHasSourceJarAttached(LibraryKey libraryKey, boolean hasSourceJar) {
+ if (hasSourceJar) {
+ librariesWithSourceJarsAttached.add(libraryKey);
+ } else {
+ librariesWithSourceJarsAttached.remove(libraryKey);
+ }
+ }
+
+ @Override
+ public Element getState() {
+ Element element = new Element("state");
+ for (LibraryKey libraryKey : librariesWithSourceJarsAttached) {
+ Element libElement = new Element("library");
+ libElement.setText(libraryKey.getIntelliJLibraryName());
+ element.addContent(libElement);
+ }
+ return element;
+ }
+
+ @Override
+ public void loadState(Element state) {
+ Set<LibraryKey> librariesWithSourceJars = Sets.newHashSet();
+ for (Element libElement : state.getChildren()) {
+ LibraryKey libraryKey = LibraryKey.fromIntelliJLibraryName(libElement.getText());
+ librariesWithSourceJars.add(libraryKey);
+ }
+ this.librariesWithSourceJarsAttached = librariesWithSourceJars;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/projectview/ExcludeLibrarySection.java b/java/src/com/google/idea/blaze/java/projectview/ExcludeLibrarySection.java
new file mode 100644
index 0000000..e1c466d
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/projectview/ExcludeLibrarySection.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.projectview;
+
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.GlobSectionParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** Section for excluding libraries. */
+public class ExcludeLibrarySection {
+ public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("exclude_library");
+ public static final SectionParser PARSER = new GlobSectionParser(KEY);
+}
diff --git a/java/src/com/google/idea/blaze/java/projectview/ExcludedLibrarySection.java b/java/src/com/google/idea/blaze/java/projectview/ExcludedLibrarySection.java
new file mode 100644
index 0000000..908d48d
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/projectview/ExcludedLibrarySection.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.projectview;
+
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.GlobSectionParser;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+
+/** Section for excluding libraries. */
+@Deprecated
+public class ExcludedLibrarySection {
+ public static final SectionKey<Glob, ListSection<Glob>> KEY = SectionKey.of("excluded_libraries");
+ public static final SectionParser PARSER =
+ new GlobSectionParser(KEY) {
+ @Override
+ public boolean isDeprecated() {
+ return true;
+ }
+ };
+}
diff --git a/java/src/com/google/idea/blaze/java/projectview/JavaLanguageLevelSection.java b/java/src/com/google/idea/blaze/java/projectview/JavaLanguageLevelSection.java
new file mode 100644
index 0000000..09cd3b4
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/projectview/JavaLanguageLevelSection.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.projectview;
+
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.parser.ParseContext;
+import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.ScalarSectionParser;
+import com.google.idea.blaze.base.projectview.section.SectionKey;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.intellij.pom.java.LanguageLevel;
+import javax.annotation.Nullable;
+
+/** Section to force the java language level used */
+public class JavaLanguageLevelSection {
+ public static final SectionKey<Integer, ScalarSection<Integer>> KEY =
+ SectionKey.of("java_language_level");
+ public static final SectionParser PARSER = new JavaLanguageLevelParser();
+
+ public static LanguageLevel getLanguageLevel(
+ ProjectViewSet projectViewSet, LanguageLevel defaultValue) {
+ Integer level = projectViewSet.getScalarValue(KEY, null);
+ if (level == null) {
+ return defaultValue;
+ }
+ return getLanguageLevel(level, defaultValue);
+ }
+
+ @Nullable
+ private static LanguageLevel getLanguageLevel(
+ Integer level, @Nullable LanguageLevel defaultValue) {
+ switch (level) {
+ case 3:
+ return LanguageLevel.JDK_1_3;
+ case 4:
+ return LanguageLevel.JDK_1_4;
+ case 5:
+ return LanguageLevel.JDK_1_5;
+ case 6:
+ return LanguageLevel.JDK_1_6;
+ case 7:
+ return LanguageLevel.JDK_1_7;
+ case 8:
+ return LanguageLevel.JDK_1_8;
+ case 9:
+ return LanguageLevel.JDK_1_9;
+ default:
+ return defaultValue;
+ }
+ }
+
+ private static class JavaLanguageLevelParser extends ScalarSectionParser<Integer> {
+ public JavaLanguageLevelParser() {
+ super(KEY, ':');
+ }
+
+ @Nullable
+ @Override
+ protected Integer parseItem(ProjectViewParser parser, ParseContext parseContext, String rest) {
+ try {
+ Integer value = Integer.parseInt(rest);
+ if (getLanguageLevel(value, null) != null) {
+ return value;
+ }
+ // Fall through to error handler
+ } catch (NumberFormatException e) {
+ // Fall through to error handler
+ }
+ parseContext.addError("Illegal java language level: " + rest);
+ return null;
+ }
+
+ @Override
+ protected void printItem(StringBuilder sb, Integer value) {
+ sb.append(value.toString());
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/psi/JavaPsiFileProvider.java b/java/src/com/google/idea/blaze/java/psi/JavaPsiFileProvider.java
new file mode 100644
index 0000000..2e0d282
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/psi/JavaPsiFileProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.psi;
+
+import com.google.idea.blaze.base.lang.buildfile.search.PsiFileProvider;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import javax.annotation.Nullable;
+
+/** Replaces top-level java classes with their corresponding PsiFile */
+public class JavaPsiFileProvider implements PsiFileProvider {
+
+ @Nullable
+ @Override
+ public PsiFile asFileSearch(PsiElement elementToSearch) {
+ if (elementToSearch instanceof PsiClass) {
+ elementToSearch = elementToSearch.getParent();
+ }
+ return elementToSearch instanceof PsiFile ? (PsiFile) elementToSearch : null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java
new file mode 100644
index 0000000..55f9900
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.intellij.debugger.impl.GenericDebuggerRunner;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.JavaParameters;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RunnerSettings;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.ui.RunContentDescriptor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** A runner that adapts the GenericDebuggerRunner to work with Blaze run configurations. */
+public class BlazeJavaDebuggerRunner extends GenericDebuggerRunner {
+ @Override
+ @NotNull
+ public String getRunnerId() {
+ return "Blaze-Debug";
+ }
+
+ @Override
+ public boolean canRun(@NotNull final String executorId, @NotNull final RunProfile profile) {
+ if (executorId.equals(DefaultDebugExecutor.EXECUTOR_ID)
+ && profile instanceof BlazeCommandRunConfiguration) {
+ BlazeCommandRunConfiguration configuration = (BlazeCommandRunConfiguration) profile;
+ RuleIdeInfo rule = configuration.getRuleForTarget();
+ return rule != null && BlazeJavaRunConfigurationHandlerProvider.supportsKind(rule.kind);
+ }
+ return false;
+ }
+
+ @Override
+ public void patch(
+ JavaParameters javaParameters,
+ RunnerSettings runnerSettings,
+ RunProfile runProfile,
+ final boolean beforeExecution) {
+ // We don't want to support Java run configuration patching.
+ }
+
+ @Override
+ @Nullable
+ public RunContentDescriptor createContentDescriptor(
+ @NotNull RunProfileState state, @NotNull ExecutionEnvironment environment)
+ throws ExecutionException {
+ if (!(state instanceof BlazeJavaRunProfileState)) {
+ return null;
+ }
+ BlazeJavaRunProfileState blazeState = (BlazeJavaRunProfileState) state;
+ RemoteConnection connection = blazeState.getRemoteConnection();
+ return attachVirtualMachine(state, environment, connection, true /* pollConnection */);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaRuleConfigurationFactory.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaRuleConfigurationFactory.java
new file mode 100644
index 0000000..2ed1ca8
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaRuleConfigurationFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
+
+/** Creates run configurations for java_binary. */
+public class BlazeJavaRuleConfigurationFactory extends BlazeRuleConfigurationFactory {
+ @Override
+ public boolean handlesRule(
+ WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule) {
+ return rule.kind == Kind.JAVA_BINARY;
+ }
+
+ @Override
+ protected ConfigurationFactory getConfigurationFactory() {
+ return BlazeCommandRunConfigurationType.getInstance().getFactory();
+ }
+
+ @Override
+ public void setupConfiguration(RunConfiguration configuration, RuleIdeInfo rule) {
+ final BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) configuration;
+ blazeConfig.setTarget(rule.label);
+
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) blazeConfig.getHandler();
+ handler.setCommand(BlazeCommandName.RUN);
+
+ blazeConfig.setGeneratedName();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandlerProvider.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..966fe91
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandlerProvider.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.runners.ExecutionEnvironment;
+
+/** Java-specific handler for {@link BlazeCommandRunConfiguration}s. */
+public class BlazeJavaRunConfigurationHandlerProvider
+ implements BlazeCommandRunConfigurationHandlerProvider {
+
+ private static final ImmutableSet<Kind> RELEVANT_RULE_KINDS =
+ ImmutableSet.of(Kind.ANDROID_ROBOLECTRIC_TEST, Kind.JAVA_TEST, Kind.JAVA_BINARY);
+
+ static boolean supportsKind(Kind kind) {
+ return RELEVANT_RULE_KINDS.contains(kind);
+ }
+
+ @Override
+ public boolean canHandleKind(Kind kind) {
+ return supportsKind(kind);
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config) {
+ return new BlazeJavaRunConfigurationHandler(config);
+ }
+
+ @Override
+ public String getId() {
+ return "BlazeJavaRunConfigurationHandlerProvider";
+ }
+
+ private static class BlazeJavaRunConfigurationHandler
+ extends BlazeCommandGenericRunConfigurationHandler {
+
+ BlazeJavaRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ super(configuration);
+ }
+
+ private BlazeJavaRunConfigurationHandler(
+ BlazeJavaRunConfigurationHandler other, BlazeCommandRunConfiguration configuration) {
+ super(other, configuration);
+ }
+
+ @Override
+ public BlazeJavaRunConfigurationHandler cloneFor(BlazeCommandRunConfiguration configuration) {
+ return new BlazeJavaRunConfigurationHandler(this, configuration);
+ }
+
+ @Override
+ public RunProfileState getState(Executor executor, ExecutionEnvironment environment) {
+ return new BlazeJavaRunProfileState(environment, executor instanceof DefaultDebugExecutor);
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "Java Handler";
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java
new file mode 100644
index 0000000..935a1e0
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.processhandler.LineProcessingProcessAdapter;
+import com.google.idea.blaze.base.run.processhandler.ScopedBlazeProcessHandler;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.configurations.CommandLineState;
+import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.execution.configurations.RemoteState;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.process.ProcessListener;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.project.Project;
+
+/**
+ * A Blaze run configuration set up with a an executor, program runner, and other settings, ready to
+ * be executed. This class creates a command line for Blaze and exposes debug connection information
+ * when using a debug executor.
+ */
+final class BlazeJavaRunProfileState extends CommandLineState implements RemoteState {
+ // Blaze seems to always use this port for --java_debug.
+ // TODO(joshgiles): Look at manually identifying and setting port.
+ private static final int DEBUG_PORT = 5005;
+ private static final String DEBUG_HOST_NAME = "localhost";
+
+ private final BlazeCommandRunConfiguration configuration;
+ private final boolean debug;
+
+ public BlazeJavaRunProfileState(ExecutionEnvironment environment, boolean debug) {
+ super(environment);
+ RunProfile runProfile = environment.getRunProfile();
+ assert runProfile instanceof BlazeCommandRunConfiguration;
+ configuration = (BlazeCommandRunConfiguration) runProfile;
+ this.debug = debug;
+ }
+
+ @Override
+ protected ProcessHandler startProcess() throws ExecutionException {
+ Project project = configuration.getProject();
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ assert importSettings != null;
+
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ assert projectViewSet != null;
+
+ BlazeCommand blazeCommand = getBlazeCommand(project, configuration, projectViewSet, debug);
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
+ return new ScopedBlazeProcessHandler(
+ project,
+ blazeCommand,
+ workspaceRoot,
+ new ScopedBlazeProcessHandler.ScopedProcessHandlerDelegate() {
+ @Override
+ public void onBlazeContextStart(BlazeContext context) {
+ context
+ .push(new LoggedTimingScope(project, Action.BLAZE_COMMAND_USAGE))
+ .push(new IssuesScope(project))
+ .push(new IdeaLogScope());
+ }
+
+ @Override
+ public ImmutableList<ProcessListener> createProcessListeners(BlazeContext context) {
+ LineProcessingOutputStream outputStream =
+ LineProcessingOutputStream.of(
+ new IssueOutputLineProcessor(project, context, workspaceRoot));
+ return ImmutableList.of(new LineProcessingProcessAdapter(outputStream));
+ }
+ });
+ }
+
+ @Override
+ public RemoteConnection getRemoteConnection() {
+ if (!debug) {
+ return null;
+ }
+ return new RemoteConnection(
+ true /* useSockets */,
+ DEBUG_HOST_NAME,
+ Integer.toString(DEBUG_PORT),
+ false /* serverMode */);
+ }
+
+ @VisibleForTesting
+ static BlazeCommand getBlazeCommand(
+ Project project,
+ BlazeCommandRunConfiguration configuration,
+ ProjectViewSet projectViewSet,
+ boolean debug) {
+
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ assert handler != null;
+
+ BlazeCommandName blazeCommand = handler.getCommand();
+ assert blazeCommand != null;
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(Blaze.getBuildSystem(project), blazeCommand)
+ .setBlazeBinary(handler.getBlazeBinary())
+ .addTargets(configuration.getTarget())
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
+ .addBlazeFlags(handler.getAllBlazeFlags());
+
+ if (debug) {
+ boolean isJavaBinary = false;
+ RuleIdeInfo rule = configuration.getRuleForTarget();
+ if (rule != null && (rule.kind == Kind.JAVA_BINARY)) {
+ isJavaBinary = true;
+ }
+
+ if (isJavaBinary) {
+ command.addExeFlags(BlazeFlags.JAVA_BINARY_DEBUG);
+ } else {
+ command.addBlazeFlags(BlazeFlags.JAVA_TEST_DEBUG);
+ }
+ }
+
+ command.addExeFlags(handler.getAllExeFlags());
+ return command.build();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRuleConfigurationFactory.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRuleConfigurationFactory.java
new file mode 100644
index 0000000..42c6256
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRuleConfigurationFactory.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
+
+/** Creates run configurations for java_test and android_robolectric_test. */
+public class BlazeJavaTestRuleConfigurationFactory extends BlazeRuleConfigurationFactory {
+ @Override
+ public boolean handlesRule(
+ WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule) {
+ return rule.kindIsOneOf(Kind.JAVA_TEST, Kind.ANDROID_ROBOLECTRIC_TEST);
+ }
+
+ @Override
+ protected ConfigurationFactory getConfigurationFactory() {
+ return BlazeCommandRunConfigurationType.getInstance().getFactory();
+ }
+
+ @Override
+ public void setupConfiguration(RunConfiguration configuration, RuleIdeInfo rule) {
+ final BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) configuration;
+ blazeConfig.setTarget(rule.label);
+
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) blazeConfig.getHandler();
+ handler.setCommand(BlazeCommandName.TEST);
+
+ blazeConfig.setGeneratedName();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/RunUtil.java b/java/src/com/google/idea/blaze/java/run/RunUtil.java
new file mode 100644
index 0000000..fab9497
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/RunUtil.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.run.TestRuleFinder;
+import com.google.idea.blaze.base.run.TestRuleHeuristic;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiFile;
+import java.io.File;
+import java.util.Collection;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Utility methods for finding rules and Android facets. */
+public final class RunUtil {
+
+ private RunUtil() {}
+
+ /**
+ * @return The Blaze test rule containing the target test class. In the case of multiple
+ * containing rules, the first rule sorted alphabetically by label.
+ */
+ @Nullable
+ public static RuleIdeInfo ruleForTestClass(
+ @NotNull Project project,
+ @NotNull PsiClass testClass,
+ @Nullable TestIdeInfo.TestSize testSize) {
+ File testFile = getFileForClass(testClass);
+ if (testFile == null) {
+ return null;
+ }
+ Collection<RuleIdeInfo> rules =
+ TestRuleFinder.getInstance(project).testTargetsForSourceFile(testFile);
+ Label testLabel = TestRuleHeuristic.chooseTestTargetForSourceFile(testFile, rules, testSize);
+ if (testLabel == null) {
+ return null;
+ }
+ return RuleFinder.getInstance().ruleForTarget(project, testLabel);
+ }
+
+ /**
+ * Returns an instance of {@link java.io.File} related to the containing file of the given class.
+ * It returns {@code null} if the given class is not contained in a file and only exists in
+ * memory.
+ */
+ @Nullable
+ public static File getFileForClass(@NotNull PsiClass aClass) {
+ PsiFile containingFile = aClass.getContainingFile();
+ if (containingFile == null) {
+ return null;
+ }
+
+ VirtualFile virtualFile = containingFile.getVirtualFile();
+ if (virtualFile == null) {
+ return null;
+ }
+
+ return new File(virtualFile.getPath());
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassRunConfigurationProducer.java b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassRunConfigurationProducer.java
new file mode 100644
index 0000000..72c35f6
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassRunConfigurationProducer.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.rulemaps.SourceToRuleMap;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.run.RunUtil;
+import com.intellij.execution.JavaExecutionUtil;
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.application.ApplicationConfigurationType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.util.PsiMethodUtil;
+import java.io.File;
+import java.util.Objects;
+import org.jetbrains.annotations.Nullable;
+
+/** Creates run configurations for Java main classes sourced by java_binary targets. */
+public class BlazeJavaMainClassRunConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ public BlazeJavaMainClassRunConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+ PsiClass mainClass = getMainClass(context);
+ if (mainClass == null) {
+ return false;
+ }
+ // Try setting source element to a main method so ApplicationConfigurationProducer
+ // can't override our configuration by producing a more specific one.
+ PsiMethod mainMethod = PsiMethodUtil.findMainMethod(mainClass);
+ if (mainMethod == null) {
+ sourceElement.set(mainClass);
+ } else {
+ sourceElement.set(mainMethod);
+ }
+
+ Label label = getRuleLabel(context.getProject(), mainClass);
+ if (label == null) {
+ return false;
+ }
+ configuration.setTarget(label);
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ handler.setCommand(BlazeCommandName.RUN);
+ configuration.setGeneratedName();
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ if (!Objects.equals(handler.getCommand(), BlazeCommandName.RUN)) {
+ return false;
+ }
+ PsiClass mainClass = getMainClass(context);
+ if (mainClass == null) {
+ return false;
+ }
+ Label label = getRuleLabel(context.getProject(), mainClass);
+ if (label == null) {
+ return false;
+ }
+ return Objects.equals(configuration.getTarget(), label);
+ }
+
+ @Nullable
+ private static PsiClass getMainClass(ConfigurationContext context) {
+ Location location = context.getLocation();
+ if (location == null) {
+ return null;
+ }
+ location = JavaExecutionUtil.stepIntoSingleClass(location);
+ if (location == null) {
+ return null;
+ }
+ PsiElement element = location.getPsiElement();
+ if (!element.isPhysical()) {
+ return null;
+ }
+ return ApplicationConfigurationType.getMainClass(element);
+ }
+
+ @Nullable
+ private static Label getRuleLabel(Project project, PsiClass mainClass) {
+ File mainClassFile = RunUtil.getFileForClass(mainClass);
+ ImmutableCollection<Label> labels =
+ SourceToRuleMap.getInstance(project).getTargetsForSourceFile(mainClassFile);
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return null;
+ }
+ RuleMap ruleMap = blazeProjectData.ruleMap;
+ for (Label label : labels) {
+ RuleIdeInfo rule = ruleMap.get(label);
+ if (rule.kind == Kind.JAVA_BINARY) {
+ // Best-effort guess: the main_class attribute isn't exposed, but assume
+ // mainClass is the main_class because it is sourced by the java_binary.
+ return label;
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java
new file mode 100644
index 0000000..c9c4c3e
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.java.run.RunUtil;
+import com.intellij.execution.JavaExecutionUtil;
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiMethod;
+import java.util.List;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
+
+/** Producer for run configurations related to Java test classes in Blaze. */
+public class BlazeJavaTestClassConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ public BlazeJavaTestClassConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ @NotNull BlazeCommandRunConfiguration configuration,
+ @NotNull ConfigurationContext context,
+ @NotNull Ref<PsiElement> sourceElement) {
+
+ final Location contextLocation = context.getLocation();
+ assert contextLocation != null;
+ final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);
+ if (location == null) {
+ return false;
+ }
+
+ if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
+ return false;
+ }
+
+ PsiClass testClass = JUnitUtil.getTestClass(location);
+ if (testClass == null) {
+ return false;
+ }
+ sourceElement.set(testClass);
+
+ TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(testClass);
+ RuleIdeInfo rule = RunUtil.ruleForTestClass(context.getProject(), testClass, testSize);
+ if (rule == null) {
+ return false;
+ }
+
+ configuration.setTarget(rule.label);
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ handler.setCommand(BlazeCommandName.TEST);
+
+ ImmutableList.Builder<String> flags = ImmutableList.builder();
+
+ String qualifiedName = testClass.getQualifiedName();
+ if (qualifiedName != null) {
+ flags.add(BlazeFlags.testFilterFlagForClass(qualifiedName));
+ }
+
+ flags.add(BlazeFlags.TEST_OUTPUT_STREAMED);
+ flags.addAll(handler.getAllBlazeFlags());
+
+ handler.setBlazeFlags(flags.build());
+
+ BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
+ nameBuilder.setTargetString(testClass.getName());
+ configuration.setName(nameBuilder.build());
+
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ @NotNull BlazeCommandRunConfiguration configuration, @NotNull ConfigurationContext context) {
+
+ final Location contextLocation = context.getLocation();
+ assert contextLocation != null;
+ final Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);
+ if (location == null) {
+ return false;
+ }
+
+ if (JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
+ return false;
+ }
+
+ Location<PsiMethod> methodLocation = ProducerUtils.getMethodLocation(contextLocation);
+ if (methodLocation != null) {
+ return false;
+ }
+
+ PsiClass testClass = JUnitUtil.getTestClass(location);
+ if (testClass == null) {
+ return false;
+ }
+
+ return checkIfAttributesAreTheSame(configuration, testClass);
+ }
+
+ private boolean checkIfAttributesAreTheSame(
+ @NotNull BlazeCommandRunConfiguration configuration, @NotNull PsiClass testClass) {
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ if (!Objects.equals(handler.getCommand(), BlazeCommandName.TEST)) {
+ return false;
+ }
+ List<String> flags = handler.getAllBlazeFlags();
+
+ return flags.contains(BlazeFlags.testFilterFlagForClass(testClass.getQualifiedName()));
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java
new file mode 100644
index 0000000..4b67696
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.java.run.RunUtil;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiMethod;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import org.jetbrains.annotations.NotNull;
+
+/** Producer for run configurations related to Java test methods in Blaze. */
+public class BlazeJavaTestMethodConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ private static class SelectedMethodInfo {
+ private final PsiMethod firstMethod;
+ private final PsiClass containingClass;
+ private final List<String> methodNames;
+ private final String testFilterFlag;
+
+ public SelectedMethodInfo(
+ PsiMethod firstMethod,
+ PsiClass containingClass,
+ List<String> methodNames,
+ String testFilterFlag) {
+ this.firstMethod = firstMethod;
+ this.containingClass = containingClass;
+ this.methodNames = methodNames;
+ this.testFilterFlag = testFilterFlag;
+ }
+ }
+
+ public BlazeJavaTestMethodConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ @NotNull BlazeCommandRunConfiguration configuration,
+ @NotNull ConfigurationContext context,
+ @NotNull Ref<PsiElement> sourceElement) {
+
+ SelectedMethodInfo methodInfo = getSelectedMethodInfo(context);
+ if (methodInfo == null) {
+ return false;
+ }
+
+ // PatternConfigurationProducer also chooses the first method as its source element.
+ // As long as we choose an element at the same PSI hierarchy level,
+ // PatternConfigurationProducer won't override our configuration.
+ sourceElement.set(methodInfo.firstMethod);
+
+ TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(methodInfo.firstMethod);
+ RuleIdeInfo rule =
+ RunUtil.ruleForTestClass(context.getProject(), methodInfo.containingClass, testSize);
+ if (rule == null) {
+ return false;
+ }
+
+ configuration.setTarget(rule.label);
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ handler.setCommand(BlazeCommandName.TEST);
+
+ ImmutableList.Builder<String> flags = ImmutableList.builder();
+ flags.add(methodInfo.testFilterFlag);
+ flags.add(BlazeFlags.TEST_OUTPUT_STREAMED);
+ flags.addAll(handler.getAllBlazeFlags());
+
+ handler.setBlazeFlags(flags.build());
+
+ BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
+ nameBuilder.setTargetString(
+ String.format(
+ "%s.%s",
+ methodInfo.containingClass.getName(), String.join(",", methodInfo.methodNames)));
+ configuration.setName(nameBuilder.build());
+
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ @NotNull BlazeCommandRunConfiguration configuration, @NotNull ConfigurationContext context) {
+ BlazeCommandGenericRunConfigurationHandler handler =
+ configuration.getHandlerIfType(BlazeCommandGenericRunConfigurationHandler.class);
+ if (handler == null) {
+ return false;
+ }
+ if (!Objects.equals(handler.getCommand(), BlazeCommandName.TEST)) {
+ return false;
+ }
+
+ SelectedMethodInfo methodInfo = getSelectedMethodInfo(context);
+ if (methodInfo == null) {
+ return false;
+ }
+
+ List<String> flags = handler.getAllBlazeFlags();
+ return flags.contains(methodInfo.testFilterFlag);
+ }
+
+ private static SelectedMethodInfo getSelectedMethodInfo(ConfigurationContext context) {
+ final List<PsiMethod> selectedMethods = TestMethodSelectionUtil.getSelectedMethods(context);
+ if (selectedMethods == null) {
+ return null;
+ }
+ assert selectedMethods.size() > 0;
+ final PsiMethod firstMethod = selectedMethods.get(0);
+
+ final PsiClass containingClass = firstMethod.getContainingClass();
+ if (containingClass == null) {
+ return null;
+ }
+ for (PsiMethod method : selectedMethods) {
+ if (!containingClass.equals(method.getContainingClass())) {
+ return null;
+ }
+ }
+
+ final List<String> methodNames = new ArrayList<>();
+ for (PsiMethod method : selectedMethods) {
+ methodNames.add(method.getName());
+ }
+ // Sort so multiple configurations created with different selection orders are the same.
+ Collections.sort(methodNames);
+
+ final String qualifiedName = containingClass.getQualifiedName();
+ if (qualifiedName == null) {
+ return null;
+ }
+ final boolean isJUnit3Class = JUnitUtil.isJUnit3TestClass(containingClass);
+ final String testFilterFlag =
+ BlazeFlags.testFilterFlagForClassAndMethods(qualifiedName, methodNames, isJUnit3Class);
+
+ return new SelectedMethodInfo(firstMethod, containingClass, methodNames, testFilterFlag);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java b/java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java
new file mode 100644
index 0000000..b994e36
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
+import com.intellij.execution.junit2.info.MethodLocation;
+import com.intellij.execution.testframework.TestsUIUtil;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.JavaDirectoryService;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.PsiMember;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiPackage;
+import com.intellij.psi.search.PsiElementProcessor;
+import com.intellij.psi.util.ClassUtil;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+/**
+ * Cloned from PatternConfigurationProducer, stripped down to only contain
+ * isMultipleElementsSelected.
+ */
+public class JUnitConfigurationUtil {
+ protected static boolean isTestClass(PsiClass psiClass) {
+ return JUnitUtil.isTestClass(psiClass);
+ }
+
+ protected static boolean isTestMethod(boolean checkAbstract, PsiElement psiElement) {
+ return JUnitUtil.getTestMethod(psiElement, checkAbstract) != null;
+ }
+
+ public static boolean isMultipleElementsSelected(ConfigurationContext context) {
+ final DataContext dataContext = context.getDataContext();
+ if (TestsUIUtil.isMultipleSelectionImpossible(dataContext)) {
+ return false;
+ }
+ final LinkedHashSet<String> classes = new LinkedHashSet<String>();
+ final PsiElementProcessor.CollectElementsWithLimit<PsiElement> processor =
+ new PsiElementProcessor.CollectElementsWithLimit<PsiElement>(2);
+ final PsiElement[] locationElements = collectLocationElements(classes, dataContext);
+ if (locationElements != null) {
+ collectTestMembers(locationElements, false, false, processor);
+ } else {
+ collectContextElements(dataContext, false, false, classes, processor);
+ }
+ return processor.getCollection().size() > 1;
+ }
+
+ public static void collectTestMembers(
+ PsiElement[] psiElements,
+ boolean checkAbstract,
+ boolean checkIsTest,
+ PsiElementProcessor.CollectElements<PsiElement> collectingProcessor) {
+ for (PsiElement psiElement : psiElements) {
+ if (psiElement instanceof PsiClassOwner) {
+ final PsiClass[] classes = ((PsiClassOwner) psiElement).getClasses();
+ for (PsiClass aClass : classes) {
+ if ((!checkIsTest && aClass.hasModifierProperty(PsiModifier.PUBLIC)
+ || checkIsTest && isTestClass(aClass))
+ && !collectingProcessor.execute(aClass)) {
+ return;
+ }
+ }
+ } else if (psiElement instanceof PsiClass) {
+ if ((!checkIsTest && ((PsiClass) psiElement).hasModifierProperty(PsiModifier.PUBLIC)
+ || checkIsTest && isTestClass((PsiClass) psiElement))
+ && !collectingProcessor.execute(psiElement)) {
+ return;
+ }
+ } else if (psiElement instanceof PsiMethod) {
+ if (checkIsTest
+ && isTestMethod(checkAbstract, psiElement)
+ && !collectingProcessor.execute(psiElement)) {
+ return;
+ }
+ if (!checkIsTest) {
+ final PsiClass containingClass = ((PsiMethod) psiElement).getContainingClass();
+ if (containingClass != null
+ && containingClass.hasModifierProperty(PsiModifier.PUBLIC)
+ && !collectingProcessor.execute(psiElement)) {
+ return;
+ }
+ }
+ } else if (psiElement instanceof PsiDirectory) {
+ final PsiPackage aPackage =
+ JavaDirectoryService.getInstance().getPackage((PsiDirectory) psiElement);
+ if (aPackage != null && !collectingProcessor.execute(aPackage)) {
+ return;
+ }
+ }
+ }
+ }
+
+ private static boolean collectContextElements(
+ DataContext dataContext,
+ boolean checkAbstract,
+ boolean checkIsTest,
+ LinkedHashSet<String> classes,
+ PsiElementProcessor.CollectElements<PsiElement> processor) {
+ PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
+ if (elements != null) {
+ collectTestMembers(elements, checkAbstract, checkIsTest, processor);
+ for (PsiElement psiClass : processor.getCollection()) {
+ classes.add(getQName(psiClass));
+ }
+ return true;
+ } else {
+ final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
+ if (files != null) {
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ if (project != null) {
+ final PsiManager psiManager = PsiManager.getInstance(project);
+ for (VirtualFile file : files) {
+ final PsiFile psiFile = psiManager.findFile(file);
+ if (psiFile instanceof PsiClassOwner) {
+ collectTestMembers(
+ ((PsiClassOwner) psiFile).getClasses(), checkAbstract, checkIsTest, processor);
+ for (PsiElement psiMember : processor.getCollection()) {
+ classes.add(((PsiClass) psiMember).getQualifiedName());
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static PsiElement[] collectLocationElements(
+ LinkedHashSet<String> classes, DataContext dataContext) {
+ final Location<?>[] locations = Location.DATA_KEYS.getData(dataContext);
+ if (locations != null) {
+ List<PsiElement> elements = new ArrayList<PsiElement>();
+ for (Location<?> location : locations) {
+ final PsiElement psiElement = location.getPsiElement();
+ classes.add(getQName(psiElement, location));
+ elements.add(psiElement);
+ }
+ return elements.toArray(new PsiElement[elements.size()]);
+ }
+ return null;
+ }
+
+ public static String getQName(PsiElement psiMember) {
+ return getQName(psiMember, null);
+ }
+
+ public static String getQName(PsiElement psiMember, Location location) {
+ if (psiMember instanceof PsiClass) {
+ return ClassUtil.getJVMClassName((PsiClass) psiMember);
+ } else if (psiMember instanceof PsiMember) {
+ final PsiClass containingClass =
+ location instanceof MethodLocation
+ ? ((MethodLocation) location).getContainingClass()
+ : location instanceof PsiMemberParameterizedLocation
+ ? ((PsiMemberParameterizedLocation) location).getContainingClass()
+ : ((PsiMember) psiMember).getContainingClass();
+ assert containingClass != null;
+ return ClassUtil.getJVMClassName(containingClass) + "," + ((PsiMember) psiMember).getName();
+ } else if (psiMember instanceof PsiPackage) {
+ return ((PsiPackage) psiMember).getQualifiedName();
+ }
+ assert false;
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java b/java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java
new file mode 100644
index 0000000..b1b40ab
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.intellij.execution.Location;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
+import com.intellij.execution.junit2.info.MethodLocation;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import java.util.Iterator;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Copy of {@link org.jetbrains.plugins.gradle.execution.test.runner.TestRunnerUtils}.
+ *
+ * <p>
+ *
+ * <p>Do not modify.
+ */
+public class ProducerUtils {
+ @Nullable
+ public static Location<PsiMethod> getMethodLocation(@NotNull Location contextLocation) {
+ Location<PsiMethod> methodLocation = getTestMethod(contextLocation);
+ if (methodLocation == null) {
+ return null;
+ }
+
+ if (contextLocation instanceof PsiMemberParameterizedLocation) {
+ PsiClass containingClass =
+ ((PsiMemberParameterizedLocation) contextLocation).getContainingClass();
+ if (containingClass != null) {
+ methodLocation =
+ MethodLocation.elementInClass(methodLocation.getPsiElement(), containingClass);
+ }
+ }
+ return methodLocation;
+ }
+
+ @Nullable
+ public static Location<PsiMethod> getTestMethod(final Location<?> location) {
+ for (Iterator<Location<PsiMethod>> iterator = location.getAncestors(PsiMethod.class, false);
+ iterator.hasNext();
+ ) {
+ final Location<PsiMethod> methodLocation = iterator.next();
+ if (JUnitUtil.isTestMethod(methodLocation, false)) {
+ return methodLocation;
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/TestMethodSelectionUtil.java b/java/src/com/google/idea/blaze/java/run/producers/TestMethodSelectionUtil.java
new file mode 100644
index 0000000..e19f9bf
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/TestMethodSelectionUtil.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.intellij.execution.Location;
+import com.intellij.execution.PsiLocation;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiMethod;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Helper functions for getting selected test methods. */
+public class TestMethodSelectionUtil {
+
+ /**
+ * Get all test methods directly or indirectly selected in the given context. This includes
+ * methods selected in the Structure panel, as well as methods the context location is inside of.
+ *
+ * @param context The context to get selected test methods from.
+ * @param allMustMatch If true, will return null if any selected elements are not test methods.
+ * @return A list of test methods (with at least one element), or null if:
+ * <ul>
+ * <li>There are no selected test methods
+ * <li>{@code allMustMatch} is true, but elements other than test methods are selected
+ * </ul>
+ *
+ * @see #getDirectlySelectedMethods(ConfigurationContext, boolean)
+ * @see #getIndirectlySelectedMethod(ConfigurationContext)
+ */
+ @Nullable
+ public static List<PsiMethod> getSelectedMethods(
+ @NotNull ConfigurationContext context, boolean allMustMatch) {
+ List<PsiMethod> directlySelectedMethods = getDirectlySelectedMethods(context, allMustMatch);
+ if (directlySelectedMethods != null && directlySelectedMethods.size() > 0) {
+ return directlySelectedMethods;
+ }
+ if (allMustMatch && JUnitConfigurationUtil.isMultipleElementsSelected(context)) {
+ return null;
+ }
+ PsiMethod indirectlySelectedMethod = getIndirectlySelectedMethod(context);
+ if (indirectlySelectedMethod != null) {
+ return Collections.singletonList(indirectlySelectedMethod);
+ }
+ return null;
+ }
+
+ /**
+ * Get all test methods directly or indirectly selected in the given context. This includes
+ * methods selected in the Structure panel, as well as methods the context location is inside of.
+ *
+ * @param context The context to get selected test methods from.
+ * @return A list of test methods (with at least one element), or null if:
+ * <ul>
+ * <li>There are no selected test methods
+ * <li>Any elements other than test methods are selected
+ * </ul>
+ *
+ * @see #getDirectlySelectedMethods(ConfigurationContext, boolean)
+ * @see #getIndirectlySelectedMethod(ConfigurationContext)
+ */
+ @Nullable
+ public static List<PsiMethod> getSelectedMethods(@NotNull ConfigurationContext context) {
+ return getSelectedMethods(context, true);
+ }
+
+ /**
+ * Get all test methods directly selected in the given context. This includes, for example,
+ * methods selected from the Structure panel. It does not include methods the context location is
+ * inside of. Note that methods may belong to different classes (possible if methods are selected
+ * from the Project panel with "Show Members" checked), and methods in abstract classes are not
+ * returned.
+ *
+ * @param context The context to get selected test methods from.
+ * @param allMustMatch If true, will return null if any selected elements are not test methods.
+ * @return A list of test methods (possibly empty), or null if:
+ * <ul>
+ * <li>There is no selection
+ * <li>{@code allMustMatch} is true, but elements other than test methods are selected
+ * </ul>
+ */
+ @Nullable
+ public static List<PsiMethod> getDirectlySelectedMethods(
+ @NotNull ConfigurationContext context, boolean allMustMatch) {
+ final DataContext dataContext = context.getDataContext();
+ PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
+ if (elements == null) {
+ return null;
+ }
+ List<PsiMethod> methods = new ArrayList<>();
+ for (PsiElement element : elements) {
+ if (element instanceof PsiMethod) {
+ PsiMethod method = (PsiMethod) element;
+ if (JUnitUtil.isTestMethod(PsiLocation.fromPsiElement(method))) {
+ methods.add(method);
+ } else if (allMustMatch) {
+ return null;
+ }
+ } else if (allMustMatch) {
+ return null;
+ }
+ }
+ return methods;
+ }
+
+ /**
+ * Get a test method which is considered selected in the given context, belonging to a
+ * non-abstract class. The context location may be the method itself, or anywhere inside the
+ * method.
+ *
+ * @param context The context to search for a test method in.
+ * @return A test method, or null if none are found.
+ */
+ @Nullable
+ public static PsiMethod getIndirectlySelectedMethod(@NotNull ConfigurationContext context) {
+ final Location<?> contextLocation = context.getLocation();
+ if (contextLocation == null) {
+ return null;
+ }
+ Iterator<Location<PsiMethod>> locationIterator =
+ contextLocation.getAncestors(PsiMethod.class, false);
+ while (locationIterator.hasNext()) {
+ Location<PsiMethod> methodLocation = locationIterator.next();
+ if (JUnitUtil.isTestMethod(methodLocation)) {
+ return methodLocation.getPsiElement();
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java b/java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java
new file mode 100644
index 0000000..13062b3
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run.producers;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiModifierList;
+import javax.annotation.Nullable;
+
+/** Maps method and class annotations to our test size enumeration. */
+public class TestSizeAnnotationMap {
+ private static ImmutableMap<String, TestIdeInfo.TestSize> ANNOTATION_TO_TEST_SIZE =
+ ImmutableMap.<String, TestIdeInfo.TestSize>builder()
+ .put("com.google.testing.testsize.SmallTest", TestIdeInfo.TestSize.SMALL)
+ .put("com.google.testing.testsize.MediumTest", TestIdeInfo.TestSize.MEDIUM)
+ .put("com.google.testing.testsize.LargeTest", TestIdeInfo.TestSize.LARGE)
+ .put("com.google.testing.testsize.EnormousTest", TestIdeInfo.TestSize.ENORMOUS)
+ .build();
+
+ @Nullable
+ public static TestIdeInfo.TestSize getTestSize(PsiMethod psiMethod) {
+ PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations();
+ TestIdeInfo.TestSize testSize = getTestSize(annotations);
+ if (testSize != null) {
+ return testSize;
+ }
+ return getTestSize(psiMethod.getContainingClass());
+ }
+
+ @Nullable
+ public static TestIdeInfo.TestSize getTestSize(PsiClass psiClass) {
+ PsiModifierList psiModifierList = psiClass.getModifierList();
+ if (psiModifierList == null) {
+ return null;
+ }
+ PsiAnnotation[] annotations = psiModifierList.getAnnotations();
+ TestIdeInfo.TestSize testSize = getTestSize(annotations);
+ if (testSize == null) {
+ return null;
+ }
+ return testSize;
+ }
+
+ @Nullable
+ private static TestIdeInfo.TestSize getTestSize(PsiAnnotation[] annotations) {
+ for (PsiAnnotation annotation : annotations) {
+ String qualifiedName = annotation.getQualifiedName();
+ TestIdeInfo.TestSize testSize = ANNOTATION_TO_TEST_SIZE.get(qualifiedName);
+ if (testSize != null) {
+ return testSize;
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/settings/BlazeJavaUserSettings.java b/java/src/com/google/idea/blaze/java/settings/BlazeJavaUserSettings.java
new file mode 100644
index 0000000..d9b9d57
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/settings/BlazeJavaUserSettings.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.settings;
+
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.util.xmlb.XmlSerializerUtil;
+import org.jetbrains.annotations.NotNull;
+
+/** Java-specific user settings. */
+@State(name = "BlazeJavaUserSettings", storages = @Storage("blaze.java.user.settings.xml"))
+public class BlazeJavaUserSettings implements PersistentStateComponent<BlazeJavaUserSettings> {
+ private boolean useJarCache = getDefaultJarCacheValue();
+ private boolean attachSourcesByDefault = false;
+ private boolean attachSourcesOnDemand = false;
+ private boolean migrated;
+
+ public static BlazeJavaUserSettings getInstance() {
+ BlazeJavaUserSettings settings = ServiceManager.getService(BlazeJavaUserSettings.class);
+ settings.migrate();
+ return settings;
+ }
+
+ private static boolean getDefaultJarCacheValue() {
+ return BuildSystemProvider.defaultBuildSystem().buildSystem() == Blaze.BuildSystem.Blaze;
+ }
+
+ @Override
+ @NotNull
+ public BlazeJavaUserSettings getState() {
+ return this;
+ }
+
+ @Override
+ public void loadState(BlazeJavaUserSettings state) {
+ XmlSerializerUtil.copyBean(state, this);
+ migrate();
+ }
+
+ /**
+ * Added in 1.8, can be removed ~2.2. When this is removed, java settings can no longer be
+ * migrated. (This is non-catastrophic though -- the settings will just reset)
+ */
+ private void migrate() {
+ if (!migrated) {
+ BlazeUserSettings userSettings = BlazeUserSettings.getInstance();
+ this.attachSourcesByDefault = userSettings.getAttachSourcesByDefault();
+ this.attachSourcesOnDemand = userSettings.getAttachSourcesOnDemand();
+ this.migrated = true;
+ }
+ }
+
+ public boolean getUseJarCache() {
+ return useJarCache;
+ }
+
+ public void setUseJarCache(boolean useJarCache) {
+ this.useJarCache = useJarCache;
+ }
+
+ public boolean getAttachSourcesByDefault() {
+ return attachSourcesByDefault;
+ }
+
+ public void setAttachSourcesByDefault(boolean attachSourcesByDefault) {
+ this.attachSourcesByDefault = attachSourcesByDefault;
+ }
+
+ public boolean getAttachSourcesOnDemand() {
+ return attachSourcesOnDemand;
+ }
+
+ public void setAttachSourcesOnDemand(boolean attachSourcesOnDemand) {
+ this.attachSourcesOnDemand = attachSourcesOnDemand;
+ }
+
+ @SuppressWarnings("unused") // Used by bean serialization
+ public boolean getMigrated() {
+ return migrated;
+ }
+
+ @SuppressWarnings("unused") // Used by bean serialization
+ public void setMigrated(boolean migrated) {
+ this.migrated = migrated;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/settings/BlazeJavaUserSettingsContributor.java b/java/src/com/google/idea/blaze/java/settings/BlazeJavaUserSettingsContributor.java
new file mode 100644
index 0000000..bf5bad9
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/settings/BlazeJavaUserSettingsContributor.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.settings;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.ui.BlazeUserSettingsContributor;
+import com.google.idea.blaze.java.libraries.JarCache;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.uiDesigner.core.GridConstraints;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+/** Contributes java-specific settings. */
+public class BlazeJavaUserSettingsContributor implements BlazeUserSettingsContributor {
+ private JCheckBox useJarCache;
+ private JCheckBox attachSourcesByDefault;
+ private JCheckBox attachSourcesOnDemand;
+ private final ImmutableList<JComponent> components;
+
+ BlazeJavaUserSettingsContributor() {
+ useJarCache = new JCheckBox();
+ useJarCache.setText(
+ String.format(
+ "Use a local jar cache. More robust, but we can miss %s changes made outside the IDE.",
+ Blaze.defaultBuildSystemName()));
+
+ attachSourcesByDefault = new JCheckBox();
+ attachSourcesByDefault.setSelected(false);
+ attachSourcesByDefault.setText(
+ "Automatically attach sources on project sync (WARNING: increases index time by 100%+)");
+
+ attachSourcesByDefault.addActionListener(
+ (event) -> {
+ BlazeJavaUserSettings settings = BlazeJavaUserSettings.getInstance();
+ if (attachSourcesByDefault.isSelected() && !settings.getAttachSourcesByDefault()) {
+ int result =
+ Messages.showOkCancelDialog(
+ "You are turning on source jars by default. "
+ + "This setting increases indexing time by "
+ + ">100%, can cost ~1GB RAM, and will increase "
+ + "project reopen time significantly. "
+ + "Are you sure you want to proceed?",
+ "Turn On Sources By Default?", null);
+ if (result != Messages.OK) {
+ attachSourcesByDefault.setSelected(false);
+ }
+ }
+ });
+
+ attachSourcesOnDemand = new JCheckBox();
+ attachSourcesOnDemand.setSelected(false);
+ attachSourcesOnDemand.setText("Automatically attach sources when you open decompiled source");
+
+ ImmutableList.Builder<JComponent> builder = ImmutableList.builder();
+ if (JarCache.ENABLE_JAR_CACHE.getValue()) {
+ builder.add(useJarCache);
+ }
+ builder.add(attachSourcesOnDemand).add(attachSourcesByDefault);
+ components = builder.build();
+ }
+
+ @Override
+ public void apply() {
+ BlazeJavaUserSettings settings = BlazeJavaUserSettings.getInstance();
+ settings.setUseJarCache(useJarCache.isSelected());
+ settings.setAttachSourcesByDefault(attachSourcesByDefault.isSelected());
+ settings.setAttachSourcesOnDemand(attachSourcesOnDemand.isSelected());
+ }
+
+ @Override
+ public void reset() {
+ BlazeJavaUserSettings settings = BlazeJavaUserSettings.getInstance();
+ useJarCache.setSelected(settings.getUseJarCache());
+ attachSourcesByDefault.setSelected(settings.getAttachSourcesByDefault());
+ attachSourcesOnDemand.setSelected(settings.getAttachSourcesOnDemand());
+ }
+
+ @Override
+ public boolean isModified() {
+ BlazeJavaUserSettings settings = BlazeJavaUserSettings.getInstance();
+ return !Objects.equal(useJarCache.isSelected(), settings.getUseJarCache())
+ || !Objects.equal(attachSourcesByDefault.isSelected(), settings.getAttachSourcesByDefault())
+ || !Objects.equal(attachSourcesOnDemand.isSelected(), settings.getAttachSourcesOnDemand());
+ }
+
+ @Override
+ public int getRowCount() {
+ return components.size();
+ }
+
+ @Override
+ public int addComponents(JPanel panel, int rowi) {
+ for (JComponent contributedComponent : components) {
+ panel.add(
+ contributedComponent,
+ new GridConstraints(
+ rowi++,
+ 0,
+ 1,
+ 2,
+ GridConstraints.ANCHOR_NORTHWEST,
+ GridConstraints.FILL_NONE,
+ GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
+ GridConstraints.SIZEPOLICY_FIXED,
+ null,
+ null,
+ null,
+ 0,
+ false));
+ }
+ return rowi;
+ }
+
+ static class BlazeJavaUserSettingsProvider implements BlazeUserSettingsContributor.Provider {
+ @Override
+ public BlazeUserSettingsContributor getContributor() {
+ return new BlazeJavaUserSettingsContributor();
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
new file mode 100644
index 0000000..7bd32d9
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.util.Collection;
+import java.util.List;
+
+/** Augments the java importer */
+public interface BlazeJavaSyncAugmenter {
+ ExtensionPointName<BlazeJavaSyncAugmenter> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.java.JavaSyncAugmenter");
+
+ static Collection<BlazeJavaSyncAugmenter> getActiveSyncAgumenters(
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
+ List<BlazeJavaSyncAugmenter> result = Lists.newArrayList();
+ for (BlazeJavaSyncAugmenter augmenter : EP_NAME.getExtensions()) {
+ if (augmenter.isActive(workspaceLanguageSettings)) {
+ result.add(augmenter);
+ }
+ }
+ return result;
+ }
+
+ boolean isActive(WorkspaceLanguageSettings workspaceLanguageSettings);
+
+ /**
+ * Adds extra libraries for this source rule.
+ *
+ * @param jars The output jars for the rule. Subject to jdeps optimization.
+ * @param genJars Generated jars from this rule. Added unconditionally.
+ */
+ void addJarsForSourceRule(
+ RuleIdeInfo rule, Collection<BlazeJarLibrary> jars, Collection<BlazeJarLibrary> genJars);
+
+ /**
+ * Adds any library filters. Useful if some libraries are supplied by this plugin in some other
+ * way, eg. via an SDK.
+ */
+ void addLibraryFilter(Glob.GlobSet excludedLibraries);
+
+ /** Called during the project structure phase to get additional libraries. */
+ Collection<BlazeLibrary> getAdditionalLibraries(BlazeProjectData blazeProjectData);
+
+ /**
+ * Returns a collection of library names for libraries that are added by some framework and
+ * shouldn't be removed during sync. Examples are typescript and dart support.
+ */
+ Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData);
+
+ /** Adapter class for the sync augmenter interface */
+ abstract class Adapter implements BlazeJavaSyncAugmenter {
+ @Override
+ public void addJarsForSourceRule(
+ RuleIdeInfo rule, Collection<BlazeJarLibrary> jars, Collection<BlazeJarLibrary> genJars) {}
+
+ @Override
+ public void addLibraryFilter(Glob.GlobSet excludedLibraries) {}
+
+ @Override
+ public Collection<BlazeLibrary> getAdditionalLibraries(BlazeProjectData blazeProjectData) {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public Collection<String> getExternallyAddedLibraries(BlazeProjectData blazeProjectData) {
+ return ImmutableList.of();
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
new file mode 100644
index 0000000..9d6eb17
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.output.PerformanceWarning;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.java.projectview.ExcludeLibrarySection;
+import com.google.idea.blaze.java.projectview.ExcludedLibrarySection;
+import com.google.idea.blaze.java.projectview.JavaLanguageLevelSection;
+import com.google.idea.blaze.java.sync.importer.BlazeJavaWorkspaceImporter;
+import com.google.idea.blaze.java.sync.jdeps.JdepsFileReader;
+import com.google.idea.blaze.java.sync.jdeps.JdepsMap;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.google.idea.blaze.java.sync.projectstructure.Jdks;
+import com.google.idea.blaze.java.sync.projectstructure.LibraryEditor;
+import com.google.idea.blaze.java.sync.projectstructure.SourceFolderEditor;
+import com.google.idea.blaze.java.sync.workingset.JavaWorkingSet;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.util.ui.UIUtil;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/** Sync support for Java. */
+public class BlazeJavaSyncPlugin extends BlazeSyncPlugin.Adapter {
+ private static final Logger LOG = Logger.getInstance(BlazeJavaSyncPlugin.class);
+ private final JdepsFileReader jdepsFileReader = new JdepsFileReader();
+
+ @Nullable
+ @Override
+ public WorkspaceType getDefaultWorkspaceType() {
+ return WorkspaceType.JAVA;
+ }
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ if (workspaceType == WorkspaceType.JAVA) {
+ return ImmutableSet.of(LanguageClass.JAVA);
+ }
+ return ImmutableSet.of();
+ }
+
+ @Nullable
+ @Override
+ public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
+ if (workspaceType == WorkspaceType.JAVA) {
+ return StdModuleTypes.JAVA;
+ }
+ return null;
+ }
+
+ @Override
+ public void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeRoots blazeRoots,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {
+ JavaWorkingSet javaWorkingSet = null;
+ if (workingSet != null) {
+ javaWorkingSet = new JavaWorkingSet(workspaceRoot, workingSet);
+ }
+
+ JdepsMap jdepsMap =
+ jdepsFileReader.loadJdepsFiles(
+ project, context, ruleMap, syncStateBuilder, previousSyncState);
+ if (context.isCancelled()) {
+ return;
+ }
+
+ BlazeJavaWorkspaceImporter blazeJavaWorkspaceImporter =
+ new BlazeJavaWorkspaceImporter(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ workspaceLanguageSettings,
+ ruleMap,
+ jdepsMap,
+ javaWorkingSet,
+ new ArtifactLocationDecoder(blazeRoots, workspacePathResolver));
+ BlazeJavaImportResult importResult =
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("JavaWorkspaceImporter"));
+ return blazeJavaWorkspaceImporter.importWorkspace(childContext);
+ });
+ Glob.GlobSet excludedLibraries =
+ new Glob.GlobSet(
+ ImmutableList.<Glob>builder()
+ .addAll(projectViewSet.listItems(ExcludeLibrarySection.KEY))
+ .addAll(projectViewSet.listItems(ExcludedLibrarySection.KEY))
+ .build());
+ for (BlazeJavaSyncAugmenter augmenter :
+ BlazeJavaSyncAugmenter.getActiveSyncAgumenters(workspaceLanguageSettings)) {
+ augmenter.addLibraryFilter(excludedLibraries);
+ }
+ BlazeJavaSyncData syncData = new BlazeJavaSyncData(importResult, excludedLibraries);
+ syncStateBuilder.put(BlazeJavaSyncData.class, syncData);
+ }
+
+ @Override
+ public void updateSdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData) {
+ if (!blazeProjectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.JAVA)) {
+ return;
+ }
+ updateJdk(project, context, projectViewSet, blazeProjectData);
+ }
+
+ @Override
+ public void updateContentEntries(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<ContentEntry> contentEntries) {
+ if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.JAVA)) {
+ return;
+ }
+ BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ return;
+ }
+
+ SourceFolderEditor.modifyContentEntries(syncData.importResult, contentEntries);
+ }
+
+ @Override
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
+ BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ return;
+ }
+
+ List<BlazeLibrary> libraries = BlazeLibraryCollector.getLibraries(blazeProjectData);
+
+ Scope.push(
+ context,
+ childContext -> {
+ childContext.push(new TimingScope("UpdateLibraries"));
+ LibraryEditor.updateProjectLibraries(project, context, blazeProjectData, libraries);
+ });
+
+ LibraryEditor.configureDependencies(workspaceModifiableModel, libraries);
+ }
+
+ private static void updateJdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData) {
+
+ LanguageLevel javaLanguageLevel =
+ JavaLanguageLevelHelper.getJavaLanguageLevel(
+ projectViewSet, blazeProjectData, LanguageLevel.JDK_1_7);
+
+ final Sdk sdk = Jdks.chooseOrCreateJavaSdk(javaLanguageLevel);
+ if (sdk == null) {
+ String msg =
+ String.format(
+ "Unable to find a JDK %1$s installed.\n", javaLanguageLevel.getPresentableText());
+ msg +=
+ "After configuring a suitable JDK in the \"Project Structure\" dialog, "
+ + "sync the project again.";
+ IssueOutput.error(msg).submit(context);
+ return;
+ }
+ setProjectSdkAndLanguageLevel(project, sdk, javaLanguageLevel);
+ }
+
+ private static void setProjectSdkAndLanguageLevel(
+ final Project project, final Sdk sdk, final LanguageLevel javaLanguageLevel) {
+ UIUtil.invokeAndWaitIfNeeded(
+ (Runnable)
+ () ->
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ ProjectRootManagerEx rootManager =
+ ProjectRootManagerEx.getInstanceEx(project);
+ rootManager.setProjectSdk(sdk);
+ LanguageLevelProjectExtension ext =
+ LanguageLevelProjectExtension.getInstance(project);
+ ext.setLanguageLevel(javaLanguageLevel);
+ }));
+ }
+
+ @Override
+ public boolean validate(
+ Project project, BlazeContext context, BlazeProjectData blazeProjectData) {
+ BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ return true;
+ }
+ warnAboutDeployJars(context, syncData);
+ return true;
+ }
+
+ @Override
+ public Collection<SectionParser> getSections() {
+ return ImmutableList.of(
+ ExcludedLibrarySection.PARSER,
+ ExcludeLibrarySection.PARSER,
+ JavaLanguageLevelSection.PARSER);
+ }
+
+ @Override
+ public boolean requiresResolveIdeArtifacts() {
+ return true;
+ }
+
+ /**
+ * Looks at your jars for anything that seems to be a deploy jar and warns about it. This often
+ * turns out to be a duplicate copy of all your application's code, so you don't want it in your
+ * project.
+ */
+ private static void warnAboutDeployJars(BlazeContext context, BlazeJavaSyncData syncData) {
+ for (BlazeLibrary library : syncData.importResult.libraries.values()) {
+ if (!(library instanceof BlazeJarLibrary)) {
+ continue;
+ }
+ BlazeJarLibrary jarLibrary = (BlazeJarLibrary) library;
+ LibraryArtifact libraryArtifact = jarLibrary.libraryArtifact;
+ ArtifactLocation artifactLocation = libraryArtifact.jarForIntellijLibrary();
+ if (artifactLocation.getRelativePath().endsWith("deploy.jar")
+ || artifactLocation.getRelativePath().endsWith("deploy-ijar.jar")
+ || artifactLocation.getRelativePath().endsWith("deploy-hjar.jar")) {
+ context.output(
+ new PerformanceWarning(
+ "Performance warning: You have added a deploy jar as a library. "
+ + "This can lead to poor indexing performance, and the debugger may "
+ + "become confused and step into the deploy jar instead of your code. "
+ + "Consider redoing the rule to not use deploy jars, exclude the target "
+ + "from your .blazeproject, or exclude the library.\n"
+ + "Library path: "
+ + artifactLocation.getRelativePath()));
+ }
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/BlazeLibraryCollector.java b/java/src/com/google/idea/blaze/java/sync/BlazeLibraryCollector.java
new file mode 100644
index 0000000..99cd0b5
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/BlazeLibraryCollector.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Collects libraries from the sync data using all contributors. */
+public class BlazeLibraryCollector {
+ public static List<BlazeLibrary> getLibraries(BlazeProjectData blazeProjectData) {
+ BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ return ImmutableList.of();
+ }
+
+ Glob.GlobSet excludedLibraries = syncData.excludedLibraries;
+
+ List<BlazeLibrary> libraries = Lists.newArrayList();
+ libraries.addAll(syncData.importResult.libraries.values());
+ for (BlazeJavaSyncAugmenter augmenter :
+ BlazeJavaSyncAugmenter.getActiveSyncAgumenters(
+ blazeProjectData.workspaceLanguageSettings)) {
+ libraries.addAll(augmenter.getAdditionalLibraries(blazeProjectData));
+ }
+ return libraries
+ .stream()
+ .filter(blazeLibrary -> !isExcluded(excludedLibraries, blazeLibrary))
+ .collect(Collectors.toList());
+ }
+
+ private static boolean isExcluded(Glob.GlobSet excludedLibraries, BlazeLibrary blazeLibrary) {
+ if (!(blazeLibrary instanceof BlazeJarLibrary)) {
+ return false;
+ }
+ BlazeJarLibrary jarLibrary = (BlazeJarLibrary) blazeLibrary;
+ ArtifactLocation interfaceJar = jarLibrary.libraryArtifact.interfaceJar;
+ ArtifactLocation classJar = jarLibrary.libraryArtifact.classJar;
+ return (interfaceJar != null && excludedLibraries.matches(interfaceJar.getRelativePath()))
+ || (classJar != null && excludedLibraries.matches(classJar.getRelativePath()));
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java b/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
new file mode 100644
index 0000000..9357346
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.PerformanceWarning;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/** Detects and reports duplicate sources */
+public class DuplicateSourceDetector {
+ Multimap<ArtifactLocation, Label> artifacts = ArrayListMultimap.create();
+
+ public void add(Label label, ArtifactLocation artifactLocation) {
+ artifacts.put(artifactLocation, label);
+ }
+
+ static class Duplicate {
+ final ArtifactLocation artifactLocation;
+ final Collection<Label> labels;
+
+ public Duplicate(ArtifactLocation artifactLocation, Collection<Label> labels) {
+ this.artifactLocation = artifactLocation;
+ this.labels = labels;
+ }
+ }
+
+ public void reportDuplicates(BlazeContext context) {
+ List<Duplicate> duplicates = Lists.newArrayList();
+ for (ArtifactLocation key : artifacts.keySet()) {
+ Collection<Label> labels = artifacts.get(key);
+ if (labels.size() > 1) {
+
+ // Workaround for aspect bug. Can be removed after the next blaze release, as of May 27 2016
+ Set<Label> labelSet = Sets.newHashSet(labels);
+ if (labelSet.size() > 1) {
+ duplicates.add(new Duplicate(key, labelSet));
+ }
+ }
+ }
+
+ if (duplicates.isEmpty()) {
+ return;
+ }
+
+ Collections.sort(
+ duplicates,
+ (lhs, rhs) ->
+ lhs.artifactLocation
+ .getRelativePath()
+ .compareTo(rhs.artifactLocation.getRelativePath()));
+
+ context.output(new PerformanceWarning("Duplicate sources detected:"));
+ for (Duplicate duplicate : duplicates) {
+ ArtifactLocation artifactLocation = duplicate.artifactLocation;
+ context.output(new PerformanceWarning(" Source: " + artifactLocation.getRelativePath()));
+ context.output(new PerformanceWarning(" Consumed by rules:"));
+ for (Label label : duplicate.labels) {
+ context.output(new PerformanceWarning(" " + label));
+ }
+ context.output(new PerformanceWarning("")); // Newline
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/JavaLanguageLevelHelper.java b/java/src/com/google/idea/blaze/java/sync/JavaLanguageLevelHelper.java
new file mode 100644
index 0000000..c0c3dd3
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/JavaLanguageLevelHelper.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import com.google.common.base.Strings;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.java.projectview.JavaLanguageLevelSection;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.intellij.pom.java.LanguageLevel;
+
+/** Called by sync plugins to determine the appropriate java language level. */
+public class JavaLanguageLevelHelper {
+
+ public static LanguageLevel getJavaLanguageLevel(
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ LanguageLevel defaultLanguageLevel) {
+
+ defaultLanguageLevel = getLanguageLevelFromToolchain(blazeProjectData, defaultLanguageLevel);
+ return JavaLanguageLevelSection.getLanguageLevel(projectViewSet, defaultLanguageLevel);
+ }
+
+ private static LanguageLevel getLanguageLevelFromToolchain(
+ BlazeProjectData blazeProjectData, LanguageLevel defaultLanguageLevel) {
+ BlazeJavaSyncData blazeJavaSyncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (blazeJavaSyncData != null) {
+ String sourceVersion = blazeJavaSyncData.importResult.sourceVersion;
+ if (!Strings.isNullOrEmpty(sourceVersion)) {
+ switch (sourceVersion) {
+ case "6":
+ return LanguageLevel.JDK_1_6;
+ case "7":
+ return LanguageLevel.JDK_1_7;
+ case "8":
+ return LanguageLevel.JDK_1_8;
+ case "9":
+ return LanguageLevel.JDK_1_9;
+ }
+ }
+ }
+ return defaultLanguageLevel;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java b/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java
new file mode 100644
index 0000000..b77741a
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.prefetch.PrefetchFileSource;
+import com.google.idea.blaze.java.libraries.JarCache;
+import com.google.idea.blaze.java.libraries.SourceJarManager;
+import com.google.idea.blaze.java.settings.BlazeJavaUserSettings;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Set;
+
+/** Adds the jars to prefetch. */
+public class JavaPrefetchFileSource implements PrefetchFileSource {
+ @Override
+ public void addFilesToPrefetch(
+ Project project, BlazeProjectData blazeProjectData, Collection<File> files) {
+ BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ return;
+ }
+ // If we have a local jar cache we don't need to prefetch anything
+ if (JarCache.getInstance(project).isEnabled()) {
+ return;
+ }
+ boolean attachSourcesByDefault =
+ BlazeJavaUserSettings.getInstance().getAttachSourcesByDefault();
+ SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
+ Collection<BlazeLibrary> libraries = BlazeLibraryCollector.getLibraries(blazeProjectData);
+ for (BlazeLibrary library : libraries) {
+ if (!(library instanceof BlazeJarLibrary)) {
+ continue;
+ }
+ BlazeJarLibrary jarLibrary = (BlazeJarLibrary) library;
+ files.add(jarLibrary.libraryArtifact.jarForIntellijLibrary().getFile());
+
+ boolean attachSourceJar =
+ attachSourcesByDefault || sourceJarManager.hasSourceJarAttached(jarLibrary.key);
+ if (attachSourceJar && jarLibrary.libraryArtifact.sourceJar != null) {
+ files.add(jarLibrary.libraryArtifact.sourceJar.getFile());
+ }
+ }
+ }
+
+ @Override
+ public Set<String> prefetchSrcFileExtensions() {
+ return ImmutableSet.of("java");
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java b/java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java
new file mode 100644
index 0000000..61d7155
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.importer;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.ProtoLibraryLegacyInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.google.idea.blaze.base.sync.projectview.ProjectViewRuleImportFilter;
+import com.google.idea.blaze.base.sync.projectview.SourceTestConfig;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
+import com.google.idea.blaze.java.sync.DuplicateSourceDetector;
+import com.google.idea.blaze.java.sync.jdeps.JdepsMap;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.google.idea.blaze.java.sync.source.SourceArtifact;
+import com.google.idea.blaze.java.sync.source.SourceDirectoryCalculator;
+import com.google.idea.blaze.java.sync.workingset.JavaWorkingSet;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** Builds a BlazeWorkspace. */
+public final class BlazeJavaWorkspaceImporter {
+ private static final Logger LOG = Logger.getInstance(BlazeJavaWorkspaceImporter.class);
+
+ private static final BoolExperiment NO_EMPTY_SOURCE_RULES =
+ new BoolExperiment("no.empty.source.rules", true);
+
+ private final Project project;
+ private final BlazeContext context;
+ private final WorkspaceRoot workspaceRoot;
+ private final ImportRoots importRoots;
+ private final RuleMap ruleMap;
+ private final SourceTestConfig sourceTestConfig;
+ private final JdepsMap jdepsMap;
+ @Nullable private final JavaWorkingSet workingSet;
+ private final ArtifactLocationDecoder artifactLocationDecoder;
+ private final ProjectViewRuleImportFilter importFilter;
+ private final DuplicateSourceDetector duplicateSourceDetector = new DuplicateSourceDetector();
+ private final Collection<BlazeJavaSyncAugmenter> augmenters;
+
+ public BlazeJavaWorkspaceImporter(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ RuleMap ruleMap,
+ JdepsMap jdepsMap,
+ @Nullable JavaWorkingSet workingSet,
+ ArtifactLocationDecoder artifactLocationDecoder) {
+ this.project = project;
+ this.context = context;
+ this.workspaceRoot = workspaceRoot;
+ this.importRoots =
+ ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
+ .add(projectViewSet)
+ .build();
+ this.ruleMap = ruleMap;
+ this.jdepsMap = jdepsMap;
+ this.workingSet = workingSet;
+ this.artifactLocationDecoder = artifactLocationDecoder;
+ this.importFilter = new ProjectViewRuleImportFilter(project, workspaceRoot, projectViewSet);
+ this.sourceTestConfig = new SourceTestConfig(projectViewSet);
+ this.augmenters = BlazeJavaSyncAugmenter.getActiveSyncAgumenters(workspaceLanguageSettings);
+ }
+
+ public BlazeJavaImportResult importWorkspace(BlazeContext context) {
+ List<RuleIdeInfo> includedRules =
+ ruleMap
+ .rules()
+ .stream()
+ .filter(rule -> !importFilter.excludeTarget(rule))
+ .collect(Collectors.toList());
+
+ List<RuleIdeInfo> javaRules =
+ includedRules
+ .stream()
+ .filter(rule -> rule.javaRuleIdeInfo != null)
+ .collect(Collectors.toList());
+
+ Map<Label, Collection<ArtifactLocation>> ruleToJavaSources = Maps.newHashMap();
+ for (RuleIdeInfo rule : javaRules) {
+ List<ArtifactLocation> javaSources =
+ rule.sources
+ .stream()
+ .filter(source -> source.getRelativePath().endsWith(".java"))
+ .collect(Collectors.toList());
+ ruleToJavaSources.put(rule.label, javaSources);
+ }
+
+ boolean noEmptySourceRules = NO_EMPTY_SOURCE_RULES.getValue();
+ List<RuleIdeInfo> sourceRules = Lists.newArrayList();
+ List<RuleIdeInfo> libraryRules = Lists.newArrayList();
+ for (RuleIdeInfo rule : javaRules) {
+ boolean importAsSource =
+ importFilter.isSourceRule(rule)
+ && canImportAsSource(rule)
+ && (noEmptySourceRules
+ ? anyNonGeneratedSources(ruleToJavaSources.get(rule.label))
+ : !allSourcesGenerated(ruleToJavaSources.get(rule.label)));
+
+ if (importAsSource) {
+ sourceRules.add(rule);
+ } else {
+ libraryRules.add(rule);
+ }
+ }
+
+ List<RuleIdeInfo> protoLibraries =
+ includedRules
+ .stream()
+ .filter(rule -> rule.kind == Kind.PROTO_LIBRARY)
+ .collect(Collectors.toList());
+
+ WorkspaceBuilder workspaceBuilder = new WorkspaceBuilder();
+ for (RuleIdeInfo rule : sourceRules) {
+ addRuleAsSource(workspaceBuilder, rule, ruleToJavaSources.get(rule.label));
+ }
+
+ SourceDirectoryCalculator sourceDirectoryCalculator = new SourceDirectoryCalculator();
+ ImmutableList<BlazeContentEntry> contentEntries =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ sourceTestConfig,
+ artifactLocationDecoder,
+ importRoots.rootDirectories(),
+ workspaceBuilder.sourceArtifacts,
+ workspaceBuilder.javaPackageManifests);
+
+ int totalContentEntryCount = 0;
+ for (BlazeContentEntry contentEntry : contentEntries) {
+ totalContentEntryCount += contentEntry.sources.size();
+ }
+ context.output(PrintOutput.log("Java content entry count: " + totalContentEntryCount));
+
+ ImmutableMap<LibraryKey, BlazeJarLibrary> libraries =
+ buildLibraries(workspaceBuilder, ruleMap, libraryRules, protoLibraries);
+
+ duplicateSourceDetector.reportDuplicates(context);
+
+ String sourceVersion = findSourceVersion(ruleMap);
+
+ return new BlazeJavaImportResult(
+ contentEntries,
+ libraries,
+ ImmutableList.copyOf(
+ workspaceBuilder.buildOutputJars.stream().sorted().collect(Collectors.toList())),
+ ImmutableSet.copyOf(workspaceBuilder.addedSourceFiles),
+ sourceVersion);
+ }
+
+ private boolean canImportAsSource(RuleIdeInfo rule) {
+ return !rule.kindIsOneOf(Kind.JAVA_WRAP_CC, Kind.JAVA_IMPORT);
+ }
+
+ private boolean allSourcesGenerated(Collection<ArtifactLocation> sources) {
+ return !sources.isEmpty() && sources.stream().allMatch(ArtifactLocation::isGenerated);
+ }
+
+ private boolean anyNonGeneratedSources(Collection<ArtifactLocation> sources) {
+ return sources.stream().anyMatch(ArtifactLocation::isSource);
+ }
+
+ private ImmutableMap<LibraryKey, BlazeJarLibrary> buildLibraries(
+ WorkspaceBuilder workspaceBuilder,
+ RuleMap ruleMap,
+ List<RuleIdeInfo> libraryRules,
+ List<RuleIdeInfo> protoLibraries) {
+ // Build library maps
+ Multimap<Label, BlazeJarLibrary> labelToLibrary = ArrayListMultimap.create();
+ Map<String, BlazeJarLibrary> jdepsPathToLibrary = Maps.newHashMap();
+
+ // Add any output jars from source rules
+ for (Label label : workspaceBuilder.outputJarsFromSourceRules.keySet()) {
+ Collection<BlazeJarLibrary> jars = workspaceBuilder.outputJarsFromSourceRules.get(label);
+ labelToLibrary.putAll(label, jars);
+ for (BlazeJarLibrary library : jars) {
+ addLibraryToJdeps(jdepsPathToLibrary, library);
+ }
+ }
+
+ for (RuleIdeInfo rule : libraryRules) {
+ JavaRuleIdeInfo javaRuleIdeInfo = rule.javaRuleIdeInfo;
+ if (javaRuleIdeInfo == null) {
+ continue;
+ }
+ List<LibraryArtifact> allJars = Lists.newArrayList();
+ allJars.addAll(javaRuleIdeInfo.jars);
+ Collection<BlazeJarLibrary> libraries =
+ allJars
+ .stream()
+ .map(library -> new BlazeJarLibrary(library, rule.label))
+ .collect(Collectors.toList());
+
+ labelToLibrary.putAll(rule.label, libraries);
+ for (BlazeJarLibrary library : libraries) {
+ addLibraryToJdeps(jdepsPathToLibrary, library);
+ }
+ }
+
+ // proto legacy jdeps support
+ for (RuleIdeInfo rule : protoLibraries) {
+ ProtoLibraryLegacyInfo protoLibraryLegacyInfo = rule.protoLibraryLegacyInfo;
+ if (protoLibraryLegacyInfo == null) {
+ continue;
+ }
+ for (LibraryArtifact libraryArtifact :
+ Iterables.concat(
+ protoLibraryLegacyInfo.jarsV1,
+ protoLibraryLegacyInfo.jarsMutable,
+ protoLibraryLegacyInfo.jarsImmutable)) {
+ addLibraryToJdeps(jdepsPathToLibrary, new BlazeJarLibrary(libraryArtifact, rule.label));
+ }
+ }
+
+ Map<LibraryKey, BlazeJarLibrary> result = Maps.newHashMap();
+
+ // Collect jars from jdep references
+ for (String jdepsPath : workspaceBuilder.jdeps) {
+ BlazeJarLibrary library = jdepsPathToLibrary.get(jdepsPath);
+ if (library != null) {
+ result.put(library.key, library);
+ }
+ }
+
+ // Collect jars referenced by direct deps from your working set
+ for (Label deps : workspaceBuilder.directDeps) {
+ for (BlazeJarLibrary library : labelToLibrary.get(deps)) {
+ result.put(library.key, library);
+ }
+ }
+
+ // Collect legacy proto libraries from direct deps
+ addProtoLegacyLibrariesFromDirectDeps(workspaceBuilder, ruleMap, result);
+
+ // Collect generated jars from source rules
+ for (BlazeJarLibrary library : workspaceBuilder.generatedJarsFromSourceRules) {
+ result.put(library.key, library);
+ }
+
+ return ImmutableMap.copyOf(result);
+ }
+
+ private void addProtoLegacyLibrariesFromDirectDeps(
+ WorkspaceBuilder workspaceBuilder, RuleMap ruleMap, Map<LibraryKey, BlazeJarLibrary> result) {
+ List<Label> version1Roots = Lists.newArrayList();
+ List<Label> immutableRoots = Lists.newArrayList();
+ List<Label> mutableRoots = Lists.newArrayList();
+ for (Label label : workspaceBuilder.directDeps) {
+ RuleIdeInfo rule = ruleMap.get(label);
+ if (rule == null) {
+ continue;
+ }
+ ProtoLibraryLegacyInfo protoLibraryLegacyInfo = rule.protoLibraryLegacyInfo;
+ if (protoLibraryLegacyInfo == null) {
+ continue;
+ }
+ switch (protoLibraryLegacyInfo.apiFlavor) {
+ case VERSION_1:
+ version1Roots.add(label);
+ break;
+ case IMMUTABLE:
+ immutableRoots.add(label);
+ break;
+ case MUTABLE:
+ mutableRoots.add(label);
+ break;
+ case BOTH:
+ mutableRoots.add(label);
+ immutableRoots.add(label);
+ break;
+ default:
+ // Can't happen
+ break;
+ }
+ }
+
+ addProtoLegacyLibrariesFromDirectDepsForFlavor(
+ ruleMap, ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1, version1Roots, result);
+ addProtoLegacyLibrariesFromDirectDepsForFlavor(
+ ruleMap, ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE, immutableRoots, result);
+ addProtoLegacyLibrariesFromDirectDepsForFlavor(
+ ruleMap, ProtoLibraryLegacyInfo.ApiFlavor.MUTABLE, mutableRoots, result);
+ }
+
+ private void addProtoLegacyLibrariesFromDirectDepsForFlavor(
+ RuleMap ruleMap,
+ ProtoLibraryLegacyInfo.ApiFlavor apiFlavor,
+ List<Label> roots,
+ Map<LibraryKey, BlazeJarLibrary> result) {
+ Set<Label> seen = Sets.newHashSet();
+ while (!roots.isEmpty()) {
+ Label label = roots.remove(roots.size() - 1);
+ if (!seen.add(label)) {
+ continue;
+ }
+ RuleIdeInfo rule = ruleMap.get(label);
+ if (rule == null) {
+ continue;
+ }
+ ProtoLibraryLegacyInfo protoLibraryLegacyInfo = rule.protoLibraryLegacyInfo;
+ if (protoLibraryLegacyInfo == null) {
+ continue;
+ }
+ final Collection<LibraryArtifact> libraries;
+ switch (apiFlavor) {
+ case VERSION_1:
+ libraries = protoLibraryLegacyInfo.jarsV1;
+ break;
+ case MUTABLE:
+ libraries = protoLibraryLegacyInfo.jarsMutable;
+ break;
+ case IMMUTABLE:
+ libraries = protoLibraryLegacyInfo.jarsImmutable;
+ break;
+ default:
+ // Can't happen
+ libraries = null;
+ break;
+ }
+
+ if (libraries != null) {
+ for (LibraryArtifact libraryArtifact : libraries) {
+ BlazeJarLibrary library = new BlazeJarLibrary(libraryArtifact, label);
+ result.put(library.key, library);
+ }
+ }
+
+ roots.addAll(rule.dependencies);
+ }
+ }
+
+ private void addLibraryToJdeps(
+ Map<String, BlazeJarLibrary> jdepsPathToLibrary, BlazeJarLibrary library) {
+ LibraryArtifact libraryArtifact = library.libraryArtifact;
+ ArtifactLocation interfaceJar = libraryArtifact.interfaceJar;
+ if (interfaceJar != null) {
+ jdepsPathToLibrary.put(interfaceJar.getExecutionRootRelativePath(), library);
+ }
+ ArtifactLocation classJar = libraryArtifact.classJar;
+ if (classJar != null) {
+ jdepsPathToLibrary.put(classJar.getExecutionRootRelativePath(), library);
+ }
+ }
+
+ private void addRuleAsSource(
+ WorkspaceBuilder workspaceBuilder,
+ RuleIdeInfo rule,
+ Collection<ArtifactLocation> javaSources) {
+ JavaRuleIdeInfo javaRuleIdeInfo = rule.javaRuleIdeInfo;
+ if (javaRuleIdeInfo == null) {
+ return;
+ }
+
+ Label label = rule.label;
+ Collection<String> jars = jdepsMap.getDependenciesForRule(label);
+ if (jars != null) {
+ workspaceBuilder.jdeps.addAll(jars);
+ }
+
+ // Add all deps if this rule is in the current working set
+ if (workingSet == null || workingSet.isRuleInWorkingSet(rule)) {
+ workspaceBuilder.directDeps.add(
+ label); // Add self, so we pick up our own gen jars if in working set
+ workspaceBuilder.directDeps.addAll(rule.dependencies);
+ }
+
+ for (ArtifactLocation artifactLocation : javaSources) {
+ if (artifactLocation.isSource()) {
+ duplicateSourceDetector.add(label, artifactLocation);
+ workspaceBuilder.sourceArtifacts.add(new SourceArtifact(label, artifactLocation));
+ workspaceBuilder.addedSourceFiles.add(artifactLocation.getFile());
+ }
+ }
+
+ ArtifactLocation manifest = javaRuleIdeInfo.packageManifest;
+ if (manifest != null) {
+ workspaceBuilder.javaPackageManifests.put(label, manifest);
+ }
+ for (LibraryArtifact libraryArtifact : javaRuleIdeInfo.jars) {
+ ArtifactLocation classJar = libraryArtifact.classJar;
+ if (classJar != null) {
+ workspaceBuilder.buildOutputJars.add(classJar.getFile());
+ }
+ }
+ workspaceBuilder.generatedJarsFromSourceRules.addAll(
+ javaRuleIdeInfo
+ .generatedJars
+ .stream()
+ .map(libraryArtifact -> new BlazeJarLibrary(libraryArtifact, label))
+ .collect(Collectors.toList()));
+ if (javaRuleIdeInfo.filteredGenJar != null) {
+ workspaceBuilder.generatedJarsFromSourceRules.add(
+ new BlazeJarLibrary(javaRuleIdeInfo.filteredGenJar, label));
+ }
+
+ for (BlazeJavaSyncAugmenter augmenter : augmenters) {
+ augmenter.addJarsForSourceRule(
+ rule,
+ workspaceBuilder.outputJarsFromSourceRules.get(label),
+ workspaceBuilder.generatedJarsFromSourceRules);
+ }
+ }
+
+ @Nullable
+ private String findSourceVersion(RuleMap ruleMap) {
+ for (RuleIdeInfo rule : ruleMap.rules()) {
+ if (rule.javaToolchainIdeInfo != null) {
+ return rule.javaToolchainIdeInfo.sourceVersion;
+ }
+ }
+ return null;
+ }
+
+ static class WorkspaceBuilder {
+ Set<String> jdeps = Sets.newHashSet();
+ Set<Label> directDeps = Sets.newHashSet();
+ Set<File> addedSourceFiles = Sets.newHashSet();
+ Multimap<Label, BlazeJarLibrary> outputJarsFromSourceRules = ArrayListMultimap.create();
+ List<BlazeJarLibrary> generatedJarsFromSourceRules = Lists.newArrayList();
+ List<File> buildOutputJars = Lists.newArrayList();
+ List<SourceArtifact> sourceArtifacts = Lists.newArrayList();
+ Map<Label, ArtifactLocation> javaPackageManifests = Maps.newHashMap();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsFileReader.java b/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsFileReader.java
new file mode 100644
index 0000000..4570965
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsFileReader.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.jdeps;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.async.FutureUtil;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.filecache.FileDiffer;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.prefetch.PrefetchService;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.repackaged.devtools.build.lib.view.proto.Deps;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.annotation.Nullable;
+
+/** Reads jdeps from the ide info result. */
+public class JdepsFileReader {
+ private static final Logger LOG = Logger.getInstance(JdepsFileReader.class);
+
+ static class JdepsState implements Serializable {
+ private static final long serialVersionUID = 3L;
+ private ImmutableMap<File, Long> fileState = null;
+ private Map<File, Label> fileToLabelMap = Maps.newHashMap();
+ private Map<Label, List<String>> labelToJdeps = Maps.newHashMap();
+ }
+
+ private static class Result {
+ File file;
+ Label label;
+ List<String> dependencies;
+
+ public Result(File file, Label label, List<String> dependencies) {
+ this.file = file;
+ this.label = label;
+ this.dependencies = dependencies;
+ }
+ }
+
+ /** Loads any updated jdeps files since the last invocation of this method. */
+ @Nullable
+ public JdepsMap loadJdepsFiles(
+ Project project,
+ BlazeContext parentContext,
+ RuleMap ruleMap,
+ SyncState.Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {
+ JdepsState oldState =
+ previousSyncState != null ? previousSyncState.get(JdepsState.class) : null;
+ JdepsState jdepsState =
+ Scope.push(
+ parentContext,
+ (context) -> {
+ context.push(new TimingScope("LoadJdepsFiles"));
+ return doLoadJdepsFiles(project, context, oldState, ruleMap);
+ });
+ if (jdepsState == null) {
+ return null;
+ }
+ syncStateBuilder.put(JdepsState.class, jdepsState);
+ return label -> jdepsState.labelToJdeps.get(label);
+ }
+
+ private JdepsState doLoadJdepsFiles(
+ Project project, BlazeContext context, @Nullable JdepsState oldState, RuleMap ruleMap) {
+ JdepsState state = new JdepsState();
+ if (oldState != null) {
+ state.labelToJdeps = Maps.newHashMap(oldState.labelToJdeps);
+ state.fileToLabelMap = Maps.newHashMap(oldState.fileToLabelMap);
+ }
+
+ List<File> files = Lists.newArrayList();
+ for (RuleIdeInfo ruleIdeInfo : ruleMap.rules()) {
+ JavaRuleIdeInfo javaRuleIdeInfo = ruleIdeInfo.javaRuleIdeInfo;
+ if (javaRuleIdeInfo != null) {
+ ArtifactLocation jdepsFile = javaRuleIdeInfo.jdepsFile;
+ if (jdepsFile != null) {
+ files.add(jdepsFile.getFile());
+ }
+ }
+ }
+
+ List<File> updatedFiles = Lists.newArrayList();
+ List<File> removedFiles = Lists.newArrayList();
+ state.fileState =
+ FileDiffer.updateFiles(
+ oldState != null ? oldState.fileState : null, files, updatedFiles, removedFiles);
+
+ ListenableFuture<?> fetchFuture =
+ PrefetchService.getInstance().prefetchFiles(project, updatedFiles);
+ if (!FutureUtil.waitForFuture(context, fetchFuture)
+ .timed("FetchJdeps")
+ .withProgressMessage("Reading jdeps files...")
+ .run()
+ .success()) {
+ return null;
+ }
+
+ for (File removedFile : removedFiles) {
+ Label label = state.fileToLabelMap.remove(removedFile);
+ if (label != null) {
+ state.labelToJdeps.remove(label);
+ }
+ }
+
+ AtomicLong totalSizeLoaded = new AtomicLong(0);
+
+ List<ListenableFuture<Result>> futures = Lists.newArrayList();
+ for (File updatedFile : updatedFiles) {
+ futures.add(
+ submit(
+ () -> {
+ totalSizeLoaded.addAndGet(updatedFile.length());
+ try (InputStream inputStream = new FileInputStream(updatedFile)) {
+ Deps.Dependencies dependencies = Deps.Dependencies.parseFrom(inputStream);
+ if (dependencies != null) {
+ if (dependencies.hasRuleLabel()) {
+ Label label = new Label(dependencies.getRuleLabel());
+ List<String> dependencyStringList = Lists.newArrayList();
+ for (Deps.Dependency dependency : dependencies.getDependencyList()) {
+ // We only want explicit or implicit deps that were
+ // actually resolved by the compiler, not ones that are
+ // available for use in the same package
+ if (dependency.getKind() == Deps.Dependency.Kind.EXPLICIT
+ || dependency.getKind() == Deps.Dependency.Kind.IMPLICIT) {
+ dependencyStringList.add(dependency.getPath());
+ }
+ }
+ return new Result(updatedFile, label, dependencyStringList);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ LOG.info("Could not open jdeps file: " + updatedFile);
+ }
+ return null;
+ }));
+ }
+ try {
+ for (Result result : Futures.allAsList(futures).get()) {
+ if (result != null) {
+ state.fileToLabelMap.put(result.file, result.label);
+ state.labelToJdeps.put(result.label, result.dependencies);
+ }
+ }
+ context.output(
+ PrintOutput.log(
+ String.format(
+ "Loaded %d jdeps files, total size %dkB",
+ updatedFiles.size(), totalSizeLoaded.get() / 1024)));
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.error(e);
+ return null;
+ }
+ return state;
+ }
+
+ private static <T> ListenableFuture<T> submit(Callable<T> callable) {
+ return BlazeExecutor.getInstance().submit(callable);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java b/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java
new file mode 100644
index 0000000..73ae6a2
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.jdeps;
+
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Map of rule -> jdeps dependencies. */
+public interface JdepsMap {
+ /**
+ * For a given rule, returns workspace root relative paths of artifacts that were used during
+ * compilation.
+ *
+ * <p>It's not specified whether jars or ijars are used during compilation.
+ *
+ * <p>If the rule doesn't have source or otherwise wasn't instrumented, null is returned.
+ */
+ @Nullable
+ List<String> getDependenciesForRule(@NotNull Label label);
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeContentEntry.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeContentEntry.java
new file mode 100644
index 0000000..996265d
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeContentEntry.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.concurrent.Immutable;
+
+/** Corresponds to an IntelliJ content entry. */
+@Immutable
+public class BlazeContentEntry implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final File contentRoot;
+ public final ImmutableList<BlazeSourceDirectory> sources;
+
+ public BlazeContentEntry(File contentRoot, ImmutableList<BlazeSourceDirectory> sources) {
+ this.contentRoot = contentRoot;
+ this.sources = sources;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ BlazeContentEntry that = (BlazeContentEntry) o;
+ return Objects.equal(contentRoot, that.contentRoot) && Objects.equal(sources, that.sources);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(contentRoot, sources);
+ }
+
+ @Override
+ public String toString() {
+ return "BlazeContentEntry {\n"
+ + " contentRoot: "
+ + contentRoot
+ + "\n"
+ + " sources: "
+ + sources
+ + "\n"
+ + '}';
+ }
+
+ public static Builder builder(String contentRoot) {
+ return new Builder(new File(contentRoot));
+ }
+
+ public static Builder builder(File contentRoot) {
+ return new Builder(contentRoot);
+ }
+
+ /** Builder for content entries */
+ public static class Builder {
+ File contentRoot;
+ List<BlazeSourceDirectory> sources = Lists.newArrayList();
+
+ public Builder(File contentRoot) {
+ this.contentRoot = contentRoot;
+ }
+
+ public Builder addSource(BlazeSourceDirectory sourceDirectory) {
+ this.sources.add(sourceDirectory);
+ return this;
+ }
+
+ public BlazeContentEntry build() {
+ Collections.sort(sources, BlazeSourceDirectory.COMPARATOR);
+ return new BlazeContentEntry(contentRoot, ImmutableList.copyOf(sources));
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java
new file mode 100644
index 0000000..2470e63
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.google.common.base.Objects;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.java.libraries.JarCache;
+import com.google.idea.blaze.java.libraries.SourceJarManager;
+import com.google.idea.blaze.java.settings.BlazeJavaUserSettings;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.libraries.Library;
+import java.io.File;
+import javax.annotation.concurrent.Immutable;
+
+/** An immutable reference to a .jar required by a rule. */
+@Immutable
+public final class BlazeJarLibrary extends BlazeLibrary {
+ private static final long serialVersionUID = 1L;
+
+ public final LibraryArtifact libraryArtifact;
+
+ public final Label originatingRule;
+
+ public BlazeJarLibrary(LibraryArtifact libraryArtifact, Label originatingRule) {
+ super(LibraryKey.fromJarFile(libraryArtifact.jarForIntellijLibrary().getFile()));
+ this.libraryArtifact = libraryArtifact;
+ this.originatingRule = originatingRule;
+ }
+
+ @Override
+ public void modifyLibraryModel(Project project, Library.ModifiableModel libraryModel) {
+ JarCache jarCache = JarCache.getInstance(project);
+ File jar = jarCache.getCachedJar(this);
+ libraryModel.addRoot(pathToUrl(jar), OrderRootType.CLASSES);
+
+ boolean attachSourcesByDefault =
+ BlazeJavaUserSettings.getInstance().getAttachSourcesByDefault();
+ SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
+ boolean attachSourceJar = attachSourcesByDefault || sourceJarManager.hasSourceJarAttached(key);
+ if (attachSourceJar && libraryArtifact.sourceJar != null) {
+ File sourceJar = jarCache.getCachedSourceJar(this);
+ if (sourceJar != null) {
+ libraryModel.addRoot(pathToUrl(sourceJar), OrderRootType.SOURCES);
+ }
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(super.hashCode(), libraryArtifact, originatingRule);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof BlazeJarLibrary)) {
+ return false;
+ }
+
+ BlazeJarLibrary that = (BlazeJarLibrary) other;
+
+ return super.equals(other)
+ && Objects.equal(libraryArtifact, that.libraryArtifact)
+ && Objects.equal(originatingRule, that.originatingRule);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeJavaImportResult.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeJavaImportResult.java
new file mode 100644
index 0000000..f033772
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeJavaImportResult.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.io.File;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+/** The result of a blaze import operation. */
+@Immutable
+public class BlazeJavaImportResult implements Serializable {
+ private static final long serialVersionUID = 3L;
+
+ public final ImmutableList<BlazeContentEntry> contentEntries;
+ public final ImmutableMap<LibraryKey, BlazeJarLibrary> libraries;
+ public final ImmutableCollection<File> buildOutputJars;
+ public final ImmutableSet<File> javaSourceFiles;
+ @Nullable public final String sourceVersion;
+
+ public BlazeJavaImportResult(
+ ImmutableList<BlazeContentEntry> contentEntries,
+ ImmutableMap<LibraryKey, BlazeJarLibrary> libraries,
+ ImmutableCollection<File> buildOutputJars,
+ ImmutableSet<File> javaSourceFiles,
+ @Nullable String sourceVersion) {
+ this.contentEntries = contentEntries;
+ this.libraries = libraries;
+ this.buildOutputJars = buildOutputJars;
+ this.javaSourceFiles = javaSourceFiles;
+ this.sourceVersion = sourceVersion;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeJavaSyncData.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeJavaSyncData.java
new file mode 100644
index 0000000..25e71c6
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeJavaSyncData.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.google.idea.blaze.base.projectview.section.Glob;
+import java.io.Serializable;
+
+/** Sync data for the java plugin. */
+public class BlazeJavaSyncData implements Serializable {
+ private static final long serialVersionUID = 3L;
+
+ public final BlazeJavaImportResult importResult;
+ public final Glob.GlobSet excludedLibraries;
+
+ public BlazeJavaSyncData(BlazeJavaImportResult importResult, Glob.GlobSet excludedLibraries) {
+ this.importResult = importResult;
+ this.excludedLibraries = excludedLibraries;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeLibrary.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeLibrary.java
new file mode 100644
index 0000000..f84fc4c
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeLibrary.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.google.common.base.Objects;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.openapi.vfs.StandardFileSystems;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.util.io.URLUtil;
+import java.io.File;
+import java.io.Serializable;
+import javax.annotation.concurrent.Immutable;
+
+/** A model object for something that will map to an IntelliJ library. */
+@Immutable
+public abstract class BlazeLibrary implements Serializable {
+ private static final long serialVersionUID = 8L;
+
+ public final LibraryKey key;
+
+ protected BlazeLibrary(LibraryKey key) {
+ this.key = key;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(key);
+ }
+
+ @Override
+ public String toString() {
+ return key.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof BlazeLibrary)) {
+ return false;
+ }
+
+ BlazeLibrary that = (BlazeLibrary) other;
+ return Objects.equal(key, that.key);
+ }
+
+ public abstract void modifyLibraryModel(Project project, Library.ModifiableModel libraryModel);
+
+ protected static String pathToUrl(File path) {
+ String name = path.getName();
+ boolean isJarFile =
+ FileUtilRt.extensionEquals(name, "jar") || FileUtilRt.extensionEquals(name, "zip");
+ // .jar files require an URL with "jar" protocol.
+ String protocol =
+ isJarFile ? StandardFileSystems.JAR_PROTOCOL : StandardFileSystems.FILE_PROTOCOL;
+ String filePath = FileUtil.toSystemIndependentName(path.getPath());
+ String url = VirtualFileManager.constructUrl(protocol, filePath);
+ if (isJarFile) {
+ url += URLUtil.JAR_SEPARATOR;
+ }
+ return url;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/BlazeSourceDirectory.java b/java/src/com/google/idea/blaze/java/sync/model/BlazeSourceDirectory.java
new file mode 100644
index 0000000..f39a2e0
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeSourceDirectory.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.google.common.base.Objects;
+import java.io.File;
+import java.io.Serializable;
+import java.util.Comparator;
+import javax.annotation.concurrent.Immutable;
+import org.jetbrains.annotations.NotNull;
+
+/** A source directory. */
+@Immutable
+public final class BlazeSourceDirectory implements Serializable {
+ private static final long serialVersionUID = 2L;
+
+ public static final Comparator<BlazeSourceDirectory> COMPARATOR =
+ (o1, o2) ->
+ String.CASE_INSENSITIVE_ORDER.compare(
+ o1.getDirectory().getPath(), o2.getDirectory().getPath());
+
+ @NotNull private final File directory;
+ private final boolean isTest;
+ private final boolean isGenerated;
+ private final boolean isResource;
+ @NotNull private final String packagePrefix;
+
+ /** Bulider for source directory */
+ public static class Builder {
+ @NotNull private final File directory;
+ @NotNull private String packagePrefix = "";
+ private boolean isTest;
+ private boolean isResource;
+ private boolean isGenerated;
+
+ private Builder(@NotNull File directory) {
+ this.directory = directory;
+ }
+
+ public Builder setPackagePrefix(@NotNull String packagePrefix) {
+ this.packagePrefix = packagePrefix;
+ return this;
+ }
+
+ public Builder setTest(boolean isTest) {
+ this.isTest = isTest;
+ return this;
+ }
+
+ public Builder setResource(boolean isResource) {
+ this.isResource = isResource;
+ return this;
+ }
+
+ public Builder setGenerated(boolean isGenerated) {
+ this.isGenerated = isGenerated;
+ return this;
+ }
+
+ public BlazeSourceDirectory build() {
+ return new BlazeSourceDirectory(directory, isTest, isResource, isGenerated, packagePrefix);
+ }
+ }
+
+ @NotNull
+ public static Builder builder(@NotNull String directory) {
+ return new Builder(new File(directory));
+ }
+
+ @NotNull
+ public static Builder builder(@NotNull File directory) {
+ return new Builder(directory);
+ }
+
+ private BlazeSourceDirectory(
+ @NotNull File directory,
+ boolean isTest,
+ boolean isResource,
+ boolean isGenerated,
+ @NotNull String packagePrefix) {
+ this.directory = directory;
+ this.isTest = isTest;
+ this.isResource = isResource;
+ this.isGenerated = isGenerated;
+ this.packagePrefix = packagePrefix;
+ }
+
+ /** Returns the full path name of the root of a source directory. */
+ @NotNull
+ public File getDirectory() {
+ return directory;
+ }
+
+ /** Returns {@code true} if the directory contains test sources. */
+ public boolean getIsTest() {
+ return isTest;
+ }
+
+ /** Returns {@code true} if the directory contains resources. */
+ public boolean getIsResource() {
+ return isResource;
+ }
+
+ /** Returns {@code true} if the directory contains generated files. */
+ public boolean getIsGenerated() {
+ return isGenerated;
+ }
+
+ /**
+ * Returns the package prefix for the directory. If the directory is a source root, such as a
+ * "src" directory, then this returns an empty string.
+ */
+ @NotNull
+ public String getPackagePrefix() {
+ return packagePrefix;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(directory, isTest, isResource, packagePrefix, isGenerated);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof BlazeSourceDirectory)) {
+ return false;
+ }
+ BlazeSourceDirectory that = (BlazeSourceDirectory) other;
+ return directory.equals(that.directory)
+ && packagePrefix.equals(that.packagePrefix)
+ && isResource == that.isResource
+ && isTest == that.isTest
+ && isGenerated == that.isGenerated;
+ }
+
+ @Override
+ public String toString() {
+ return "BlazeSourceDirectory {\n"
+ + " directory: "
+ + directory
+ + "\n"
+ + " isTest: "
+ + isTest
+ + "\n"
+ + " isGenerated: "
+ + isGenerated
+ + "\n"
+ + " isResource: "
+ + isResource
+ + "\n"
+ + " packagePrefix: "
+ + packagePrefix
+ + "\n"
+ + '}';
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/model/LibraryKey.java b/java/src/com/google/idea/blaze/java/sync/model/LibraryKey.java
new file mode 100644
index 0000000..8496a31
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/model/LibraryKey.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.model;
+
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.util.io.FileUtil;
+import java.io.File;
+import java.io.Serializable;
+import javax.annotation.concurrent.Immutable;
+import org.jetbrains.annotations.NotNull;
+
+/** Uniquely identifies a library as imported into IntellJ. */
+@Immutable
+public final class LibraryKey implements Serializable {
+ public static final long serialVersionUID = 1L;
+
+ @NotNull private final String name;
+
+ @NotNull
+ public static LibraryKey fromJarFile(@NotNull File jarFile) {
+ int parentHash = jarFile.getParent().hashCode();
+ String name = FileUtil.getNameWithoutExtension(jarFile) + "_" + Integer.toHexString(parentHash);
+ return new LibraryKey(name);
+ }
+
+ @NotNull
+ public static LibraryKey forResourceLibrary() {
+ return new LibraryKey("external_resources_library");
+ }
+
+ @NotNull
+ public static LibraryKey fromIntelliJLibrary(@NotNull Library library) {
+ String name = library.getName();
+ if (name == null) {
+ throw new IllegalArgumentException("Null library name");
+ }
+ return fromIntelliJLibraryName(name);
+ }
+
+ @NotNull
+ public static LibraryKey fromIntelliJLibraryName(@NotNull String name) {
+ return new LibraryKey(name);
+ }
+
+ LibraryKey(@NotNull String name) {
+ this.name = name;
+ }
+
+ public String getIntelliJLibraryName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ LibraryKey that = (LibraryKey) o;
+ return name.equals(that.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java b/java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java
new file mode 100644
index 0000000..e80c98b
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.projectstructure;
+
+import static com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil.createAndAddSDK;
+import static com.intellij.openapi.util.io.FileUtil.notNullize;
+import static com.intellij.openapi.util.text.StringUtil.isNotEmpty;
+import static java.util.Collections.emptyList;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Lists;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.sync.sdk.DefaultSdkProvider;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.JavaSdkVersion;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.util.SystemProperties;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Utility methods related to IDEA JDKs. */
+public class Jdks {
+ @NonNls private static final LanguageLevel DEFAULT_LANG_LEVEL = LanguageLevel.JDK_1_7;
+
+ @Nullable
+ public static Sdk chooseOrCreateJavaSdk(LanguageLevel langLevel) {
+ for (Sdk sdk : ProjectJdkTable.getInstance().getAllJdks()) {
+ if (isApplicableJdk(sdk, langLevel)) {
+ return sdk;
+ }
+ }
+ String jdkHomePath = null;
+ for (DefaultSdkProvider defaultSdkProvider : DefaultSdkProvider.EP_NAME.getExtensions()) {
+ File sdk = defaultSdkProvider.provideSdkForLanguage(LanguageClass.JAVA);
+ if (sdk != null) {
+ jdkHomePath = sdk.getPath();
+ break;
+ }
+ }
+
+ if (jdkHomePath == null) {
+ jdkHomePath = getJdkHomePath(langLevel);
+ }
+
+ if (jdkHomePath == null) {
+ return null;
+ }
+
+ return createJdk(jdkHomePath);
+ }
+
+ public static boolean isApplicableJdk(@NotNull Sdk jdk, @Nullable LanguageLevel langLevel) {
+ if (!(jdk.getSdkType() instanceof JavaSdk)) {
+ return false;
+ }
+ if (langLevel == null) {
+ langLevel = DEFAULT_LANG_LEVEL;
+ }
+ JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk);
+ if (version != null) {
+ //noinspection TestOnlyProblems
+ return hasMatchingLangLevel(version, langLevel);
+ }
+ return false;
+ }
+
+ @Nullable
+ public static String getJdkHomePath(@NotNull LanguageLevel langLevel) {
+ Collection<String> jdkHomePaths =
+ new ArrayList<String>(JavaSdk.getInstance().suggestHomePaths());
+ if (jdkHomePaths.isEmpty()) {
+ return null;
+ }
+ // prefer jdk path of getJavaHome(), since we have to allow access to it in tests
+ // see AndroidProjectDataServiceTest#testImportData()
+ final List<String> list = new ArrayList<String>();
+ String javaHome = SystemProperties.getJavaHome();
+
+ if (javaHome != null && !javaHome.isEmpty()) {
+ for (Iterator<String> it = jdkHomePaths.iterator(); it.hasNext(); ) {
+ final String path = it.next();
+
+ if (path != null && javaHome.startsWith(path)) {
+ it.remove();
+ list.add(path);
+ }
+ }
+ }
+ list.addAll(jdkHomePaths);
+ return getBestJdkHomePath(list, langLevel);
+ }
+
+ @VisibleForTesting
+ @Nullable
+ static String getBestJdkHomePath(
+ @NotNull Collection<String> jdkHomePaths, @NotNull LanguageLevel langLevel) {
+ // Search for JDKs in both the suggest folder and all its sub folders.
+ List<String> roots = Lists.newArrayList();
+ for (String jdkHomePath : jdkHomePaths) {
+ if (isNotEmpty(jdkHomePath)) {
+ roots.add(jdkHomePath);
+ roots.addAll(getChildrenPaths(jdkHomePath));
+ }
+ }
+ return getBestJdk(roots, langLevel);
+ }
+
+ @NotNull
+ private static List<String> getChildrenPaths(@NotNull String dirPath) {
+ File dir = new File(dirPath);
+ if (!dir.isDirectory()) {
+ return emptyList();
+ }
+ List<String> childrenPaths = Lists.newArrayList();
+ for (File child : notNullize(dir.listFiles())) {
+ boolean directory = child.isDirectory();
+ if (directory) {
+ childrenPaths.add(child.getAbsolutePath());
+ }
+ }
+ return childrenPaths;
+ }
+
+ @Nullable
+ private static String getBestJdk(
+ @NotNull List<String> jdkRoots, @NotNull LanguageLevel langLevel) {
+ String bestJdk = null;
+ for (String jdkRoot : jdkRoots) {
+ if (JavaSdk.getInstance().isValidSdkHome(jdkRoot)) {
+ if (bestJdk == null && hasMatchingLangLevel(jdkRoot, langLevel)) {
+ bestJdk = jdkRoot;
+ } else if (bestJdk != null) {
+ bestJdk = selectJdk(bestJdk, jdkRoot, langLevel);
+ }
+ }
+ }
+ return bestJdk;
+ }
+
+ @Nullable
+ private static String selectJdk(
+ @NotNull String jdk1, @NotNull String jdk2, @NotNull LanguageLevel langLevel) {
+ if (hasMatchingLangLevel(jdk1, langLevel)) {
+ return jdk1;
+ }
+ if (hasMatchingLangLevel(jdk2, langLevel)) {
+ return jdk2;
+ }
+ return null;
+ }
+
+ private static boolean hasMatchingLangLevel(
+ @NotNull String jdkRoot, @NotNull LanguageLevel langLevel) {
+ JavaSdkVersion version = getVersion(jdkRoot);
+ return hasMatchingLangLevel(version, langLevel);
+ }
+
+ @VisibleForTesting
+ static boolean hasMatchingLangLevel(
+ @NotNull JavaSdkVersion jdkVersion, @NotNull LanguageLevel langLevel) {
+ LanguageLevel max = jdkVersion.getMaxLanguageLevel();
+ return max.isAtLeast(langLevel);
+ }
+
+ @NotNull
+ private static JavaSdkVersion getVersion(@NotNull String jdkRoot) {
+ String version = JavaSdk.getInstance().getVersionString(jdkRoot);
+ if (version == null) {
+ return JavaSdkVersion.JDK_1_0;
+ }
+ JavaSdkVersion sdkVersion = JavaSdk.getInstance().getVersion(version);
+ return sdkVersion == null ? JavaSdkVersion.JDK_1_0 : sdkVersion;
+ }
+
+ @Nullable
+ public static Sdk createJdk(@NotNull String jdkHomePath) {
+ Sdk jdk = createAndAddSDK(jdkHomePath, JavaSdk.getInstance());
+ if (jdk == null) {
+ String msg = String.format("Unable to create JDK from path '%1$s'", jdkHomePath);
+ Logger.getInstance(Jdks.class).error(msg);
+ }
+ return jdk;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/projectstructure/LibraryEditor.java b/java/src/com/google/idea/blaze/java/sync/projectstructure/LibraryEditor.java
new file mode 100644
index 0000000..ea197ed
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/projectstructure/LibraryEditor.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.projectstructure;
+
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.PrintOutput;
+import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
+import com.google.idea.blaze.java.sync.model.BlazeLibrary;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import java.util.Collection;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/** Edits IntelliJ libraries */
+public class LibraryEditor {
+ private static final Logger LOG = Logger.getInstance(LibraryEditor.class);
+
+ public static void updateProjectLibraries(
+ Project project,
+ BlazeContext context,
+ BlazeProjectData blazeProjectData,
+ Collection<BlazeLibrary> libraries) {
+ Set<LibraryKey> intelliJLibraryState = Sets.newHashSet();
+ for (Library library : ProjectLibraryTable.getInstance(project).getLibraries()) {
+ String name = library.getName();
+ if (name != null) {
+ intelliJLibraryState.add(LibraryKey.fromIntelliJLibraryName(name));
+ }
+ }
+ context.output(PrintOutput.log(String.format("Workspace has %d libraries", libraries.size())));
+
+ Set<String> externallyAddedLibraries = Sets.newHashSet();
+ for (BlazeJavaSyncAugmenter augmenter :
+ BlazeJavaSyncAugmenter.getActiveSyncAgumenters(
+ blazeProjectData.workspaceLanguageSettings)) {
+ externallyAddedLibraries.addAll(augmenter.getExternallyAddedLibraries(blazeProjectData));
+ }
+
+ LibraryTable libraryTable = ProjectLibraryTable.getInstance(project);
+ LibraryTable.ModifiableModel libraryTableModel = libraryTable.getModifiableModel();
+ try {
+ for (BlazeLibrary library : libraries) {
+ updateLibrary(project, libraryTable, libraryTableModel, library);
+ }
+
+ // Garbage collect unused libraries
+ Set<LibraryKey> newLibraryKeys =
+ libraries.stream().map((blazeLibrary) -> blazeLibrary.key).collect(Collectors.toSet());
+ for (LibraryKey libraryKey : intelliJLibraryState) {
+ String libraryIntellijName = libraryKey.getIntelliJLibraryName();
+ if (!newLibraryKeys.contains(libraryKey)
+ && !externallyAddedLibraries.contains(libraryIntellijName)) {
+ Library library = libraryTable.getLibraryByName(libraryIntellijName);
+ if (library != null) {
+ libraryTableModel.removeLibrary(library);
+ }
+ }
+ }
+ } finally {
+ libraryTableModel.commit();
+ }
+ }
+
+ public static void updateLibrary(
+ Project project,
+ LibraryTable libraryTable,
+ LibraryTable.ModifiableModel libraryTableModel,
+ BlazeLibrary blazeLibrary) {
+ String libraryName = blazeLibrary.key.getIntelliJLibraryName();
+
+ Library library = libraryTable.getLibraryByName(libraryName);
+ boolean libraryExists = library != null;
+ if (!libraryExists) {
+ library = libraryTableModel.createLibrary(libraryName);
+ }
+ Library.ModifiableModel libraryModel = library.getModifiableModel();
+ if (libraryExists) {
+ for (String url : libraryModel.getUrls(OrderRootType.CLASSES)) {
+ libraryModel.removeRoot(url, OrderRootType.CLASSES);
+ }
+ for (String url : libraryModel.getUrls(OrderRootType.SOURCES)) {
+ libraryModel.removeRoot(url, OrderRootType.SOURCES);
+ }
+ }
+ try {
+ blazeLibrary.modifyLibraryModel(project, libraryModel);
+ } finally {
+ libraryModel.commit();
+ }
+ }
+
+ public static void configureDependencies(
+ ModifiableRootModel modifiableRootModel, Collection<BlazeLibrary> libraries) {
+ for (BlazeLibrary library : libraries) {
+ updateLibraryDependency(modifiableRootModel, library.key);
+ }
+ }
+
+ private static void updateLibraryDependency(ModifiableRootModel model, LibraryKey libraryKey) {
+ LibraryTable libraryTable = ProjectLibraryTable.getInstance(model.getProject());
+ Library library = libraryTable.getLibraryByName(libraryKey.getIntelliJLibraryName());
+ if (library == null) {
+ LOG.error(
+ "Library missing: "
+ + libraryKey.getIntelliJLibraryName()
+ + ". Please resync project to resolve.");
+ return;
+ }
+ model.addLibraryEntry(library);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/projectstructure/SourceFolderEditor.java b/java/src/com/google/idea/blaze/java/sync/projectstructure/SourceFolderEditor.java
new file mode 100644
index 0000000..0d88c4e
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/projectstructure/SourceFolderEditor.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.projectstructure;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
+import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.SourceFolder;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VfsUtilCore;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.io.URLUtil;
+import java.io.File;
+import java.util.Collection;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElement;
+import org.jetbrains.jps.model.java.JavaResourceRootType;
+import org.jetbrains.jps.model.java.JavaSourceRootProperties;
+import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
+
+/** Edits source folders in IntelliJ content entries */
+public class SourceFolderEditor {
+ private static final Logger LOG = Logger.getInstance(SourceFolderEditor.class);
+
+ public static void modifyContentEntries(
+ BlazeJavaImportResult importResult, Collection<ContentEntry> contentEntries) {
+
+ Map<File, BlazeContentEntry> contentEntryMap = Maps.newHashMap();
+ for (BlazeContentEntry contentEntry : importResult.contentEntries) {
+ contentEntryMap.put(contentEntry.contentRoot, contentEntry);
+ }
+
+ for (ContentEntry contentEntry : contentEntries) {
+ VirtualFile virtualFile = contentEntry.getFile();
+ if (virtualFile == null) {
+ continue;
+ }
+
+ File contentRoot = new File(virtualFile.getPath());
+ BlazeContentEntry javaContentEntry = contentEntryMap.get(contentRoot);
+ if (javaContentEntry != null) {
+ for (BlazeSourceDirectory sourceDirectory : javaContentEntry.sources) {
+ addSourceFolderToContentEntry(contentEntry, sourceDirectory);
+ }
+ }
+ }
+ }
+
+ private static void addSourceFolderToContentEntry(
+ ContentEntry contentEntry, BlazeSourceDirectory sourceDirectory) {
+ File sourceDir = sourceDirectory.getDirectory();
+
+ // Create the source folder
+ SourceFolder sourceFolder;
+ if (sourceDirectory.getIsResource()) {
+ JavaResourceRootType resourceRootType =
+ sourceDirectory.getIsTest()
+ ? JavaResourceRootType.TEST_RESOURCE
+ : JavaResourceRootType.RESOURCE;
+ sourceFolder = contentEntry.addSourceFolder(pathToUrl(sourceDir.getPath()), resourceRootType);
+ } else {
+ sourceFolder =
+ contentEntry.addSourceFolder(pathToUrl(sourceDir.getPath()), sourceDirectory.getIsTest());
+ }
+ JpsModuleSourceRoot sourceRoot = sourceFolder.getJpsElement();
+ JpsElement properties = sourceRoot.getProperties();
+ if (properties instanceof JavaSourceRootProperties) {
+ JavaSourceRootProperties rootProperties = (JavaSourceRootProperties) properties;
+ if (sourceDirectory.getIsGenerated()) {
+ rootProperties.setForGeneratedSources(true);
+ }
+ String packagePrefix = sourceDirectory.getPackagePrefix();
+ if (!Strings.isNullOrEmpty(packagePrefix)) {
+ rootProperties.setPackagePrefix(packagePrefix);
+ }
+ }
+ }
+
+ @NotNull
+ private static String pathToUrl(@NotNull String filePath) {
+ filePath = FileUtil.toSystemIndependentName(filePath);
+ if (filePath.endsWith(".srcjar") || filePath.endsWith(".jar")) {
+ return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR + filePath + URLUtil.JAR_SEPARATOR;
+ } else if (filePath.contains("src.jar!")) {
+ return URLUtil.JAR_PROTOCOL + URLUtil.SCHEME_SEPARATOR + filePath;
+ } else {
+ return VfsUtilCore.pathToUrl(filePath);
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/FilePathJavaPackageReader.java b/java/src/com/google/idea/blaze/java/sync/source/FilePathJavaPackageReader.java
new file mode 100644
index 0000000..99e3c66
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/FilePathJavaPackageReader.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.util.PackagePrefixCalculator;
+
+/** Gets the package from a java file by its file path alone (i.e. without opening the file). */
+public final class FilePathJavaPackageReader extends JavaPackageReader {
+ @Override
+ public String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact) {
+ String directory = sourceArtifact.artifactLocation.getRelativePath();
+ int i = directory.lastIndexOf('/');
+ if (i >= 0) {
+ directory = directory.substring(0, i);
+ }
+ return PackagePrefixCalculator.packagePrefixOf(new WorkspacePath(directory));
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/JavaPackageReader.java b/java/src/com/google/idea/blaze/java/sync/source/JavaPackageReader.java
new file mode 100644
index 0000000..9c1f037
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/JavaPackageReader.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.idea.blaze.base.scope.BlazeContext;
+import javax.annotation.Nullable;
+
+/** Reads java packages from files. */
+public abstract class JavaPackageReader {
+ @Nullable
+ abstract String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact);
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java b/java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java
new file mode 100644
index 0000000..0f3eca0
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.idea.blaze.base.io.InputStreamProvider;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** Parse package string directly from java source */
+public class JavaSourcePackageReader extends JavaPackageReader {
+
+ public static JavaSourcePackageReader getInstance() {
+ return ServiceManager.getService(JavaSourcePackageReader.class);
+ }
+
+ private static final Logger LOG = Logger.getInstance(SourceDirectoryCalculator.class);
+
+ private static final Pattern JAVA_PACKAGE_PATTERN =
+ Pattern.compile("^\\s*package\\s+([\\w\\.]+);");
+
+ @Override
+ @Nullable
+ public String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact) {
+ if (sourceArtifact.artifactLocation.isGenerated()) {
+ return null;
+ }
+ InputStreamProvider inputStreamProvider = InputStreamProvider.getInstance();
+ File sourceFile = sourceArtifact.artifactLocation.getFile();
+ try (InputStream javaInputStream = inputStreamProvider.getFile(sourceFile)) {
+ BufferedReader javaReader = new BufferedReader(new InputStreamReader(javaInputStream));
+ String javaLine;
+
+ while ((javaLine = javaReader.readLine()) != null) {
+ Matcher packageMatch = JAVA_PACKAGE_PATTERN.matcher(javaLine);
+ if (packageMatch.find()) {
+ return packageMatch.group(1);
+ }
+ }
+ IssueOutput.warn("No package name string found in java source file: " + sourceFile)
+ .inFile(sourceFile)
+ .submit(context);
+ return null;
+ } catch (FileNotFoundException e) {
+ IssueOutput.warn("No source file found for: " + sourceFile)
+ .inFile(sourceFile)
+ .submit(context);
+ return null;
+ } catch (IOException e) {
+ LOG.error(e);
+ return null;
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/ManifestFilePackageReader.java b/java/src/com/google/idea/blaze/java/sync/source/ManifestFilePackageReader.java
new file mode 100644
index 0000000..726d60a
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/ManifestFilePackageReader.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import java.util.Map;
+import javax.annotation.Nullable;
+
+class ManifestFilePackageReader extends JavaPackageReader {
+
+ private final Map<Label, Map<String, String>> manifestMap;
+
+ public ManifestFilePackageReader(Map<Label, Map<String, String>> manifestMap) {
+ this.manifestMap = manifestMap;
+ }
+
+ @Nullable
+ @Override
+ String getDeclaredPackageOfJavaFile(BlazeContext context, SourceArtifact sourceArtifact) {
+ Map<String, String> manifestMapForRule = manifestMap.get(sourceArtifact.originatingRule);
+ if (manifestMapForRule != null) {
+ return manifestMapForRule.get(sourceArtifact.artifactLocation.getFile().getPath());
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java b/java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java
new file mode 100644
index 0000000..61ec202
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.idea.blaze.base.async.FutureUtil;
+import com.google.idea.blaze.base.filecache.FileDiffer;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.io.InputStreamProvider;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.prefetch.PrefetchService;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.JavaSourcePackage;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.PackageManifest;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
+
+/** Reads package manifests. */
+public class PackageManifestReader {
+ private static final Logger LOG = Logger.getInstance(SourceDirectoryCalculator.class);
+
+ public static PackageManifestReader getInstance() {
+ return ServiceManager.getService(PackageManifestReader.class);
+ }
+
+ private ImmutableMap<File, Long> fileDiffState;
+
+ private Map<File, Label> fileToLabelMap = Maps.newHashMap();
+ private final Map<Label, Map<String, String>> manifestMap = Maps.newConcurrentMap();
+
+ /** @return A map from java source absolute file path to declared package string. */
+ public Map<Label, Map<String, String>> readPackageManifestFiles(
+ Project project,
+ BlazeContext context,
+ ArtifactLocationDecoder decoder,
+ Map<Label, ArtifactLocation> javaPackageManifests,
+ ListeningExecutorService executorService) {
+
+ Map<File, Label> fileToLabelMap = Maps.newHashMap();
+ for (Map.Entry<Label, ArtifactLocation> entry : javaPackageManifests.entrySet()) {
+ Label label = entry.getKey();
+ File file = entry.getValue().getFile();
+ fileToLabelMap.put(file, label);
+ }
+ List<File> updatedFiles = Lists.newArrayList();
+ List<File> removedFiles = Lists.newArrayList();
+ fileDiffState =
+ FileDiffer.updateFiles(fileDiffState, fileToLabelMap.keySet(), updatedFiles, removedFiles);
+
+ ListenableFuture<?> fetchFuture =
+ PrefetchService.getInstance().prefetchFiles(project, updatedFiles);
+ if (!FutureUtil.waitForFuture(context, fetchFuture)
+ .timed("FetchPackageManifests")
+ .withProgressMessage("Reading package manifests...")
+ .run()
+ .success()) {
+ return null;
+ }
+
+ List<ListenableFuture<Void>> futures = Lists.newArrayList();
+ for (File file : updatedFiles) {
+ futures.add(
+ executorService.submit(
+ () -> {
+ Map<String, String> manifest = parseManifestFile(decoder, file);
+ manifestMap.put(fileToLabelMap.get(file), manifest);
+ return null;
+ }));
+ }
+ for (File file : removedFiles) {
+ Label label = this.fileToLabelMap.get(file);
+ if (label != null) {
+ manifestMap.remove(label);
+ }
+ }
+ this.fileToLabelMap = fileToLabelMap;
+
+ try {
+ Futures.allAsList(futures).get();
+ } catch (ExecutionException | InterruptedException e) {
+ LOG.error(e);
+ throw new IllegalStateException("Could not read sources");
+ }
+ return manifestMap;
+ }
+
+ protected Map<String, String> parseManifestFile(
+ ArtifactLocationDecoder decoder, File packageManifest) {
+ Map<String, String> outputMap = Maps.newHashMap();
+ InputStreamProvider inputStreamProvider = InputStreamProvider.getInstance();
+
+ try (InputStream input = inputStreamProvider.getFile(packageManifest)) {
+ try (BufferedInputStream bufferedInputStream = new BufferedInputStream(input)) {
+ PackageManifest proto = PackageManifest.parseFrom(bufferedInputStream);
+ for (JavaSourcePackage source : proto.getSourcesList()) {
+ String absPath = getAbsolutePath(decoder, source);
+ if (absPath != null) {
+ outputMap.put(absPath, source.getPackageString());
+ }
+ }
+ }
+ return outputMap;
+ } catch (IOException e) {
+ LOG.error(e);
+ return outputMap;
+ }
+ }
+
+ /**
+ * Returns null if the artifact location file can't be found, presumably because it's been removed
+ * from the file system since the blaze build.
+ */
+ @Nullable
+ private static String getAbsolutePath(ArtifactLocationDecoder decoder, JavaSourcePackage source) {
+ ArtifactLocation location = decoder.decode(source.getArtifactLocation());
+ if (location == null) {
+ return null;
+ }
+ return location.getFile().getAbsolutePath();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/SourceArtifact.java b/java/src/com/google/idea/blaze/java/sync/source/SourceArtifact.java
new file mode 100644
index 0000000..37e35bd
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/SourceArtifact.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.model.primitives.Label;
+
+/** Pairing of rule and source artifact. */
+public class SourceArtifact {
+ public final Label originatingRule;
+ public final ArtifactLocation artifactLocation;
+
+ public SourceArtifact(Label originatingRule, ArtifactLocation artifactLocation) {
+ this.originatingRule = originatingRule;
+ this.artifactLocation = artifactLocation;
+ }
+
+ public static Builder builder(Label originatingRule) {
+ return new Builder(originatingRule);
+ }
+
+ static class Builder {
+ Label originatingRule;
+ ArtifactLocation artifactLocation;
+
+ Builder(Label originatingRule) {
+ this.originatingRule = originatingRule;
+ }
+
+ public Builder setArtifactLocation(ArtifactLocation artifactLocation) {
+ this.artifactLocation = artifactLocation;
+ return this;
+ }
+
+ public Builder setArtifactLocation(ArtifactLocation.Builder artifactLocation) {
+ return setArtifactLocation(artifactLocation.build());
+ }
+
+ public SourceArtifact build() {
+ return new SourceArtifact(originatingRule, artifactLocation);
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java b/java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java
new file mode 100644
index 0000000..c4d992c
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.idea.blaze.base.async.executor.TransientExecutor;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.sync.projectview.SourceTestConfig;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.util.PackagePrefixCalculator;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * This is a utility class for calculating the java sources and their package prefixes given a
+ * module and its Blaze {@link ArtifactLocation} list.
+ */
+public final class SourceDirectoryCalculator {
+
+ private static final Logger LOG = Logger.getInstance(SourceDirectoryCalculator.class);
+
+ private static final Splitter PACKAGE_SPLITTER = Splitter.on('.');
+ private static final Splitter PATH_SPLITTER = Splitter.on('/');
+ private static final Joiner PACKAGE_JOINER = Joiner.on('.');
+ private static final Joiner PATH_JOINER = Joiner.on('/');
+
+ private static final JavaPackageReader generatedFileJavaPackageReader =
+ new FilePathJavaPackageReader();
+ private final ListeningExecutorService executorService = MoreExecutors.sameThreadExecutor();
+ private final ListeningExecutorService packageReaderExecutorService =
+ MoreExecutors.listeningDecorator(new TransientExecutor(16));
+
+ public ImmutableList<BlazeContentEntry> calculateContentEntries(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ SourceTestConfig sourceTestConfig,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ Collection<WorkspacePath> rootDirectories,
+ Collection<SourceArtifact> sources,
+ Map<Label, ArtifactLocation> javaPackageManifests) {
+
+ ManifestFilePackageReader manifestFilePackageReader =
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("ReadPackageManifests"));
+ Map<Label, Map<String, String>> manifestMap =
+ PackageManifestReader.getInstance()
+ .readPackageManifestFiles(
+ project,
+ childContext,
+ artifactLocationDecoder,
+ javaPackageManifests,
+ packageReaderExecutorService);
+ return new ManifestFilePackageReader(manifestMap);
+ });
+
+ final List<JavaPackageReader> javaPackageReaders =
+ Lists.newArrayList(
+ manifestFilePackageReader,
+ JavaSourcePackageReader.getInstance(),
+ generatedFileJavaPackageReader);
+
+ Collection<SourceArtifact> nonGeneratedSources = filterGeneratedArtifacts(sources);
+
+ // Sort artifacts and excludes into their respective workspace paths
+ Multimap<WorkspacePath, SourceArtifact> sourcesUnderDirectoryRoot =
+ sortArtifactLocationsByRootDirectory(context, rootDirectories, nonGeneratedSources);
+
+ List<BlazeContentEntry> result = Lists.newArrayList();
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("CalculateSourceDirectories"));
+ for (WorkspacePath workspacePath : rootDirectories) {
+ File contentRoot = workspaceRoot.fileForPath(workspacePath);
+ ImmutableList<BlazeSourceDirectory> sourceDirectories =
+ calculateSourceDirectoriesForContentRoot(
+ context,
+ sourceTestConfig,
+ workspaceRoot,
+ workspacePath,
+ sourcesUnderDirectoryRoot.get(workspacePath),
+ javaPackageReaders);
+ if (!sourceDirectories.isEmpty()) {
+ result.add(new BlazeContentEntry(contentRoot, sourceDirectories));
+ }
+ }
+ Collections.sort(result, (lhs, rhs) -> lhs.contentRoot.compareTo(rhs.contentRoot));
+ });
+ return ImmutableList.copyOf(result);
+ }
+
+ private Collection<SourceArtifact> filterGeneratedArtifacts(
+ Collection<SourceArtifact> artifactLocations) {
+ return artifactLocations
+ .stream()
+ .filter(sourceArtifact -> sourceArtifact.artifactLocation.isSource())
+ .collect(Collectors.toList());
+ }
+
+ private static Multimap<WorkspacePath, SourceArtifact> sortArtifactLocationsByRootDirectory(
+ BlazeContext context,
+ Collection<WorkspacePath> rootDirectories,
+ Collection<SourceArtifact> sources) {
+
+ Multimap<WorkspacePath, SourceArtifact> result = ArrayListMultimap.create();
+
+ for (SourceArtifact sourceArtifact : sources) {
+ WorkspacePath foundWorkspacePath =
+ rootDirectories
+ .stream()
+ .filter(
+ rootDirectory ->
+ isUnderRootDirectory(
+ rootDirectory, sourceArtifact.artifactLocation.getRelativePath()))
+ .findFirst()
+ .orElse(null);
+
+ if (foundWorkspacePath != null) {
+ result.put(foundWorkspacePath, sourceArtifact);
+ } else if (sourceArtifact.artifactLocation.isSource()) {
+ File sourceFile = sourceArtifact.artifactLocation.getFile();
+ String message =
+ String.format(
+ "Did not add %s. You're probably using a java file from outside the workspace"
+ + " that has been exported using export_files. Don't do that.",
+ sourceFile);
+ IssueOutput.warn(message).inFile(sourceFile).submit(context);
+ }
+ }
+ return result;
+ }
+
+ private static boolean isUnderRootDirectory(WorkspacePath rootDirectory, String relativePath) {
+ if (rootDirectory.isWorkspaceRoot()) {
+ return true;
+ }
+ String rootDirectoryString = rootDirectory.toString();
+ return relativePath.startsWith(rootDirectoryString)
+ && (relativePath.length() == rootDirectoryString.length()
+ || (relativePath.charAt(rootDirectoryString.length()) == '/'));
+ }
+
+ /** Calculates all source directories for a single content root. */
+ private ImmutableList<BlazeSourceDirectory> calculateSourceDirectoriesForContentRoot(
+ BlazeContext context,
+ SourceTestConfig sourceTestConfig,
+ WorkspaceRoot workspaceRoot,
+ WorkspacePath directoryRoot,
+ Collection<SourceArtifact> sourceArtifacts,
+ Collection<JavaPackageReader> javaPackageReaders) {
+
+ // Split out java files
+ List<SourceArtifact> javaArtifacts = Lists.newArrayList();
+ for (SourceArtifact sourceArtifact : sourceArtifacts) {
+ if (isJavaFile(sourceArtifact.artifactLocation)) {
+ javaArtifacts.add(sourceArtifact);
+ }
+ }
+
+ List<BlazeSourceDirectory> result = Lists.newArrayList();
+
+ // Add java source directories
+ calculateJavaSourceDirectories(
+ context,
+ workspaceRoot,
+ directoryRoot,
+ sourceTestConfig,
+ javaArtifacts,
+ javaPackageReaders,
+ result);
+
+ Collections.sort(result, BlazeSourceDirectory.COMPARATOR);
+ return ImmutableList.copyOf(result);
+ }
+
+ /** Adds the java source directories. */
+ private void calculateJavaSourceDirectories(
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ WorkspacePath directoryRoot,
+ SourceTestConfig sourceTestConfig,
+ Collection<SourceArtifact> javaArtifacts,
+ Collection<JavaPackageReader> javaPackageReaders,
+ Collection<BlazeSourceDirectory> result) {
+
+ List<SourceRoot> sourceRootsPerFile = Lists.newArrayList();
+
+ // Get java sources
+ List<ListenableFuture<SourceRoot>> sourceRootFutures = Lists.newArrayList();
+ for (final SourceArtifact sourceArtifact : javaArtifacts) {
+ ListenableFuture<SourceRoot> future =
+ executorService.submit(
+ () -> sourceRootForJavaSource(context, sourceArtifact, javaPackageReaders));
+ sourceRootFutures.add(future);
+ }
+ try {
+ for (SourceRoot sourceRoot : Futures.allAsList(sourceRootFutures).get()) {
+ if (sourceRoot != null) {
+ sourceRootsPerFile.add(sourceRoot);
+ }
+ }
+ } catch (ExecutionException | InterruptedException e) {
+ LOG.error(e);
+ throw new IllegalStateException("Could not read sources");
+ }
+
+ // Sort source roots into their respective directories
+ Multimap<WorkspacePath, SourceRoot> sourceDirectoryToSourceRoots = HashMultimap.create();
+ for (SourceRoot sourceRoot : sourceRootsPerFile) {
+ sourceDirectoryToSourceRoots.put(sourceRoot.workspacePath, sourceRoot);
+ }
+
+ // Create a mapping from directory to package prefix
+ Map<WorkspacePath, SourceRoot> workspacePathToSourceRoot = Maps.newHashMap();
+ for (WorkspacePath workspacePath : sourceDirectoryToSourceRoots.keySet()) {
+ Collection<SourceRoot> sources = sourceDirectoryToSourceRoots.get(workspacePath);
+ Multiset<String> packages = HashMultiset.create();
+
+ for (SourceRoot source : sources) {
+ packages.add(source.packagePrefix);
+ }
+
+ final String directoryPackagePrefix;
+ // Common case -- all source files agree on a single package
+ if (packages.elementSet().size() == 1) {
+ directoryPackagePrefix = packages.elementSet().iterator().next();
+ } else {
+ String preferredPackagePrefix = PackagePrefixCalculator.packagePrefixOf(workspacePath);
+ directoryPackagePrefix = pickMostFrequentlyOccurring(packages, preferredPackagePrefix);
+ }
+
+ SourceRoot candidateRoot = new SourceRoot(workspacePath, directoryPackagePrefix);
+ workspacePathToSourceRoot.put(workspacePath, candidateRoot);
+ }
+
+ // Add content entry base if it doesn't exist
+ if (!workspacePathToSourceRoot.containsKey(directoryRoot)) {
+ SourceRoot candidateRoot =
+ new SourceRoot(directoryRoot, PackagePrefixCalculator.packagePrefixOf(directoryRoot));
+ workspacePathToSourceRoot.put(directoryRoot, candidateRoot);
+ }
+
+ // First, create a graph of the directory structure from root to each source file
+ Map<WorkspacePath, SourceRootDirectoryNode> sourceRootDirectoryNodeMap = Maps.newHashMap();
+ SourceRootDirectoryNode rootNode = new SourceRootDirectoryNode(directoryRoot, null);
+ sourceRootDirectoryNodeMap.put(directoryRoot, rootNode);
+ for (SourceRoot sourceRoot : workspacePathToSourceRoot.values()) {
+ final String sourcePathRelativeToDirectoryRoot =
+ sourcePathRelativeToDirectoryRoot(directoryRoot, sourceRoot.workspacePath);
+ List<String> pathComponents =
+ !Strings.isNullOrEmpty(sourcePathRelativeToDirectoryRoot)
+ ? PATH_SPLITTER.splitToList(sourcePathRelativeToDirectoryRoot)
+ : ImmutableList.of();
+ SourceRootDirectoryNode previousNode = rootNode;
+ for (int i = 0; i < pathComponents.size(); ++i) {
+ final WorkspacePath workspacePath =
+ getWorkspacePathFromPathComponents(directoryRoot, pathComponents, i + 1);
+ SourceRootDirectoryNode node = sourceRootDirectoryNodeMap.get(workspacePath);
+ if (node == null) {
+ node = new SourceRootDirectoryNode(workspacePath, pathComponents.get(i));
+ sourceRootDirectoryNodeMap.put(workspacePath, node);
+ previousNode.children.add(node);
+ }
+ previousNode = node;
+ }
+ }
+
+ // Add package prefix votes at each directory node
+ for (SourceRoot sourceRoot : workspacePathToSourceRoot.values()) {
+ final String sourcePathRelativeToDirectoryRoot =
+ sourcePathRelativeToDirectoryRoot(directoryRoot, sourceRoot.workspacePath);
+
+ List<String> packageComponents = PACKAGE_SPLITTER.splitToList(sourceRoot.packagePrefix);
+ List<String> pathComponents =
+ !Strings.isNullOrEmpty(sourcePathRelativeToDirectoryRoot)
+ ? PATH_SPLITTER.splitToList(sourcePathRelativeToDirectoryRoot)
+ : ImmutableList.of();
+ int packageIndex = packageComponents.size();
+ int pathIndex = pathComponents.size();
+ while (pathIndex >= 0 && packageIndex >= 0) {
+ final WorkspacePath workspacePath =
+ getWorkspacePathFromPathComponents(directoryRoot, pathComponents, pathIndex);
+
+ SourceRootDirectoryNode node = sourceRootDirectoryNodeMap.get(workspacePath);
+
+ String packagePrefix = PACKAGE_JOINER.join(packageComponents.subList(0, packageIndex));
+
+ // If this is the source root containing Java files, we *have* to pick its package prefix
+ // Otherwise just add a vote
+ if (sourceRoot.workspacePath.equals(workspacePath)) {
+ node.forcedPackagePrefix = packagePrefix;
+ } else {
+ node.packagePrefixVotes.add(packagePrefix);
+ }
+
+ String pathComponent = pathIndex > 0 ? pathComponents.get(pathIndex - 1) : "";
+ String packageComponent = packageIndex > 0 ? packageComponents.get(packageIndex - 1) : "";
+ if (!pathComponent.equals(packageComponent)) {
+ break;
+ }
+
+ --packageIndex;
+ --pathIndex;
+ }
+ }
+
+ Map<WorkspacePath, SourceRoot> sourceRoots = Maps.newHashMap();
+ SourceRootDirectoryNode root = sourceRootDirectoryNodeMap.get(directoryRoot);
+ visitDirectoryNode(sourceRoots, root, null);
+
+ for (SourceRoot sourceRoot : sourceRoots.values()) {
+ result.add(
+ BlazeSourceDirectory.builder(workspaceRoot.fileForPath(sourceRoot.workspacePath))
+ .setPackagePrefix(sourceRoot.packagePrefix)
+ .setTest(sourceTestConfig.isTestSource(sourceRoot.workspacePath.relativePath()))
+ .setGenerated(false)
+ .build());
+ }
+ }
+
+ private static String sourcePathRelativeToDirectoryRoot(
+ WorkspacePath directoryRoot, WorkspacePath workspacePath) {
+ int directoryRootLength = directoryRoot.relativePath().length();
+ String relativePath = workspacePath.relativePath();
+ final String relativeSourcePath;
+ if (relativePath.length() > directoryRootLength) {
+ if (directoryRootLength > 0) {
+ relativeSourcePath = relativePath.substring(directoryRootLength + 1);
+ } else {
+ relativeSourcePath = relativePath;
+ }
+ } else {
+ relativeSourcePath = "";
+ }
+ return relativeSourcePath;
+ }
+
+ private static WorkspacePath getWorkspacePathFromPathComponents(
+ WorkspacePath directoryRoot, List<String> pathComponents, int pathIndex) {
+ String directoryRootRelativePath = PATH_JOINER.join(pathComponents.subList(0, pathIndex));
+ final WorkspacePath workspacePath;
+ if (directoryRootRelativePath.isEmpty()) {
+ workspacePath = directoryRoot;
+ } else if (directoryRoot.isWorkspaceRoot()) {
+ workspacePath = new WorkspacePath(directoryRootRelativePath);
+ } else {
+ workspacePath =
+ new WorkspacePath(
+ PATH_JOINER.join(directoryRoot.relativePath(), directoryRootRelativePath));
+ }
+ return workspacePath;
+ }
+
+ private static void visitDirectoryNode(
+ Map<WorkspacePath, SourceRoot> sourceRoots,
+ SourceRootDirectoryNode node,
+ @Nullable String parentCompatiblePackagePrefix) {
+ String packagePrefix =
+ node.forcedPackagePrefix != null
+ ? node.forcedPackagePrefix
+ : pickMostFrequentlyOccurring(
+ node.packagePrefixVotes,
+ PackagePrefixCalculator.packagePrefixOf(node.workspacePath));
+ packagePrefix = packagePrefix != null ? packagePrefix : parentCompatiblePackagePrefix;
+ if (packagePrefix != null && !packagePrefix.equals(parentCompatiblePackagePrefix)) {
+ sourceRoots.put(node.workspacePath, new SourceRoot(node.workspacePath, packagePrefix));
+ }
+ for (SourceRootDirectoryNode child : node.children) {
+ String compatiblePackagePrefix = null;
+ if (packagePrefix != null) {
+ compatiblePackagePrefix =
+ Strings.isNullOrEmpty(packagePrefix)
+ ? child.directoryName
+ : packagePrefix + "." + child.directoryName;
+ }
+ visitDirectoryNode(sourceRoots, child, compatiblePackagePrefix);
+ }
+ }
+
+ @Nullable
+ private static <T> T pickMostFrequentlyOccurring(Multiset<T> set, String prefer) {
+ T best = null;
+ int bestCount = 0;
+
+ for (T candidate : set.elementSet()) {
+ int candidateCount = set.count(candidate);
+ if (candidateCount > bestCount || (candidateCount == bestCount && candidate.equals(prefer))) {
+ best = candidate;
+ bestCount = candidateCount;
+ }
+ }
+ return best;
+ }
+
+ @Nullable
+ private static SourceRoot sourceRootForJavaSource(
+ BlazeContext context,
+ SourceArtifact sourceArtifact,
+ Collection<JavaPackageReader> javaPackageReaders) {
+
+ File javaFile = sourceArtifact.artifactLocation.getFile();
+
+ String declaredPackage = null;
+ for (JavaPackageReader reader : javaPackageReaders) {
+ declaredPackage = reader.getDeclaredPackageOfJavaFile(context, sourceArtifact);
+ if (declaredPackage != null) {
+ break;
+ }
+ }
+ if (declaredPackage == null) {
+ IssueOutput.warn("Failed to inspect the package name of java source file: " + javaFile)
+ .inFile(javaFile)
+ .submit(context);
+ return null;
+ }
+ return new SourceRoot(
+ new WorkspacePath(new File(sourceArtifact.artifactLocation.getRelativePath()).getParent()),
+ declaredPackage);
+ }
+
+ static class SourceRoot {
+ final WorkspacePath workspacePath;
+ final String packagePrefix;
+
+ public SourceRoot(WorkspacePath workspacePath, String packagePrefix) {
+ this.workspacePath = workspacePath;
+ this.packagePrefix = packagePrefix;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SourceRoot that = (SourceRoot) o;
+ return Objects.equal(workspacePath, that.workspacePath)
+ && Objects.equal(packagePrefix, that.packagePrefix);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(workspacePath, packagePrefix);
+ }
+
+ @Override
+ public String toString() {
+ return "SourceRoot {"
+ + '\n'
+ + " workspacePath: "
+ + workspacePath
+ + '\n'
+ + " packagePrefix: "
+ + packagePrefix
+ + '\n'
+ + '}';
+ }
+ }
+
+ static class SourceRootDirectoryNode {
+ final WorkspacePath workspacePath;
+ @Nullable final String directoryName;
+ final Set<SourceRootDirectoryNode> children = Sets.newHashSet();
+ final Multiset<String> packagePrefixVotes = HashMultiset.create();
+ String forcedPackagePrefix;
+
+ public SourceRootDirectoryNode(WorkspacePath workspacePath, @Nullable String directoryName) {
+ this.workspacePath = workspacePath;
+ this.directoryName = directoryName;
+ }
+ }
+
+ private static boolean isJavaFile(ArtifactLocation artifactLocation) {
+ return artifactLocation.getRelativePath().endsWith(".java");
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/sync/workingset/JavaWorkingSet.java b/java/src/com/google/idea/blaze/java/sync/workingset/JavaWorkingSet.java
new file mode 100644
index 0000000..0f40445
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/workingset/JavaWorkingSet.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.workingset;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import java.util.Set;
+
+/**
+ * Computes the working set of files of directories from source control.
+ *
+ * <p>The working set is: - All new untracked directories (git only) - All modified BUILD files -
+ * All modified java files
+ *
+ * <p>A rule is considered part of the working set if any of the following is true: - Its BUILD file
+ * is modified - Its BUILD file is under a new directory - Any of its java files are modified - Any
+ * of its java files are under a new directory
+ *
+ * <p>Rules in the working set get an expanded classpath of their direct deps, i.e. they temporarily
+ * defeat classpath reduction.
+ */
+public class JavaWorkingSet {
+ private final Set<String> modifiedBuildFileRelativePaths;
+ private final Set<String> modifiedJavaFileRelativePaths;
+
+ public JavaWorkingSet(WorkspaceRoot workspaceRoot, WorkingSet workingSet) {
+ Set<String> modifiedBuildFileRelativePaths = Sets.newHashSet();
+ Set<String> modifiedJavaFileRelativePaths = Sets.newHashSet();
+
+ for (WorkspacePath workspacePath :
+ Iterables.concat(workingSet.addedFiles, workingSet.modifiedFiles)) {
+ if (workspaceRoot.fileForPath(workspacePath).getName().equals("BUILD")) {
+ modifiedBuildFileRelativePaths.add(workspacePath.relativePath());
+ } else if (workspacePath.relativePath().endsWith(".java")) {
+ modifiedJavaFileRelativePaths.add(workspacePath.relativePath());
+ }
+ }
+
+ this.modifiedBuildFileRelativePaths = modifiedBuildFileRelativePaths;
+ this.modifiedJavaFileRelativePaths = modifiedJavaFileRelativePaths;
+ }
+
+ public boolean isRuleInWorkingSet(RuleIdeInfo ruleIdeInfo) {
+ ArtifactLocation buildFile = ruleIdeInfo.buildFile;
+ if (buildFile != null) {
+ if (modifiedBuildFileRelativePaths.contains(buildFile.getRelativePath())) {
+ return true;
+ }
+ }
+
+ for (ArtifactLocation artifactLocation : ruleIdeInfo.sources) {
+ if (isInWorkingSet(artifactLocation)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isInWorkingSet(ArtifactLocation artifactLocation) {
+ return isInWorkingSet(artifactLocation.getRelativePath());
+ }
+
+ boolean isInWorkingSet(String relativePath) {
+ return modifiedJavaFileRelativePaths.contains(relativePath);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
new file mode 100644
index 0000000..6ffabc2
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.syncstatus;
+
+import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ProjectViewNode;
+import com.intellij.ide.projectView.ProjectViewNodeDecorator;
+import com.intellij.ide.projectView.impl.nodes.ClassTreeNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.packageDependencies.ui.PackageDependenciesNode;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiFile;
+import com.intellij.ui.ColoredTreeCellRenderer;
+import com.intellij.ui.SimpleTextAttributes;
+
+/** Grays out any unreachable java classes. */
+public class BlazeJavaSyncStatusClassNodeDecorator implements ProjectViewNodeDecorator {
+ @Override
+ public void decorate(ProjectViewNode node, PresentationData data) {
+ if (!(node instanceof ClassTreeNode)) {
+ return;
+ }
+ PsiClass psiClass = ((ClassTreeNode) node).getPsiClass();
+ if (psiClass == null) {
+ return;
+ }
+ PsiFile psiFile = psiClass.getContainingFile();
+ if (psiFile == null) {
+ return;
+ }
+ VirtualFile virtualFile = psiFile.getVirtualFile();
+ if (virtualFile == null) {
+ return;
+ }
+
+ Project project = node.getProject();
+ if (SyncStatusHelper.isUnsynced(project, virtualFile)) {
+ data.clearText();
+ data.addText(psiClass.getName(), SimpleTextAttributes.GRAY_ATTRIBUTES);
+ data.addText(" (unsynced)", SimpleTextAttributes.GRAY_ATTRIBUTES);
+ }
+ }
+
+ @Override
+ public void decorate(PackageDependenciesNode node, ColoredTreeCellRenderer cellRenderer) {}
+}
diff --git a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
new file mode 100644
index 0000000..ad8e396
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.syncstatus;
+
+import com.intellij.openapi.fileEditor.impl.EditorTabColorProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.JBColor;
+import java.awt.Color;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Changes the color for unsynced files. */
+public class BlazeJavaSyncStatusEditorTabColorProvider implements EditorTabColorProvider {
+ private static final JBColor UNSYNCED_COLOR =
+ new JBColor(new Color(252, 234, 234), new Color(121, 105, 105));
+
+ @Nullable
+ @Override
+ public Color getEditorTabColor(@NotNull Project project, @NotNull VirtualFile file) {
+ if (file.getName().endsWith(".java") && SyncStatusHelper.isUnsynced(project, file)) {
+ return UNSYNCED_COLOR;
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java
new file mode 100644
index 0000000..fce5c89
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.syncstatus;
+
+import com.intellij.openapi.fileEditor.impl.EditorTabTitleProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.Nullable;
+
+/** Changes the tab title for unsynced files. */
+public class BlazeJavaSyncStatusEditorTabTitleProvider implements EditorTabTitleProvider {
+ @Nullable
+ @Override
+ public String getEditorTabTitle(Project project, VirtualFile file) {
+ if (file.getName().endsWith("java") && SyncStatusHelper.isUnsynced(project, file)) {
+ return file.getPresentableName() + " (unsynced)";
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java b/java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java
new file mode 100644
index 0000000..2ea5884
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.syncstatus;
+
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.io.File;
+
+class SyncStatusHelper {
+ static boolean isUnsynced(Project project, VirtualFile virtualFile) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return false;
+ }
+ BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ if (syncData == null) {
+ return false;
+ }
+ if (!virtualFile.isInLocalFileSystem()) {
+ return false;
+ }
+
+ File file = new File(virtualFile.getPath());
+ return !syncData.importResult.javaSourceFiles.contains(file);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java b/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
new file mode 100644
index 0000000..a2f0582
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.ui;
+
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.ui.BlazeProblemsView;
+import com.intellij.compiler.CompilerMessageImpl;
+import com.intellij.compiler.ProblemsView;
+import com.intellij.openapi.compiler.CompilerMessageCategory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.util.UUID;
+
+class BlazeIntelliJProblemsView implements BlazeProblemsView {
+ private final Project project;
+
+ private BlazeIntelliJProblemsView(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public void clearOldMessages(UUID sessionId) {
+ ProblemsView.SERVICE.getInstance(project).clearOldMessages(null, sessionId);
+ }
+
+ @Override
+ public void addMessage(IssueOutput issue, UUID sessionId) {
+ VirtualFile virtualFile =
+ issue.getFile() != null
+ ? VfsUtil.findFileByIoFile(issue.getFile(), true /* refresh */)
+ : null;
+ CompilerMessageCategory category =
+ issue.getCategory() == IssueOutput.Category.ERROR
+ ? CompilerMessageCategory.ERROR
+ : CompilerMessageCategory.WARNING;
+ CompilerMessageImpl message =
+ new CompilerMessageImpl(
+ project,
+ category,
+ issue.getMessage(),
+ virtualFile,
+ issue.getLine(),
+ issue.getColumn(),
+ issue.getNavigatable());
+ ProblemsView.SERVICE.getInstance(project).addMessage(message, sessionId);
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
new file mode 100644
index 0000000..4a6bc6a
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.BlazeProjectCommitException;
+import com.google.idea.blaze.base.wizard2.ui.BlazeEditProjectViewControl;
+import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.ide.wizard.CommitStepException;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.projectImport.ProjectImportWizardStep;
+import java.awt.BorderLayout;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+
+/** Shows the edit project view screen. */
+class BlazeEditProjectViewImportWizardStep extends ProjectImportWizardStep {
+
+ private final JPanel component = new JPanel(new BorderLayout());
+ private BlazeEditProjectViewControl control;
+ private boolean settingsInitialised;
+
+ public BlazeEditProjectViewImportWizardStep(@NotNull WizardContext context) {
+ super(context);
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return component;
+ }
+
+ @Override
+ public void updateStep() {
+ if (!settingsInitialised) {
+ init();
+ } else {
+ control.update(getProjectBuilder());
+ }
+ }
+
+ private void init() {
+ control =
+ new BlazeEditProjectViewControl(getProjectBuilder(), getWizardContext().getDisposable());
+ this.component.add(control.getUiComponent());
+ settingsInitialised = true;
+ }
+
+ @Override
+ public boolean validate() throws ConfigurationException {
+ BlazeValidationResult validationResult = control.validate();
+ if (validationResult.error != null) {
+ throw new ConfigurationException(validationResult.error.getError());
+ }
+ return validationResult.success;
+ }
+
+ @Override
+ public void updateDataModel() {
+ BlazeNewProjectBuilder builder = getProjectBuilder();
+ control.updateBuilder(builder);
+
+ WizardContext wizardContext = getWizardContext();
+ wizardContext.setProjectName(builder.getProjectName());
+ wizardContext.setProjectFileDirectory(builder.getProjectDataDirectory());
+ }
+
+ @Override
+ public void onWizardFinished() throws CommitStepException {
+ try {
+ getProjectBuilder().commit();
+ } catch (BlazeProjectCommitException e) {
+ throw new CommitStepException(e.getMessage());
+ }
+ }
+
+ @Override
+ public String getHelpId() {
+ return "docs/project-views";
+ }
+
+ private BlazeNewProjectBuilder getProjectBuilder() {
+ BlazeProjectImportBuilder builder =
+ (BlazeProjectImportBuilder) getWizardContext().getProjectBuilder();
+ assert builder != null;
+ return builder.builder();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeImportProjectAction.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeImportProjectAction.java
new file mode 100644
index 0000000..273a4ff
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeImportProjectAction.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.ide.impl.NewProjectUtil;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+
+class BlazeImportProjectAction extends AnAction {
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ BlazeNewProjectWizard wizard =
+ new BlazeNewProjectWizard(
+ new BlazeNewProjectImportProvider(new BlazeProjectImportBuilder()));
+ if (!wizard.showAndGet()) {
+ return;
+ }
+ //noinspection ConstantConditions
+ NewProjectUtil.createFromWizard(wizard, null);
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ super.update(e);
+ e.getPresentation()
+ .setText(String.format("Import %s Project...", Blaze.defaultBuildSystemName()));
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectImportProvider.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectImportProvider.java
new file mode 100644
index 0000000..d73e681
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectImportProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.intellij.ide.util.projectWizard.ModuleWizardStep;
+import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.projectImport.ProjectImportProvider;
+
+/** The import provider for the Blaze plugin. */
+class BlazeNewProjectImportProvider extends ProjectImportProvider {
+
+ public BlazeNewProjectImportProvider(BlazeProjectImportBuilder builder) {
+ super(builder);
+ }
+
+ @Override
+ public ModuleWizardStep[] createSteps(WizardContext context) {
+ return new ModuleWizardStep[] {
+ new BlazeSelectWorkspaceImportWizardStep(context),
+ new BlazeSelectBuildSystemBinaryStep(context),
+ new BlazeSelectProjectViewImportWizardStep(context),
+ new BlazeEditProjectViewImportWizardStep(context)
+ };
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
new file mode 100644
index 0000000..62be22e
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.idea.blaze.base.help.BlazeHelpHandler;
+import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
+import com.intellij.projectImport.ProjectImportProvider;
+import java.awt.event.ActionListener;
+import org.jetbrains.annotations.Nullable;
+
+final class BlazeNewProjectWizard extends AddModuleWizard {
+ public BlazeNewProjectWizard(ProjectImportProvider provider) {
+ super(null, null, provider);
+ }
+
+ @Override
+ protected String getDimensionServiceKey() {
+ return null; // No dimension service
+ }
+
+ @Override
+ protected void helpAction() {
+ doHelpAction();
+ }
+
+ @Override
+ protected void doHelpAction() {
+ String helpId = getHelpID();
+ BlazeHelpHandler helpHandler = BlazeHelpHandler.getInstance();
+ if (helpId != null && helpHandler != null) {
+ helpHandler.handleHelp(helpId);
+ }
+ }
+
+ // Swallow the escape key
+ @Nullable
+ @Override
+ protected ActionListener createCancelAction() {
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeProjectImportBuilder.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeProjectImportBuilder.java
new file mode 100644
index 0000000..30445a4
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeProjectImportBuilder.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.intellij.openapi.module.ModifiableModuleModel;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.SdkTypeId;
+import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
+import com.intellij.packaging.artifacts.ModifiableArtifactModel;
+import com.intellij.projectImport.ProjectImportBuilder;
+import icons.BlazeIcons;
+import java.util.List;
+import javax.swing.Icon;
+import org.jetbrains.annotations.NotNull;
+
+/** Wrapper around a {@link BlazeNewProjectBuilder} to fit into IntelliJ's import framework. */
+class BlazeProjectImportBuilder extends ProjectImportBuilder<Void> {
+ private BlazeNewProjectBuilder builder = new BlazeNewProjectBuilder();
+
+ @NotNull
+ @Override
+ public String getName() {
+ return Blaze.defaultBuildSystemName();
+ }
+
+ @Override
+ public Icon getIcon() {
+ return BlazeIcons.Blaze;
+ }
+
+ @Override
+ public boolean isSuitableSdkType(SdkTypeId sdk) {
+ return sdk == JavaSdk.getInstance();
+ }
+
+ @Override
+ public List<Void> getList() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean isMarked(Void element) {
+ return true;
+ }
+
+ @Override
+ public void setList(List<Void> gradleProjects) {}
+
+ @Override
+ public void setOpenProjectSettingsAfter(boolean on) {}
+
+ @Override
+ public List<Module> commit(
+ final Project project,
+ ModifiableModuleModel model,
+ ModulesProvider modulesProvider,
+ ModifiableArtifactModel artifactModel) {
+ builder.commitToProject(project);
+ return ImmutableList.of();
+ }
+
+ public BlazeNewProjectBuilder builder() {
+ return builder;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectBuildSystemBinaryStep.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectBuildSystemBinaryStep.java
new file mode 100644
index 0000000..7b50624
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectBuildSystemBinaryStep.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.ui.SelectBazelBinaryControl;
+import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.ide.wizard.CommitStepException;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.projectImport.ProjectImportWizardStep;
+import java.awt.BorderLayout;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+
+class BlazeSelectBuildSystemBinaryStep extends ProjectImportWizardStep {
+
+ private final JPanel component = new JPanel(new BorderLayout());
+ private SelectBazelBinaryControl control;
+ private boolean settingsInitialized = false;
+
+ public BlazeSelectBuildSystemBinaryStep(@NotNull WizardContext context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isStepVisible() {
+ updateStep();
+ if (control.builder.getBuildSystem() != BuildSystem.Bazel) {
+ return false;
+ }
+ String currentBinaryPath = BlazeUserSettings.getInstance().getBazelBinaryPath();
+ return currentBinaryPath == null;
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return component;
+ }
+
+ @Override
+ public void updateStep() {
+ if (!settingsInitialized) {
+ init();
+ }
+ }
+
+ private void init() {
+ control = new SelectBazelBinaryControl(getProjectBuilder());
+ component.add(control.getUiComponent());
+ settingsInitialized = true;
+ }
+
+ @Override
+ public boolean validate() throws ConfigurationException {
+ BlazeValidationResult result = control.validate();
+ if (!result.success) {
+ throw new ConfigurationException(result.error.getError());
+ }
+ return true;
+ }
+
+ @Override
+ public void updateDataModel() {}
+
+ @Override
+ public void onWizardFinished() throws CommitStepException {
+ control.commit();
+ }
+
+ private BlazeNewProjectBuilder getProjectBuilder() {
+ BlazeProjectImportBuilder builder =
+ (BlazeProjectImportBuilder) getWizardContext().getProjectBuilder();
+ assert builder != null;
+ return builder.builder();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectProjectViewImportWizardStep.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectProjectViewImportWizardStep.java
new file mode 100644
index 0000000..9978f07
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectProjectViewImportWizardStep.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.ui.BlazeSelectProjectViewControl;
+import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.ide.wizard.CommitStepException;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.projectImport.ProjectImportWizardStep;
+import java.awt.BorderLayout;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+
+class BlazeSelectProjectViewImportWizardStep extends ProjectImportWizardStep {
+
+ private final JPanel component = new JPanel(new BorderLayout());
+ private BlazeSelectProjectViewControl control;
+ private boolean settingsInitialised;
+
+ public BlazeSelectProjectViewImportWizardStep(@NotNull WizardContext context) {
+ super(context);
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return component;
+ }
+
+ @Override
+ public void updateStep() {
+ if (!settingsInitialised) {
+ init();
+ } else {
+ control.update(getProjectBuilder());
+ }
+ }
+
+ private void init() {
+ control = new BlazeSelectProjectViewControl(getProjectBuilder());
+ this.component.add(control.getUiComponent());
+ settingsInitialised = true;
+ }
+
+ @Override
+ public boolean validate() throws ConfigurationException {
+ BlazeValidationResult result = control.validate();
+ if (!result.success) {
+ throw new ConfigurationException(result.error.getError());
+ }
+ return true;
+ }
+
+ @Override
+ public void updateDataModel() {
+ control.updateBuilder(getProjectBuilder());
+ }
+
+ @Override
+ public void onWizardFinished() throws CommitStepException {
+ control.commit();
+ }
+
+ @Override
+ public String getHelpId() {
+ return "docs/project-views";
+ }
+
+ private BlazeNewProjectBuilder getProjectBuilder() {
+ BlazeProjectImportBuilder builder =
+ (BlazeProjectImportBuilder) getWizardContext().getProjectBuilder();
+ assert builder != null;
+ return builder.builder();
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectWorkspaceImportWizardStep.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectWorkspaceImportWizardStep.java
new file mode 100644
index 0000000..b5b5b6a
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeSelectWorkspaceImportWizardStep.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.wizard2;
+
+import com.google.idea.blaze.base.ui.BlazeValidationResult;
+import com.google.idea.blaze.base.wizard2.BlazeNewProjectBuilder;
+import com.google.idea.blaze.base.wizard2.ui.BlazeSelectWorkspaceControl;
+import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.ide.wizard.CommitStepException;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.projectImport.ProjectImportWizardStep;
+import java.awt.BorderLayout;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import org.jetbrains.annotations.NotNull;
+
+class BlazeSelectWorkspaceImportWizardStep extends ProjectImportWizardStep {
+
+ private final JPanel component = new JPanel(new BorderLayout());
+ private BlazeSelectWorkspaceControl control;
+ private boolean settingsInitialised;
+
+ public BlazeSelectWorkspaceImportWizardStep(@NotNull WizardContext context) {
+ super(context);
+ }
+
+ @Override
+ public JComponent getComponent() {
+ return component;
+ }
+
+ @Override
+ public void updateStep() {
+ if (!settingsInitialised) {
+ init();
+ }
+ }
+
+ private void init() {
+ control = new BlazeSelectWorkspaceControl(getProjectBuilder());
+ this.component.add(control.getUiComponent());
+ settingsInitialised = true;
+ }
+
+ @Override
+ public boolean validate() throws ConfigurationException {
+ BlazeValidationResult result = control.validate();
+ if (!result.success) {
+ throw new ConfigurationException(result.error.getError());
+ }
+ return true;
+ }
+
+ @Override
+ public void updateDataModel() {
+ control.updateBuilder(getProjectBuilder());
+ }
+
+ @Override
+ public void onWizardFinished() throws CommitStepException {
+ control.commit();
+ }
+
+ @Override
+ public String getHelpId() {
+ return "docs/import-project";
+ }
+
+ private BlazeNewProjectBuilder getProjectBuilder() {
+ BlazeProjectImportBuilder builder =
+ (BlazeProjectImportBuilder) getWizardContext().getProjectBuilder();
+ assert builder != null;
+ return builder.builder();
+ }
+}
diff --git a/blaze-java/src/com/google/idea/blaze/java/wizard2/README b/java/src/com/google/idea/blaze/java/wizard2/README
similarity index 100%
rename from blaze-java/src/com/google/idea/blaze/java/wizard2/README
rename to java/src/com/google/idea/blaze/java/wizard2/README
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/lang/build/JavaClassRenameTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/lang/build/JavaClassRenameTest.java
new file mode 100644
index 0000000..7a1a64d
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/lang/build/JavaClassRenameTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.lang.build;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.refactoring.rename.RenameProcessor;
+
+/** Tests that BUILD file references are correctly updated when performing rename refactors. */
+public class JavaClassRenameTest extends BuildFileIntegrationTestCase {
+
+ public void testRenameJavaClass() {
+ PsiJavaFile javaFile =
+ (PsiJavaFile)
+ createPsiFile(
+ "com/google/foo/JavaClass.java",
+ "package com.google.foo;",
+ "public class JavaClass {}");
+
+ BuildFile buildFile =
+ createBuildFile(
+ "com/google/foo/BUILD", "java_library(name = \"ref2\", srcs = [\"JavaClass.java\"])");
+
+ new RenameProcessor(getProject(), javaFile.getClasses()[0], "NewName", false, false).run();
+
+ assertFileContents(buildFile, "java_library(name = \"ref2\", srcs = [\"NewName.java\"])");
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/lang/build/SafeDeleteTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/lang/build/SafeDeleteTest.java
new file mode 100644
index 0000000..535932a
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/lang/build/SafeDeleteTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.lang.build;
+
+import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.refactoring.BaseRefactoringProcessor;
+import com.intellij.refactoring.safeDelete.SafeDeleteHandler;
+
+/** Tests for the safe delete action which aren't covered by existing tests. */
+public class SafeDeleteTest extends BuildFileIntegrationTestCase {
+
+ public void testIndirectGlobReferencesNotIncluded() {
+ PsiFile javaFile =
+ createPsiFile("com/google/Test.java", "package com.google;", "public class Test {}");
+
+ PsiClass javaClass = PsiUtils.findFirstChildOfClassRecursive(javaFile, PsiClass.class);
+
+ BuildFile buildFile =
+ createBuildFile(
+ "com/google/BUILD",
+ "java_library(",
+ " name = 'lib'",
+ " srcs = glob(['*.java'])",
+ ")");
+
+ try {
+ SafeDeleteHandler.invoke(getProject(), new PsiElement[] {javaClass}, true);
+ } catch (BaseRefactoringProcessor.ConflictsInTestsException e) {
+ fail("Glob reference was incorrectly included");
+ return;
+ }
+ }
+
+ public void testDirectGlobReferencesIncluded() {
+ PsiFile javaFile =
+ createPsiFile("com/google/Test.java", "package com.google;", "public class Test {}");
+
+ PsiClass javaClass = PsiUtils.findFirstChildOfClassRecursive(javaFile, PsiClass.class);
+
+ BuildFile buildFile =
+ createBuildFile(
+ "com/google/BUILD",
+ "java_library(",
+ " name = 'lib'",
+ " srcs = glob(['Test.java'])",
+ ")");
+
+ try {
+ SafeDeleteHandler.invoke(getProject(), new PsiElement[] {javaClass}, true);
+ } catch (BaseRefactoringProcessor.ConflictsInTestsException expected) {
+ return;
+ }
+ fail("Expected an unsafe usage to be found");
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/sync/JavaSyncTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/sync/JavaSyncTest.java
new file mode 100644
index 0000000..76dc9e1
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/sync/JavaSyncTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.sync.BlazeSyncIntegrationTestCase;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
+import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
+import java.util.List;
+
+/** Java-specific sync integration tests. */
+public class JavaSyncTest extends BlazeSyncIntegrationTestCase {
+
+ public void testJavaClassesPresentInClassPath() throws Exception {
+ setProjectView(
+ "directories:",
+ " java/com/google",
+ "targets:",
+ " //java/com/google:lib",
+ "workspace_type: java");
+
+ createWorkspaceFile(
+ "java/com/google/ClassWithUniqueName1.java",
+ "package com.google;",
+ "public class ClassWithUniqueName1 {}");
+
+ createWorkspaceFile(
+ "java/com/google/ClassWithUniqueName2.java",
+ "package com.google;",
+ "public class ClassWithUniqueName2 {}");
+
+ RuleMap ruleMap =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("java/com/google/ClassWithUniqueName1.java"))
+ .addSource(sourceRoot("java/com/google/ClassWithUniqueName2.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder()))
+ .build();
+
+ setRuleMap(ruleMap);
+
+ BlazeSyncParams syncParams =
+ new BlazeSyncParams.Builder("Full Sync", BlazeSyncParams.SyncMode.FULL)
+ .addProjectViewTargets(true)
+ .build();
+ runBlazeSync(syncParams);
+
+ assertNoErrors();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.ruleMap).isEqualTo(ruleMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
+ .isEqualTo(WorkspaceType.JAVA);
+
+ BlazeJavaSyncData javaSyncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ List<BlazeContentEntry> contentEntries = javaSyncData.importResult.contentEntries;
+ assertThat(contentEntries).hasSize(1);
+
+ BlazeContentEntry contentEntry = contentEntries.get(0);
+ assertThat(contentEntry.contentRoot.getPath())
+ .isEqualTo(tempDirectory.getPath() + "/java/com/google");
+ assertThat(contentEntry.sources).hasSize(1);
+
+ BlazeSourceDirectory sourceDir = contentEntry.sources.get(0);
+ assertThat(sourceDir.getPackagePrefix()).isEqualTo("com.google");
+ assertThat(sourceDir.getDirectory().getPath())
+ .isEqualTo(tempDirectory.getPath() + "/java/com/google");
+ }
+
+ public void testSimpleSync() throws Exception {
+ setProjectView(
+ "directories:",
+ " java/com/google",
+ "targets:",
+ " //java/com/google:lib",
+ "workspace_type: java");
+
+ createFile("java/com/google/Source.java", "package com.google;", "public class Source {}");
+
+ createFile("java/com/google/Other.java", "package com.google;", "public class Other {}");
+
+ RuleMap ruleMap =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("java/com/google/Source.java"))
+ .addSource(sourceRoot("java/com/google/Other.java")))
+ .build();
+
+ setRuleMap(ruleMap);
+
+ runBlazeSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .build());
+
+ assertNoErrors();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.ruleMap).isEqualTo(ruleMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
+ .isEqualTo(WorkspaceType.JAVA);
+ }
+}
diff --git a/java/tests/unittests/com/google/idea/blaze/java/run/BlazeJavaRunProfileStateTest.java b/java/tests/unittests/com/google/idea/blaze/java/run/BlazeJavaRunProfileStateTest.java
new file mode 100644
index 0000000..b3dd584
--- /dev/null
+++ b/java/tests/unittests/com/google/idea/blaze/java/run/BlazeJavaRunProfileStateTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.command.BuildFlagsProvider;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationHandlerProvider;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import com.intellij.openapi.project.Project;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeJavaRunProfileState}. */
+@RunWith(JUnit4.class)
+public class BlazeJavaRunProfileStateTest extends BlazeTestCase {
+
+ private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
+ new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+
+ private BlazeCommandRunConfiguration configuration;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ projectServices.register(
+ BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
+
+ configuration =
+ new BlazeCommandRunConfigurationType().getFactory().createTemplateConfiguration(project);
+
+ ExperimentService experimentService = new MockExperimentService();
+ applicationServices.register(ExperimentService.class, experimentService);
+ applicationServices.register(RuleFinder.class, new MockRuleFinder());
+ applicationServices.register(BlazeUserSettings.class, new BlazeUserSettings());
+ registerExtensionPoint(BuildFlagsProvider.EP_NAME, BuildFlagsProvider.class);
+ ExtensionPointImpl<BlazeCommandRunConfigurationHandlerProvider> handlerProviderEp =
+ registerExtensionPoint(
+ BlazeCommandRunConfigurationHandlerProvider.EP_NAME,
+ BlazeCommandRunConfigurationHandlerProvider.class);
+ handlerProviderEp.registerExtension(new BlazeCommandGenericRunConfigurationHandlerProvider());
+ }
+
+ @Test
+ public void flagsShouldBeAppendedIfPresent() {
+ configuration.setTarget(new Label("//label:rule"));
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+ handler.setCommand(BlazeCommandName.fromString("command"));
+ handler.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ assertThat(
+ BlazeJavaRunProfileState.getBlazeCommand(
+ project, configuration, ProjectViewSet.builder().build(), false /* debug */)
+ .toList())
+ .isEqualTo(
+ ImmutableList.of(
+ "/usr/bin/blaze",
+ "command",
+ BlazeFlags.getToolTagFlag(),
+ "--flag1",
+ "--flag2",
+ "--",
+ "//label:rule"));
+ }
+
+ @Test
+ public void debugFlagShouldBeIncludedForJavaTest() {
+ configuration.setTarget(new Label("//label:rule"));
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+ handler.setCommand(BlazeCommandName.fromString("command"));
+ assertThat(
+ BlazeJavaRunProfileState.getBlazeCommand(
+ project, configuration, ProjectViewSet.builder().build(), true /* debug */)
+ .toList())
+ .isEqualTo(
+ ImmutableList.of(
+ "/usr/bin/blaze",
+ "command",
+ BlazeFlags.getToolTagFlag(),
+ "--java_debug",
+ "--",
+ "//label:rule"));
+ }
+
+ @Test
+ public void debugFlagShouldBeIncludedForJavaBinary() {
+ configuration.setTarget(new Label("//label:java_binary_rule"));
+ BlazeCommandGenericRunConfigurationHandler handler =
+ (BlazeCommandGenericRunConfigurationHandler) configuration.getHandler();
+ handler.setCommand(BlazeCommandName.fromString("command"));
+ assertThat(
+ BlazeJavaRunProfileState.getBlazeCommand(
+ project, configuration, ProjectViewSet.builder().build(), true /* debug */)
+ .toList())
+ .isEqualTo(
+ ImmutableList.of(
+ "/usr/bin/blaze",
+ "command",
+ BlazeFlags.getToolTagFlag(),
+ "--",
+ "//label:java_binary_rule",
+ "--debug"));
+ }
+
+ private static class MockRuleFinder extends RuleFinder {
+ @Override
+ public List<RuleIdeInfo> findRules(Project project, Predicate<RuleIdeInfo> predicate) {
+ return null;
+ }
+
+ @Override
+ public RuleIdeInfo ruleForTarget(Project project, final Label target) {
+ RuleIdeInfo.Builder builder = RuleIdeInfo.builder().setLabel(target);
+ if (target.ruleName().toString().equals("java_binary_rule")) {
+ builder.setKind(Kind.JAVA_BINARY);
+ } else {
+ builder.setKind(Kind.JAVA_TEST);
+ }
+ return builder.build();
+ }
+ }
+}
diff --git a/java/tests/unittests/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporterTest.java b/java/tests/unittests/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporterTest.java
new file mode 100644
index 0000000..9b5aa31
--- /dev/null
+++ b/java/tests/unittests/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporterTest.java
@@ -0,0 +1,1424 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.importer;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
+import com.google.idea.blaze.base.ideinfo.AndroidRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.JavaToolchainIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.ProtoLibraryLegacyInfo;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
+import com.google.idea.blaze.base.ideinfo.Tags;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.prefetch.MockPrefetchService;
+import com.google.idea.blaze.base.prefetch.PrefetchService;
+import com.google.idea.blaze.base.projectview.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.section.Glob;
+import com.google.idea.blaze.base.projectview.section.ListSection;
+import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
+import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.projectview.section.sections.ExcludeTargetSection;
+import com.google.idea.blaze.base.projectview.section.sections.ImportTargetOutputSection;
+import com.google.idea.blaze.base.projectview.section.sections.TestSourceSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ErrorCollector;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.settings.BlazeImportSettings;
+import com.google.idea.blaze.base.settings.BlazeImportSettingsManager;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkingSet;
+import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
+import com.google.idea.blaze.java.sync.jdeps.JdepsMap;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.java.sync.model.BlazeJavaImportResult;
+import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
+import com.google.idea.blaze.java.sync.model.LibraryKey;
+import com.google.idea.blaze.java.sync.source.JavaSourcePackageReader;
+import com.google.idea.blaze.java.sync.source.PackageManifestReader;
+import com.google.idea.blaze.java.sync.source.SourceArtifact;
+import com.google.idea.blaze.java.sync.workingset.JavaWorkingSet;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for BlazeJavaWorkspaceImporter */
+@RunWith(JUnit4.class)
+public class BlazeJavaWorkspaceImporterTest extends BlazeTestCase {
+
+ private static final String FAKE_WORKSPACE_ROOT = "/root";
+ private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File(FAKE_WORKSPACE_ROOT));
+
+ private static final String FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT =
+ "blaze-out/gcc-4.X.Y-crosstool-v17-hybrid-grtev3-k8-fastbuild/bin";
+
+ private static final String FAKE_GEN_ROOT =
+ "/path/to/8093958afcfde6c33d08b621dfaa4e09/root/" + FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT;
+
+ private static final ArtifactLocationDecoder FAKE_ARTIFACT_DECODER =
+ new ArtifactLocationDecoder(
+ new BlazeRoots(
+ new File("/"),
+ ImmutableList.of(),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen")),
+ null);
+
+ private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
+ new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+ private ExtensionPointImpl<BlazeJavaSyncAugmenter> augmenters;
+
+ private static class JdepsMock implements JdepsMap {
+ Map<Label, List<String>> jdeps = Maps.newHashMap();
+
+ @Nullable
+ @Override
+ public List<String> getDependenciesForRule(@NotNull Label label) {
+ return jdeps.get(label);
+ }
+
+ JdepsMock put(Label label, List<String> values) {
+ jdeps.put(label, values);
+ return this;
+ }
+ }
+
+ private BlazeContext context;
+ private ErrorCollector errorCollector = new ErrorCollector();
+ private final JdepsMock jdepsMap = new JdepsMock();
+ private JavaWorkingSet workingSet = null;
+ private final WorkspaceLanguageSettings workspaceLanguageSettings =
+ new WorkspaceLanguageSettings(WorkspaceType.JAVA, ImmutableSet.of(LanguageClass.JAVA));
+ private MockExperimentService experimentService;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ experimentService = new MockExperimentService();
+ applicationServices.register(ExperimentService.class, experimentService);
+
+ BlazeExecutor blazeExecutor = new MockBlazeExecutor();
+ applicationServices.register(BlazeExecutor.class, blazeExecutor);
+ projectServices.register(
+ BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
+
+ // will silently fall back to FilePathJavaPackageReader
+ applicationServices.register(
+ JavaSourcePackageReader.class,
+ new JavaSourcePackageReader() {
+ @Nullable
+ @Override
+ public String getDeclaredPackageOfJavaFile(
+ @NotNull BlazeContext context, @NotNull SourceArtifact sourceArtifact) {
+ return null;
+ }
+ });
+ applicationServices.register(PackageManifestReader.class, new PackageManifestReader());
+ applicationServices.register(PrefetchService.class, new MockPrefetchService());
+
+ context = new BlazeContext();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+
+ augmenters =
+ registerExtensionPoint(BlazeJavaSyncAugmenter.EP_NAME, BlazeJavaSyncAugmenter.class);
+ }
+
+ BlazeJavaImportResult importWorkspace(
+ WorkspaceRoot workspaceRoot, RuleMapBuilder ruleMapBuilder, ProjectView projectView) {
+
+ ProjectViewSet projectViewSet = ProjectViewSet.builder().add(projectView).build();
+
+ BlazeJavaWorkspaceImporter blazeWorkspaceImporter =
+ new BlazeJavaWorkspaceImporter(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ workspaceLanguageSettings,
+ ruleMapBuilder.build(),
+ jdepsMap,
+ workingSet,
+ FAKE_ARTIFACT_DECODER);
+
+ return blazeWorkspaceImporter.importWorkspace(context);
+ }
+
+ /** Ensure an empty response results in an empty import result. */
+ @Test
+ public void testEmptyProject() {
+ BlazeJavaImportResult result =
+ importWorkspace(workspaceRoot, RuleMapBuilder.builder(), ProjectView.builder().build());
+ errorCollector.assertNoIssues();
+ assertTrue(result.contentEntries.isEmpty());
+ }
+
+ @Test
+ public void testSingleModule() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .addSource(source("java/apps/example/subdir/SubdirHelper.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("java/apps/example/example_debug-ijar.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertEquals(1, result.buildOutputJars.size());
+ File compilerOutputLib = result.buildOutputJars.iterator().next();
+ assertNotNull(compilerOutputLib);
+ assertTrue(compilerOutputLib.getPath().endsWith("example_debug.jar"));
+
+ assertThat(result.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build());
+
+ assertThat(result.javaSourceFiles)
+ .containsExactly(
+ source("java/apps/example/MainActivity.java").getFile(),
+ source("java/apps/example/subdir/SubdirHelper.java").getFile());
+ }
+
+ @Test
+ public void testGeneratedLibrariesIncluded() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:lib")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/example/Test.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/example/lib-ijar.jar"))
+ .setClassJar(gen("java/example/lib.jar")))
+ .addGeneratedJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/example/lib-gen.jar"))
+ .setClassJar(gen("java/example/lib-gen.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ assertThat(
+ result
+ .libraries
+ .values()
+ .stream()
+ .map(BlazeJavaWorkspaceImporterTest::libraryFileName)
+ .collect(Collectors.toList()))
+ .containsExactly("lib-gen.jar");
+ }
+
+ /** Imports two binaries and a library. Only one binary should pass the package filter. */
+ @Test
+ public void testImportFilter() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .addDependency("//java/libraries/example:example")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/example_debug.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/libraries/example:example")
+ .setBuildFile(source("java/libraries/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/libraries/example/SharedActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/libraries/example/AndroidManifest.xml"))
+ .addResource(source("java/libraries/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.libraries.example"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/libraries/example/example.jar"))
+ .setClassJar(gen("java/libraries/example/example.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/com/dontimport:example_debug")
+ .setBuildFile(source("java/com/dontimport/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/com/dontimport/MainActivity.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/com/dontimport/AndroidManifest.xml"))
+ .addResource(source("java/com/dontimport/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.dontimport"))
+ .addDependency("//java/com/dontimport:sometarget")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/com/dontimport/example_debug.jar"))
+ .setClassJar(gen("java/com/dontimport/example_debug.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build());
+ assertThat(result.javaSourceFiles)
+ .containsExactly(source("java/apps/example/MainActivity.java").getFile());
+ }
+
+ /** Import a project and its tests */
+ @Test
+ public void testProjectAndTests() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .add(ListSection.builder(TestSourceSection.KEY).add(new Glob("javatests/*")))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .addSource(source("java/apps/example/subdir/SubdirHelper.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/example_debug.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//javatests/apps/example:example")
+ .setBuildFile(source("javatests/apps/example/BUILD"))
+ .setKind("android_test")
+ .addSource(source("javatests/apps/example/ExampleTests.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .addDependency("//java/apps/example:example_debug")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("javatests/apps/example/example.jar"))
+ .setClassJar(gen("javatests/apps/example/example.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/javatests/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/javatests/apps/example")
+ .setPackagePrefix("apps.example")
+ .setTest(true)
+ .build())
+ .build());
+ }
+
+ /** Test library with a source jar */
+ @Test
+ public void testLibraryWithSourceJar() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .addSource(source("java/apps/example/subdir/SubdirHelper.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(gen("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .addDependency("//thirdparty/some/library:library")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/example_debug.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/some/library:library")
+ .setBuildFile(source("/thirdparty/some/library/BUILD"))
+ .setKind("java_import")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/some/library.jar"))
+ .setClassJar(gen("thirdparty/some/library.jar"))
+ .setSourceJar(gen("thirdparty/some/library.srcjar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ BlazeJarLibrary library = findLibrary(result.libraries, "library.jar");
+ assertNotNull(library);
+ assertNotNull(library.libraryArtifact.sourceJar);
+ }
+
+ /** Test a project with a java test rule */
+ @Test
+ public void testJavaTestRule() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .add(ListSection.builder(TestSourceSection.KEY).add(new Glob("javatests/*")))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .addSource(source("java/apps/example/subdir/SubdirHelper.java"))
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/apps/example/example_debug.jar"))
+ .setClassJar(gen("java/apps/example/example_debug.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//javatests/apps/example:example")
+ .setBuildFile(source("javatests/apps/example/BUILD"))
+ .setKind("java_test")
+ .addSource(source("javatests/apps/example/ExampleTests.java"))
+ .addDependency("//java/apps/example:example_debug")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("javatests/apps/example/example.jar"))
+ .setClassJar(gen("javatests/apps/example/example.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/javatests/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/javatests/apps/example")
+ .setPackagePrefix("apps.example")
+ .setTest(true)
+ .build())
+ .build());
+ }
+
+ /*
+ * Test that the non-android libraries can be imported.
+ */
+ @Test
+ public void testNormalJavaLibraryPackage() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("java/library/something"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .addSource(source("java/apps/example/subdir/SubdirHelper.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .addDependency("//java/library/something:something"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/library/something:something")
+ .setBuildFile(source("java/library/something/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/library/something/SomeJavaFile.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/library/something/something.jar"))
+ .setClassJar(gen("java/library/something/something.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/java/library/something")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/library/something")
+ .setPackagePrefix("library.something")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testImportTargetOutputTag() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("lib")))
+ .add(DirectoryEntry.include(new WorkspacePath("lib2"))))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib:lib")
+ .setBuildFile(source("lib/BUILD"))
+ .setKind("java_library")
+ .addSource(source("lib/Lib.java"))
+ .addDependency("//lib2:lib2")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("lib/lib.jar"))
+ .setClassJar(gen("lib/lib.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib2:lib2")
+ .setBuildFile(source("lib2/BUILD"))
+ .setKind("java_library")
+ .addSource(source("lib2/Lib2.java"))
+ .addTag("intellij-import-target-output")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("lib2/lib2.jar"))
+ .setClassJar(gen("lib2/lib2.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+ assertEquals(1, result.libraries.size());
+ }
+
+ @Test
+ public void testImportAsLibraryTagLegacy() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("lib")))
+ .add(DirectoryEntry.include(new WorkspacePath("lib2"))))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib:lib")
+ .setBuildFile(source("lib/BUILD"))
+ .setKind("java_library")
+ .addSource(source("lib/Lib.java"))
+ .addDependency("//lib2:lib2")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("lib/lib.jar"))
+ .setClassJar(gen("lib/lib.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib2:lib2")
+ .setBuildFile(source("lib2/BUILD"))
+ .setKind("java_library")
+ .addSource(source("lib2/Lib2.java"))
+ .addTag("aswb-import-as-library")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("lib2/lib2.jar"))
+ .setClassJar(gen("lib2/lib2.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+
+ assertEquals(1, result.libraries.size());
+ }
+
+ @Test
+ public void testMultipleImportOfJarsGetMerged() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("lib"))))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib:libsource")
+ .setBuildFile(source("lib/BUILD"))
+ .setKind("java_library")
+ .addSource(source("lib/Source.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//lib:lib0")
+ .addDependency("//lib:lib1"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib:lib0")
+ .setBuildFile(source("lib/BUILD"))
+ .setKind("java_import")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(source("lib/lib.jar"))
+ .setClassJar(source("lib/lib.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//lib:lib1")
+ .setBuildFile(source("lib/BUILD"))
+ .setKind("java_import")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(source("lib/lib.jar"))
+ .setClassJar(source("lib/lib.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+ assertEquals(1, result.libraries.size()); // The libraries were merged
+ }
+
+ @Test
+ public void testRuleWithOnlyGeneratedSourcesIsAddedAsLibrary() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("import"))))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:lib")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("android_library")
+ .addSource(source("import/Lib.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//import:import")
+ .addDependency("//import:import_android"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:import")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("java_library")
+ .addSource(gen("import/GenSource.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("import/import.jar"))
+ .setClassJar(gen("import/import.jar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:import_android")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("android_library")
+ .addSource(gen("import/GenSource.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("import/import_android.jar"))
+ .setClassJar(gen("import/import_android.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(findLibrary(result.libraries, "import.jar")).isNotNull();
+ assertThat(findLibrary(result.libraries, "import_android.jar")).isNotNull();
+ }
+
+ @Test
+ public void testRuleWithMixedGeneratedSourcesAddsFilteredGenJar() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("import"))))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:lib")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("java_library")
+ .addSource(source("import/Import.java"))
+ .addSource(gen("import/Import.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .setFilteredGenJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("import/filtered-gen.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+ assertThat(findLibrary(result.libraries, "filtered-gen.jar")).isNotNull();
+ }
+
+ @Test
+ public void testRuleWithOnlySourceJarAsSourceAddedAsLibrary() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("import"))))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:lib")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("android_library")
+ .addSource(source("import/Lib.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//import:import")
+ .addDependency("//import:import_android"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:import")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("java_library")
+ .addSource(gen("import/gen-src.jar"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("import/import.jar"))
+ .setClassJar(gen("import/import.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(findLibrary(result.libraries, "import.jar")).isNotNull();
+ }
+
+ @Test
+ public void testImportTargetOutput() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("import"))))
+ .add(
+ ListSection.builder(ImportTargetOutputSection.KEY)
+ .add(new Label("//import:import")))
+ .build();
+
+ RuleMapBuilder response =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:lib")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("java_library")
+ .addSource(source("import/Lib.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//import:import"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//import:import")
+ .setBuildFile(source("import/BUILD"))
+ .setKind("java_library")
+ .addSource(source("import/Import.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("import/import.jar"))
+ .setClassJar(gen("import/import.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.libraries).isNotEmpty();
+ }
+
+ private RuleMapBuilder ruleMapForJdepsSuite() {
+ return RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/apps/example/Test.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//thirdparty/a:a"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/a:a")
+ .setKind("java_library")
+ .addSource(source("thirdparty/a/A.java"))
+ .setBuildFile(source("third_party/a/BUILD"))
+ .addDependency("//thirdparty/b:b")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/a.jar"))
+ .setClassJar(gen("thirdparty/a.jar"))
+ .setSourceJar(gen("thirdparty/a.srcjar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/b:b")
+ .setKind("java_library")
+ .addSource(source("thirdparty/b/B.java"))
+ .setBuildFile(source("third_party/b/BUILD"))
+ .addDependency("//thirdparty/c:c")
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/b.jar"))
+ .setClassJar(gen("thirdparty/b.jar"))
+ .setSourceJar(gen("thirdparty/b.srcjar")))))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/c:c")
+ .setKind("java_library")
+ .addSource(source("thirdparty/c/C.java"))
+ .setBuildFile(source("third_party/c/BUILD"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/c.jar"))
+ .setClassJar(gen("thirdparty/c.jar"))
+ .setSourceJar(gen("thirdparty/c.srcjar")))));
+ }
+
+ @Test
+ public void testLibraryDependenciesWithJdepsSet() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .build();
+ RuleMapBuilder ruleMapBuilder = ruleMapForJdepsSuite();
+ jdepsMap.put(
+ new Label("//java/apps/example:example_debug"),
+ Lists.newArrayList(jdepsPath("thirdparty/a.jar"), jdepsPath("thirdparty/c.jar")));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ assertThat(
+ result
+ .libraries
+ .values()
+ .stream()
+ .map(BlazeJavaWorkspaceImporterTest::libraryFileName)
+ .collect(Collectors.toList()))
+ .containsExactly("a.jar", "c.jar");
+ }
+
+ @Test
+ public void
+ testLibraryDependenciesWithJdepsReportingNothingShouldStillIncludeDirectDepsIfInWorkingSet() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .build();
+ RuleMapBuilder ruleMapBuilder = ruleMapForJdepsSuite();
+ workingSet =
+ new JavaWorkingSet(
+ workspaceRoot,
+ new WorkingSet(
+ ImmutableList.of(new WorkspacePath("java/apps/example/Test.java")),
+ ImmutableList.of(),
+ ImmutableList.of()));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ assertThat(
+ result
+ .libraries
+ .values()
+ .stream()
+ .map(BlazeJavaWorkspaceImporterTest::libraryFileName)
+ .collect(Collectors.toList()))
+ .containsExactly("a.jar");
+ }
+
+ @Test
+ public void testLibraryDepsWithJdepsReportingZeroShouldNotIncludeDirectDepsIfNotInWorkingSet() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("javatests/apps/example"))))
+ .build();
+ RuleMapBuilder ruleMapBuilder = ruleMapForJdepsSuite();
+ workingSet =
+ new JavaWorkingSet(
+ workspaceRoot,
+ new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ assertThat(
+ result
+ .libraries
+ .values()
+ .stream()
+ .map(BlazeJavaWorkspaceImporterTest::libraryFileName)
+ .collect(Collectors.toList()))
+ .isEmpty();
+ }
+
+ /*
+ * Test the exclude_target section
+ */
+ @Test
+ public void testExcludeTarget() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example"))))
+ .add(
+ ListSection.builder(ExcludeTargetSection.KEY)
+ .add(new Label("//java/apps/example:example")))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/apps/example/Example.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder().setInterfaceJar(gen("example.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.javaSourceFiles).isEmpty();
+ }
+
+ /*
+ * Test the intellij-exclude-target tag
+ */
+ @Test
+ public void testExcludeTargetTag() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/apps/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example")
+ .addTag(Tags.RULE_TAG_EXCLUDE_TARGET)
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/apps/example/Example.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder().setInterfaceJar(gen("example.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.javaSourceFiles).isEmpty();
+ }
+
+ /** Test legacy proto_library jars, complete with overrides and everything. */
+ @Test
+ public void testLegacyProtoLibraryInfo() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:liba")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/example/Liba.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//thirdparty/proto/a:a"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:libb")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/example/Libb.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .addDependency("//thirdparty/proto/b:b"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/proto/a:a")
+ .setBuildFile(source("/thirdparty/a/BUILD"))
+ .setKind("proto_library")
+ .setProtoLibraryLegacyInfo(
+ ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE)
+ .addJarV1(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/a/liba-1-ijar.jar")))
+ .addJarImmutable(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/a/liba-ijar.jar"))))
+ .addDependency("//thirdparty/proto/b:b")
+ .addDependency("//thirdparty/proto/c:c"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/proto/b:b")
+ .setBuildFile(source("/thirdparty/b/BUILD"))
+ .setKind("proto_library")
+ .setProtoLibraryLegacyInfo(
+ ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1)
+ .addJarV1(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/b/libb-ijar.jar")))
+ .addJarImmutable(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/b/libb-2-ijar.jar"))))
+ .addDependency("//thirdparty/proto/d:d"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/proto/c:c")
+ .setBuildFile(source("/thirdparty/c/BUILD"))
+ .setKind("proto_library")
+ .setProtoLibraryLegacyInfo(
+ ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.IMMUTABLE)
+ .addJarV1(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/c/libc-1-ijar.jar")))
+ .addJarImmutable(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/c/libc-ijar.jar"))))
+ .addDependency("//thirdparty/proto/d:d"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//thirdparty/proto/d:d")
+ .setBuildFile(source("/thirdparty/d/BUILD"))
+ .setKind("proto_library")
+ .setProtoLibraryLegacyInfo(
+ ProtoLibraryLegacyInfo.builder(ProtoLibraryLegacyInfo.ApiFlavor.VERSION_1)
+ .addJarV1(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/d/libd-ijar.jar")))
+ .addJarImmutable(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("thirdparty/proto/d/libd-2-ijar.jar")))));
+
+ workingSet =
+ new JavaWorkingSet(
+ workspaceRoot,
+ new WorkingSet(ImmutableList.of(), ImmutableList.of(), ImmutableList.of()));
+
+ // First test - make sure that jdeps is working
+ jdepsMap.put(
+ new Label("//java/example:liba"),
+ Lists.newArrayList(jdepsPath("thirdparty/proto/a/liba-ijar.jar")));
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+ assertThat(result.libraries).hasSize(1);
+ assertThat(findLibrary(result.libraries, "liba-ijar.jar")).isNotNull();
+
+ // Second test
+ // Put everything in the working set, which should expand to the full transitive closure
+ workingSet =
+ new JavaWorkingSet(
+ workspaceRoot,
+ new WorkingSet(
+ ImmutableList.of(new WorkspacePath("java/example/BUILD")),
+ ImmutableList.of(),
+ ImmutableList.of()));
+
+ result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.libraries).hasSize(6);
+ assertThat(findLibrary(result.libraries, "liba-ijar.jar")).isNotNull();
+ assertThat(findLibrary(result.libraries, "libb-ijar.jar")).isNotNull();
+ assertThat(findLibrary(result.libraries, "libb-2-ijar.jar")).isNotNull();
+ assertThat(findLibrary(result.libraries, "libc-ijar.jar")).isNotNull();
+ assertThat(findLibrary(result.libraries, "libd-ijar.jar")).isNotNull();
+ assertThat(findLibrary(result.libraries, "libd-2-ijar.jar")).isNotNull();
+ }
+
+ /** Test that the non-android libraries can be imported. */
+ @Test
+ public void testImporterWorksWithWorkspaceRootDirectoryIncluded() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath(""))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/apps/example:example_debug")
+ .setBuildFile(source("java/apps/example/BUILD"))
+ .setKind("android_binary")
+ .addSource(source("java/apps/example/MainActivity.java"))
+ .addSource(source("java/apps/example/subdir/SubdirHelper.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder())
+ .setAndroidInfo(
+ AndroidRuleIdeInfo.builder()
+ .setManifestFile(source("java/apps/example/AndroidManifest.xml"))
+ .addResource(source("java/apps/example/res"))
+ .setGenerateResourceClass(true)
+ .setResourceJavaPackage("com.google.android.apps.example"))
+ .addDependency("//java/library/something:something"))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/library/something:something")
+ .setBuildFile(source("java/library/something/BUILD"))
+ .setKind("java_library")
+ .addSource(source("java/library/something/SomeJavaFile.java"))
+ .setJavaInfo(
+ JavaRuleIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("java/library/something/something.jar"))
+ .setClassJar(gen("java/library/something/something.jar")))));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ errorCollector.assertNoIssues();
+
+ assertThat(result.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root")
+ .addSource(BlazeSourceDirectory.builder("/root").build())
+ .addSource(BlazeSourceDirectory.builder("/root/java").build())
+ .build());
+ }
+
+ @Test
+ public void testLanguageLevelIsReadFromToolchain() {
+ ProjectView projectView = ProjectView.builder().build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java:toolchain")
+ .setBuildFile(source("java/BUILD"))
+ .setKind("java_toolchain")
+ .setJavaToolchainIdeInfo(
+ JavaToolchainIdeInfo.builder()
+ .setSourceVersion("8")
+ .setTargetVersion("8")));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ assertThat(result.sourceVersion).isEqualTo("8");
+ }
+
+ @Test
+ public void testSyncAugmenter() {
+ augmenters.registerExtension(
+ new BlazeJavaSyncAugmenter.Adapter() {
+ @Override
+ public boolean isActive(WorkspaceLanguageSettings workspaceLanguageSettings) {
+ return true;
+ }
+
+ @Override
+ public void addJarsForSourceRule(
+ RuleIdeInfo rule,
+ Collection<BlazeJarLibrary> jars,
+ Collection<BlazeJarLibrary> genJars) {
+ if (rule.label.equals(new Label("//java/example:source"))) {
+ jars.add(
+ new BlazeJarLibrary(
+ LibraryArtifact.builder().setInterfaceJar(gen("source.jar")).build(),
+ rule.label));
+ }
+ }
+ });
+
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("java/example"))))
+ .build();
+
+ RuleMapBuilder ruleMapBuilder =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/example:source")
+ .setBuildFile(source("java/example/BUILD"))
+ .setKind("java_library")
+ .addSource(source("Source.java"))
+ .addDependency("//java/lib:lib")
+ .setJavaInfo(JavaRuleIdeInfo.builder()))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setLabel("//java/lib:lib")
+ .setBuildFile(source("java/lib/BUILD"))
+ .setKind("java_library")
+ .addSource(source("Lib.java"))
+ .setJavaInfo(JavaRuleIdeInfo.builder()));
+
+ BlazeJavaImportResult result = importWorkspace(workspaceRoot, ruleMapBuilder, projectView);
+ assertThat(
+ result
+ .libraries
+ .values()
+ .stream()
+ .map(BlazeJavaWorkspaceImporterTest::libraryFileName)
+ .collect(Collectors.toList()))
+ .containsExactly("source.jar");
+ }
+
+ /* Utility methods */
+
+ private static String libraryFileName(BlazeJarLibrary library) {
+ return library.libraryArtifact.jarForIntellijLibrary().getFile().getName();
+ }
+
+ @Nullable
+ private static BlazeJarLibrary findLibrary(
+ Map<LibraryKey, BlazeJarLibrary> libraries, String libraryName) {
+ for (BlazeJarLibrary library : libraries.values()) {
+ if (library
+ .libraryArtifact
+ .jarForIntellijLibrary()
+ .getFile()
+ .getPath()
+ .endsWith(libraryName)) {
+ return library;
+ }
+ }
+ return null;
+ }
+
+ private ArtifactLocation source(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootPath(FAKE_WORKSPACE_ROOT)
+ .setRelativePath(relativePath)
+ .setIsSource(true)
+ .build();
+ }
+
+ private static ArtifactLocation gen(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootPath(FAKE_GEN_ROOT)
+ .setRootExecutionPathFragment(FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT)
+ .setRelativePath(relativePath)
+ .setIsSource(false)
+ .build();
+ }
+
+ private static String jdepsPath(String relativePath) {
+ return FAKE_GEN_ROOT_EXECUTION_PATH_FRAGMENT + "/" + relativePath;
+ }
+}
diff --git a/java/tests/unittests/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculatorTest.java b/java/tests/unittests/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculatorTest.java
new file mode 100644
index 0000000..dec8f90
--- /dev/null
+++ b/java/tests/unittests/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculatorTest.java
@@ -0,0 +1,1185 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.java.sync.source;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.async.executor.MockBlazeExecutor;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.io.InputStreamProvider;
+import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.prefetch.MockPrefetchService;
+import com.google.idea.blaze.base.prefetch.PrefetchService;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ErrorCollector;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.sync.projectview.SourceTestConfig;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
+import com.google.idea.common.experiments.ExperimentService;
+import com.google.idea.common.experiments.MockExperimentService;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.JavaSourcePackage;
+import com.google.repackaged.devtools.build.lib.ideinfo.androidstudio.PackageManifestOuterClass.PackageManifest;
+import com.intellij.util.containers.HashMap;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.Map;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test cases for {@link SourceDirectoryCalculator}. */
+@RunWith(JUnit4.class)
+public class SourceDirectoryCalculatorTest extends BlazeTestCase {
+
+ private static final ImmutableMap<Label, ArtifactLocation> NO_MANIFESTS = ImmutableMap.of();
+ private static final Label LABEL = new Label("//fake:label");
+
+ private MockInputStreamProvider mockInputStreamProvider;
+ private SourceDirectoryCalculator sourceDirectoryCalculator;
+
+ private BlazeContext context = new BlazeContext();
+ private ErrorCollector issues = new ErrorCollector();
+ private MockExperimentService experimentService;
+
+ private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/root"));
+ private ArtifactLocationDecoder decoder =
+ new ArtifactLocationDecoder(
+ new BlazeRoots(
+ new File("/"),
+ Lists.newArrayList(new File("/usr/local/code")),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen")),
+ null);
+
+ static final class TestSourceImportConfig extends SourceTestConfig {
+ final boolean isTest;
+
+ public TestSourceImportConfig(boolean isTest) {
+ super(ProjectViewSet.builder().build());
+ this.isTest = isTest;
+ }
+
+ @Override
+ public boolean isTestSource(String relativePath) {
+ return isTest;
+ }
+ }
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ mockInputStreamProvider = new MockInputStreamProvider();
+ applicationServices.register(InputStreamProvider.class, mockInputStreamProvider);
+ applicationServices.register(JavaSourcePackageReader.class, new JavaSourcePackageReader());
+ applicationServices.register(PackageManifestReader.class, new PackageManifestReader());
+ applicationServices.register(FileAttributeProvider.class, new MockFileAttributeProvider());
+
+ context.addOutputSink(IssueOutput.class, issues);
+ sourceDirectoryCalculator = new SourceDirectoryCalculator();
+
+ BlazeExecutor blazeExecutor = new MockBlazeExecutor();
+ applicationServices.register(BlazeExecutor.class, blazeExecutor);
+
+ experimentService = new MockExperimentService();
+ applicationServices.register(ExperimentService.class, experimentService);
+
+ applicationServices.register(PrefetchService.class, new MockPrefetchService());
+ }
+
+ @Test
+ public void testWorkspacePathIsAddedWithoutSources() throws Exception {
+ List<SourceArtifact> sourceArtifacts = ImmutableList.of();
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false /* isTest */),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google/app")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google/app")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/app")
+ .setPackagePrefix("com.google.app")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testCalculatesPackageForSimpleCase() throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build());
+ issues.assertNoIssues();
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_testReturnsTest() throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(true),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .setTest(true)
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_multipleMatchingPackagesAreMerged() throws Exception {
+ mockInputStreamProvider
+ .addFile("/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/subpackage/Bla.java",
+ "package com.google.subpackage;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testMultipleDirectoriesAreMergedWithDirectoryRootAsWorkspaceRoot() throws Exception {
+ mockInputStreamProvider
+ .addFile(
+ "/root/java/com/google/idea/blaze/plugin/run/Run.java",
+ "package com.google.idea.blaze.plugin.run;\n public class run {}")
+ .addFile(
+ "/root/java/com/google/idea/blaze/plugin/sync/Sync.java",
+ "package com.google.idea.blaze.plugin.sync;\n public class Sync {}")
+ .addFile(
+ "/root/java/com/google/idea/blaze/plugin/Plugin.java",
+ "package com.google.idea.blaze.plugin;\n public class Plugin {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/idea/blaze/plugin/run/Run.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/idea/blaze/plugin/sync/Sync.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/idea/blaze/plugin/Plugin.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root")
+ .addSource(BlazeSourceDirectory.builder("/root").setPackagePrefix("").build())
+ .addSource(BlazeSourceDirectory.builder("/root/java").setPackagePrefix("").build())
+ .build());
+ }
+
+ @Test
+ public void testIncorrectPackageInMiddleOfTreeCausesMergePointHigherUp() throws Exception {
+ mockInputStreamProvider
+ .addFile(
+ "/root/java/com/google/idea/blaze/plugin/run/Run.java",
+ "package com.google.idea.blaze.plugin.run;\n public class run {}")
+ .addFile(
+ "/root/java/com/google/idea/blaze/plugin/sync/Sync.java",
+ "package com.google.idea.blaze.plugin.sync;\n public class Sync {}")
+ .addFile(
+ "/root/java/com/google/idea/blaze/Incorrect.java",
+ "package com.google.idea.blaze.incorrect;\n public class Incorrect {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/idea/blaze/plugin/run/Run.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/idea/blaze/plugin/sync/Sync.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/idea/blaze/Incorrect.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root")
+ .addSource(BlazeSourceDirectory.builder("/root").setPackagePrefix("").build())
+ .addSource(BlazeSourceDirectory.builder("/root/java").setPackagePrefix("").build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/idea/blaze")
+ .setPackagePrefix("com.google.idea.blaze.incorrect")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/idea/blaze/plugin")
+ .setPackagePrefix("com.google.idea.blaze.plugin")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_multipleNonMatchingPackagesAreNotMerged()
+ throws Exception {
+ mockInputStreamProvider
+ .addFile("/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/subpackage/Bla.java",
+ "package com.google.different;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
+ .setPackagePrefix("com.google.different")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_childMatchesPathButParentDoesnt() throws Exception {
+ mockInputStreamProvider
+ .addFile("/root/java/com/google/Bla.java", "package com.facebook;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/subpackage/Bla.java",
+ "package com.google.subpackage;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.facebook")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
+ .setPackagePrefix("com.google.subpackage")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_orderIsIrrelevant() throws Exception {
+ mockInputStreamProvider
+ .addFile("/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/subpackage/Bla.java",
+ "package com.google.different;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
+ .setPackagePrefix("com.google.different")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_packagesMatchPath() throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_packagesDoNotMatchPath() throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/google/Bla.java", "package com.facebook;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.facebook")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_completePackagePathMismatch() throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/org/foo/Bla.java", "package com.facebook;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/org/foo/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/org")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/org")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/org")
+ .setPackagePrefix("com.org")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/org/foo")
+ .setPackagePrefix("com.facebook")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_sourcesOutsideOfModuleGeneratesIssue()
+ throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/facebook/Bla.java", "package com.facebook;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/facebook/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+
+ issues.assertIssueContaining("Did not add");
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_generatedSourcesOutsideOfModuleGeneratesNoIssue()
+ throws Exception {
+ mockInputStreamProvider.addFile(
+ "/root/java/com/facebook/Bla.java", "package com.facebook;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/facebook/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(false))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google/my")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_missingPackageDeclaration() throws Exception {
+ mockInputStreamProvider.addFile("/root/java/com/google/Bla.java", "public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+
+ issues.assertIssueContaining("No package name string found");
+ }
+
+ @Test
+ public void testCompetingPackageDeclarationPicksMajority() throws Exception {
+ mockInputStreamProvider
+ .addFile(
+ "/root/java/com/google/Foo.java", "package com.google.different;\n public class Foo {}")
+ .addFile("/root/java/com/google/Bla.java", "package com.google;\n public class Bla {}")
+ .addFile("/root/java/com/google/Bla2.java", "package com.google;\n public class Bla2 {}")
+ .addFile("/root/java/com/google/Bla3.java", "package com.google;\n public class Bla3 {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla2.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla3.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Foo.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_packagesMatchPathButNotAtRoot() throws Exception {
+ mockInputStreamProvider
+ .addFile(
+ "/root/java/com/google/Bla.java", "package com.google.different;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/subpackage/Bla.java",
+ "package com.google.subpackage;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/subpackage/subsubpackage/Bla.java",
+ "package com.google.subpackage.subsubpackage;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/subsubpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google.different")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
+ .setPackagePrefix("com.google.subpackage")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testSourcesToSourceDirectories_multipleSubdirectoriesAreNotMerged() throws Exception {
+ mockInputStreamProvider
+ .addFile(
+ "/root/java/com/google/package0/Bla.java",
+ "package com.google.packagewrong0;\n public class Bla {}")
+ .addFile(
+ "/root/java/com/google/package1/Bla.java",
+ "package com.google.packagewrong1;\n public class Bla {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/package0/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/package1/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/package0")
+ .setPackagePrefix("com.google.packagewrong0")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/package1")
+ .setPackagePrefix("com.google.packagewrong1")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testLowestDirectoryIsPrioritised() throws Exception {
+ mockInputStreamProvider
+ .addFile(
+ "/root/java/com/google/android/chimera/internal/Preconditions.java",
+ "package com.google.android.chimera.container.internal;\n "
+ + "public class Preconditions {}")
+ .addFile(
+ "/root/java/com/google/android/chimera/container/FileApkUtils.java",
+ "package com.google.android.chimera.container;\n public class FileApkUtils {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath(
+ "java/com/google/android/chimera/internal/Preconditions.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath(
+ "java/com/google/android/chimera/container/FileApkUtils.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ decoder,
+ ImmutableList.of(new WorkspacePath("java/com/google/android")),
+ sourceArtifacts,
+ NO_MANIFESTS);
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google/android")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/android")
+ .setPackagePrefix("com.google.android")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/android/chimera/internal")
+ .setPackagePrefix("com.google.android.chimera.container.internal")
+ .build())
+ .build());
+ }
+
+ @Test
+ public void testNewFormatManifest() throws Exception {
+ setNewFormatPackageManifest(
+ "/root/java/com/test.manifest",
+ ImmutableList.of(
+ PackageManifestOuterClass.ArtifactLocation.newBuilder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setIsSource(true)
+ .build()),
+ ImmutableList.of("com.google"));
+ ImmutableMap<Label, ArtifactLocation> manifests =
+ ImmutableMap.<Label, ArtifactLocation>builder()
+ .put(
+ LABEL,
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setRootPath("/root")
+ .setIsSource(true)
+ .build())
+ .build();
+ Map<Label, Map<String, String>> manifestMap =
+ readPackageManifestFiles(manifests, getDecoder("/root"));
+
+ assertThat(manifestMap.get(LABEL))
+ .containsEntry("/root/java/com/google/Bla.java", "com.google");
+ }
+
+ @Test
+ public void testManifestSingleFile() throws Exception {
+ setPackageManifest(
+ "/root/java/com/test.manifest",
+ ImmutableList.of("java/com/google/Bla.java"),
+ ImmutableList.of("com.google"));
+ ImmutableMap<Label, ArtifactLocation> manifests =
+ ImmutableMap.<Label, ArtifactLocation>builder()
+ .put(
+ LABEL,
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setRootPath("/root")
+ .setIsSource(true)
+ .build())
+ .build();
+ Map<Label, Map<String, String>> manifestMap =
+ readPackageManifestFiles(manifests, getDecoder("/root"));
+
+ assertThat(manifestMap.get(LABEL))
+ .containsEntry("/root/java/com/google/Bla.java", "com.google");
+ }
+
+ @Test
+ public void testManifestRepeatedSources() throws Exception {
+ setPackageManifest(
+ "/root/java/com/test.manifest",
+ ImmutableList.of("java/com/google/Bla.java", "java/com/google/Foo.java"),
+ ImmutableList.of("com.google", "com.google.subpackage"));
+ setPackageManifest(
+ "/root/java/com/test2.manifest",
+ ImmutableList.of("java/com/google/Bla.java", "java/com/google/other/Temp.java"),
+ ImmutableList.of("com.google", "com.google.other"));
+ ImmutableMap<Label, ArtifactLocation> manifests =
+ ImmutableMap.<Label, ArtifactLocation>builder()
+ .put(
+ new Label("//a:a"),
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setRootPath("/root")
+ .setIsSource(true)
+ .build())
+ .put(
+ new Label("//b:b"),
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test2.manifest")
+ .setRootPath("/root")
+ .setIsSource(true)
+ .build())
+ .build();
+ Map<Label, Map<String, String>> manifestMap =
+ readPackageManifestFiles(manifests, getDecoder("/root"));
+
+ assertThat(manifestMap).hasSize(2);
+
+ assertThat(manifestMap.get(new Label("//a:a")))
+ .containsEntry("/root/java/com/google/Bla.java", "com.google");
+ assertThat(manifestMap.get(new Label("//a:a")))
+ .containsEntry("/root/java/com/google/Foo.java", "com.google.subpackage");
+ assertThat(manifestMap.get(new Label("//b:b")))
+ .containsEntry("/root/java/com/google/other/Temp.java", "com.google.other");
+ }
+
+ @Test
+ public void testManifestMissingSourcesFallback() throws Exception {
+ setPackageManifest(
+ "/root/java/com/test.manifest",
+ ImmutableList.of("java/com/google/Bla.java", "java/com/google/Foo.java"),
+ ImmutableList.of("com.google", "com.google"));
+
+ mockInputStreamProvider.addFile(
+ "/root/java/com/google/subpackage/Bla.java",
+ "package com.google.different;\n public class Bla {}");
+
+ ImmutableMap<Label, ArtifactLocation> manifests =
+ ImmutableMap.<Label, ArtifactLocation>builder()
+ .put(
+ LABEL,
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setRootPath("/root")
+ .setIsSource(true)
+ .build())
+ .build();
+
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/Foo.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(LABEL)
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/google/subpackage/Bla.java")
+ .setRootPath("/root")
+ .setIsSource(true))
+ .build());
+
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ new TestSourceImportConfig(false),
+ getDecoder("/root"),
+ ImmutableList.of(new WorkspacePath("java/com/google")),
+ sourceArtifacts,
+ manifests);
+
+ issues.assertNoIssues();
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .addSource(
+ BlazeSourceDirectory.builder("/root/java/com/google/subpackage")
+ .setPackagePrefix("com.google.different")
+ .build())
+ .build());
+ }
+
+ private void setPackageManifest(
+ String manifestPath,
+ List<String> sourceRelativePaths,
+ List<String> packages) {
+ PackageManifest.Builder manifest = PackageManifest.newBuilder();
+ for (int i = 0; i < sourceRelativePaths.size(); i++) {
+ String sourceRelativePath = sourceRelativePaths.get(i);
+ PackageManifestOuterClass.ArtifactLocation source =
+ PackageManifestOuterClass.ArtifactLocation.newBuilder()
+ .setRelativePath(sourceRelativePath)
+ .setIsSource(true)
+ .build();
+ manifest.addSources(
+ JavaSourcePackage.newBuilder()
+ .setArtifactLocation(source)
+ .setPackageString(packages.get(i)));
+ }
+ mockInputStreamProvider.addFile(manifestPath, manifest.build().toByteArray());
+ }
+
+ private void setNewFormatPackageManifest(
+ String manifestPath,
+ List<PackageManifestOuterClass.ArtifactLocation> sources,
+ List<String> packages) {
+ PackageManifest.Builder manifest = PackageManifest.newBuilder();
+ for (int i = 0; i < sources.size(); i++) {
+ manifest.addSources(
+ JavaSourcePackage.newBuilder()
+ .setArtifactLocation(sources.get(i))
+ .setPackageString(packages.get(i)));
+ }
+ mockInputStreamProvider.addFile(manifestPath, manifest.build().toByteArray());
+ }
+
+ private static ArtifactLocationDecoder getDecoder(String rootPath) {
+ File root = new File(rootPath);
+ WorkspaceRoot workspaceRoot = new WorkspaceRoot(root);
+ BlazeRoots roots =
+ new BlazeRoots(
+ root,
+ ImmutableList.of(root),
+ new ExecutionRootPath("out/crosstool/bin"),
+ new ExecutionRootPath("out/crosstool/gen"));
+ return new ArtifactLocationDecoder(roots, new WorkspacePathResolverImpl(workspaceRoot, roots));
+ }
+
+ private static class MockInputStreamProvider implements InputStreamProvider {
+
+ private final Map<String, InputStream> javaFiles = new HashMap<String, InputStream>();
+
+ public MockInputStreamProvider addFile(String filePath, String javaSrc) {
+ try {
+ addFile(filePath, javaSrc.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ fail(e.getMessage());
+ }
+ return this;
+ }
+
+ public MockInputStreamProvider addFile(String filePath, byte[] contents) {
+ javaFiles.put(filePath, new ByteArrayInputStream(contents));
+ return this;
+ }
+
+ @Override
+ public InputStream getFile(@NotNull File path) throws FileNotFoundException {
+ final InputStream inputStream = javaFiles.get(path.getPath());
+ if (inputStream == null) {
+ throw new FileNotFoundException(
+ path + " has not been mapped into MockInputStreamProvider.");
+ }
+ return inputStream;
+ }
+ }
+
+ private Map<Label, Map<String, String>> readPackageManifestFiles(
+ Map<Label, ArtifactLocation> manifests, ArtifactLocationDecoder decoder) {
+ return PackageManifestReader.getInstance()
+ .readPackageManifestFiles(
+ project, context, decoder, manifests, MoreExecutors.sameThreadExecutor());
+ }
+
+ static class MockFileAttributeProvider extends FileAttributeProvider {
+ @Override
+ public long getFileModifiedTime(@NotNull File file) {
+ return 1;
+ }
+ }
+}
diff --git a/plugin_dev/BUILD b/plugin_dev/BUILD
new file mode 100644
index 0000000..0e90f5a
--- /dev/null
+++ b/plugin_dev/BUILD
@@ -0,0 +1,78 @@
+licenses(["notice"]) # Apache 2.0
+
+java_library(
+ name = "plugin_dev",
+ srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//intellij_platform_sdk:devkit",
+ "//intellij_platform_sdk:plugin_api",
+ "//java",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+filegroup(
+ name = "plugin_xml",
+ srcs = ["src/META-INF/blaze-plugin-dev.xml"],
+ visibility = ["//visibility:public"],
+)
+
+load(
+ "//build_defs:build_defs.bzl",
+ "merged_plugin_xml",
+ "stamped_plugin_xml",
+ "intellij_plugin",
+)
+
+merged_plugin_xml(
+ name = "merged_plugin_xml",
+ srcs = [
+ "//base:plugin_xml",
+ "//java:plugin_xml",
+ ] + [
+ ":plugin_xml",
+ ],
+)
+
+stamped_plugin_xml(
+ name = "plugin_dev_plugin_xml",
+ plugin_id = "com.google.idea.blaze.plugin_dev",
+ plugin_name = "com.google.idea.blaze.plugin_dev",
+ plugin_xml = "merged_plugin_xml",
+)
+
+intellij_plugin(
+ name = "plugin_dev_integration_test_plugin",
+ testonly = 1,
+ plugin_xml = ":plugin_dev_plugin_xml",
+ deps = [
+ ":plugin_dev",
+ "//base",
+ "//java",
+ ],
+)
+
+load(
+ "//intellij_test:test_defs.bzl",
+ "intellij_integration_test_suite",
+)
+
+intellij_integration_test_suite(
+ name = "integration_tests",
+ srcs = glob(["tests/integrationtests/**/*.java"]),
+ required_plugins = "com.google.idea.blaze.ijwb",
+ test_package_root = "com.google.idea.blaze.plugin",
+ runtime_deps = [
+ ":plugin_dev_integration_test_plugin",
+ ],
+ deps = [
+ ":plugin_dev",
+ "//base",
+ "//base:integration_test_utils",
+ "//base:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@jsr305_annotations//jar",
+ ],
+)
diff --git a/blaze-plugin-dev/src/META-INF/blaze-plugin-dev.xml b/plugin_dev/src/META-INF/blaze-plugin-dev.xml
similarity index 100%
rename from blaze-plugin-dev/src/META-INF/blaze-plugin-dev.xml
rename to plugin_dev/src/META-INF/blaze-plugin-dev.xml
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java b/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
new file mode 100644
index 0000000..5e5668d
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Kind;
+
+/** Utility methods for intellij_plugin blaze rules */
+public class IntellijPluginRule {
+
+ public static final String RULE_TAG_IJ_PLUGIN = "intellij-plugin";
+ public static final String RULE_TAG_IJ_PLUGIN_BUNDLE = "intellij-plugin-bundle";
+
+ public static boolean isPluginRule(RuleIdeInfo rule) {
+ return isPluginBundle(rule) || isSinglePluginRule(rule);
+ }
+
+ public static boolean isPluginBundle(RuleIdeInfo rule) {
+ return rule.kindIsOneOf(Kind.JAVA_LIBRARY) && rule.tags.contains(RULE_TAG_IJ_PLUGIN_BUNDLE);
+ }
+
+ public static boolean isSinglePluginRule(RuleIdeInfo rule) {
+ return rule.kindIsOneOf(Kind.JAVA_IMPORT) && rule.tags.contains(RULE_TAG_IJ_PLUGIN);
+ }
+
+}
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java
new file mode 100644
index 0000000..d909032
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java
@@ -0,0 +1,531 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.run;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.JavaRuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.BlazeRunConfiguration;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.google.idea.blaze.plugin.IntellijPluginRule;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.JavaCommandLineState;
+import com.intellij.execution.configurations.JavaParameters;
+import com.intellij.execution.configurations.LocatableConfigurationBase;
+import com.intellij.execution.configurations.ModuleRunConfiguration;
+import com.intellij.execution.configurations.ParametersList;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.RuntimeConfigurationError;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.process.ProcessAdapter;
+import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.ide.plugins.IdeaPluginDescriptor;
+import com.intellij.ide.plugins.PluginManagerCore;
+import com.intellij.openapi.application.JetBrainsProtocolHandler;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.roots.ui.configuration.JdkComboBox;
+import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel;
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.openapi.ui.LabeledComponent;
+import com.intellij.openapi.util.BuildNumber;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.ui.ListCellRendererWrapper;
+import com.intellij.ui.RawCommandLineEditor;
+import com.intellij.util.PlatformUtils;
+import com.intellij.util.execution.ParametersListUtil;
+import java.awt.BorderLayout;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JTextArea;
+import org.jdom.Element;
+
+/**
+ * A run configuration that builds a plugin jar via blaze, copies it to the SDK sandbox, then runs
+ * IJ with the plugin loaded.
+ */
+public class BlazeIntellijPluginConfiguration extends LocatableConfigurationBase
+ implements BlazeRunConfiguration, ModuleRunConfiguration {
+
+ private static final String TARGET_TAG = "blaze-target";
+ private static final String USER_BLAZE_FLAG_TAG = "blaze-user-flag";
+ private static final String USER_EXE_FLAG_TAG = "blaze-user-exe-flag";
+ private static final String SDK_ATTR = "blaze-plugin-sdk";
+ private static final String VM_PARAMS_ATTR = "blaze-vm-params";
+ private static final String PROGRAM_PARAMS_ATTR = "blaze-program-params";
+
+ private final String buildSystem;
+
+ @Nullable private Label target;
+ private ImmutableList<String> blazeFlags = ImmutableList.of();
+ private ImmutableList<String> exeFlags = ImmutableList.of();
+ @Nullable private Sdk pluginSdk;
+ @Nullable String vmParameters;
+ @Nullable private String programParameters;
+
+ public BlazeIntellijPluginConfiguration(
+ Project project,
+ ConfigurationFactory factory,
+ String name,
+ @Nullable RuleIdeInfo initialRule) {
+ super(project, factory, name);
+ this.buildSystem = Blaze.buildSystemName(project);
+ Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdk();
+ if (IdeaJdkHelper.isIdeaJdk(projectSdk)) {
+ pluginSdk = projectSdk;
+ }
+ if (initialRule != null) {
+ target = initialRule.label;
+ }
+ }
+
+ @Override
+ @Nullable
+ public Label getTarget() {
+ return target;
+ }
+
+ public void setTarget(Label target) {
+ this.target = target;
+ }
+
+ private ImmutableList<File> findPluginJars() throws ExecutionException {
+ RuleIdeInfo rule = RuleFinder.getInstance().ruleForTarget(getProject(), getTarget());
+ if (rule == null) {
+ throw new ExecutionException(
+ buildSystem + " rule '" + getTarget() + "' not imported during sync");
+ }
+ return IntellijPluginRule.isPluginBundle(rule)
+ ? findBundledJars(rule)
+ : ImmutableList.of(findPluginJar(rule));
+ }
+
+ private ImmutableList<File> findBundledJars(RuleIdeInfo rule) throws ExecutionException {
+ ImmutableList.Builder<File> jars = ImmutableList.builder();
+ for (Label dep : rule.dependencies) {
+ RuleIdeInfo depRule = RuleFinder.getInstance().ruleForTarget(getProject(), dep);
+ if (depRule != null && IntellijPluginRule.isSinglePluginRule(depRule)) {
+ jars.add(findPluginJar(depRule));
+ }
+ }
+ return jars.build();
+ }
+
+ private File findPluginJar(RuleIdeInfo rule) throws ExecutionException {
+ JavaRuleIdeInfo javaRuleIdeInfo = rule.javaRuleIdeInfo;
+ if (!IntellijPluginRule.isSinglePluginRule(rule) || javaRuleIdeInfo == null) {
+ throw new ExecutionException(
+ buildSystem + " rule '" + rule.label + "' is not a valid intellij_plugin rule");
+ }
+ Collection<LibraryArtifact> jars = javaRuleIdeInfo.jars;
+ if (javaRuleIdeInfo.jars.size() > 1) {
+ throw new ExecutionException("Invalid IntelliJ plugin rule: it has multiple output jars");
+ }
+ LibraryArtifact artifact = jars.isEmpty() ? null : jars.iterator().next();
+ if (artifact == null || artifact.classJar == null) {
+ throw new ExecutionException("No output plugin jar found for '" + rule.label + "'");
+ }
+ return artifact.classJar.getFile();
+ }
+
+ /**
+ * Plugin jar has been previously created via blaze build. This method: - copies jar to sandbox
+ * environment - cracks open jar and finds plugin.xml (with ID, etc., needed for JVM args) - sets
+ * up the SDK, etc. (use project SDK?) - sets up the JVM, and returns a JavaCommandLineState
+ */
+ @Nullable
+ @Override
+ public RunProfileState getState(Executor executor, ExecutionEnvironment env)
+ throws ExecutionException {
+ final Sdk ideaJdk = pluginSdk;
+ if (!IdeaJdkHelper.isIdeaJdk(ideaJdk)) {
+ throw new ExecutionException("Choose an IntelliJ Platform Plugin SDK");
+ }
+ String sandboxHome = IdeaJdkHelper.getSandboxHome(ideaJdk);
+ if (sandboxHome == null) {
+ throw new ExecutionException("No sandbox specified for IntelliJ Platform Plugin SDK");
+ }
+
+ try {
+ sandboxHome = new File(sandboxHome).getCanonicalPath();
+ } catch (IOException e) {
+ throw new ExecutionException("No sandbox specified for IntelliJ Platform Plugin SDK");
+ }
+ final String canonicalSandbox = sandboxHome;
+ final ImmutableList<File> pluginJars = findPluginJars();
+ for (File file : pluginJars) {
+ if (!file.exists()) {
+ throw new ExecutionException(
+ String.format(
+ "Plugin jar '%s' not found. Did the %s build fail?", file.getName(), buildSystem));
+ }
+ }
+ // copy license from running instance of idea
+ IdeaJdkHelper.copyIDEALicense(sandboxHome);
+
+ final JavaCommandLineState state =
+ new JavaCommandLineState(env) {
+ @Override
+ protected JavaParameters createJavaParameters() throws ExecutionException {
+ String buildNumber = IdeaJdkHelper.getBuildNumber(ideaJdk);
+ List<String> pluginIds = Lists.newArrayList();
+ for (File jar : pluginJars) {
+ pluginIds.add(copyPluginJarToSandbox(jar, buildNumber, canonicalSandbox));
+ }
+
+ final JavaParameters params = new JavaParameters();
+
+ ParametersList vm = params.getVMParametersList();
+
+ fillParameterList(vm, vmParameters);
+ fillParameterList(params.getProgramParametersList(), programParameters);
+
+ IntellijWithPluginClasspathHelper.addRequiredVmParams(params, ideaJdk);
+
+ vm.defineProperty(
+ JetBrainsProtocolHandler.REQUIRED_PLUGINS_KEY, Joiner.on(',').join(pluginIds));
+
+ if (!vm.hasProperty(PlatformUtils.PLATFORM_PREFIX_KEY) && buildNumber != null) {
+ String prefix = IdeaJdkHelper.getPlatformPrefix(buildNumber);
+ if (prefix != null) {
+ vm.defineProperty(PlatformUtils.PLATFORM_PREFIX_KEY, prefix);
+ }
+ }
+ return params;
+ }
+
+ @Override
+ protected OSProcessHandler startProcess() throws ExecutionException {
+ final OSProcessHandler handler = super.startProcess();
+ handler.addProcessListener(
+ new ProcessAdapter() {
+ @Override
+ public void processTerminated(ProcessEvent event) {
+ for (File jar : pluginJars) {
+ pluginDestination(jar, canonicalSandbox).delete();
+ }
+ }
+ });
+ return handler;
+ }
+ };
+ return state;
+ }
+
+ private static File pluginDestination(File jar, String sandboxPath) {
+ return new File(sandboxPath, "plugins/" + jar.getName());
+ }
+
+ /** Copies the plugin jar to the sandbox, and returns the plugin ID. */
+ private static String copyPluginJarToSandbox(File jar, String buildNumber, String sandboxPath)
+ throws ExecutionException {
+ IdeaPluginDescriptor pluginDescriptor = PluginManagerCore.loadDescriptor(jar, "plugin.xml");
+ if (PluginManagerCore.isIncompatible(pluginDescriptor, BuildNumber.fromString(buildNumber))) {
+ throw new ExecutionException(
+ String.format(
+ "Plugin SDK version '%s' is incompatible with this plugin "
+ + "(since: '%s', until: '%s')",
+ buildNumber, pluginDescriptor.getSinceBuild(), pluginDescriptor.getUntilBuild()));
+ }
+ File pluginJarDestination = pluginDestination(jar, sandboxPath);
+ try {
+ pluginJarDestination.getParentFile().mkdirs();
+ Files.copy(jar.toPath(), pluginJarDestination.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ throw new ExecutionException("Error copying plugin jar to sandbox", e);
+ }
+ return pluginDescriptor.getPluginId().getIdString();
+ }
+
+ private static void fillParameterList(ParametersList list, @Nullable String value) {
+ if (value == null) {
+ return;
+ }
+
+ for (String parameter : value.split(" ")) {
+ if (parameter != null && parameter.length() > 0) {
+ list.add(parameter);
+ }
+ }
+ }
+
+ @Override
+ public Module[] getModules() {
+ return Module.EMPTY_ARRAY;
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ super.checkConfiguration();
+
+ Label target = getTarget();
+ if (target == null) {
+ throw new RuntimeConfigurationError("Select a target to run");
+ }
+ RuleIdeInfo rule = RuleFinder.getInstance().ruleForTarget(getProject(), target);
+ if (rule == null) {
+ throw new RuntimeConfigurationError("The selected target does not exist.");
+ }
+ if (!IntellijPluginRule.isPluginRule(rule)) {
+ throw new RuntimeConfigurationError("The selected target is not an intellij_plugin");
+ }
+ if (!IdeaJdkHelper.isIdeaJdk(pluginSdk)) {
+ throw new RuntimeConfigurationError("Select an IntelliJ Platform Plugin SDK");
+ }
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ super.readExternal(element);
+ // Target is persisted as a tag to permit multiple targets in the future.
+ Element targetElement = element.getChild(TARGET_TAG);
+ if (targetElement != null && !Strings.isNullOrEmpty(targetElement.getTextTrim())) {
+ target = (Label) TargetExpression.fromString(targetElement.getTextTrim());
+ } else {
+ target = null;
+ }
+ blazeFlags = loadUserFlags(element, USER_BLAZE_FLAG_TAG);
+ exeFlags = loadUserFlags(element, USER_EXE_FLAG_TAG);
+
+ String sdkName = element.getAttributeValue(SDK_ATTR);
+ if (!Strings.isNullOrEmpty(sdkName)) {
+ pluginSdk = ProjectJdkTable.getInstance().findJdk(sdkName);
+ }
+ vmParameters = Strings.emptyToNull(element.getAttributeValue(VM_PARAMS_ATTR));
+ programParameters = Strings.emptyToNull(element.getAttributeValue(PROGRAM_PARAMS_ATTR));
+ }
+
+ private static ImmutableList<String> loadUserFlags(Element root, String tag) {
+ ImmutableList.Builder<String> flagsBuilder = ImmutableList.builder();
+ for (Element e : root.getChildren(tag)) {
+ String flag = e.getTextTrim();
+ if (flag != null && !flag.isEmpty()) {
+ flagsBuilder.add(flag);
+ }
+ }
+ return flagsBuilder.build();
+ }
+
+ private static void saveUserFlags(Element root, List<String> flags, String tag) {
+ for (String flag : flags) {
+ Element child = new Element(tag);
+ child.setText(flag);
+ root.addContent(child);
+ }
+ }
+
+ @Override
+ public void writeExternal(Element element) throws WriteExternalException {
+ super.writeExternal(element);
+ if (target != null) {
+ // Target is persisted as a tag to permit multiple targets in the future.
+ Element targetElement = new Element(TARGET_TAG);
+ targetElement.setText(target.toString());
+ element.addContent(targetElement);
+ }
+ saveUserFlags(element, blazeFlags, USER_BLAZE_FLAG_TAG);
+ saveUserFlags(element, exeFlags, USER_EXE_FLAG_TAG);
+ if (pluginSdk != null) {
+ element.setAttribute(SDK_ATTR, pluginSdk.getName());
+ }
+ if (vmParameters != null) {
+ element.setAttribute(VM_PARAMS_ATTR, vmParameters);
+ }
+ if (programParameters != null) {
+ element.setAttribute(PROGRAM_PARAMS_ATTR, programParameters);
+ }
+ }
+
+ @Override
+ public BlazeIntellijPluginConfiguration clone() {
+ final BlazeIntellijPluginConfiguration configuration =
+ (BlazeIntellijPluginConfiguration) super.clone();
+ configuration.target = target;
+ configuration.blazeFlags = blazeFlags;
+ configuration.exeFlags = exeFlags;
+ configuration.pluginSdk = pluginSdk;
+ configuration.vmParameters = vmParameters;
+ configuration.programParameters = programParameters;
+ return configuration;
+ }
+
+ protected BlazeCommand buildBlazeCommand(Project project, ProjectViewSet projectViewSet) {
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(Blaze.getBuildSystem(getProject()), BlazeCommandName.BUILD)
+ .addTargets(getTarget())
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
+ .addBlazeFlags(blazeFlags)
+ .addExeFlags(exeFlags);
+ return command.build();
+ }
+
+ @Override
+ public BlazeIntellijPluginConfigurationSettingsEditor getConfigurationEditor() {
+ List<RuleIdeInfo> javaRules =
+ RuleFinder.getInstance().findRules(getProject(), IntellijPluginRule::isPluginRule);
+ List<Label> javaLabels = Lists.newArrayList();
+ for (RuleIdeInfo rule : javaRules) {
+ javaLabels.add(rule.label);
+ }
+ return new BlazeIntellijPluginConfigurationSettingsEditor(buildSystem, javaLabels);
+ }
+
+ @Override
+ @Nullable
+ public String suggestedName() {
+ Label target = getTarget();
+ if (target == null) {
+ return null;
+ }
+ return new BlazeConfigurationNameBuilder()
+ .setBuildSystemName(getProject())
+ .setCommandName("build")
+ .setTargetString(target)
+ .build();
+ }
+
+ @VisibleForTesting
+ static class BlazeIntellijPluginConfigurationSettingsEditor
+ extends SettingsEditor<BlazeIntellijPluginConfiguration> {
+ private final String buildSystemName;
+ private final ComboBox targetCombo;
+ private final JTextArea blazeFlagsField = new JTextArea(5, 0);
+ private final JTextArea exeFlagsField = new JTextArea(5, 0);
+ private final JdkComboBox sdkCombo;
+ private final LabeledComponent<RawCommandLineEditor> vmParameters = new LabeledComponent<>();
+ private final LabeledComponent<RawCommandLineEditor> programParameters =
+ new LabeledComponent<>();
+
+ public BlazeIntellijPluginConfigurationSettingsEditor(
+ String buildSystemName, List<Label> javaLabels) {
+ this.buildSystemName = buildSystemName;
+ targetCombo =
+ new ComboBox(
+ new DefaultComboBoxModel(Ordering.usingToString().sortedCopy(javaLabels).toArray()));
+ targetCombo.setRenderer(
+ new ListCellRendererWrapper<Label>() {
+ @Override
+ public void customize(
+ JList list, @Nullable Label value, int index, boolean selected, boolean hasFocus) {
+ setText(value == null ? null : value.toString());
+ }
+ });
+
+ ProjectSdksModel sdksModel = new ProjectSdksModel();
+ sdksModel.reset(null);
+ sdkCombo = new JdkComboBox(sdksModel, IdeaJdkHelper::isIdeaJdkType);
+ }
+
+ @VisibleForTesting
+ @Override
+ public void resetEditorFrom(BlazeIntellijPluginConfiguration s) {
+ targetCombo.setSelectedItem(s.getTarget());
+ blazeFlagsField.setText(ParametersListUtil.join(s.blazeFlags));
+ exeFlagsField.setText(ParametersListUtil.join(s.exeFlags));
+ if (s.pluginSdk != null) {
+ sdkCombo.setSelectedJdk(s.pluginSdk);
+ } else {
+ s.pluginSdk = sdkCombo.getSelectedJdk();
+ }
+ if (s.vmParameters != null) {
+ vmParameters.getComponent().setText(s.vmParameters);
+ }
+ if (s.programParameters != null) {
+ programParameters.getComponent().setText(s.programParameters);
+ }
+ }
+
+ @VisibleForTesting
+ @Override
+ public void applyEditorTo(BlazeIntellijPluginConfiguration s) throws ConfigurationException {
+ try {
+ s.target = (Label) targetCombo.getSelectedItem();
+ } catch (ClassCastException e) {
+ throw new ConfigurationException("Invalid label specified.");
+ }
+ s.blazeFlags =
+ ImmutableList.copyOf(
+ ParametersListUtil.parse(Strings.nullToEmpty(blazeFlagsField.getText())));
+ s.exeFlags =
+ ImmutableList.copyOf(
+ ParametersListUtil.parse(Strings.nullToEmpty(exeFlagsField.getText())));
+ s.pluginSdk = sdkCombo.getSelectedJdk();
+ s.vmParameters = vmParameters.getComponent().getText();
+ s.programParameters = programParameters.getComponent().getText();
+ }
+
+ @Override
+ protected JComponent createEditor() {
+ vmParameters.setText("VM options:");
+ vmParameters.setComponent(new RawCommandLineEditor());
+ vmParameters.getComponent().setDialogCaption(vmParameters.getRawText());
+ vmParameters.setLabelLocation(BorderLayout.WEST);
+
+ programParameters.setText("Program arguments");
+ programParameters.setComponent(new RawCommandLineEditor());
+ programParameters.getComponent().setDialogCaption(programParameters.getRawText());
+ programParameters.setLabelLocation(BorderLayout.WEST);
+
+ return UiUtil.createBox(
+ new JLabel("Target:"),
+ targetCombo,
+ new JLabel("Plugin SDK"),
+ sdkCombo,
+ vmParameters.getLabel(),
+ vmParameters.getComponent(),
+ programParameters.getLabel(),
+ programParameters.getComponent(),
+ new JLabel(buildSystemName + " flags:"),
+ blazeFlagsField,
+ new JLabel("Executable flags:"),
+ exeFlagsField);
+ }
+ }
+}
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfigurationType.java b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfigurationType.java
new file mode 100644
index 0000000..38baa96
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfigurationType.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.run;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.run.BlazeRuleConfigurationFactory;
+import com.google.idea.blaze.base.run.rulefinder.RuleFinder;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.plugin.IntellijPluginRule;
+import com.intellij.diagnostic.VMOptions;
+import com.intellij.execution.BeforeRunTask;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.ConfigurationTypeUtil;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.NullableLazyValue;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * A type for run configurations that build an IntelliJ plugin jar via blaze, then load them in an
+ * IntelliJ application
+ */
+public class BlazeIntellijPluginConfigurationType implements ConfigurationType {
+
+ private final BlazeIntellijPluginConfigurationFactory factory =
+ new BlazeIntellijPluginConfigurationFactory(this);
+
+ static class BlazeIntellijPluginRuleConfigurationFactory extends BlazeRuleConfigurationFactory {
+ @Override
+ public boolean handlesRule(
+ WorkspaceLanguageSettings workspaceLanguageSettings, RuleIdeInfo rule) {
+ return workspaceLanguageSettings.isWorkspaceType(WorkspaceType.INTELLIJ_PLUGIN)
+ && IntellijPluginRule.isPluginRule(rule);
+ }
+
+ @Override
+ protected ConfigurationFactory getConfigurationFactory() {
+ return getInstance().factory;
+ }
+
+ @Override
+ public void setupConfiguration(RunConfiguration configuration, RuleIdeInfo rule) {
+ final BlazeIntellijPluginConfiguration pluginConfig =
+ (BlazeIntellijPluginConfiguration) configuration;
+ getInstance().factory.setupConfigurationForRule(pluginConfig, rule);
+ }
+ }
+
+ static class BlazeIntellijPluginConfigurationFactory extends ConfigurationFactory {
+
+ private static NullableLazyValue<String> currentVmOptions =
+ new NullableLazyValue<String>() {
+ @Nullable
+ @Override
+ protected String compute() {
+ return defaultVmOptions();
+ }
+ };
+
+ protected BlazeIntellijPluginConfigurationFactory(ConfigurationType type) {
+ super(type);
+ }
+
+ @Override
+ public boolean isApplicable(Project project) {
+ return Blaze.isBlazeProject(project);
+ }
+
+ @Override
+ public BlazeIntellijPluginConfiguration createTemplateConfiguration(Project project) {
+ BlazeIntellijPluginConfiguration config =
+ new BlazeIntellijPluginConfiguration(
+ project,
+ this,
+ "Unnamed",
+ RuleFinder.getInstance().findFirstRule(project, IntellijPluginRule::isPluginRule));
+ config.vmParameters = currentVmOptions.getValue();
+ return config;
+ }
+
+ @Override
+ public void configureBeforeRunTaskDefaults(
+ Key<? extends BeforeRunTask> providerID, BeforeRunTask task) {
+ task.setEnabled(providerID.equals(BuildPluginBeforeRunTaskProvider.ID));
+ }
+
+ void setupConfigurationForRule(
+ BlazeIntellijPluginConfiguration configuration, RuleIdeInfo rule) {
+ configuration.setTarget(rule.label);
+ configuration.setGeneratedName();
+ if (configuration.vmParameters == null) {
+ configuration.vmParameters = currentVmOptions.getValue();
+ }
+ }
+
+ @Override
+ public boolean isConfigurationSingletonByDefault() {
+ return true;
+ }
+
+ private static String defaultVmOptions() {
+ String vmoptions = VMOptions.read();
+ if (vmoptions == null) {
+ return null;
+ }
+ vmoptions = vmoptions.replaceAll("\\s+", " ").trim();
+ String vmoptionsFile = System.getProperty("jb.vmOptionsFile");
+ if (vmoptionsFile != null) {
+ vmoptions += " -Djb.vmOptionsFile=" + vmoptionsFile;
+ }
+ return vmoptions;
+ }
+ }
+
+ public static BlazeIntellijPluginConfigurationType getInstance() {
+ return ConfigurationTypeUtil.findConfigurationType(BlazeIntellijPluginConfigurationType.class);
+ }
+
+ @Override
+ public String getDisplayName() {
+ return Blaze.defaultBuildSystemName() + " IntelliJ Plugin";
+ }
+
+ @Override
+ public String getConfigurationTypeDescription() {
+ return "Configuration for launching an IntelliJ plugin in a sandbox environment.";
+ }
+
+ @Override
+ public Icon getIcon() {
+ return AllIcons.Nodes.Plugin;
+ }
+
+ @Override
+ public String getId() {
+ return "BlazeIntellijPluginConfigurationType";
+ }
+
+ @Override
+ public BlazeIntellijPluginConfigurationFactory[] getConfigurationFactories() {
+ return new BlazeIntellijPluginConfigurationFactory[] {factory};
+ }
+
+ public BlazeIntellijPluginConfigurationFactory getFactory() {
+ return factory;
+ }
+}
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java b/plugin_dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java
new file mode 100644
index 0000000..de99b7a
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.run;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.async.executor.BlazeExecutor;
+import com.google.idea.blaze.base.async.process.ExternalTask;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.command.BlazeCommand;
+import com.google.idea.blaze.base.experiments.ExperimentScope;
+import com.google.idea.blaze.base.filecache.FileCaches;
+import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
+import com.google.idea.blaze.base.metrics.Action;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.projectview.ProjectViewManager;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.Scope;
+import com.google.idea.blaze.base.scope.ScopedTask;
+import com.google.idea.blaze.base.scope.output.IssueOutput;
+import com.google.idea.blaze.base.scope.scopes.BlazeConsoleScope;
+import com.google.idea.blaze.base.scope.scopes.IdeaLogScope;
+import com.google.idea.blaze.base.scope.scopes.IssuesScope;
+import com.google.idea.blaze.base.scope.scopes.LoggedTimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.util.SaveUtil;
+import com.intellij.execution.BeforeRunTask;
+import com.intellij.execution.BeforeRunTaskProvider;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import icons.BlazeIcons;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/**
+ * Builds the intellij_plugin jar via 'blaze build', for Blaze Intellij Plugin run configurations
+ */
+public final class BuildPluginBeforeRunTaskProvider
+ extends BeforeRunTaskProvider<BuildPluginBeforeRunTaskProvider.Task> {
+ public static final Key<Task> ID = Key.create("Blaze.Intellij.Plugin.BeforeRunTask");
+
+ static class Task extends BeforeRunTask<Task> {
+ private Task() {
+ super(ID);
+ setEnabled(true);
+ }
+ }
+
+ private final Project project;
+
+ public BuildPluginBeforeRunTaskProvider(Project project) {
+ this.project = project;
+ }
+
+ @Override
+ public Icon getIcon() {
+ return BlazeIcons.Blaze;
+ }
+
+ @Override
+ public Icon getTaskIcon(Task task) {
+ return BlazeIcons.Blaze;
+ }
+
+ @Override
+ public boolean isConfigurable() {
+ return false;
+ }
+
+ @Override
+ public boolean configureTask(RunConfiguration runConfiguration, Task task) {
+ return false;
+ }
+
+ @Override
+ public Key<Task> getId() {
+ return ID;
+ }
+
+ @Override
+ public String getName() {
+ return taskName();
+ }
+
+ @Override
+ public String getDescription(Task task) {
+ return taskName();
+ }
+
+ private String taskName() {
+ return Blaze.buildSystemName(project) + " build plugin before-run task";
+ }
+
+ @Override
+ public final boolean canExecuteTask(RunConfiguration configuration, Task task) {
+ return isValidConfiguration(configuration);
+ }
+
+ @Nullable
+ @Override
+ public Task createTask(RunConfiguration runConfiguration) {
+ if (isValidConfiguration(runConfiguration)) {
+ return new Task();
+ }
+ return null;
+ }
+
+ private static boolean isValidConfiguration(RunConfiguration runConfiguration) {
+ return runConfiguration instanceof BlazeIntellijPluginConfiguration;
+ }
+
+ @Override
+ public final boolean executeTask(
+ final DataContext dataContext,
+ final RunConfiguration configuration,
+ final ExecutionEnvironment env,
+ Task task) {
+ if (!canExecuteTask(configuration, task)) {
+ return false;
+ }
+ boolean suppressConsole = BlazeUserSettings.getInstance().getSuppressConsoleForRunAction();
+ return Scope.root(
+ context -> {
+ context
+ .push(new ExperimentScope())
+ .push(new IssuesScope(project))
+ .push(
+ new BlazeConsoleScope.Builder(project)
+ .setSuppressConsole(suppressConsole)
+ .build())
+ .push(new IdeaLogScope());
+
+ final ProjectViewSet projectViewSet =
+ ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ IssueOutput.error("Could not load project view. Please resync project").submit(context);
+ return false;
+ }
+
+ final ScopedTask buildTask =
+ new ScopedTask(context) {
+ @Override
+ protected void execute(BlazeContext context) {
+ BlazeIntellijPluginConfiguration config =
+ (BlazeIntellijPluginConfiguration) configuration;
+ BlazeCommand command = config.buildBlazeCommand(project, projectViewSet);
+ if (command == null || context.hasErrors() || context.isCancelled()) {
+ return;
+ }
+ SaveUtil.saveAllFiles();
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command)
+ .context(context)
+ .stderr(
+ LineProcessingOutputStream.of(
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run(new LoggedTimingScope(project, Action.BLAZE_BUILD));
+ if (retVal != 0) {
+ context.setHasError();
+ }
+ FileCaches.refresh(project);
+ }
+ };
+
+ ListenableFuture<Void> buildFuture =
+ BlazeExecutor.submitTask(
+ project, "Executing blaze build for IntelliJ plugin jar", buildTask);
+
+ try {
+ Futures.get(buildFuture, ExecutionException.class);
+ } catch (ExecutionException e) {
+ context.setHasError();
+ } catch (CancellationException e) {
+ context.setCancelled();
+ }
+
+ if (context.hasErrors() || context.isCancelled()) {
+ return false;
+ }
+ return true;
+ });
+ }
+}
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/run/IdeaJdkHelper.java b/plugin_dev/src/com/google/idea/blaze/plugin/run/IdeaJdkHelper.java
new file mode 100644
index 0000000..74daeee
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/IdeaJdkHelper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.run;
+
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkTypeId;
+import javax.annotation.Nullable;
+import org.jetbrains.idea.devkit.projectRoots.IdeaJdk;
+import org.jetbrains.idea.devkit.projectRoots.IntelliJPlatformProduct;
+import org.jetbrains.idea.devkit.projectRoots.Sandbox;
+import org.jetbrains.idea.devkit.run.IdeaLicenseHelper;
+
+/** Contains all dependencies on devkit (not included in plugin SDK) */
+public class IdeaJdkHelper {
+
+ public static boolean isIdeaJdk(@Nullable Sdk sdk) {
+ return sdk != null && isIdeaJdkType(sdk.getSdkType());
+ }
+
+ public static boolean isIdeaJdkType(SdkTypeId type) {
+ return IdeaJdk.getInstance().equals(type);
+ }
+
+ @Nullable
+ public static String getBuildNumber(Sdk sdk) {
+ return IdeaJdk.getBuildNumber(sdk.getHomePath());
+ }
+
+ public static void copyIDEALicense(final String sandboxHome) {
+ IdeaLicenseHelper.copyIDEALicense(sandboxHome);
+ }
+
+ /** @throws RuntimeException if input Sdk is not an IdeaJdk */
+ public static String getSandboxHome(Sdk sdk) {
+ if (!isIdeaJdk(sdk)) {
+ throw new RuntimeException("Invalid SDK type: " + sdk.getSdkType());
+ }
+ return ((Sandbox) sdk.getSdkAdditionalData()).getSandboxHome();
+ }
+
+ @Nullable
+ public static String getPlatformPrefix(String buildNumber) {
+ return IntelliJPlatformProduct.fromBuildNumber(buildNumber).getPlatformPrefix();
+ }
+}
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/run/IntellijWithPluginClasspathHelper.java b/plugin_dev/src/com/google/idea/blaze/plugin/run/IntellijWithPluginClasspathHelper.java
new file mode 100644
index 0000000..b3d0b2e
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/IntellijWithPluginClasspathHelper.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.run;
+
+import com.google.common.collect.Lists;
+import com.intellij.execution.configurations.JavaParameters;
+import com.intellij.execution.configurations.ParametersList;
+import com.intellij.openapi.projectRoots.JavaSdkType;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.util.PathsList;
+import java.io.File;
+import java.util.List;
+import org.jetbrains.annotations.NonNls;
+
+/**
+ * Boilerplate for running an IJ application with an additional plugin, copied from
+ * org.jetbrains.idea.devkit.run.PluginRunConfiguration
+ */
+public class IntellijWithPluginClasspathHelper {
+
+ private static final List<String> IJ_LIBRARIES =
+ Lists.newArrayList(
+ "log4j.jar",
+ "trove4j.jar",
+ "openapi.jar",
+ "util.jar",
+ "extensions.jar",
+ "bootstrap.jar",
+ "idea.jar",
+ "idea_rt.jar");
+
+ private static void addIntellijLibraries(JavaParameters params, Sdk ideaJdk) {
+ @NonNls String libPath = ideaJdk.getHomePath() + File.separator + "lib";
+ PathsList list = params.getClassPath();
+ for (String lib : IJ_LIBRARIES) {
+ list.addFirst(libPath + File.separator + lib);
+ }
+ list.addFirst(((JavaSdkType) ideaJdk.getSdkType()).getToolsPath(ideaJdk));
+ }
+
+ public static void addRequiredVmParams(JavaParameters params, Sdk ideaJdk) {
+ String canonicalSandbox = IdeaJdkHelper.getSandboxHome(ideaJdk);
+ ParametersList vm = params.getVMParametersList();
+
+ @NonNls String libPath = ideaJdk.getHomePath() + File.separator + "lib";
+ vm.add("-Xbootclasspath/a:" + libPath + File.separator + "boot.jar");
+
+ vm.defineProperty("idea.config.path", canonicalSandbox + File.separator + "config");
+ vm.defineProperty("idea.system.path", canonicalSandbox + File.separator + "system");
+ vm.defineProperty("idea.plugins.path", canonicalSandbox + File.separator + "plugins");
+ vm.defineProperty("idea.classpath.index.enabled", "false");
+
+ if (SystemInfo.isMac) {
+ vm.defineProperty("idea.smooth.progress", "false");
+ vm.defineProperty("apple.laf.useScreenMenuBar", "true");
+ }
+
+ if (SystemInfo.isXWindow) {
+ if (!vm.hasProperty("sun.awt.disablegrab")) {
+ vm.defineProperty(
+ "sun.awt.disablegrab", "true"); // See http://devnet.jetbrains.net/docs/DOC-1142
+ }
+ }
+
+ params.setWorkingDirectory(ideaJdk.getHomePath() + File.separator + "bin" + File.separator);
+ params.setJdk(ideaJdk);
+
+ addIntellijLibraries(params, ideaJdk);
+
+ params.setMainClass("com.intellij.idea.Main");
+ }
+}
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/sync/IntellijPluginSyncPlugin.java b/plugin_dev/src/com/google/idea/blaze/plugin/sync/IntellijPluginSyncPlugin.java
new file mode 100644
index 0000000..b4d13c7
--- /dev/null
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/sync/IntellijPluginSyncPlugin.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.sync;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.java.sync.JavaLanguageLevelHelper;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.module.StdModuleTypes;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.util.ui.UIUtil;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/**
+ * Development environment support for intellij plugin projects. Prevents the project SDK being
+ * reset during sync
+ */
+public class IntellijPluginSyncPlugin extends BlazeSyncPlugin.Adapter {
+
+ @Nullable
+ @Override
+ public WorkspaceType getDefaultWorkspaceType() {
+ return WorkspaceType.INTELLIJ_PLUGIN;
+ }
+
+ @Nullable
+ @Override
+ public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
+ if (workspaceType == WorkspaceType.INTELLIJ_PLUGIN) {
+ return StdModuleTypes.JAVA;
+ }
+ return null;
+ }
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ if (workspaceType == WorkspaceType.INTELLIJ_PLUGIN) {
+ return ImmutableSet.of(LanguageClass.JAVA);
+ }
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public void updateSdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData) {
+ if (!blazeProjectData.workspaceLanguageSettings.isWorkspaceType(
+ WorkspaceType.INTELLIJ_PLUGIN)) {
+ return;
+ }
+
+ LanguageLevel javaLanguageLevel =
+ JavaLanguageLevelHelper.getJavaLanguageLevel(
+ projectViewSet, blazeProjectData, LanguageLevel.JDK_1_7);
+
+ // Leave the SDK, but set the language level
+ UIUtil.invokeAndWaitIfNeeded(
+ (Runnable)
+ () ->
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ LanguageLevelProjectExtension ext =
+ LanguageLevelProjectExtension.getInstance(project);
+ ext.setLanguageLevel(javaLanguageLevel);
+ }));
+ }
+}
diff --git a/plugin_dev/tests/integrationtests/com/google/idea/blaze/plugin/sync/PluginDevSyncTest.java b/plugin_dev/tests/integrationtests/com/google/idea/blaze/plugin/sync/PluginDevSyncTest.java
new file mode 100644
index 0000000..492a6fb
--- /dev/null
+++ b/plugin_dev/tests/integrationtests/com/google/idea/blaze/plugin/sync/PluginDevSyncTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 The Bazel Authors. All rights reserved.
+ *
+ * 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 com.google.idea.blaze.plugin.sync;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.ideinfo.RuleIdeInfo;
+import com.google.idea.blaze.base.ideinfo.RuleMapBuilder;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.RuleMap;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.sync.BlazeSyncIntegrationTestCase;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.plugin.run.BlazeIntellijPluginConfiguration;
+import com.intellij.execution.RunManager;
+import com.intellij.execution.configurations.RunConfiguration;
+import java.util.List;
+
+/** Plugin-dev specific sync integration test. */
+public class PluginDevSyncTest extends BlazeSyncIntegrationTestCase {
+
+ public void testRunConfigurationCreatedDuringSync() throws Exception {
+ setProjectView(
+ "directories:",
+ " java/com/google",
+ "targets:",
+ " //java/com/google:lib",
+ " //java/com/google:plugin",
+ "workspace_type: intellij_plugin");
+
+ createFile(
+ "java/com/google/ClassWithUniqueName1.java",
+ "package com.google;",
+ "public class ClassWithUniqueName1 {}");
+
+ createFile(
+ "java/com/google/ClassWithUniqueName2.java",
+ "package com.google;",
+ "public class ClassWithUniqueName2 {}");
+
+ RuleMap ruleMap =
+ RuleMapBuilder.builder()
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:lib")
+ .setKind("java_library")
+ .addSource(sourceRoot("java/com/google/ClassWithUniqueName1.java"))
+ .addSource(sourceRoot("java/com/google/ClassWithUniqueName2.java")))
+ .addRule(
+ RuleIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:plugin")
+ .setKind("java_import")
+ .addTag("intellij-plugin"))
+ .build();
+
+ setRuleMap(ruleMap);
+
+ runBlazeSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .build());
+
+ assertNoErrors();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.ruleMap).isEqualTo(ruleMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
+ .isEqualTo(WorkspaceType.INTELLIJ_PLUGIN);
+
+ List<RunConfiguration> runConfigs =
+ RunManager.getInstance(getProject()).getAllConfigurationsList();
+ assertThat(runConfigs).hasSize(1);
+ assertThat(runConfigs.get(0)).isInstanceOf(BlazeIntellijPluginConfiguration.class);
+ }
+}
diff --git a/proto_deps/BUILD b/proto_deps/BUILD
new file mode 100644
index 0000000..f90fbfa
--- /dev/null
+++ b/proto_deps/BUILD
@@ -0,0 +1,12 @@
+#
+# Description:
+# Checked-in copy of the bazel proto deps.
+#
+
+licenses(["notice"]) # Apache 2.0
+
+java_import(
+ name = "proto_deps",
+ jars = ["proto_deps.jar"],
+ visibility = ["//visibility:public"],
+)
diff --git a/proto_deps/proto_deps.jar b/proto_deps/proto_deps.jar
new file mode 100755
index 0000000..80b6046
--- /dev/null
+++ b/proto_deps/proto_deps.jar
Binary files differ
diff --git a/remote_platform_sdks/BUILD.android_studio b/remote_platform_sdks/BUILD.android_studio
deleted file mode 100644
index 3e394c2..0000000
--- a/remote_platform_sdks/BUILD.android_studio
+++ /dev/null
@@ -1,36 +0,0 @@
-# Description:
-#
-# Plugin source jars for Android Studio 2.2. Preview 4, accessed remotely.
-
-package(default_visibility = ["//visibility:public"])
-
-java_import(
- name = "plugin_api",
- jars = glob([
- "android-studio/lib/*.jar",
- "android-studio/plugins/android/lib/*.jar",
- "android-studio/plugins/android-ndk/lib/*.jar",
- ]),
- tags = ["intellij-provided-by-sdk"],
-)
-
-# The plugins required by ASwB. We need to include them
-# when running integration tests.
-java_import(
- name = "bundled_plugins",
- jars = glob([
- "android-studio/plugins/android/lib/*.jar",
- "android-studio/plugins/android-ndk/lib/*.jar",
- "android-studio/plugins/gradle/lib/*.jar",
- "android-studio/plugins/Groovy/lib/*.jar",
- "android-studio/plugins/java-i18n/lib/*.jar",
- "android-studio/plugins/junit/lib/*.jar",
- "android-studio/plugins/properties/lib/*.jar",
- ]),
- tags = ["intellij-provided-by-sdk"],
-)
-
-filegroup(
- name = "build_number",
- srcs = ["android-studio/build.txt"],
-)
diff --git a/remote_platform_sdks/BUILD.clion b/remote_platform_sdks/BUILD.clion
deleted file mode 100644
index 48593a8..0000000
--- a/remote_platform_sdks/BUILD.clion
+++ /dev/null
@@ -1,24 +0,0 @@
-# Description:
-#
-# Plugin source jars for CLion 2016.1.3, accessed remotely.
-
-package(default_visibility = ["//visibility:public"])
-
-java_import(
- name = "plugin_api",
- jars = glob(["clion-2016.1.3/lib/*.jar"]),
- tags = ["intellij-provided-by-sdk"],
-)
-
-filegroup(
- name = "build_number",
- srcs = ["clion-2016.1.3/build.txt"],
-)
-
-# The plugins required by CLwB. Presumably there will be some, when we write
-# some integration tests.
-java_import(
- name = "bundled_plugins",
- jars = [],
- tags = ["intellij-provided-by-sdk"],
-)
diff --git a/remote_platform_sdks/BUILD.idea b/remote_platform_sdks/BUILD.idea
deleted file mode 100644
index c8106a5..0000000
--- a/remote_platform_sdks/BUILD.idea
+++ /dev/null
@@ -1,35 +0,0 @@
-# Description:
-#
-# Plugin source jars for IntelliJ 2016.1.3, accessed remotely.
-
-package(default_visibility = ["//visibility:public"])
-
-java_import(
- name = "plugin_api",
- jars = glob(["idea-IC-145.*/lib/*.jar"]),
- tags = ["intellij-provided-by-sdk"],
-)
-
-java_import(
- name = "devkit",
- jars = glob(["idea-IC-145.*/plugins/devkit/lib/devkit.jar"]),
- tags = ["intellij-provided-by-sdk"],
-)
-
-# The plugins required by IJwB. We need to include them
-# when running integration tests.
-java_import(
- name = "bundled_plugins",
- jars = glob([
- "idea-IC-145.*/plugins/devkit/lib/*.jar",
- "idea-IC-145.*/plugins/java-i18n/lib/*.jar",
- "idea-IC-145.*/plugins/junit/lib/*.jar",
- "idea-IC-145.*/plugins/properties/lib/*.jar",
- ]),
- tags = ["intellij-provided-by-sdk"],
-)
-
-filegroup(
- name = "build_number",
- srcs = glob(["idea-IC-145.*/build.txt"]),
-)
diff --git a/third_party/BUILD b/third_party/BUILD
index 37a3284..d7eae12 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -1,22 +1,11 @@
package(default_visibility = ["//visibility:public"])
java_import(
- name = "trickle",
- jars = ["trickle/trickle-0.6.1.jar"],
+ name = "jdk8_tools",
+ jars = ["jdk8/tools.jar"],
)
-java_import(
- name = "jsr305",
- jars = ["jsr305/jsr305.jar"],
-)
-
-java_import(
- name = "test_lib",
- jars = [
- "jdk8/tools.jar",
- "truth/truth.jar",
- "mockito/mockito-core-1.9.5.jar",
- "junit4/junit-4.12.jar",
- "objenesis/objenesis-1_3.jar",
- ],
+sh_binary(
+ name = "zip",
+ srcs = ["zip/zip.sh"],
)
diff --git a/third_party/README.md b/third_party/README.md
index 0cceaa6..b62d641 100644
--- a/third_party/README.md
+++ b/third_party/README.md
@@ -2,38 +2,7 @@
author, but ship together with the source so building IJwB requires
a minimal set of extra dependencies.
-
-## [trickle](https://github.com/spotify/trickle/archive/trickle-0.6.1.zip)
-
-* Version: 0.6.1
-* License: Apache License 2.0
-
-## [mockito](http://mockito.googlecode.com/files/mockito-1.9.5.zip)
-
-* Version: 1.9.5
-* License: MIT
-
-## [jsr-305](http://central.maven.org/maven2/com/google/code/findbugs/jsr305/3.0.1/jsr305-3.0.1.jar)
-
-* Version: 3.0.1
-* License: BSD License
-
-## [junit4](https://github.com/junit-team/junit/archive/r4.12.zip)
-
-* Version: 4.12
-* License: Eclipse Public License 1.0
-
-## [objenesis](https://objenesis.googlecode.com/files/objenesis-1.3-bin.zip)
-
-* Version: 1.3
-* License: Apache 2.0
-
## [java jdk8](http://hg.openjdk.java.net/jdk8u/jdk8u60)
* Version: jdk8u60-b27 (rev)
* License: GPLv2 and GPLv2+ClassPath Exception
-
-## [truth](https://github.com/google/truth)
-
-* Version: 0.28
-* License: Apache 2.0
diff --git a/third_party/jdk8/tools.jar b/third_party/jdk8/tools.jar
index 1e18b3e..f9f71d6 100644
--- a/third_party/jdk8/tools.jar
+++ b/third_party/jdk8/tools.jar
Binary files differ
diff --git a/third_party/jsr305/LICENSE b/third_party/jsr305/LICENSE
deleted file mode 100644
index 6736681..0000000
--- a/third_party/jsr305/LICENSE
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright (c) 2007-2009, JSR305 expert group
-All rights reserved.
-
-http://www.opensource.org/licenses/bsd-license.php
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the JSR305 expert group nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/jsr305/jsr305.jar b/third_party/jsr305/jsr305.jar
deleted file mode 100644
index f973aea..0000000
--- a/third_party/jsr305/jsr305.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/junit4/LICENSE b/third_party/junit4/LICENSE
deleted file mode 100644
index fb68629..0000000
--- a/third_party/junit4/LICENSE
+++ /dev/null
@@ -1,214 +0,0 @@
-JUnit
-
-Eclipse Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
-LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
-CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
- a) in the case of the initial Contributor, the initial code and
- documentation distributed under this Agreement, and
- b) in the case of each subsequent Contributor:
-
- i) changes to the Program, and
-
- ii) additions to the Program;
-
- where such changes and/or additions to the Program originate from and are
-distributed by that particular Contributor. A Contribution 'originates' from a
-Contributor if it was added to the Program by such Contributor itself or anyone
-acting on such Contributor's behalf. Contributions do not include additions to
-the Program which: (i) are separate modules of software distributed in
-conjunction with the Program under their own license agreement, and (ii) are
-not derivative works of the Program.
-
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents " mean patent claims licensable by a Contributor which are
-necessarily infringed by the use or sale of its Contribution alone or when
-combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this Agreement.
-
-"Recipient" means anyone who receives the Program under this Agreement,
-including all Contributors.
-
-2. GRANT OF RIGHTS
-
- a) Subject to the terms of this Agreement, each Contributor hereby grants
-Recipient a non-exclusive, worldwide, royalty-free copyright license to
-reproduce, prepare derivative works of, publicly display, publicly perform,
-distribute and sublicense the Contribution of such Contributor, if any, and
-such derivative works, in source code and object code form.
-
- b) Subject to the terms of this Agreement, each Contributor hereby grants
-Recipient a non-exclusive, worldwide, royalty-free patent license under
-Licensed Patents to make, use, sell, offer to sell, import and otherwise
-transfer the Contribution of such Contributor, if any, in source code and
-object code form. This patent license shall apply to the combination of the
-Contribution and the Program if, at the time the Contribution is added by the
-Contributor, such addition of the Contribution causes such combination to be
-covered by the Licensed Patents. The patent license shall not apply to any
-other combinations which include the Contribution. No hardware per se is
-licensed hereunder.
-
- c) Recipient understands that although each Contributor grants the
-licenses to its Contributions set forth herein, no assurances are provided by
-any Contributor that the Program does not infringe the patent or other
-intellectual property rights of any other entity. Each Contributor disclaims
-any liability to Recipient for claims brought by any other entity based on
-infringement of intellectual property rights or otherwise. As a condition to
-exercising the rights and licenses granted hereunder, each Recipient hereby
-assumes sole responsibility to secure any other intellectual property rights
-needed, if any. For example, if a third party patent license is required to
-allow Recipient to distribute the Program, it is Recipient's responsibility to
-acquire that license before distributing the Program.
-
- d) Each Contributor represents that to its knowledge it has sufficient
-copyright rights in its Contribution, if any, to grant the copyright license
-set forth in this Agreement.
-
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form under
-its own license agreement, provided that:
-
- a) it complies with the terms and conditions of this Agreement; and
-
- b) its license agreement:
-
- i) effectively disclaims on behalf of all Contributors all warranties and
-conditions, express and implied, including warranties or conditions of title
-and non-infringement, and implied warranties or conditions of merchantability
-and fitness for a particular purpose;
-
- ii) effectively excludes on behalf of all Contributors all liability for
-damages, including direct, indirect, special, incidental and consequential
-damages, such as lost profits;
-
- iii) states that any provisions which differ from this Agreement are
-offered by that Contributor alone and not by any other party; and
-
- iv) states that source code for the Program is available from such
-Contributor, and informs licensees how to obtain it in a reasonable manner on
-or through a medium customarily used for software exchange.
-
-When the Program is made available in source code form:
-
- a) it must be made available under this Agreement; and
-
- b) a copy of this Agreement must be included with each copy of the
-Program.
-
-Contributors may not remove or alter any copyright notices contained within the
-Program.
-
-Each Contributor must identify itself as the originator of its Contribution, if
-any, in a manner that reasonably allows subsequent Recipients to identify the
-originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain responsibilities with
-respect to end users, business partners and the like. While this license is
-intended to facilitate the commercial use of the Program, the Contributor who
-includes the Program in a commercial product offering should do so in a manner
-which does not create potential liability for other Contributors. Therefore, if
-a Contributor includes the Program in a commercial product offering, such
-Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
-every other Contributor ("Indemnified Contributor") against any losses, damages
-and costs (collectively "Losses") arising from claims, lawsuits and other legal
-actions brought by a third party against the Indemnified Contributor to the
-extent caused by the acts or omissions of such Commercial Contributor in
-connection with its distribution of the Program in a commercial product
-offering. The obligations in this section do not apply to any claims or Losses
-relating to any actual or alleged intellectual property infringement. In order
-to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
-Contributor in writing of such claim, and b) allow the Commercial Contributor
-to control, and cooperate with the Commercial Contributor in, the defense and
-any related settlement negotiations. The Indemnified Contributor may
-participate in any such claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial product
-offering, Product X. That Contributor is then a Commercial Contributor. If that
-Commercial Contributor then makes performance claims, or offers warranties
-related to Product X, those performance claims and warranties are such
-Commercial Contributor's responsibility alone. Under this section, the
-Commercial Contributor would have to defend claims against the other
-Contributors related to those performance claims and warranties, and if a court
-requires any other Contributor to pay any damages as a result, the Commercial
-Contributor must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
-IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
-NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
-Recipient is solely responsible for determining the appropriateness of using
-and distributing the Program and assumes all risks associated with its exercise
-of rights under this Agreement, including but not limited to the risks and
-costs of program errors, compliance with applicable laws, damage to or loss of
-data, programs or equipment, and unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
-CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
-PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
-WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
-GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under applicable
-law, it shall not affect the validity or enforceability of the remainder of the
-terms of this Agreement, and without further action by the parties hereto, such
-provision shall be reformed to the minimum extent necessary to make such
-provision valid and enforceable.
-
-If Recipient institutes patent litigation against any
-entity (including a cross-claim or counterclaim in a lawsuit) alleging that the
-Program itself (excluding combinations of the Program with other software or
-hardware) infringes such Recipient's patent(s), then such Recipient's rights
-granted under Section 2(b) shall terminate as of the date such litigation is
-filed.
-
-All Recipient's rights under this Agreement shall terminate if it fails to
-comply with any of the material terms or conditions of this Agreement and does
-not cure such failure in a reasonable period of time after becoming aware of
-such noncompliance. If all Recipient's rights under this Agreement terminate,
-Recipient agrees to cease use and distribution of the Program as soon as
-reasonably practicable. However, Recipient's obligations under this Agreement
-and any licenses granted by Recipient relating to the Program shall continue
-and survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement, but in
-order to avoid inconsistency the Agreement is copyrighted and may only be
-modified in the following manner. The Agreement Steward reserves the right to
-publish new versions (including revisions) of this Agreement from time to time.
-No one other than the Agreement Steward has the right to modify this Agreement.
-The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to
-serve as the Agreement Steward to a suitable separate entity. Each new version
-of the Agreement will be given a distinguishing version number. The Program
-(including Contributions) may always be distributed subject to the version of
-the Agreement under which it was received. In addition, after a new version of
-the Agreement is published, Contributor may elect to distribute the Program
-(including its Contributions) under the new version. Except as expressly stated
-in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
-the intellectual property of any Contributor under this Agreement, whether
-expressly, by implication, estoppel or otherwise. All rights in the Program not
-expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and the
-intellectual property laws of the United States of America. No party to this
-Agreement will bring a legal action under this Agreement more than one year
-after the cause of action arose. Each party waives its rights to a jury trial
-in any resulting litigation.
-
diff --git a/third_party/junit4/junit-4.12.jar b/third_party/junit4/junit-4.12.jar
deleted file mode 100644
index 3a7fc26..0000000
--- a/third_party/junit4/junit-4.12.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/mockito/LICENSE b/third_party/mockito/LICENSE
deleted file mode 100644
index e0840a4..0000000
--- a/third_party/mockito/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License
-
-Copyright (c) 2007 Mockito contributors
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
\ No newline at end of file
diff --git a/third_party/mockito/mockito-core-1.9.5.jar b/third_party/mockito/mockito-core-1.9.5.jar
deleted file mode 100644
index 5de7610..0000000
--- a/third_party/mockito/mockito-core-1.9.5.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/objenesis/LICENSE b/third_party/objenesis/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/third_party/objenesis/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- 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.
diff --git a/third_party/objenesis/objenesis-1_3.jar b/third_party/objenesis/objenesis-1_3.jar
deleted file mode 100644
index d56dc2b..0000000
--- a/third_party/objenesis/objenesis-1_3.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/trickle/LICENSE b/third_party/trickle/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/third_party/trickle/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- 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.
diff --git a/third_party/trickle/trickle-0.6.1.jar b/third_party/trickle/trickle-0.6.1.jar
deleted file mode 100644
index bb0965e..0000000
--- a/third_party/trickle/trickle-0.6.1.jar
+++ /dev/null
Binary files differ
diff --git a/third_party/truth/LICENSE b/third_party/truth/LICENSE
deleted file mode 100644
index d645695..0000000
--- a/third_party/truth/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- 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.
diff --git a/third_party/truth/truth.jar b/third_party/truth/truth.jar
deleted file mode 100755
index e0a5a6e..0000000
--- a/third_party/truth/truth.jar
+++ /dev/null
Binary files differ
diff --git a/tools/zip/zip.sh b/third_party/zip/zip.sh
similarity index 100%
rename from tools/zip/zip.sh
rename to third_party/zip/zip.sh
diff --git a/tools/zip/BUILD b/tools/zip/BUILD
deleted file mode 100644
index 13c4d21..0000000
--- a/tools/zip/BUILD
+++ /dev/null
@@ -1,6 +0,0 @@
-package(default_visibility = ["//visibility:public"])
-
-sh_binary(
- name = "zip",
- srcs = ["zip.sh"],
-)
diff --git a/version.bzl b/version.bzl
new file mode 100644
index 0000000..96c8141
--- /dev/null
+++ b/version.bzl
@@ -0,0 +1,3 @@
+"""Version of the blaze plugin."""
+
+VERSION = "1.9.2"