Merge pull request #90 from brendandouglas/master
Import of bazel plugin using copybara
diff --git a/BUILD b/BUILD
index 99282bc..5e26650 100644
--- a/BUILD
+++ b/BUILD
@@ -4,6 +4,13 @@
licenses(["notice"]) # Apache 2.0
+# Changelog file
+filegroup(
+ name = "changelog",
+ srcs = ["CHANGELOG"],
+ visibility = ["//:__subpackages__"],
+)
+
# IJwB tests, run with an IntelliJ plugin SDK
test_suite(
name = "ijwb_tests",
@@ -16,6 +23,10 @@
"//java:integration_tests",
"//java:unit_tests",
"//plugin_dev:integration_tests",
+ "//python:integration_tests",
+ "//python:unit_tests",
+ "//scala:integration_tests",
+ "//scala:unit_tests",
],
)
@@ -38,5 +49,6 @@
tests = [
"//base:unit_tests",
"//cpp:unit_tests",
+ "//python:unit_tests",
],
)
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
index 0000000..32034b6
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,101 @@
+v2017.05.08
+===========
+* Add Python support to CLion
+* Fix some bazel targets not being linkified in the run configuration console
+ output
+* Add an action to open a workspace file outside your project (File > Open
+ Workspace File...)
+* Add an action to add a source directory to your bazel project (Bazel >
+ Project > Add Directory To Project...)
+* CLion: fix project directories being cleared when reopening a project
+
+v2017.04.17
+===========
+* Add support for IntelliJ 2017.1
+* Support bazel build sharding for large projects
+* Detect out-of-memory errors during sync, and suggest enabling sharding
+* Add documentation links for .bazelproject items
+
+v2017.04.03
+===========
+* Add python support for IntelliJ
+* Prefetch project files on project open, prior to initial indexing
+* Handle nested junit test classes
+
+v2017.03.15
+===========
+* Bazel: WORKSPACE file language integration (syntax highlighting, navigation,
+ etc.)
+* Bazel: Find usages, navigation support for external workspace labels
+* Expand macros in run configuration build flags
+
+v2017.02.27
+===========
+* Add CLion support
+* Run configuration support for abstract test classes/methods
+* Support running all test classes in a directory
+* BUILD support: don't suggest private symbols in 'load' statement autocomplete
+
+v2017.02.13
+===========
+* Test UI support for parameterized tests
+* Test UI support for sharded tests, run locally
+* BUILD: Fix navigation for overridden built-in symbols
+* BUILD: Add auto-complete for fully-qualified class names
+
+v2017.01.30
+============
+* Integrate bazel test results with the IDE's test runner UI.
+* Add support for sharing run configurations
+* Restructure Bazel menu items
+
+v2017.01.09
+===========
+* Create source roots for all directories matching 'test_sources'.
+* When viewing source files for supported but inactive languages, suggest
+ enabling support for that language.
+* BUILD: Add syntax highlight/autocomplete support for more built-in functions.
+* Fix java debugger connection timeout
+* Basic support for Go-lang projects
+
+v2016.12.5
+==========
+* BUILD files: add syntax hightlighting for built-in names
+* BUILD files: support aliased load statements
+* ASwB: enable NDK support
+
+v1.12
+=====
+* Add autocomplete in run configuration target editor.
+* Fix debugging of java_binary targets with args
+
+v1.11
+=====
+* Completely suppress JUnit for Bazel projects, removing a common source of
+ confusion.
+* Improve sync working set / partial sync to include more targets that
+ users might expect should be included.
+* Add more history to import wizard.
+
+v1.10
+=====
+* Compatibility with 2016.2.4
+* Improve create run configuration from scratch experience
+
+v1.9
+==========
+* Better tolerance of broken BUILD files during sync
+* Sync working set action -- sync only the files you're
+ working on.
+* BUILD file support: performance improvements.
+* Unified run configurations -- there is only one type,
+ the Bazel Command Run Configuration.
+* Add test rule chooser heuristics, to support some common
+ test genrules.
+
+v1.8
+==========
+* Add local jar cache to improve performance and robustness.
+* Support filtered gen jars to allow mixed generated/non-
+ generated rules (requires bazel release to activate).
+* Abbreviate generated run configuration names.
diff --git a/README.md b/README.md
index a6ba730..439b85e 100644
--- a/README.md
+++ b/README.md
@@ -13,8 +13,8 @@
## Installation
You can find our plugin in the Jetbrains plugin repository by going to
-`Settings -> Browse Repositories`, and searching for `IntelliJ with Bazel`
-or `Android Studio with Bazel`.
+`Settings -> Browse Repositories`, and searching for `IntelliJ with Bazel`,
+`Android Studio with Bazel`, or `CLion with Bazel`.
## Usage
@@ -25,6 +25,6 @@
## Building the plugin
-Install Bazel, then run 'bazel build //ijwb:ijwb_bazel --define=ij_product=intellij-latest'
+Install Bazel, then run `bazel build //ijwb:ijwb_bazel --define=ij_product=intellij-latest`
from the project root. This will create a plugin jar in
-'bazel-genfiles/ijwb/ijwb_bazel.jar'.
+`bazel-genfiles/ijwb/ijwb_bazel.jar`.
diff --git a/WORKSPACE b/WORKSPACE
index bad62f5..9a4eaff 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -2,6 +2,14 @@
# Long-lived download links available at: https://www.jetbrains.com/intellij-repository/releases
+# The plugin api for IntelliJ 2017.1.1. This is required to build IJwB,
+# and run integration tests.
+new_http_archive(
+ name = "intellij_ce_2017_1_1",
+ build_file = "intellij_platform_sdk/BUILD.idea",
+ url = "https://www.jetbrains.com/intellij-repository/releases/com/jetbrains/intellij/idea/ideaIC/2017.1.1/ideaIC-2017.1.1.zip",
+)
+
# The plugin api for IntelliJ 2016.3.1. This is required to build IJwB,
# and run integration tests.
new_http_archive(
@@ -34,28 +42,62 @@
url = "https://download.jetbrains.com/cpp/CLion-2016.3.2.tar.gz",
)
-# The plugin api for Android Studio 2.3 Beta 1. This is required to build ASwB,
+# The plugin api for CLion 2017.1.1. This is required to build CLwB,
# and run integration tests.
new_http_archive(
- name = "android_studio_2_3_0_3",
- build_file = "intellij_platform_sdk/BUILD.android_studio",
- url = "https://dl.google.com/dl/android/studio/ide-zips/2.3.0.3/android-studio-ide-162.3573574-linux.zip",
+ name = "clion_2017_1_1",
+ build_file = "intellij_platform_sdk/BUILD.clion",
+ url = "https://download.jetbrains.com/cpp/CLion-2017.1.1.tar.gz",
)
-# The plugin api for Android Studio 2.3 Beta 2. This is required to build ASwB,
+# The plugin api for Android Studio 2.3.1. This is required to build ASwB,
# and run integration tests.
new_http_archive(
- name = "android_studio_2_3_0_4",
+ name = "android_studio_2_3_1_0",
build_file = "intellij_platform_sdk/BUILD.android_studio",
- url = "https://dl.google.com/dl/android/studio/ide-zips/2.3.0.4/android-studio-ide-162.3616766-linux.zip",
+ url = "https://dl.google.com/dl/android/studio/ide-zips/2.3.1.0/android-studio-ide-162.3871768-linux.zip",
)
-# The plugin api for Android Studio 2.2 stable. This is required to build ASwB,
-# and run integration tests.
+# Python plugin for IntelliJ CE 2016.3. Required at compile-time for python-specific features.
new_http_archive(
- name = "AI_145_1617_8",
- 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",
+ name = "python_2016_3",
+ build_file_content = "\n".join([
+ "java_import(",
+ " name = 'python',",
+ " jars = ['python/lib/python.jar'],",
+ " visibility = ['//visibility:public'],",
+ ")"]),
+ url = "https://plugins.jetbrains.com/files/7322/32326/python-community-163.298.zip",
+)
+
+# Python plugin for IntelliJ CE 2017.1. Required at compile-time for python-specific features.
+new_http_archive(
+ name = "python_2017_1",
+ build_file_content = "\n".join([
+ "java_import(",
+ " name = 'python',",
+ " jars = ['python-ce/lib/python-ce.jar'],",
+ " visibility = ['//visibility:public'],",
+ ")"]),
+ url = "https://plugins.jetbrains.com/files/7322/33704/python-ce-2017.1.171.3780.116.zip",
+)
+
+# Scala plugin for IntelliJ CE 2017.1. Required at compile-time for scala-specific features.
+new_http_archive(
+ name = "scala_2017_1",
+ build_file_content = "\n".join([
+ "java_import(",
+ " name = 'scala-library',",
+ " jars = ['Scala/lib/scala-library.jar'],",
+ ")",
+ "",
+ "java_import(",
+ " name = 'scala',",
+ " jars = ['Scala/lib/scala-plugin.jar'],",
+ " runtime_deps = [':scala-library'],",
+ " visibility = ['//visibility:public'],",
+ ")"]),
+ url = "https://plugins.jetbrains.com/files/1347/33637/scala-intellij-bin-2017.1.15.zip",
)
# LICENSE: Common Public License 1.0
diff --git a/aswb/2.2/src/com/google/idea/blaze/android/compatibility/Compatibility.java b/aswb/2.2/src/com/google/idea/blaze/android/compatibility/Compatibility.java
deleted file mode 100644
index d65d9f2..0000000
--- a/aswb/2.2/src/com/google/idea/blaze/android/compatibility/Compatibility.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.compatibility;
-
-import com.android.sdklib.AndroidVersion;
-import com.android.tools.idea.run.ConsolePrinter;
-import com.android.tools.idea.run.editor.AndroidDebugger;
-import com.android.tools.idea.run.editor.AndroidDebuggerState;
-import com.android.tools.idea.run.tasks.DebugConnectorTask;
-import com.android.tools.idea.run.util.LaunchStatus;
-import com.intellij.execution.Executor;
-import com.intellij.execution.configurations.ConfigurationFactory;
-import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import java.io.File;
-import java.util.List;
-import java.util.Set;
-import org.jetbrains.android.facet.AndroidFacet;
-import org.jetbrains.android.sdk.AndroidSdkAdditionalData;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.android.model.impl.JpsAndroidModuleProperties;
-
-/** Compatibility facades for Android Studio 2.2. */
-public class Compatibility {
- private Compatibility() {}
- /**
- * Facade for {@link org.jetbrains.android.sdk.AndroidSdkUtils} and {@link
- * com.android.tools.idea.sdk.AndroidSdks#getInstance()}.
- */
- public static class AndroidSdkUtils {
- private AndroidSdkUtils() {}
-
- public static Sdk findSuitableAndroidSdk(String targetHash) {
- return org.jetbrains.android.sdk.AndroidSdkUtils.findSuitableAndroidSdk(targetHash);
- }
-
- public static List<Sdk> getAllAndroidSdks() {
- return org.jetbrains.android.sdk.AndroidSdkUtils.getAllAndroidSdks();
- }
-
- public static AndroidSdkAdditionalData getAndroidSdkAdditionalData(Sdk sdk) {
- return org.jetbrains.android.sdk.AndroidSdkUtils.getAndroidSdkAdditionalData(sdk);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.sdk.IdeSdks} and {@link
- * com.android.tools.idea.sdk.IdeSdks#getInstance()}.
- */
- public static class IdeSdks {
- private IdeSdks() {}
-
- public static File getAndroidSdkPath() {
- return com.android.tools.idea.sdk.IdeSdks.getAndroidSdkPath();
- }
-
- public static List<Sdk> createAndroidSdkPerAndroidTarget(File androidSdkPath) {
- return com.android.tools.idea.sdk.IdeSdks.createAndroidSdkPerAndroidTarget(androidSdkPath);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.run.testing.AndroidTestListener} and {@link
- * com.android.tools.idea.testartifacts.instrumented.AndroidTestListener}
- */
- public static class AndroidTestListener
- extends com.android.tools.idea.run.testing.AndroidTestListener {
- public AndroidTestListener(LaunchStatus launchStatus, ConsolePrinter consolePrinter) {
- super(launchStatus, consolePrinter);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.run.testing.AndroidTestConsoleProperties} and {@link
- * com.android.tools.idea.testartifacts.instrumented.AndroidTestConsoleProperties}
- */
- public static class AndroidTestConsoleProperties
- extends com.android.tools.idea.run.testing.AndroidTestConsoleProperties {
- public AndroidTestConsoleProperties(RunConfiguration runConfiguration, Executor executor) {
- super(runConfiguration, executor);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.run.testing.AndroidTestRunConfiguration} and {@link
- * com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration}
- */
- public static class AndroidTestRunConfiguration
- extends com.android.tools.idea.run.testing.AndroidTestRunConfiguration {
- public AndroidTestRunConfiguration(Project project, ConfigurationFactory configurationFactory) {
- super(project, configurationFactory);
- }
- }
-
- /** Facade for {@link com.android.tools.idea.run.tasks.ConnectDebuggerTask}. */
- public abstract static class ConnectDebuggerTask
- extends com.android.tools.idea.run.tasks.ConnectDebuggerTask {
- protected ConnectDebuggerTask(
- Set<String> applicationIds,
- AndroidDebugger<?> debugger,
- Project project,
- boolean monitorRemoteProcess) {
- super(applicationIds, debugger, project);
- }
- }
-
- public static <S extends AndroidDebuggerState> DebugConnectorTask getConnectDebuggerTask(
- AndroidDebugger<S> androidDebugger,
- ExecutionEnvironment env,
- @Nullable AndroidVersion version,
- Set<String> applicationIds,
- AndroidFacet facet,
- S state,
- String runConfigTypeId,
- boolean monitorRemoteProcess) {
- return androidDebugger.getConnectDebuggerTask(
- env, version, applicationIds, facet, state, runConfigTypeId);
- }
-
- public static void setFacetStateIsLibraryProject(JpsAndroidModuleProperties facetState) {
- facetState.LIBRARY_PROJECT = true;
- }
-}
diff --git a/aswb/2.2/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java b/aswb/2.2/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
deleted file mode 100644
index 20c2c22..0000000
--- a/aswb/2.2/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.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.android.sync.model.idea;
-
-import com.android.tools.idea.model.ClassJarProvider;
-import com.google.common.collect.ImmutableList;
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import java.util.List;
-import org.jetbrains.annotations.Nullable;
-
-/** Returns no class jars. Used to disable the layout editor loading jars. */
-public class BlazeClassJarProvider extends ClassJarProvider {
- public BlazeClassJarProvider(Project project) {}
-
- @Nullable
- @Override
- public VirtualFile findModuleClassFile(String className, Module module) {
- return null;
- }
-
- @Override
- public List<VirtualFile> getModuleExternalLibraries(Module module) {
- return ImmutableList.of();
- }
-}
diff --git a/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/AndroidTestCleanupHelper.java b/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/AndroidTestCleanupHelper.java
deleted file mode 100644
index 6847c67..0000000
--- a/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/AndroidTestCleanupHelper.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.android;
-
-import com.intellij.codeInsight.CodeInsightSettings;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.codeStyle.CodeStyleSchemes;
-import com.intellij.psi.codeStyle.CodeStyleSettings;
-import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
-import com.intellij.psi.impl.source.codeStyle.CodeStyleSchemeImpl;
-import com.intellij.util.xmlb.XmlSerializer;
-import org.jdom.Element;
-
-/**
- * Helper class for cleaning up after Android Studio initialization. Android Studio changes code
- * insight and style settings on initialization, so we need to revert these before tearing down the
- * integration test fixture to avoid failing because of changed settings.<br>
- * TODO: Remove once we build for a version where post-initialization insight and style settings are
- * used in the settings check.
- */
-public final class AndroidTestCleanupHelper {
-
- public static void cleanUp(Project project) {
- resetCodeInsightSettings();
- resetCodeStyleSettings(project);
- }
-
- private static void resetCodeInsightSettings() {
- // We can't just use CodeInsightSettings.getState(), because it excludes fields
- // matching the default values, and thus wouldn't change anything when loaded.
- Element codeInsightElement = new Element("state");
- XmlSerializer.serializeInto(new CodeInsightSettings(), codeInsightElement);
- CodeInsightSettings.getInstance().loadState(codeInsightElement);
- }
-
- private static void resetCodeStyleSettings(Project project) {
- CodeStyleSettingsManager settingsManager = CodeStyleSettingsManager.getInstance(project);
- if (settingsManager.USE_PER_PROJECT_SETTINGS && settingsManager.PER_PROJECT_SETTINGS != null) {
- settingsManager.PER_PROJECT_SETTINGS = new CodeStyleSettings();
- } else {
- ((CodeStyleSchemeImpl)
- CodeStyleSchemes.getInstance()
- .findPreferredScheme(settingsManager.PREFERRED_PROJECT_CODE_STYLE))
- .setCodeStyleSettings(new CodeStyleSettings());
- }
- }
-}
diff --git a/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/AndroidTestSetupRule.java b/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/AndroidTestSetupRule.java
deleted file mode 100644
index 07fc1ac..0000000
--- a/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/AndroidTestSetupRule.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.android;
-
-import com.intellij.testFramework.PlatformTestCase;
-import com.intellij.util.PlatformUtils;
-import org.junit.rules.ExternalResource;
-
-/**
- * Runs before Android Studio integration tests, to ensure the AndroidStudio platform prefix is
- * honored.
- */
-public class AndroidTestSetupRule extends ExternalResource {
-
- @Override
- protected void before() throws Throwable {
- // We require idea.platform.prefix to be defined before running tests.
- // If we don't call this before setting up the test fixture, IntelliJ ignores
- // the existing value and tries a limited set of candidate prefixes until it finds
- // a matching descriptor for one of them. Notably, "AndroidStudio" is not a candidate.
- // The first parameter doesn't matter in our case, so we pass a nonexistent class name.
- PlatformTestCase.initPlatformPrefix("", System.getProperty(PlatformUtils.PLATFORM_PREFIX_KEY));
- // TODO: Remove the above once we build for a version where "AndroidStudio" is a candidate.
- }
-}
diff --git a/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/BlazeAndroidIntegrationTestCase.java b/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/BlazeAndroidIntegrationTestCase.java
deleted file mode 100644
index 106860a..0000000
--- a/aswb/2.2/tests/utils/integration/com/google/idea/blaze/android/BlazeAndroidIntegrationTestCase.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.android;
-
-import com.google.idea.blaze.base.BlazeIntegrationTestCase;
-import org.junit.After;
-import org.junit.Rule;
-
-/** Base test class for Blaze Android integration tests. */
-public abstract class BlazeAndroidIntegrationTestCase extends BlazeIntegrationTestCase {
-
- @Rule public final AndroidTestSetupRule androidSetupRule = new AndroidTestSetupRule();
-
- @After
- public final void doTeardown() {
- AndroidTestCleanupHelper.cleanUp(getProject());
- }
-}
diff --git a/aswb/2.3/src/META-INF/aswb_beta.xml b/aswb/2.3/src/META-INF/aswb_beta.xml
deleted file mode 100644
index 8df2945..0000000
--- a/aswb/2.3/src/META-INF/aswb_beta.xml
+++ /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.
- -->
-<idea-plugin>
- <depends>com.google.gct.test.recorder</depends>
-
- <extensions defaultExtensionNs="com.google.idea.blaze">
- <BlazeUserSettingsContributor implementation="com.google.idea.blaze.android.settings.BlazeAndroidUserSettingsContributor$BlazeAndroidUserSettingsProvider"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.android.project">
- <buildSystemService implementation="com.google.idea.blaze.android.project.BlazeBuildSystemService"/>
- <featureEnableService implementation="com.google.idea.blaze.android.project.BlazeFeatureEnableService"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.android.rendering">
- <renderErrorContributor implementation="com.google.idea.blaze.android.rendering.BlazeRenderErrorContributor$BlazeProvider"/>
- </extensions>
-
- <extensions defaultExtensionNs="com.google.gct.testrecorder.run">
- <testRecorderRunConfigurationProxyProvider implementation="com.google.idea.blaze.android.run.testrecorder.TestRecorderBlazeCommandRunConfigurationProxyProvider" />
- </extensions>
-</idea-plugin>
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/compatibility/Compatibility.java b/aswb/2.3/src/com/google/idea/blaze/android/compatibility/Compatibility.java
deleted file mode 100644
index e614959..0000000
--- a/aswb/2.3/src/com/google/idea/blaze/android/compatibility/Compatibility.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.android.compatibility;
-
-import com.android.sdklib.AndroidVersion;
-import com.android.tools.idea.run.ConsolePrinter;
-import com.android.tools.idea.run.editor.AndroidDebugger;
-import com.android.tools.idea.run.editor.AndroidDebuggerState;
-import com.android.tools.idea.run.tasks.DebugConnectorTask;
-import com.android.tools.idea.run.util.LaunchStatus;
-import com.intellij.execution.Executor;
-import com.intellij.execution.configurations.ConfigurationFactory;
-import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.Sdk;
-import java.io.File;
-import java.util.List;
-import java.util.Set;
-import org.jetbrains.android.facet.AndroidFacet;
-import org.jetbrains.android.sdk.AndroidSdkAdditionalData;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.android.model.impl.JpsAndroidModuleProperties;
-
-/** Compatibility facades for Android Studio 2.3. */
-public class Compatibility {
- private Compatibility() {}
-
- /**
- * Facade for {@link org.jetbrains.android.sdk.AndroidSdkUtils} and {@link
- * com.android.tools.idea.sdk.AndroidSdks#getInstance()}.
- */
- public static class AndroidSdkUtils {
- private AndroidSdkUtils() {}
-
- public static Sdk findSuitableAndroidSdk(String targetHash) {
- return com.android.tools.idea.sdk.AndroidSdks.getInstance()
- .findSuitableAndroidSdk(targetHash);
- }
-
- public static List<Sdk> getAllAndroidSdks() {
- return com.android.tools.idea.sdk.AndroidSdks.getInstance().getAllAndroidSdks();
- }
-
- public static AndroidSdkAdditionalData getAndroidSdkAdditionalData(Sdk sdk) {
- return com.android.tools.idea.sdk.AndroidSdks.getInstance().getAndroidSdkAdditionalData(sdk);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.sdk.IdeSdks} and {@link
- * com.android.tools.idea.sdk.IdeSdks#getInstance()}.
- */
- public static class IdeSdks {
- private IdeSdks() {}
-
- public static File getAndroidSdkPath() {
- return com.android.tools.idea.sdk.IdeSdks.getInstance().getAndroidSdkPath();
- }
-
- public static List<Sdk> createAndroidSdkPerAndroidTarget(File androidSdkPath) {
- return com.android.tools.idea.sdk.IdeSdks.getInstance()
- .createAndroidSdkPerAndroidTarget(androidSdkPath);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.run.testing.AndroidTestListener} and {@link
- * com.android.tools.idea.testartifacts.instrumented.AndroidTestListener}
- */
- public static class AndroidTestListener
- extends com.android.tools.idea.testartifacts.instrumented.AndroidTestListener {
- public AndroidTestListener(LaunchStatus launchStatus, ConsolePrinter consolePrinter) {
- super(launchStatus, consolePrinter);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.run.testing.AndroidTestConsoleProperties} and {@link
- * com.android.tools.idea.testartifacts.instrumented.AndroidTestConsoleProperties}
- */
- public static class AndroidTestConsoleProperties
- extends com.android.tools.idea.testartifacts.instrumented.AndroidTestConsoleProperties {
- public AndroidTestConsoleProperties(RunConfiguration runConfiguration, Executor executor) {
- super(runConfiguration, executor);
- }
- }
-
- /**
- * Facade for {@link com.android.tools.idea.run.testing.AndroidTestRunConfiguration} and {@link
- * com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration}
- */
- public static class AndroidTestRunConfiguration
- extends com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration {
- public AndroidTestRunConfiguration(Project project, ConfigurationFactory configurationFactory) {
- super(project, configurationFactory);
- }
- }
-
- /** Facade for {@link com.android.tools.idea.run.tasks.ConnectDebuggerTask}. */
- public abstract static class ConnectDebuggerTask
- extends com.android.tools.idea.run.tasks.ConnectDebuggerTask {
- protected ConnectDebuggerTask(
- Set<String> applicationIds,
- AndroidDebugger<?> debugger,
- Project project,
- boolean monitorRemoteProcess) {
- super(applicationIds, debugger, project, monitorRemoteProcess);
- }
- }
-
- public static <S extends AndroidDebuggerState> DebugConnectorTask getConnectDebuggerTask(
- AndroidDebugger<S> androidDebugger,
- ExecutionEnvironment env,
- @Nullable AndroidVersion version,
- Set<String> applicationIds,
- AndroidFacet facet,
- S state,
- String runConfigTypeId,
- boolean monitorRemoteProcess) {
- return androidDebugger.getConnectDebuggerTask(
- env, version, applicationIds, facet, state, runConfigTypeId, monitorRemoteProcess);
- }
-
- public static void setFacetStateIsLibraryProject(JpsAndroidModuleProperties facetState) {
- facetState.PROJECT_TYPE = com.android.builder.model.AndroidProject.PROJECT_TYPE_LIBRARY;
- }
-}
diff --git a/aswb/BUILD b/aswb/BUILD
index 16fc99b..7772ebc 100644
--- a/aswb/BUILD
+++ b/aswb/BUILD
@@ -11,7 +11,6 @@
"stamped_plugin_xml",
)
load("//:version.bzl", "VERSION")
-load("//intellij_platform_sdk:build_defs.bzl", "select_for_plugin_api")
merged_plugin_xml(
name = "merged_plugin_xml_common",
@@ -20,14 +19,6 @@
"//base:plugin_xml",
"//cpp:plugin_xml",
"//java:plugin_xml",
- ] + select_for_plugin_api({
- # TODO(chaorenl): remove when 2.2 is obsolete
- "android-studio-145.1617.8": [],
- "android-studio-2.3.0.3": ["2.3/src/META-INF/aswb_beta.xml"],
- "android-studio-2.3.0.4": ["2.3/src/META-INF/aswb_beta.xml"],
- }),
- visibility = [
- "//visibility:public",
],
)
@@ -41,6 +32,7 @@
stamped_plugin_xml(
name = "stamped_plugin_xml",
+ changelog_file = "//:changelog",
include_product_code_in_stamp = True,
plugin_id = "com.google.idea.bazel.aswb",
plugin_name = "Android Studio with Bazel",
@@ -51,41 +43,26 @@
java_library(
name = "aswb_lib",
- srcs = glob(["src/**/*.java"]) + select_for_plugin_api({
- # TODO(chaorenl): remove when 2.2 is obsolete
- "android-studio-145.1617.8": glob(["2.2/src/**/*.java"]),
- "android-studio-2.3.0.3": glob(["2.3/src/**/*.java"]),
- "android-studio-2.3.0.4": glob(["2.3/src/**/*.java"]),
- }),
+ srcs = glob(["src/**/*.java"]),
resources = glob(["resources/**/*"]),
- visibility = [
- "//visibility:public",
+ runtime_deps = [
+ "//cpp",
],
deps = [
"//base",
"//common/experiments",
- "//cpp",
"//intellij_platform_sdk:plugin_api",
"//java",
- "//proto_deps",
+ "//proto:proto_deps",
"@jsr305_annotations//jar",
],
)
-# TODO(chaorenl): remove when 2.2 is obsolete
java_library(
name = "integration_test_utils",
testonly = 1,
- srcs = select_for_plugin_api({
- "android-studio-145.1617.8": glob(["2.2/tests/utils/integration/**/*.java"]),
- "android-studio-2.3.0.3": glob(["2.3/tests/utils/integration/**/*.java"]),
- "android-studio-2.3.0.4": glob(["2.3/tests/utils/integration/**/*.java"]),
- }),
+ srcs = glob(["tests/utils/integration/**/*.java"]),
deps = [
- "//base",
- "//base:integration_test_utils",
- "//base:unit_test_utils",
- "//intellij_platform_sdk:plugin_api_for_tests",
"@jsr305_annotations//jar",
"@junit//jar",
],
@@ -99,12 +76,7 @@
intellij_unit_test_suite(
name = "unit_tests",
- srcs = glob(["tests/unittests/**/*.java"]) + select_for_plugin_api({
- # TODO(chaorenl): remove when 2.2 is obsolete
- "android-studio-145.1617.8": [],
- "android-studio-2.3.0.3": glob(["2.3/tests/unittests/**/*.java"]),
- "android-studio-2.3.0.4": glob(["2.3/tests/unittests/**/*.java"]),
- }),
+ srcs = glob(["tests/unittests/**/*.java"]),
test_package_root = "com.google.idea.blaze.android",
deps = [
":aswb_lib",
@@ -114,7 +86,7 @@
"//common/experiments:unit_test_utils",
"//intellij_platform_sdk:plugin_api_for_tests",
"//java",
- "//proto_deps",
+ "//proto:proto_deps",
"@jsr305_annotations//jar",
"@junit//jar",
],
@@ -122,12 +94,7 @@
intellij_integration_test_suite(
name = "integration_tests",
- srcs = glob(["tests/integrationtests/**/*.java"]) + select_for_plugin_api({
- # TODO(chaorenl): remove when 2.2 is obsolete
- "android-studio-145.1617.8": [],
- "android-studio-2.3.0.3": glob(["2.3/tests/integrationtests/**/*.java"]),
- "android-studio-2.3.0.4": glob(["2.3/tests/integrationtests/**/*.java"]),
- }),
+ srcs = glob(["tests/integrationtests/**/*.java"]),
platform_prefix = "AndroidStudio",
required_plugins = "com.google.idea.bazel.aswb",
test_package_root = "com.google.idea.blaze.android",
@@ -142,9 +109,10 @@
"//base:unit_test_utils",
"//common/experiments",
"//common/experiments:unit_test_utils",
+ "//cpp",
"//intellij_platform_sdk:plugin_api_for_tests",
"//java",
- "//proto_deps",
+ "//proto:proto_deps",
"@jsr305_annotations//jar",
"@junit//jar",
],
diff --git a/aswb/aswb.bazelproject b/aswb/aswb.bazelproject
index c2f7d36..5700471 100644
--- a/aswb/aswb.bazelproject
+++ b/aswb/aswb.bazelproject
@@ -3,9 +3,6 @@
-ijwb
-plugin_dev
-clwb
- -cpp/src/com/google/idea/blaze/cpp/versioned/v162
- # TODO(chaorenl): remove when 2.2 is obsolete.
- -aswb/2.3
targets:
//aswb:aswb_bazel
diff --git a/aswb/src/META-INF/aswb.xml b/aswb/src/META-INF/aswb.xml
index d59d935..4bf7584 100644
--- a/aswb/src/META-INF/aswb.xml
+++ b/aswb/src/META-INF/aswb.xml
@@ -18,8 +18,7 @@
<depends>com.intellij.modules.androidstudio</depends>
<depends>org.jetbrains.android</depends>
- <!-- TODO(chaorenl): remove when 2.2 is obsolete -->
- <depends optional="true">com.android.tools.idea.updater</depends>
+ <depends>com.google.gct.test.recorder</depends>
<extensions defaultExtensionNs="com.intellij">
<java.elementFinder implementation="com.google.idea.blaze.android.resources.AndroidResourceClassFinder"
@@ -40,6 +39,9 @@
<projectService serviceImplementation="com.google.idea.blaze.android.manifest.ManifestParser"/>
<projectService serviceImplementation="com.google.idea.blaze.android.sync.model.AndroidResourceModuleRegistry"/>
<applicationService serviceImplementation="com.google.idea.blaze.android.settings.BlazeAndroidUserSettings"/>
+ <applicationService serviceInterface="com.google.idea.blaze.android.sdk.BlazeSdkProvider"
+ serviceImplementation="com.google.idea.blaze.android.sdk.BlazeSdkProviderImpl"
+ testServiceImplementation="com.google.idea.blaze.android.sdk.MockBlazeSdkProvider"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.android.actions">
@@ -57,12 +59,13 @@
<SyncListener implementation="com.google.idea.blaze.android.cppimpl.BlazeNdkSupportEnabler"/>
<SyncListener implementation="com.google.idea.blaze.android.manifest.ManifestParser$ClearManifestParser"/>
<RunConfigurationFactory implementation="com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationFactory"/>
- <java.JavaSyncAugmenter implementation="com.google.idea.blaze.android.sync.BlazeAndroidJavaSyncAugmenter"/>
+ <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"/>
<BuildSystemAndroidJdkProvider implementation="com.google.idea.blaze.android.sync.BazelAndroidJdkProvider"/>
<BlazeTestEventsHandler implementation="com.google.idea.blaze.android.run.test.smrunner.BlazeAndroidTestEventsHandler"/>
+ <ProjectViewDefaultValueProvider implementation="com.google.idea.blaze.android.projectview.AndroidSdkPlatformSection$AndroidSdkPlatformProjectViewDefaultValueProvider"/>
</extensions>
<extensions defaultExtensionNs="com.android.ide">
@@ -84,6 +87,23 @@
</extensions>
<!-- END NDK SUPPORT -->
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <BlazeUserSettingsContributor implementation="com.google.idea.blaze.android.settings.BlazeAndroidUserSettingsContributor$BlazeAndroidUserSettingsProvider"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.android.project">
+ <buildSystemService implementation="com.google.idea.blaze.android.project.BlazeBuildSystemService"/>
+ <featureEnableService implementation="com.google.idea.blaze.android.project.BlazeFeatureEnableService"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.android.rendering">
+ <renderErrorContributor implementation="com.google.idea.blaze.android.rendering.BlazeRenderErrorContributor$BlazeProvider"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.google.gct.testrecorder.run">
+ <testRecorderRunConfigurationProxyProvider implementation="com.google.idea.blaze.android.run.testrecorder.TestRecorderBlazeCommandRunConfigurationProxyProvider" />
+ </extensions>
+
<application-components>
<component>
<implementation-class>com.google.idea.blaze.android.plugin.PluginCompatibilityEnforcer</implementation-class>
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 f6b50ae..75e1a12 100644
--- a/aswb/src/com/google/idea/blaze/android/cppimpl/BlazeNdkSupportEnabler.java
+++ b/aswb/src/com/google/idea/blaze/android/cppimpl/BlazeNdkSupportEnabler.java
@@ -25,11 +25,10 @@
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
import com.google.idea.blaze.base.sync.SyncListener;
-import com.google.idea.blaze.cpp.BlazeCWorkspace;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.jetbrains.cidr.lang.workspace.OCWorkspace;
-import org.jetbrains.annotations.NotNull;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
final class BlazeNdkSupportEnabler extends SyncListener.Adapter {
@@ -57,7 +56,7 @@
* @param enabled if true, turn on C support in the IDE. If false, turn off C support in the IDE.
*/
private static void enableCSupportInIde(Project project, boolean enabled) {
- BlazeCWorkspace workspace = BlazeCWorkspace.getInstance(project);
+ OCWorkspace workspace = OCWorkspaceManager.getWorkspace(project);
Boolean isCurrentlyEnabled = !LANGUAGE_SUPPORT_DISABLED.get(project, false);
if (isCurrentlyEnabled != enabled) {
NdkHelper.disableCppLanguageSupport(project, !enabled);
@@ -65,7 +64,7 @@
}
}
- private static void rebuildSymbols(@NotNull Project project, @NotNull OCWorkspace workspace) {
+ private static void rebuildSymbols(Project project, OCWorkspace workspace) {
ApplicationManager.getApplication()
.runReadAction(
() -> {
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/project/BlazeBuildSystemService.java b/aswb/src/com/google/idea/blaze/android/project/BlazeBuildSystemService.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/project/BlazeBuildSystemService.java
rename to aswb/src/com/google/idea/blaze/android/project/BlazeBuildSystemService.java
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/project/BlazeFeatureEnableService.java b/aswb/src/com/google/idea/blaze/android/project/BlazeFeatureEnableService.java
similarity index 73%
rename from aswb/2.3/src/com/google/idea/blaze/android/project/BlazeFeatureEnableService.java
rename to aswb/src/com/google/idea/blaze/android/project/BlazeFeatureEnableService.java
index e59f375..a43374f 100644
--- a/aswb/2.3/src/com/google/idea/blaze/android/project/BlazeFeatureEnableService.java
+++ b/aswb/src/com/google/idea/blaze/android/project/BlazeFeatureEnableService.java
@@ -16,7 +16,9 @@
package com.google.idea.blaze.android.project;
import com.android.tools.idea.project.FeatureEnableService;
+import com.google.common.collect.ImmutableMap;
import com.google.idea.blaze.android.settings.BlazeAndroidUserSettings;
+import com.google.idea.blaze.base.logging.EventLogger;
import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.common.experiments.BoolExperiment;
@@ -24,6 +26,8 @@
/** Enable features supported by the blaze integration. */
public class BlazeFeatureEnableService extends FeatureEnableService {
+ private static final EventLogger logger = EventLogger.getInstance();
+
private static final BoolExperiment ENABLE_LAYOUT_EDITOR =
new BoolExperiment("enable.layout.editor", true);
@@ -34,10 +38,13 @@
@Override
public boolean isLayoutEditorEnabled(Project project) {
- return isLayoutEditorExperimentEnabled()
- && BlazeAndroidUserSettings.getInstance().getUseLayoutEditor()
- // Can't render if we don't have the data ready.
- && BlazeProjectDataManager.getInstance(project).getBlazeProjectData() != null;
+ boolean isEnabled =
+ isLayoutEditorExperimentEnabled()
+ && BlazeAndroidUserSettings.getInstance().getUseLayoutEditor();
+ boolean isReady = BlazeProjectDataManager.getInstance(project).getBlazeProjectData() != null;
+ logger.log(
+ getClass(), "layout_editor", ImmutableMap.of("enabled", Boolean.toString(isEnabled)));
+ return isEnabled && isReady;
}
public static boolean isLayoutEditorExperimentEnabled() {
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 fe75735..917da87 100644
--- a/aswb/src/com/google/idea/blaze/android/projectview/AndroidSdkPlatformSection.java
+++ b/aswb/src/com/google/idea/blaze/android/projectview/AndroidSdkPlatformSection.java
@@ -18,17 +18,20 @@
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidSdkUtils;
+import com.google.idea.blaze.android.sdk.BlazeSdkProvider;
import com.google.idea.blaze.android.sync.sdk.AndroidSdkFromProjectView;
import com.google.idea.blaze.base.projectview.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.ProjectViewDefaultValueProvider;
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.projectview.section.sections.TextBlock;
import com.google.idea.blaze.base.projectview.section.sections.TextBlockSection;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.text.StringUtil;
import java.util.List;
@@ -60,15 +63,19 @@
public ItemType getItemType() {
return ItemType.Other;
}
+ }
+ static class AndroidSdkPlatformProjectViewDefaultValueProvider
+ implements ProjectViewDefaultValueProvider {
@Override
- public ProjectView addProjectViewDefaultValue(ProjectView projectView) {
- if (!projectView.getSectionsOfType(KEY).isEmpty()) {
- return projectView;
+ public ProjectView addProjectViewDefaultValue(
+ BuildSystem buildSystem, ProjectViewSet projectViewSet, ProjectView topLevelProjectView) {
+ if (!topLevelProjectView.getSectionsOfType(KEY).isEmpty()) {
+ return topLevelProjectView;
}
- List<Sdk> sdks = AndroidSdkUtils.getAllAndroidSdks();
+ List<Sdk> sdks = BlazeSdkProvider.getInstance().getAllAndroidSdks();
ProjectView.Builder builder =
- ProjectView.builder(projectView).add(TextBlockSection.of(TextBlock.newLine()));
+ ProjectView.builder(topLevelProjectView).add(TextBlockSection.of(TextBlock.newLine()));
if (sdks.isEmpty()) {
builder
@@ -81,7 +88,7 @@
} else if (sdks.size() == 1) {
builder.add(
ScalarSection.builder(KEY)
- .set(AndroidSdkFromProjectView.getSdkTargetHash(sdks.get(0))));
+ .set(BlazeSdkProvider.getInstance().getSdkTargetHash(sdks.get(0))));
} else {
builder.add(
TextBlockSection.of(
@@ -95,5 +102,10 @@
}
return builder.build();
}
+
+ @Override
+ public SectionKey<?, ?> getSectionKey() {
+ return KEY;
+ }
}
}
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributor.java b/aswb/src/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributor.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributor.java
rename to aswb/src/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributor.java
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 6926023..eaff918 100644
--- a/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonState.java
+++ b/aswb/src/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonState.java
@@ -18,7 +18,6 @@
import static com.google.idea.blaze.android.cppapi.NdkSupport.NDK_SUPPORT;
import com.android.tools.idea.run.ValidationError;
-import com.android.tools.idea.run.editor.AndroidDebugger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.idea.blaze.android.cppapi.NdkSupport;
@@ -76,12 +75,8 @@
return debuggerManager;
}
- public List<String> getUserFlags() {
- return userFlags.getFlags();
- }
-
- public void setUserFlags(List<String> userFlags) {
- this.userFlags.setFlags(userFlags);
+ public RunConfigurationFlagsState getBlazeFlagsState() {
+ return userFlags;
}
public boolean isNativeDebuggingEnabled() {
@@ -92,10 +87,11 @@
this.nativeDebuggingEnabled = nativeDebuggingEnabled;
}
- public ImmutableList<String> getBuildFlags(Project project, ProjectViewSet projectViewSet) {
+ public ImmutableList<String> getExpandedBuildFlags(
+ Project project, ProjectViewSet projectViewSet) {
return ImmutableList.<String>builder()
.addAll(BlazeFlags.buildFlags(project, projectViewSet))
- .addAll(getUserFlags())
+ .addAll(getBlazeFlagsState().getExpandedFlags())
.addAll(getNativeDebuggerFlags())
.build();
}
@@ -127,19 +123,11 @@
Element deployTargetStatesElement = element.getChild(DEPLOY_TARGET_STATES_TAG);
if (deployTargetStatesElement != null) {
deployTargetManager.readExternal(deployTargetStatesElement);
- } else {
- // TODO Introduced in 1.12, remove in 1.14.
- // This was for migrating the state to a child element.
- deployTargetManager.readExternal(element);
}
Element debuggerStatesElement = element.getChild(DEBUGGER_STATES_TAG);
if (debuggerStatesElement != null) {
debuggerManager.readExternal(debuggerStatesElement);
- } else {
- // TODO Introduced in 1.12, remove in 1.14.
- // This was for migrating the state to a child element.
- debuggerManager.readExternal(element);
}
}
@@ -148,8 +136,6 @@
userFlags.writeExternal(element);
element.setAttribute(NATIVE_DEBUG_ATTR, Boolean.toString(nativeDebuggingEnabled));
- removeOldManagerState(element);
-
element.removeChildren(DEPLOY_TARGET_STATES_TAG);
Element deployTargetStatesElement = new Element(DEPLOY_TARGET_STATES_TAG);
deployTargetManager.writeExternal(deployTargetStatesElement);
@@ -161,19 +147,6 @@
element.addContent(debuggerStatesElement);
}
- // TODO Introduced in 1.12, remove in 1.14. This was for migrating state
- // and cleaning up mass amounts of duplicate state caused by never removing these elements before.
- private void removeOldManagerState(Element element) {
- // This is safe because we know only BlazeAndroidRunConfigurationDeployTargetManager
- // directly wrote option elements (via DefaultJDOMExternalizer.writeExternal) to our root.
- element.removeChildren("option");
- // BlazeAndroidRunConfigurationDebuggerManager, meanwhile, nested its state in
- // child elements named after the AndroidDebugger extension IDs.
- for (AndroidDebugger<?> debugger : AndroidDebugger.EP_NAME.getExtensions()) {
- element.removeChildren(debugger.getId());
- }
- }
-
@Override
public RunConfigurationStateEditor getEditor(Project project) {
return new BlazeAndroidRunConfigurationCommonStateEditor(this, project);
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 5351213..cb6b23c 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
@@ -33,7 +33,6 @@
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.compatibility.Compatibility;
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.BlazeAndroidDeviceSelector;
@@ -175,8 +174,7 @@
Set<String> packageIds,
boolean monitorRemoteProcess)
throws ExecutionException {
- return Compatibility.getConnectDebuggerTask(
- androidDebugger,
+ return androidDebugger.getConnectDebuggerTask(
env,
null,
packageIds,
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
index 3b222f7..f57d51f 100644
--- a/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandler.java
+++ b/aswb/src/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationHandler.java
@@ -104,7 +104,8 @@
ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
BlazeAndroidRunConfigurationValidationUtil.validateExecution(module, facet, projectViewSet);
- ImmutableList<String> buildFlags = configState.getBuildFlags(project, projectViewSet);
+ ImmutableList<String> buildFlags =
+ configState.getCommonState().getExpandedBuildFlags(project, projectViewSet);
BlazeAndroidRunContext runContext = createRunContext(project, facet, environment, buildFlags);
return new BlazeAndroidRunConfigurationRunner(
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 cb368d4..8bc2076 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
@@ -18,10 +18,8 @@
import com.android.tools.idea.run.ValidationError;
import com.android.tools.idea.run.util.LaunchUtils;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.run.state.RunConfigurationState;
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
import com.intellij.openapi.project.Project;
@@ -123,10 +121,6 @@
this.mode = mode;
}
- public ImmutableList<String> getBuildFlags(Project project, ProjectViewSet projectViewSet) {
- return commonState.getBuildFlags(project, projectViewSet);
- }
-
/**
* We collect errors rather than throwing to avoid missing fatal errors by exiting early for a
* warning.
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 2ea7ebc..da33631 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
@@ -30,7 +30,6 @@
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.compatibility.Compatibility;
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;
@@ -167,8 +166,7 @@
Set<String> packageIds,
boolean monitorRemoteProcess)
throws ExecutionException {
- return Compatibility.getConnectDebuggerTask(
- androidDebugger,
+ return androidDebugger.getConnectDebuggerTask(
env,
null,
packageIds,
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 1256ff4..582afea 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,22 +23,18 @@
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.compatibility.Compatibility.AndroidSdkUtils;
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;
import com.google.idea.blaze.android.run.runner.BlazeApkBuildStep;
-import com.google.idea.blaze.android.sync.model.AndroidSdkPlatform;
-import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
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.buildresult.BuildResultHelper;
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;
@@ -46,17 +42,15 @@
import com.google.idea.blaze.base.scope.output.IssueOutput;
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 java.io.File;
-import java.nio.file.Paths;
import java.util.concurrent.CancellationException;
import javax.annotation.Nullable;
+import org.jetbrains.android.sdk.AndroidSdkUtils;
/** Builds and installs the APK using mobile-install. */
public class BlazeApkBuildStepMobileInstall implements BlazeApkBuildStep {
@@ -99,11 +93,12 @@
}
BlazeCommand.Builder command =
BlazeCommand.builder(
- Blaze.getBuildSystem(project), BlazeCommandName.MOBILE_INSTALL);
+ Blaze.getBuildSystemProvider(project).getBinaryPath(),
+ BlazeCommandName.MOBILE_INSTALL);
command.addBlazeFlags(BlazeFlags.adbSerialFlags(device.getSerialNumber()));
if (USE_SDK_ADB.getValue()) {
- File adb = getSdkAdb(project);
+ File adb = AndroidSdkUtils.getAdb(project);
if (adb != null) {
command.addBlazeFlags(ImmutableList.of("--adb", adb.toString()));
}
@@ -117,13 +112,14 @@
}
WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ BlazeApkDeployInfoProtoHelper deployInfoHelper =
+ new BlazeApkDeployInfoProtoHelper(project, buildFlags);
+ BuildResultHelper buildResultHelper = deployInfoHelper.getBuildResultHelper();
+
command
.addTargets(label)
.addBlazeFlags(buildFlags)
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS);
-
- BlazeApkDeployInfoProtoHelper deployInfoHelper =
- new BlazeApkDeployInfoProtoHelper(project, buildFlags);
+ .addBlazeFlags(buildResultHelper.getBuildFlags());
SaveUtil.saveAllFiles();
int retVal =
@@ -131,8 +127,7 @@
.addBlazeCommand(command.build())
.context(context)
.stderr(
- LineProcessingOutputStream.of(
- deployInfoHelper.getLineProcessor(),
+ buildResultHelper.stderr(
new IssueOutputLineProcessor(project, context, workspaceRoot)))
.build()
.run();
@@ -172,35 +167,6 @@
return deployInfoFuture;
}
- private static File getSdkAdb(Project project) {
- BlazeProjectData projectData =
- BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (projectData == null) {
- return null;
- }
- BlazeAndroidSyncData syncData = projectData.syncState.get(BlazeAndroidSyncData.class);
- if (syncData == null) {
- return null;
- }
- AndroidSdkPlatform androidSdkPlatform = syncData.androidSdkPlatform;
- if (androidSdkPlatform == null) {
- return null;
- }
- Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdkPlatform.androidSdk);
- if (sdk == null) {
- return null;
- }
- String homePath = sdk.getHomePath();
- if (homePath == null) {
- return null;
- }
- File adb = Paths.get(homePath, "platform-tools", "adb").toFile();
- if (!adb.exists()) {
- return null;
- }
- return adb;
- }
-
@Nullable
private static IDevice resolveDevice(BlazeContext context, DeviceFutures deviceFutures) {
if (deviceFutures.get().size() != 1) {
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 241fd76..98e2e87 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
@@ -17,12 +17,11 @@
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.idea.blaze.android.manifest.ManifestParser;
-import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
-import com.google.idea.blaze.base.command.ExperimentalShowArtifactsLineProcessor;
+import com.google.idea.blaze.base.command.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.command.info.BlazeInfoRunner;
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;
@@ -44,24 +43,23 @@
private final Project project;
private final WorkspaceRoot workspaceRoot;
private final ImmutableList<String> buildFlags;
- private final List<File> deployInfoFiles = Lists.newArrayList();
- private final LineProcessingOutputStream.LineProcessor lineProcessor =
- new ExperimentalShowArtifactsLineProcessor(
- deployInfoFiles, fileName -> fileName.endsWith(".deployinfo.pb"));
+ private final BuildResultHelper buildResultHelper;
public BlazeApkDeployInfoProtoHelper(Project project, ImmutableList<String> buildFlags) {
this.project = project;
this.buildFlags = buildFlags;
this.workspaceRoot = WorkspaceRoot.fromProject(project);
+ this.buildResultHelper =
+ BuildResultHelper.forFiles(fileName -> fileName.endsWith(".deployinfo.pb"));
}
- public LineProcessingOutputStream.LineProcessor getLineProcessor() {
- return lineProcessor;
+ public BuildResultHelper getBuildResultHelper() {
+ return buildResultHelper;
}
@Nullable
public BlazeAndroidDeployInfo readDeployInfo(BlazeContext context) {
- File deployInfoFile = Iterables.getOnlyElement(deployInfoFiles, null);
+ File deployInfoFile = Iterables.getOnlyElement(buildResultHelper.getBuildArtifacts(), null);
if (deployInfoFile == null) {
return null;
}
@@ -88,10 +86,10 @@
@Nullable
private String getExecutionRoot(BlazeContext context) {
ListenableFuture<String> execRootFuture =
- BlazeInfo.getInstance()
+ BlazeInfoRunner.getInstance()
.runBlazeInfo(
context,
- Blaze.getBuildSystem(project),
+ Blaze.getBuildSystemProvider(project).getBinaryPath(),
workspaceRoot,
buildFlags,
BlazeInfo.EXECUTION_ROOT_KEY);
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 835aa1d..58daf4f 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
@@ -23,10 +23,9 @@
import com.google.idea.blaze.android.run.deployinfo.BlazeApkDeployInfoProtoHelper;
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.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.model.primitives.Label;
@@ -63,17 +62,19 @@
@Override
protected void execute(@NotNull BlazeContext context) {
BlazeCommand.Builder command =
- BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD);
+ BlazeCommand.builder(
+ Blaze.getBuildSystemProvider(project).getBinaryPath(), BlazeCommandName.BUILD);
WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ BlazeApkDeployInfoProtoHelper deployInfoHelper =
+ new BlazeApkDeployInfoProtoHelper(project, buildFlags);
+ BuildResultHelper buildResultHelper = deployInfoHelper.getBuildResultHelper();
+
command
.addTargets(label)
.addBlazeFlags("--output_groups=+android_deploy_info")
.addBlazeFlags(buildFlags)
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS);
-
- BlazeApkDeployInfoProtoHelper deployInfoHelper =
- new BlazeApkDeployInfoProtoHelper(project, buildFlags);
+ .addBlazeFlags(buildResultHelper.getBuildFlags());
SaveUtil.saveAllFiles();
int retVal =
@@ -81,8 +82,7 @@
.addBlazeCommand(command.build())
.context(context)
.stderr(
- LineProcessingOutputStream.of(
- deployInfoHelper.getLineProcessor(),
+ buildResultHelper.stderr(
new IssueOutputLineProcessor(project, context, workspaceRoot)))
.build()
.run();
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 c0cbb24..92311c4 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
@@ -16,7 +16,7 @@
package com.google.idea.blaze.android.run.test;
import com.android.tools.idea.run.ConsoleProvider;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestConsoleProperties;
+import com.android.tools.idea.testartifacts.instrumented.AndroidTestConsoleProperties;
import com.google.idea.blaze.base.run.smrunner.BlazeTestEventsHandler;
import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
import com.intellij.execution.ExecutionException;
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 a9b9515..b898e42 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
@@ -15,8 +15,8 @@
*/
package com.google.idea.blaze.android.run.test;
+import com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration;
import com.google.common.base.Strings;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
@@ -75,7 +75,7 @@
}
sourceElement.set(testClass);
- TargetIdeInfo target = RunUtil.targetForTestClass(context.getProject(), testClass, null);
+ TargetIdeInfo target = RunUtil.targetForTestClass(testClass, null);
if (target == null) {
return false;
}
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 e5f2b1d..9002f30 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
@@ -15,8 +15,8 @@
*/
package com.google.idea.blaze.android.run.test;
+import com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration;
import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration;
import com.google.idea.blaze.base.command.BlazeFlags;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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 7283e53..5bd9892 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
@@ -132,7 +132,8 @@
BlazeCommand.Builder commandBuilder =
BlazeCommand.builder(
- Blaze.getBuildSystem(project), BlazeCommandName.TEST)
+ Blaze.getBuildSystemProvider(project).getBinaryPath(),
+ BlazeCommandName.TEST)
.addTargets(target);
// Build flags must match BlazeBeforeRunTask.
commandBuilder.addBlazeFlags(buildFlags);
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 a0d4878..db2cca6 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
@@ -15,8 +15,8 @@
*/
package com.google.idea.blaze.android.run.test;
+import com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration;
import com.google.common.base.Strings;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
@@ -74,7 +74,7 @@
return false;
}
- TargetIdeInfo target = RunUtil.targetForTestClass(context.getProject(), containingClass, null);
+ TargetIdeInfo target = RunUtil.targetForTestClass(containingClass, null);
if (target == null) {
return false;
}
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
index d63ea0c..4b94b3c 100644
--- a/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandler.java
+++ b/aswb/src/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationHandler.java
@@ -102,7 +102,8 @@
ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
BlazeAndroidRunConfigurationValidationUtil.validateExecution(module, facet, projectViewSet);
- ImmutableList<String> buildFlags = configState.getBuildFlags(project, projectViewSet);
+ ImmutableList<String> buildFlags =
+ configState.getCommonState().getExpandedBuildFlags(project, projectViewSet);
BlazeAndroidRunContext runContext = createRunContext(project, facet, environment, buildFlags);
return new BlazeAndroidRunConfigurationRunner(
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 62fcbb3..074b17b 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
@@ -17,10 +17,8 @@
import com.android.tools.idea.run.ValidationError;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
-import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.run.state.RunConfigurationState;
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
import com.intellij.openapi.project.Project;
@@ -132,10 +130,6 @@
this.extraOptions = extraOptions;
}
- public ImmutableList<String> getBuildFlags(Project project, ProjectViewSet projectViewSet) {
- return commonState.getBuildFlags(project, projectViewSet);
- }
-
/**
* We collect errors rather than throwing to avoid missing fatal errors by exiting early for a
* warning.
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 5df4512..5e5e6c8 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,10 +16,10 @@
package com.google.idea.blaze.android.run.test;
-import static com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration.TEST_ALL_IN_MODULE;
-import static com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration.TEST_ALL_IN_PACKAGE;
-import static com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration.TEST_CLASS;
-import static com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestRunConfiguration.TEST_METHOD;
+import static com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration.TEST_ALL_IN_MODULE;
+import static com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration.TEST_ALL_IN_PACKAGE;
+import static com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration.TEST_CLASS;
+import static com.android.tools.idea.testartifacts.instrumented.AndroidTestRunConfiguration.TEST_METHOD;
import com.google.idea.blaze.base.run.state.RunConfigurationState;
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
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 7f5fb95..9962acf 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
@@ -33,7 +33,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
-import com.google.idea.blaze.android.compatibility.Compatibility;
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.BlazeAndroidDeviceSelector;
@@ -45,7 +44,6 @@
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
import com.google.idea.blaze.base.run.smrunner.BlazeTestEventsHandler;
-import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.executors.DefaultDebugExecutor;
@@ -61,9 +59,6 @@
/** Run context for android_test. */
class BlazeAndroidTestRunContext implements BlazeAndroidRunContext {
- private static final BoolExperiment smRunnerUiEnabled =
- new BoolExperiment("use.smrunner.ui.android", true);
-
private final Project project;
private final AndroidFacet facet;
private final BlazeCommandRunConfiguration runConfiguration;
@@ -97,7 +92,7 @@
this.apkProvider = new BlazeApkProvider(project, buildStep.getDeployInfo());
BlazeTestEventsHandler testEventsHandler = null;
- if (smRunnerUiEnabled.getValue() && !isDebugging(env.getExecutor())) {
+ if (!isDebugging(env.getExecutor())) {
testEventsHandler =
BlazeTestEventsHandler.getHandlerForTarget(project, runConfiguration.getTarget());
assert (testEventsHandler != null);
@@ -230,8 +225,7 @@
return new ConnectBlazeTestDebuggerTask(
env.getProject(), androidDebugger, packageIds, applicationIdProvider, this);
}
- return Compatibility.getConnectDebuggerTask(
- androidDebugger,
+ return androidDebugger.getConnectDebuggerTask(
env,
null,
packageIds,
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 8e2328e..8cdeedf 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
@@ -28,9 +28,9 @@
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;
import com.android.tools.idea.run.util.ProcessHandlerLaunchStatus;
-import com.google.idea.blaze.android.compatibility.Compatibility.ConnectDebuggerTask;
import com.intellij.debugger.engine.RemoteDebugProcessHandler;
import com.intellij.debugger.ui.DebuggerPanelsManager;
import com.intellij.execution.ExecutionException;
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 2430f3c..a10773e 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
@@ -22,8 +22,8 @@
import com.android.tools.idea.run.ConsolePrinter;
import com.android.tools.idea.run.tasks.LaunchTask;
import com.android.tools.idea.run.util.LaunchStatus;
+import com.android.tools.idea.testartifacts.instrumented.AndroidTestListener;
import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidTestListener;
import com.google.idea.blaze.android.run.deployinfo.BlazeAndroidDeployInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -158,6 +158,7 @@
}
@Override
+ @SuppressWarnings("FutureReturnValueIgnored")
public boolean perform(
IDevice device, final LaunchStatus launchStatus, final ConsolePrinter printer) {
printer.stdout("Running tests\n");
@@ -165,6 +166,8 @@
final RemoteAndroidTestRunner runner =
new RemoteAndroidTestRunner(testApplicationId, instrumentationTestRunner, device);
switch (configState.getTestingType()) {
+ case BlazeAndroidTestRunConfigurationState.TEST_ALL_IN_MODULE:
+ break;
case BlazeAndroidTestRunConfigurationState.TEST_ALL_IN_PACKAGE:
runner.setTestPackageName(configState.getPackageName());
break;
@@ -183,15 +186,12 @@
// 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);
- }
+ () -> {
+ try {
+ runner.run(new AndroidTestListener(launchStatus, printer));
+ } catch (Exception e) {
+ LOG.info(e);
+ printer.stderr("Error: Unexpected exception while running tests: " + e);
}
});
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfiguration.java b/aswb/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfiguration.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfiguration.java
rename to aswb/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfiguration.java
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxy.java b/aswb/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxy.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxy.java
rename to aswb/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxy.java
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxyProvider.java b/aswb/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxyProvider.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxyProvider.java
rename to aswb/src/com/google/idea/blaze/android/run/testrecorder/TestRecorderBlazeCommandRunConfigurationProxyProvider.java
diff --git a/aswb/src/com/google/idea/blaze/android/sdk/BlazeSdkProvider.java b/aswb/src/com/google/idea/blaze/android/sdk/BlazeSdkProvider.java
new file mode 100644
index 0000000..2222bd4
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/sdk/BlazeSdkProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.sdk;
+
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.projectRoots.Sdk;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Indirection to Sdks for testing purposes. */
+public interface BlazeSdkProvider {
+ static BlazeSdkProvider getInstance() {
+ return ServiceManager.getService(BlazeSdkProvider.class);
+ }
+
+ List<Sdk> getAllAndroidSdks();
+
+ Sdk findSdk(String targetHash);
+
+ @Nullable
+ String getSdkTargetHash(Sdk sdk);
+}
diff --git a/aswb/src/com/google/idea/blaze/android/sdk/BlazeSdkProviderImpl.java b/aswb/src/com/google/idea/blaze/android/sdk/BlazeSdkProviderImpl.java
new file mode 100644
index 0000000..1d1a43b
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/sdk/BlazeSdkProviderImpl.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.sdk;
+
+import com.android.tools.idea.sdk.AndroidSdks;
+import com.intellij.openapi.projectRoots.Sdk;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.jetbrains.android.sdk.AndroidSdkAdditionalData;
+
+/** Indirection to Sdks for testing purposes. */
+public class BlazeSdkProviderImpl implements BlazeSdkProvider {
+ @Override
+ public List<Sdk> getAllAndroidSdks() {
+ return AndroidSdks.getInstance().getAllAndroidSdks();
+ }
+
+ @Override
+ public Sdk findSdk(String targetHash) {
+ return AndroidSdks.getInstance().findSuitableAndroidSdk(targetHash);
+ }
+
+ @Override
+ @Nullable
+ public String getSdkTargetHash(Sdk sdk) {
+ AndroidSdkAdditionalData additionalData =
+ AndroidSdks.getInstance().getAndroidSdkAdditionalData(sdk);
+ if (additionalData == null) {
+ return null;
+ }
+ return additionalData.getBuildTargetHashString();
+ }
+}
diff --git a/aswb/src/com/google/idea/blaze/android/sdk/MockBlazeSdkProvider.java b/aswb/src/com/google/idea/blaze/android/sdk/MockBlazeSdkProvider.java
new file mode 100644
index 0000000..2a97716
--- /dev/null
+++ b/aswb/src/com/google/idea/blaze/android/sdk/MockBlazeSdkProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.sdk;
+
+import com.google.common.collect.Maps;
+import com.intellij.openapi.projectRoots.Sdk;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import javax.annotation.Nullable;
+
+/** Indirection to Sdks for testing purposes. */
+public class MockBlazeSdkProvider implements BlazeSdkProvider {
+ Map<String, Sdk> sdks = Maps.newHashMap();
+
+ public void addSdk(String targetHash, Sdk sdk) {
+ sdks.put(targetHash, sdk);
+ }
+
+ @Override
+ public List<Sdk> getAllAndroidSdks() {
+ return new ArrayList<>(sdks.values());
+ }
+
+ @Override
+ public Sdk findSdk(String targetHash) {
+ return sdks.get(targetHash);
+ }
+
+ @Override
+ @Nullable
+ public String getSdkTargetHash(Sdk sdk) {
+ return sdks.entrySet()
+ .stream()
+ .filter(entry -> entry.getValue() == sdk)
+ .map(Entry::getKey)
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/settings/BlazeAndroidUserSettingsContributor.java b/aswb/src/com/google/idea/blaze/android/settings/BlazeAndroidUserSettingsContributor.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/settings/BlazeAndroidUserSettingsContributor.java
rename to aswb/src/com/google/idea/blaze/android/settings/BlazeAndroidUserSettingsContributor.java
diff --git a/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java b/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java
index 162f693..821f098 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/AndroidPrefetchFileSource.java
@@ -19,6 +19,7 @@
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.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.intellij.openapi.project.Project;
import java.io.File;
@@ -29,7 +30,10 @@
public class AndroidPrefetchFileSource implements PrefetchFileSource {
@Override
public void addFilesToPrefetch(
- Project project, BlazeProjectData blazeProjectData, Collection<File> files) {
+ Project project,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<File> files) {
BlazeAndroidSyncData syncData = blazeProjectData.syncState.get(BlazeAndroidSyncData.class);
if (syncData == null) {
return;
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 084aec6..16afc3f 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidJavaSyncAugmenter.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidJavaSyncAugmenter.java
@@ -48,7 +48,7 @@
}
LibraryArtifact idlJar = androidIdeInfo.idlJar;
if (idlJar != null) {
- genJars.add(new BlazeJarLibrary(idlJar, target.key));
+ genJars.add(new BlazeJarLibrary(idlJar));
}
Set<String> whitelistedGenResourcePaths =
projectViewSet
@@ -66,7 +66,7 @@
if (!discardResourceJar) {
LibraryArtifact resourceJar = androidIdeInfo.resourceJar;
if (resourceJar != null) {
- jars.add(new BlazeJarLibrary(resourceJar, target.key));
+ jars.add(new BlazeJarLibrary(resourceJar));
}
}
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidLibrarySource.java b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidLibrarySource.java
index bfff837..73bb993 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidLibrarySource.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidLibrarySource.java
@@ -19,13 +19,8 @@
import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
import com.google.idea.blaze.base.model.BlazeLibrary;
import com.google.idea.blaze.base.model.BlazeProjectData;
-import com.google.idea.blaze.base.projectview.section.Glob;
-import com.google.idea.blaze.base.projectview.section.Glob.GlobSet;
import com.google.idea.blaze.base.sync.libraries.LibrarySource;
-import com.google.idea.blaze.java.sync.LibraryGlobFilter;
import java.util.Collection;
-import java.util.function.Predicate;
-import javax.annotation.Nullable;
class BlazeAndroidLibrarySource extends LibrarySource.Adapter {
private final BlazeProjectData blazeProjectData;
@@ -46,12 +41,4 @@
}
return libraries.build();
}
-
- @Nullable
- @Override
- public Predicate<BlazeLibrary> getLibraryFilter() {
- // This is supplied via the SDK
- GlobSet globSet = new GlobSet(ImmutableList.of(new Glob("*/android_blaze.jar")));
- return new LibraryGlobFilter(globSet);
- }
}
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 bee4d9a..f21d144 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncPlugin.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/BlazeAndroidSyncPlugin.java
@@ -15,20 +15,21 @@
*/
package com.google.idea.blaze.android.sync;
+import com.android.tools.idea.sdk.IdeSdks;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidSdkUtils;
-import com.google.idea.blaze.android.compatibility.Compatibility.IdeSdks;
import com.google.idea.blaze.android.cppapi.NdkSupport;
import com.google.idea.blaze.android.projectview.AndroidMinSdkSection;
import com.google.idea.blaze.android.projectview.AndroidSdkPlatformSection;
import com.google.idea.blaze.android.projectview.GeneratedAndroidResourcesSection;
+import com.google.idea.blaze.android.sdk.BlazeSdkProvider;
import com.google.idea.blaze.android.sync.importer.BlazeAndroidWorkspaceImporter;
import com.google.idea.blaze.android.sync.model.AndroidSdkPlatform;
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.android.sync.sdk.AndroidSdkFromProjectView;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.BlazeVersionData;
@@ -49,7 +50,6 @@
import com.google.idea.blaze.base.sync.libraries.LibrarySource;
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.JavaLanguageLevelSection;
@@ -111,13 +111,17 @@
@Override
public void installSdks(BlazeContext context) {
- File path = IdeSdks.getAndroidSdkPath();
+ if (ApplicationManager.getApplication().isUnitTestMode()) {
+ return;
+ }
+
+ File path = IdeSdks.getInstance().getAndroidSdkPath();
if (path != null) {
context.output(new StatusOutput("Installing SDK platforms..."));
ApplicationManager.getApplication()
.invokeAndWait(
() -> {
- IdeSdks.createAndroidSdkPerAndroidTarget(path);
+ IdeSdks.getInstance().createAndroidSdkPerAndroidTarget(path);
},
ModalityState.defaultModalityState());
}
@@ -130,7 +134,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
@Nullable WorkingSet workingSet,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
@@ -176,7 +180,7 @@
if (androidSdkPlatform == null) {
return;
}
- Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdkPlatform.androidSdk);
+ Sdk sdk = BlazeSdkProvider.getInstance().findSdk(androidSdkPlatform.androidSdk);
if (sdk == null) {
IssueOutput.error(
String.format("Android platform '%s' not found.", androidSdkPlatform.androidSdk))
@@ -260,6 +264,7 @@
@Override
public boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
@@ -306,7 +311,8 @@
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
if (!isAndroidWorkspace(blazeProjectData.workspaceLanguageSettings)) {
return null;
}
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 73d76f5..8a2cca5 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
@@ -145,7 +145,7 @@
}
public Builder addTransitiveResourceDependency(String dependency) {
- return addTransitiveResourceDependency(new Label(dependency));
+ return addTransitiveResourceDependency(Label.create(dependency));
}
@NotNull
diff --git a/aswb/2.3/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java b/aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
similarity index 100%
rename from aswb/2.3/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
rename to aswb/src/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProvider.java
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 541be52..7f04fe2 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
@@ -16,7 +16,6 @@
package com.google.idea.blaze.android.sync.projectstructure;
import com.android.builder.model.AndroidProject;
-import com.google.idea.blaze.android.compatibility.Compatibility;
import com.intellij.facet.FacetManager;
import com.intellij.facet.ModifiableFacetModel;
import com.intellij.openapi.module.Module;
@@ -56,7 +55,7 @@
private static void configureFacet(AndroidFacet facet) {
JpsAndroidModuleProperties facetState = facet.getProperties();
facetState.ALLOW_USER_CONFIGURATION = false;
- Compatibility.setFacetStateIsLibraryProject(facetState);
+ facetState.PROJECT_TYPE = AndroidProject.PROJECT_TYPE_LIBRARY;
facetState.MANIFEST_FILE_RELATIVE_PATH = "";
facetState.RES_FOLDER_RELATIVE_PATH = "";
facetState.ASSETS_FOLDER_RELATIVE_PATH = "";
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 66b020f..29a20a6 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
@@ -49,12 +49,13 @@
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.google.idea.blaze.base.sync.projectstructure.ModuleFinder;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.intellij.execution.RunManager;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.StdModuleTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
@@ -69,6 +70,8 @@
/** Updates the IDE's project structure. */
public class BlazeAndroidProjectStructureSyncer {
+ private static final Logger logger = Logger.getInstance(BlazeAndroidProjectStructureSyncer.class);
+
public static void updateProjectStructure(
Project project,
BlazeContext context,
@@ -214,7 +217,7 @@
public static Module ensureRunConfigurationModule(Project project, Label label) {
TargetKey targetKey = TargetKey.forPlainTarget(label);
String moduleName = moduleNameForAndroidModule(targetKey);
- Module module = ModuleManager.getInstance(project).findModuleByName(moduleName);
+ Module module = ModuleFinder.getInstance(project).findModuleByName(moduleName);
if (module != null) {
return module;
}
@@ -308,12 +311,16 @@
project, workspaceRoot, workspaceModule, androidSdkPlatform);
ArtifactLocationDecoder artifactLocationDecoder = blazeProjectData.artifactLocationDecoder;
- ModuleManager moduleManager = ModuleManager.getInstance(project);
+ ModuleFinder moduleFinder = ModuleFinder.getInstance(project);
for (AndroidResourceModule androidResourceModule :
syncData.importResult.androidResourceModules) {
TargetIdeInfo target = blazeProjectData.targetMap.get(androidResourceModule.targetKey);
String moduleName = moduleNameForAndroidModule(target.key);
- Module module = moduleManager.findModuleByName(moduleName);
+ Module module = moduleFinder.findModuleByName(moduleName);
+ if (module == null) {
+ logger.warn("No module found for resource target: " + target.key);
+ continue;
+ }
registry.put(module, androidResourceModule);
AndroidIdeInfo androidIdeInfo = target.androidIdeInfo;
@@ -345,7 +352,11 @@
project, projectViewSet, blazeProjectData, androidResourceModules);
for (TargetIdeInfo target : runConfigurationTargets) {
String moduleName = moduleNameForAndroidModule(target.key);
- Module module = moduleManager.findModuleByName(moduleName);
+ Module module = moduleFinder.findModuleByName(moduleName);
+ if (module == null) {
+ logger.warn("No module found for run configuration target: " + target.key);
+ continue;
+ }
AndroidIdeInfo androidIdeInfo = target.androidIdeInfo;
assert androidIdeInfo != null;
updateModuleFacetInMemoryState(
diff --git a/aswb/src/com/google/idea/blaze/android/sync/sdk/AndroidSdkFromProjectView.java b/aswb/src/com/google/idea/blaze/android/sync/sdk/AndroidSdkFromProjectView.java
index b47e238..c4eb537 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/sdk/AndroidSdkFromProjectView.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/sdk/AndroidSdkFromProjectView.java
@@ -18,9 +18,9 @@
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidSdkUtils;
import com.google.idea.blaze.android.projectview.AndroidMinSdkSection;
import com.google.idea.blaze.android.projectview.AndroidSdkPlatformSection;
+import com.google.idea.blaze.android.sdk.BlazeSdkProvider;
import com.google.idea.blaze.android.sync.model.AndroidSdkPlatform;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.projectview.ProjectViewSet.ProjectViewFile;
@@ -40,7 +40,7 @@
@Nullable
public static AndroidSdkPlatform getAndroidSdkPlatform(
BlazeContext context, ProjectViewSet projectViewSet) {
- Collection<Sdk> sdks = AndroidSdkUtils.getAllAndroidSdks();
+ List<Sdk> sdks = BlazeSdkProvider.getInstance().getAllAndroidSdks();
if (sdks.isEmpty()) {
IssueOutput.error("No Android SDK configured. Please use the SDK manager to configure.")
.navigatable(
@@ -81,7 +81,7 @@
return null;
}
- Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdk);
+ Sdk sdk = BlazeSdkProvider.getInstance().findSdk(androidSdk);
if (sdk == null) {
ProjectViewFile projectViewFile = projectViewSet.getTopLevelProjectViewFile();
IssueOutput.error(
@@ -104,19 +104,10 @@
return new AndroidSdkPlatform(androidSdk, androidMinSdk);
}
- @Nullable
- public static String getSdkTargetHash(Sdk sdk) {
- AndroidSdkAdditionalData additionalData = AndroidSdkUtils.getAndroidSdkAdditionalData(sdk);
- if (additionalData == null) {
- return null;
- }
- return additionalData.getBuildTargetHashString();
- }
-
public static List<String> getAvailableSdkTargetHashes(Collection<Sdk> sdks) {
Set<String> names = Sets.newHashSet();
for (Sdk sdk : sdks) {
- String targetHash = getSdkTargetHash(sdk);
+ String targetHash = BlazeSdkProvider.getInstance().getSdkTargetHash(sdk);
if (targetHash != null) {
names.add(targetHash);
}
diff --git a/aswb/src/com/google/idea/blaze/android/sync/sdk/SdkUtil.java b/aswb/src/com/google/idea/blaze/android/sync/sdk/SdkUtil.java
index fcbe1f9..885b931 100644
--- a/aswb/src/com/google/idea/blaze/android/sync/sdk/SdkUtil.java
+++ b/aswb/src/com/google/idea/blaze/android/sync/sdk/SdkUtil.java
@@ -16,7 +16,7 @@
package com.google.idea.blaze.android.sync.sdk;
import com.android.tools.idea.updater.configure.SdkUpdaterConfigurableProvider;
-import com.google.idea.blaze.android.compatibility.Compatibility.AndroidSdkUtils;
+import com.google.idea.blaze.android.sdk.BlazeSdkProvider;
import com.google.idea.blaze.android.sync.model.AndroidSdkPlatform;
import com.google.idea.blaze.android.sync.model.BlazeAndroidSyncData;
import com.google.idea.blaze.base.model.BlazeProjectData;
@@ -49,7 +49,7 @@
if (androidSdkPlatform == null) {
return null;
}
- Sdk sdk = AndroidSdkUtils.findSuitableAndroidSdk(androidSdkPlatform.androidSdk);
+ Sdk sdk = BlazeSdkProvider.getInstance().findSdk(androidSdkPlatform.androidSdk);
if (sdk == null) {
return null;
}
diff --git a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateMigrationTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateMigrationTest.java
deleted file mode 100644
index 7eca0c6..0000000
--- a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateMigrationTest.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.android.run;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.idea.blaze.android.BlazeAndroidIntegrationTestCase;
-import java.io.StringReader;
-import java.util.List;
-import org.jdom.Element;
-import org.jdom.input.SAXBuilder;
-import org.jdom.output.Format;
-import org.jdom.output.XMLOutputter;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Tests for migrating the storage of deploy target state and debugger state in {@link
- * BlazeAndroidRunConfigurationCommonState} TODO Introduced in 1.12, remove in 1.14 when the
- * migration code in BlazeAndroidRunConfigurationCommonState is removed.
- */
-@RunWith(JUnit4.class)
-public class BlazeAndroidRunConfigurationCommonStateMigrationTest
- extends BlazeAndroidIntegrationTestCase {
-
- private static final String DEPLOY_TARGET_STATES_RAW_XML =
- "<android-deploy-target-states>"
- + " <option name=\"USE_LAST_SELECTED_DEVICE\" value=\"true\" />"
- + " <option name=\"PREFERRED_AVD\" value=\"some avd\" />"
- + "</android-deploy-target-states>";
- private static final String DEBUGGER_STATE_AUTO_RAW_XML =
- "<Auto>"
- + " <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"true\" />"
- + " <option name=\"WORKING_DIR\" value=\"/some/directory\" />"
- + " <option name=\"TARGET_LOGGING_CHANNELS\" value=\"some channels\" />"
- + "</Auto>";
- private static final String DEBUGGER_STATE_NATIVE_RAW_XML =
- "<Native>"
- + " <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"false\" />"
- + " <option name=\"WORKING_DIR\" value=\"\" />"
- + " <option name=\"TARGET_LOGGING_CHANNELS\""
- + " value=\"lldb process:gdb-remote packets\" />"
- + "</Native>";
- private static final String DEBUGGER_STATE_JAVA_RAW_XML = "<Java />";
- private static final String DEBUGGER_STATE_HYBRID_RAW_XML =
- "<Hybrid>"
- + " <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"true\" />"
- + " <option name=\"WORKING_DIR\" value=\"\" />"
- + " <option name=\"TARGET_LOGGING_CHANNELS\""
- + " value=\"lldb process:gdb-remote packets\" />"
- + "</Hybrid>";
- private static final String DEBUGGER_STATE_BLAZE_AUTO_RAW_XML =
- "<BlazeAuto>"
- + " <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"false\" />"
- + " <option name=\"WORKING_DIR\" value=\"/some/other/directory\" />"
- + " <option name=\"TARGET_LOGGING_CHANNELS\" value=\"some other channels\" />"
- + "</BlazeAuto>";
-
- private BlazeAndroidRunConfigurationCommonState state;
- private SAXBuilder saxBuilder;
- private XMLOutputter xmlOutputter;
-
- @Before
- public final void doSetup() throws Exception {
- state = new BlazeAndroidRunConfigurationCommonState(buildSystem().getName(), false);
- saxBuilder = new SAXBuilder();
- xmlOutputter = new XMLOutputter(Format.getCompactFormat());
- }
-
- private String formatRawXml(String rawXml) throws Exception {
- Element element =
- saxBuilder.build(new StringReader("<?xml version=\"1.0\"?>" + rawXml)).getRootElement();
- return xmlOutputter.outputString(element);
- }
-
- @Test
- public void readAndWriteShouldRemoveExtraElements() throws Exception {
- String oldXml =
- "<?xml version=\"1.0\"?>"
- + "<configuration blaze-native-debug=\"true\">"
- + " <blaze-user-flag>--flag1</blaze-user-flag>"
- + " <blaze-user-flag>--flag2</blaze-user-flag>"
- + " <option name=\"USE_LAST_SELECTED_DEVICE\" value=\"true\" />"
- + " <option name=\"PREFERRED_AVD\" value=\"some avd\" />"
- + DEBUGGER_STATE_AUTO_RAW_XML
- + DEBUGGER_STATE_NATIVE_RAW_XML
- + DEBUGGER_STATE_JAVA_RAW_XML
- + DEBUGGER_STATE_HYBRID_RAW_XML
- + DEBUGGER_STATE_BLAZE_AUTO_RAW_XML
- + " <option name=\"USE_LAST_SELECTED_DEVICE\" value=\"true\" />"
- + " <option name=\"PREFERRED_AVD\" value=\"some avd\" />"
- + DEBUGGER_STATE_AUTO_RAW_XML
- + DEBUGGER_STATE_NATIVE_RAW_XML
- + DEBUGGER_STATE_JAVA_RAW_XML
- + DEBUGGER_STATE_HYBRID_RAW_XML
- + DEBUGGER_STATE_BLAZE_AUTO_RAW_XML
- + "</configuration>";
- Element oldElement = saxBuilder.build(new StringReader(oldXml)).getRootElement();
-
- state.readExternal(oldElement);
- Element migratedElement = new Element("configuration");
- state.writeExternal(migratedElement);
-
- assertThat(migratedElement.getChildren()).hasSize(4);
- List<Element> flagElements = migratedElement.getChildren("blaze-user-flag");
- assertThat(flagElements).hasSize(2);
-
- Element deployTargetStatesElement = migratedElement.getChild("android-deploy-target-states");
- assertThat(xmlOutputter.outputString(deployTargetStatesElement))
- .isEqualTo(formatRawXml(DEPLOY_TARGET_STATES_RAW_XML));
-
- Element debuggerStatesElement = migratedElement.getChild("android-debugger-states");
- assertThat(debuggerStatesElement.getChildren()).hasSize(5);
- }
-}
diff --git a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java
index 1964580..0d9cba6 100644
--- a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java
+++ b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/BlazeAndroidRunConfigurationCommonStateTest.java
@@ -19,8 +19,9 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.BlazeAndroidIntegrationTestCase;
+import com.google.idea.blaze.android.AndroidIntegrationTestSetupRule;
import com.google.idea.blaze.android.cppapi.NdkSupport;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
import com.google.idea.common.experiments.ExperimentService;
import com.google.idea.common.experiments.MockExperimentService;
import com.intellij.openapi.util.InvalidDataException;
@@ -29,14 +30,18 @@
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.junit.Before;
+import org.junit.Rule;
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 BlazeAndroidIntegrationTestCase {
+public class BlazeAndroidRunConfigurationCommonStateTest extends BlazeIntegrationTestCase {
+ @Rule
+ public final AndroidIntegrationTestSetupRule androidSetupRule =
+ new AndroidIntegrationTestSetupRule();
private BlazeAndroidRunConfigurationCommonState state;
@Before
@@ -52,7 +57,7 @@
@Test
public void readAndWriteShouldMatch() throws InvalidDataException, WriteExternalException {
- state.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
state.setNativeDebuggingEnabled(true);
Element element = new Element("test");
@@ -61,7 +66,9 @@
new BlazeAndroidRunConfigurationCommonState(buildSystem().getName(), false);
readState.readExternal(element);
- assertThat(readState.getUserFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("--flag1", "--flag2")
+ .inOrder();
assertThat(readState.isNativeDebuggingEnabled()).isTrue();
}
@@ -73,13 +80,16 @@
new BlazeAndroidRunConfigurationCommonState(buildSystem().getName(), false);
readState.readExternal(element);
- assertThat(readState.getUserFlags()).isEqualTo(state.getUserFlags());
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(state.getBlazeFlagsState().getRawFlags());
assertThat(readState.isNativeDebuggingEnabled()).isEqualTo(state.isNativeDebuggingEnabled());
}
@Test
public void readShouldOmitEmptyFlags() throws InvalidDataException, WriteExternalException {
- state.setUserFlags(ImmutableList.of("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
+ state
+ .getBlazeFlagsState()
+ .setRawFlags(ImmutableList.of("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
Element element = new Element("test");
state.writeExternal(element);
@@ -87,14 +97,16 @@
new BlazeAndroidRunConfigurationCommonState(buildSystem().getName(), false);
readState.readExternal(element);
- assertThat(readState.getUserFlags()).containsExactly("hi", "I'm", "Josh").inOrder();
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("hi", "I'm", "Josh")
+ .inOrder();
}
@Test
public void repeatedWriteShouldNotChangeElement() throws WriteExternalException {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
- state.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
state.setNativeDebuggingEnabled(true);
Element firstWrite = new Element("test");
diff --git a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateTest.java
index 05de9a5..e72c5de 100644
--- a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateTest.java
+++ b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/binary/BlazeAndroidBinaryRunConfigurationStateTest.java
@@ -19,9 +19,10 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.BlazeAndroidIntegrationTestCase;
+import com.google.idea.blaze.android.AndroidIntegrationTestSetupRule;
import com.google.idea.blaze.android.cppapi.NdkSupport;
import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
import com.google.idea.common.experiments.ExperimentService;
import com.google.idea.common.experiments.MockExperimentService;
@@ -32,14 +33,18 @@
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link BlazeAndroidBinaryRunConfigurationState}. */
@RunWith(JUnit4.class)
-public class BlazeAndroidBinaryRunConfigurationStateTest extends BlazeAndroidIntegrationTestCase {
+public class BlazeAndroidBinaryRunConfigurationStateTest extends BlazeIntegrationTestCase {
+ @Rule
+ public final AndroidIntegrationTestSetupRule androidSetupRule =
+ new AndroidIntegrationTestSetupRule();
private BlazeAndroidBinaryRunConfigurationState state;
@Before
@@ -56,7 +61,7 @@
@Test
public void readAndWriteShouldMatch() throws InvalidDataException, WriteExternalException {
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
- commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
commonState.setNativeDebuggingEnabled(true);
state.setActivityClass("com.example.TestActivity");
@@ -74,7 +79,9 @@
readState.readExternal(element);
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("--flag1", "--flag2")
+ .inOrder();
assertThat(readCommonState.isNativeDebuggingEnabled()).isTrue();
assertThat(readState.getActivityClass()).isEqualTo("com.example.TestActivity");
@@ -97,7 +104,8 @@
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(commonState.getBlazeFlagsState().getRawFlags());
assertThat(readCommonState.isNativeDebuggingEnabled())
.isEqualTo(commonState.isNativeDebuggingEnabled());
@@ -115,7 +123,7 @@
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
- commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
commonState.setNativeDebuggingEnabled(true);
state.setActivityClass("com.example.TestActivity");
@@ -140,7 +148,7 @@
RunConfigurationStateEditor editor = state.getEditor(getProject());
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
- commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
commonState.setNativeDebuggingEnabled(true);
state.setActivityClass("com.example.TestActivity");
@@ -158,7 +166,8 @@
editor.applyEditorTo(readState);
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(commonState.getBlazeFlagsState().getRawFlags());
assertThat(readCommonState.isNativeDebuggingEnabled())
.isEqualTo(commonState.isNativeDebuggingEnabled());
@@ -183,7 +192,8 @@
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(commonState.getBlazeFlagsState().getRawFlags());
assertThat(readCommonState.isNativeDebuggingEnabled())
.isEqualTo(commonState.isNativeDebuggingEnabled());
diff --git a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateTest.java
index f04a14e..4944264 100644
--- a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateTest.java
+++ b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/BlazeAndroidTestRunConfigurationStateTest.java
@@ -18,9 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.android.BlazeAndroidIntegrationTestCase;
+import com.google.idea.blaze.android.AndroidIntegrationTestSetupRule;
import com.google.idea.blaze.android.cppapi.NdkSupport;
import com.google.idea.blaze.android.run.BlazeAndroidRunConfigurationCommonState;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
import com.google.idea.common.experiments.ExperimentService;
import com.google.idea.common.experiments.MockExperimentService;
@@ -31,14 +32,18 @@
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link BlazeAndroidTestRunConfigurationState}. */
@RunWith(JUnit4.class)
-public class BlazeAndroidTestRunConfigurationStateTest extends BlazeAndroidIntegrationTestCase {
+public class BlazeAndroidTestRunConfigurationStateTest extends BlazeIntegrationTestCase {
+ @Rule
+ public final AndroidIntegrationTestSetupRule androidSetupRule =
+ new AndroidIntegrationTestSetupRule();
private BlazeAndroidTestRunConfigurationState state;
@Before
@@ -55,7 +60,7 @@
@Test
public void readAndWriteShouldMatch() throws InvalidDataException, WriteExternalException {
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
- commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
commonState.setNativeDebuggingEnabled(true);
state.setTestingType(BlazeAndroidTestRunConfigurationState.TEST_METHOD);
@@ -73,7 +78,9 @@
readState.readExternal(element);
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).containsExactly("--flag1", "--flag2").inOrder();
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("--flag1", "--flag2")
+ .inOrder();
assertThat(readCommonState.isNativeDebuggingEnabled()).isTrue();
assertThat(readState.getTestingType())
@@ -96,7 +103,8 @@
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(commonState.getBlazeFlagsState().getRawFlags());
assertThat(readCommonState.isNativeDebuggingEnabled())
.isEqualTo(commonState.isNativeDebuggingEnabled());
@@ -115,7 +123,7 @@
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
- commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
commonState.setNativeDebuggingEnabled(true);
state.setTestingType(BlazeAndroidTestRunConfigurationState.TEST_METHOD);
@@ -140,7 +148,7 @@
RunConfigurationStateEditor editor = state.getEditor(getProject());
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
- commonState.setUserFlags(ImmutableList.of("--flag1", "--flag2"));
+ commonState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
commonState.setNativeDebuggingEnabled(true);
state.setTestingType(BlazeAndroidTestRunConfigurationState.TEST_METHOD);
@@ -158,7 +166,8 @@
editor.applyEditorTo(readState);
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(commonState.getBlazeFlagsState().getRawFlags());
assertThat(readCommonState.isNativeDebuggingEnabled())
.isEqualTo(commonState.isNativeDebuggingEnabled());
@@ -184,7 +193,8 @@
BlazeAndroidRunConfigurationCommonState commonState = state.getCommonState();
BlazeAndroidRunConfigurationCommonState readCommonState = readState.getCommonState();
- assertThat(readCommonState.getUserFlags()).isEqualTo(commonState.getUserFlags());
+ assertThat(readCommonState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(commonState.getBlazeFlagsState().getRawFlags());
assertThat(readCommonState.isNativeDebuggingEnabled())
.isEqualTo(commonState.isNativeDebuggingEnabled());
diff --git a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/smrunner/BlazeAndroidTestEventsHandlerTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/smrunner/BlazeAndroidTestEventsHandlerTest.java
index 474e1b4..e888374 100644
--- a/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/smrunner/BlazeAndroidTestEventsHandlerTest.java
+++ b/aswb/tests/integrationtests/com/google/idea/blaze/android/run/test/smrunner/BlazeAndroidTestEventsHandlerTest.java
@@ -18,7 +18,8 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.Iterables;
-import com.google.idea.blaze.android.BlazeAndroidIntegrationTestCase;
+import com.google.idea.blaze.android.AndroidIntegrationTestSetupRule;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.intellij.execution.Location;
import com.intellij.openapi.vfs.VirtualFileManager;
@@ -29,14 +30,18 @@
import com.intellij.psi.search.GlobalSearchScope;
import javax.annotation.Nullable;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Integration tests for {@link BlazeAndroidTestEventsHandler}. */
@RunWith(JUnit4.class)
-public class BlazeAndroidTestEventsHandlerTest extends BlazeAndroidIntegrationTestCase {
+public class BlazeAndroidTestEventsHandlerTest extends BlazeIntegrationTestCase {
+ @Rule
+ public final AndroidIntegrationTestSetupRule androidSetupRule =
+ new AndroidIntegrationTestSetupRule();
private final BlazeAndroidTestEventsHandler handler = new BlazeAndroidTestEventsHandler();
@Before
diff --git a/aswb/tests/integrationtests/com/google/idea/blaze/android/sync/AndroidSyncTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/sync/AndroidSyncTest.java
new file mode 100644
index 0000000..a712648
--- /dev/null
+++ b/aswb/tests/integrationtests/com/google/idea/blaze/android/sync/AndroidSyncTest.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.android.AndroidIntegrationTestSetupRule;
+import com.google.idea.blaze.android.sdk.BlazeSdkProvider;
+import com.google.idea.blaze.android.sdk.MockBlazeSdkProvider;
+import com.google.idea.blaze.base.ideinfo.AndroidIdeInfo;
+import com.google.idea.blaze.base.ideinfo.CIdeInfo;
+import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMap;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+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.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+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.BlazeDataStorage;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.projectstructure.ModuleFinder;
+import com.google.idea.blaze.cpp.BlazeCWorkspace;
+import com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkTypeId;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import com.jetbrains.cidr.lang.workspace.OCWorkspace;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
+import java.util.Arrays;
+import java.util.List;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Android-specific sync integration tests. */
+@RunWith(JUnit4.class)
+public class AndroidSyncTest extends BlazeSyncIntegrationTestCase {
+
+ @Rule
+ public final AndroidIntegrationTestSetupRule androidSetupRule =
+ new AndroidIntegrationTestSetupRule();
+
+ @Before
+ public void setup() {
+ mockSdk("android-25", "Android 25 SDK");
+ registerProjectService(OCWorkspaceManager.class, new MockOCWorkspaceManager());
+ }
+
+ private void mockSdk(String targetHash, String sdkName) {
+ SdkTypeId sdkType = mock(SdkTypeId.class);
+ when(sdkType.getName()).thenReturn("Android SDK");
+ Sdk sdk = mock(Sdk.class);
+ when(sdk.getName()).thenReturn(sdkName);
+ when(sdk.getSdkType()).thenReturn(sdkType);
+ MockBlazeSdkProvider sdkProvider = (MockBlazeSdkProvider) BlazeSdkProvider.getInstance();
+ sdkProvider.addSdk(targetHash, sdk);
+ }
+
+ @Test
+ public void testAndroidSyncAugmenterPresent() {
+ assertThat(
+ Arrays.stream(BlazeJavaSyncAugmenter.EP_NAME.getExtensions())
+ .anyMatch(e -> e instanceof BlazeAndroidJavaSyncAugmenter))
+ .isTrue();
+ }
+
+ @Test
+ public void testSimpleSync() throws Exception {
+ setProjectView(
+ "directories:",
+ " java/com/google",
+ "targets:",
+ " //java/com/google:lib",
+ "android_sdk_platform: android-25");
+
+ workspace.createFile(
+ new WorkspacePath("java/com/google/Source.java"),
+ "package com.google;",
+ "public class Source {}");
+
+ workspace.createFile(
+ new WorkspacePath("java/com/google/Other.java"),
+ "package com.google;",
+ "public class Other {}");
+
+ VirtualFile javaRoot = workspace.createDirectory(new WorkspacePath("java/com/google"));
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:lib")
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidIdeInfo.builder()
+ .setManifestFile(sourceRoot("java/com/google/AndroidManifest.xml"))
+ .addResource(sourceRoot("java/com/google/res/values/strings.xml"))
+ .setResourceJavaPackage("com.google")
+ .setGenerateResourceClass(true))
+ .addSource(sourceRoot("java/com/google/Source.java"))
+ .addSource(sourceRoot("java/com/google/Other.java")))
+ .build();
+
+ setTargetMap(targetMap);
+
+ runBlazeSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .build());
+
+ errorCollector.assertNoIssues();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.targetMap).isEqualTo(targetMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
+ .isEqualTo(WorkspaceType.ANDROID);
+
+ ImmutableList<ContentEntry> contentEntries = getWorkspaceContentEntries();
+ assertThat(contentEntries).hasSize(1);
+ assertThat(findContentEntry(javaRoot)).isNotNull();
+ assertThat(findContentEntry(javaRoot).getSourceFolders()).hasLength(1);
+
+ // Check that the workspace is set to android
+ Module workspaceModule =
+ ModuleFinder.getInstance(getProject())
+ .findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME);
+ assertThat(workspaceModule).isNotNull();
+ assertThat(AndroidFacet.getInstance(workspaceModule)).isNotNull();
+
+ // Check that a resource module was created
+ Module resourceModule =
+ ModuleFinder.getInstance(getProject()).findModuleByName("java.com.google.lib");
+ assertThat(resourceModule).isNotNull();
+ assertThat(AndroidFacet.getInstance(resourceModule)).isNotNull();
+ }
+
+ @Test
+ public void testMultipleToolchainsNoIssue() {
+ // Test what happens if there are multiple toolchains in the target map
+ // (e.g., from --fat_apk_cpu)
+ setProjectView(
+ "directories:",
+ " java/com/google",
+ "targets:",
+ " //java/com/google:app",
+ "additional_languages:",
+ " c",
+ "android_sdk_platform: android-25");
+ workspace.createDirectory(new WorkspacePath("java/com/google"));
+ workspace.createFile(
+ new WorkspacePath("java/com/google/Source.java"),
+ "package com.google;",
+ "public class Source {}");
+
+ workspace.createFile(
+ new WorkspacePath("java/com/google/Other.java"),
+ "package com.google;",
+ "public class Other {}");
+
+ workspace.createFile(new WorkspacePath("java/com/google/jni/native.cc"), "void foo() {}");
+ workspace.createFile(new WorkspacePath("java/com/google/jni/native2.cc"), "void bar() {}");
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("android_ndk_linux/toolchains/BUILD"))
+ .setLabel("//android_ndk_linux/toolchains:armv7a")
+ .setKind(Kind.CC_TOOLCHAIN)
+ .setCToolchainInfo(
+ CToolchainIdeInfo.builder()
+ .setTargetName("arm-linux-androideabi")
+ .setCppExecutable(
+ new ExecutionRootPath("bin/arm-linux-androideabi-gcc"))
+ .setPreprocessorExecutable(
+ new ExecutionRootPath("bin/arm-linux-androideabi-cpp"))
+ .addBaseCompilerOptions(
+ ImmutableList.of(
+ "-DOS_ANDROID",
+ "-mbionic",
+ "-ffunction-sections",
+ "-march=armv7-a",
+ "-mfpu=vfpv3-d16"))
+ .addCppCompilerOptions(ImmutableList.of("-std=gnu++11"))
+ .addBuiltInIncludeDirectories(
+ ImmutableList.of(
+ new ExecutionRootPath(
+ "lib/gcc/arm-linux-androideabi/4.8/include")))
+ .addLinkOptions(
+ ImmutableList.of(
+ "--sysroot=android_ndk_linux/platforms/android-18/arch-arm"))
+ .addUnfilteredCompilerOptions(
+ ImmutableList.of(
+ "--sysroot=android_ndk_linux/platforms/android-18/arch-arm"))
+ .addUnfilteredToolchainSystemIncludes(
+ ImmutableList.of(
+ new ExecutionRootPath(
+ "android_ndk_linux/sources/llvm-libc++/libcxx/include")))))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("android_ndk_linux/toolchains/BUILD"))
+ .setLabel("//android_ndk_linux/toolchains:aarch64")
+ .setKind(Kind.CC_TOOLCHAIN)
+ .setCToolchainInfo(
+ CToolchainIdeInfo.builder()
+ .setTargetName("aarch64-linux-android")
+ .setCppExecutable(
+ new ExecutionRootPath("prebuilt/bin/aarch64-linux-android-gcc"))
+ .setPreprocessorExecutable(
+ new ExecutionRootPath("prebuilt/bin/aarch64-linux-android-cpp"))
+ .addBaseCompilerOptions(
+ ImmutableList.of("-DOS_ANDROID", "-mbionic", "-ffunction-sections"))
+ .addCppCompilerOptions(ImmutableList.of("-std=gnu++11"))
+ .addBuiltInIncludeDirectories(
+ ImmutableList.of(
+ new ExecutionRootPath(
+ "lib/gcc/aarch64-linux-android/4.9/include")))
+ .addLinkOptions(
+ ImmutableList.of(
+ "--sysroot=android_ndk_linux/platforms/android-21/arch-arm64"))
+ .addUnfilteredCompilerOptions(
+ ImmutableList.of(
+ "--sysroot=android_ndk_linux/platforms/android-21/arch-arm64"))
+ .addUnfilteredToolchainSystemIncludes(
+ ImmutableList.of(
+ new ExecutionRootPath(
+ "android_ndk_linux/sources/llvm-libc++/libcxx/include")))))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:lib")
+ .setKind("android_library")
+ .setAndroidInfo(
+ AndroidIdeInfo.builder()
+ .setManifestFile(sourceRoot("java/com/google/AndroidManifest.xml"))
+ .addResource(sourceRoot("java/com/google/res/values/strings.xml"))
+ .setResourceJavaPackage("com.google")
+ .setGenerateResourceClass(true))
+ .addSource(sourceRoot("java/com/google/Other.java")))
+ // Technically, blaze returns multiple instances of native libs (one for each CPU from
+ // fat APK). However, we just pick the first instance we run into for the target map.
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:native_lib")
+ .setKind("cc_library")
+ .setCInfo(
+ CIdeInfo.builder()
+ .addTransitiveQuoteIncludeDirectories(
+ ImmutableList.of(
+ new ExecutionRootPath("."),
+ new ExecutionRootPath("blaze-out/android-aarch64-etc/genfiles"),
+ new ExecutionRootPath(
+ "blaze-out/android-aarch64-etc/genfiles/third_party/java")))
+ .addTransitiveSystemIncludeDirectories(
+ ImmutableList.of(
+ new ExecutionRootPath("third_party/stl/gcc3"),
+ new ExecutionRootPath("third_party/java/jdk/include"))))
+ .addSource(sourceRoot("java/com/google/jni/native.cc"))
+ .addDependency("//android_ndk_linux/toolchains:aarch64"))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:native_lib2")
+ .setKind("cc_library")
+ .setCInfo(
+ CIdeInfo.builder()
+ .addTransitiveQuoteIncludeDirectories(
+ ImmutableList.of(
+ new ExecutionRootPath("."),
+ new ExecutionRootPath("blaze-out/android-aarch64-etc/genfiles"),
+ new ExecutionRootPath(
+ "blaze-out/android-aarch64-etc/genfiles/third_party/java")))
+ .addTransitiveSystemIncludeDirectories(
+ ImmutableList.of(
+ new ExecutionRootPath("third_party/stl/gcc3"),
+ new ExecutionRootPath("third_party/java/jdk/include"))))
+ .addSource(sourceRoot("java/com/google/jni/native2.cc"))
+ .addDependency("//java/com/google:native_lib")
+ .addDependency("//android_ndk_linux/toolchains:armv7a"))
+ // Other targets like android_binary and android_test might also depend on
+ // a cc_toolchain.
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("java/com/google/BUILD"))
+ .setLabel("//java/com/google:app")
+ .setKind("android_binary")
+ .setAndroidInfo(
+ AndroidIdeInfo.builder()
+ .setManifestFile(sourceRoot("java/com/google/AndroidManifest.xml"))
+ .setResourceJavaPackage("com.google")
+ .setGenerateResourceClass(true))
+ .addSource(sourceRoot("java/com/google/Source.java"))
+ .addDependency("//tools/jdk:toolchain")
+ .addDependency("//android_ndk_linux/toolchains:armv7a")
+ .addDependency("//java/com/google:lib")
+ .addDependency("//java/com/google:native_lib")
+ .addDependency("//java/com/google:native_lib2"))
+ .build();
+
+ setTargetMap(targetMap);
+
+ runBlazeSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .build());
+
+ errorCollector.assertNoIssues();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.targetMap).isEqualTo(targetMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings.getWorkspaceType())
+ .isEqualTo(WorkspaceType.ANDROID);
+ assertThat(blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.C))
+ .isTrue();
+
+ // Check that the workspace is set to android
+ Module workspaceModule =
+ ModuleFinder.getInstance(getProject())
+ .findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME);
+ assertThat(workspaceModule).isNotNull();
+ assertThat(AndroidFacet.getInstance(workspaceModule)).isNotNull();
+
+ // Check resolve configurations for the native code match the toolchain that was in
+ // the library's deps (not switched for some reason).
+ VirtualFile nativeCc =
+ fileSystem.findFile(
+ workspaceRoot
+ .fileForPath(new WorkspacePath("java/com/google/jni/native.cc"))
+ .getPath());
+ VirtualFile nativeCc2 =
+ fileSystem.findFile(
+ workspaceRoot
+ .fileForPath(new WorkspacePath("java/com/google/jni/native2.cc"))
+ .getPath());
+
+ List<? extends OCResolveConfiguration> resolveConfigurations =
+ OCWorkspaceManager.getWorkspace(getProject()).getConfigurationsForFile(nativeCc);
+ assertThat(resolveConfigurations).hasSize(1);
+ OCCompilerSettings compilerSettings = resolveConfigurations.get(0).getCompilerSettings();
+ List<String> compilerSwitches =
+ compilerSettings.getCompilerSwitches(OCLanguageKind.CPP, nativeCc).getCommandLineArgs();
+ assertThat(compilerSwitches)
+ .contains("--sysroot=android_ndk_linux/platforms/android-21/arch-arm64");
+
+ resolveConfigurations =
+ OCWorkspaceManager.getWorkspace(getProject()).getConfigurationsForFile(nativeCc2);
+ assertThat(resolveConfigurations).hasSize(1);
+ compilerSettings = resolveConfigurations.get(0).getCompilerSettings();
+ compilerSwitches =
+ compilerSettings.getCompilerSwitches(OCLanguageKind.CPP, nativeCc).getCommandLineArgs();
+ assertThat(compilerSwitches)
+ .contains("--sysroot=android_ndk_linux/platforms/android-18/arch-arm");
+ }
+
+ private class MockOCWorkspaceManager extends OCWorkspaceManager {
+
+ @Override
+ public OCWorkspace getWorkspace() {
+ return BlazeCWorkspace.getInstance(getProject());
+ }
+ }
+}
diff --git a/aswb/2.3/tests/integrationtests/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProviderIntegrationTest.java b/aswb/tests/integrationtests/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProviderIntegrationTest.java
similarity index 94%
rename from aswb/2.3/tests/integrationtests/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProviderIntegrationTest.java
rename to aswb/tests/integrationtests/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProviderIntegrationTest.java
index 0be0dc0..e784f6a 100644
--- a/aswb/2.3/tests/integrationtests/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProviderIntegrationTest.java
+++ b/aswb/tests/integrationtests/com/google/idea/blaze/android/sync/model/idea/BlazeClassJarProviderIntegrationTest.java
@@ -283,20 +283,21 @@
}
private TargetMap buildTargetMap() {
- Label mainResourceLibrary = new Label("//com/google/example:main");
- Label androidLibraryDependency = new Label("//com/google/example:android_lib");
- Label androidResourceDependency = new Label("//com/google/example:android_res");
- Label androidResourceDependency2 = new Label("//com/google/example:android_res2");
- Label transitiveResourceDependency = new Label("//com/google/example/transitive:android_res");
- Label javaDependency = new Label("//com/google/example:java");
- Label transitiveJavaDependency = new Label("//com/google/example/transitive:java");
- Label sharedJavaDependency = new Label("//com/google/example/shared:java");
- Label sharedJavaDependency2 = new Label("//com/google/example/shared2:java");
- Label importDependency = new Label("//com/google/example:import");
- Label transitiveImportDependency = new Label("//com/google/example/transitive:import");
- Label unrelatedJava = new Label("//com/google/unrelated:java");
- Label unrelatedAndroidLibrary = new Label("//com/google/unrelated:android_lib");
- Label unrelatedAndroidResource = new Label("//com/google/unrelated:android_res");
+ Label mainResourceLibrary = Label.create("//com/google/example:main");
+ Label androidLibraryDependency = Label.create("//com/google/example:android_lib");
+ Label androidResourceDependency = Label.create("//com/google/example:android_res");
+ Label androidResourceDependency2 = Label.create("//com/google/example:android_res2");
+ Label transitiveResourceDependency =
+ Label.create("//com/google/example/transitive:android_res");
+ Label javaDependency = Label.create("//com/google/example:java");
+ Label transitiveJavaDependency = Label.create("//com/google/example/transitive:java");
+ Label sharedJavaDependency = Label.create("//com/google/example/shared:java");
+ Label sharedJavaDependency2 = Label.create("//com/google/example/shared2:java");
+ Label importDependency = Label.create("//com/google/example:import");
+ Label transitiveImportDependency = Label.create("//com/google/example/transitive:import");
+ Label unrelatedJava = Label.create("//com/google/unrelated:java");
+ Label unrelatedAndroidLibrary = Label.create("//com/google/unrelated:android_lib");
+ Label unrelatedAndroidResource = Label.create("//com/google/unrelated:android_res");
AndroidResourceModuleRegistry registry = new AndroidResourceModuleRegistry();
registry.put(
diff --git a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/project/BlazeBuildSystemServiceTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/project/BlazeBuildSystemServiceTest.java
similarity index 96%
rename from aswb/2.3/tests/unittests/com/google/idea/blaze/android/project/BlazeBuildSystemServiceTest.java
rename to aswb/tests/unittests/com/google/idea/blaze/android/project/BlazeBuildSystemServiceTest.java
index fbd398d..283773a 100755
--- a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/project/BlazeBuildSystemServiceTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/project/BlazeBuildSystemServiceTest.java
@@ -122,7 +122,7 @@
PsiFile psiFile = mock(PsiFile.class);
BuildReferenceManager buildReferenceManager = BuildReferenceManager.getInstance(project);
- when(buildReferenceManager.resolveLabel(new Label("//foo:bar"))).thenReturn(buildTargetPsi);
+ when(buildReferenceManager.resolveLabel(Label.create("//foo:bar"))).thenReturn(buildTargetPsi);
when(buildTargetPsi.getContainingFile()).thenReturn(psiFile);
when(buildTargetPsi.getTextOffset()).thenReturn(1337);
@@ -149,7 +149,7 @@
@Test
public void testAddDependencyWithoutBuildTargetPsi() throws Exception {
// Can't find PSI for the target.
- when(BuildReferenceManager.getInstance(project).resolveLabel(new Label("//foo:bar")))
+ when(BuildReferenceManager.getInstance(project).resolveLabel(Label.create("//foo:bar")))
.thenReturn(null);
VirtualFile buildFile =
@@ -165,9 +165,9 @@
}
private void mockBlazeImportSettings(Container projectServices) {
- BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager(project);
+ BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
importSettingsManager.setImportSettings(
- new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze));
+ new BlazeImportSettings("", "", "", "", Blaze.BuildSystem.Blaze));
projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
}
@@ -195,7 +195,7 @@
AndroidResourceModuleRegistry moduleRegistry = new AndroidResourceModuleRegistry();
moduleRegistry.put(
module,
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo:bar"))).build());
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo:bar"))).build());
projectServices.register(AndroidResourceModuleRegistry.class, moduleRegistry);
}
@@ -204,7 +204,7 @@
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
- .setLabel(new Label("//foo:bar"))
+ .setLabel(Label.create("//foo:bar"))
.setBuildFile(ArtifactLocation.builder().setRelativePath("foo/BUILD").build())
.build())
.build();
diff --git a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/project/BlazeFeatureEnabledServiceTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/project/BlazeFeatureEnabledServiceTest.java
similarity index 94%
rename from aswb/2.3/tests/unittests/com/google/idea/blaze/android/project/BlazeFeatureEnabledServiceTest.java
rename to aswb/tests/unittests/com/google/idea/blaze/android/project/BlazeFeatureEnabledServiceTest.java
index efd77ea..18e44ee 100644
--- a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/project/BlazeFeatureEnabledServiceTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/project/BlazeFeatureEnabledServiceTest.java
@@ -23,11 +23,11 @@
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.android.settings.BlazeAndroidUserSettings;
import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.logging.EventLogger;
import com.google.idea.blaze.base.model.BlazeProjectData;
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.BlazeImportSettingsManagerLegacy;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.common.experiments.ExperimentService;
import com.intellij.openapi.extensions.ExtensionPoint;
@@ -59,13 +59,13 @@
projectDataManager = new MockBlazeProjectDataManager();
projectServices.register(BlazeProjectDataManager.class, projectDataManager);
- BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager(project);
+ BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
importSettingsManager.setImportSettings(
- new BlazeImportSettings(null, null, null, null, null, BuildSystem.Blaze));
+ new BlazeImportSettings("", "", "", "", BuildSystem.Blaze));
projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
- projectServices.register(
- BlazeImportSettingsManagerLegacy.class, new BlazeImportSettingsManagerLegacy(project));
+ registerExtensionPoint(
+ ExtensionPointName.create("com.google.idea.blaze.EventLogger"), EventLogger.class);
ExtensionPoint<FeatureEnableService> extensionPoint =
registerExtensionPoint(
ExtensionPointName.create("com.android.project.featureEnableService"),
diff --git a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributorTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributorTest.java
similarity index 94%
rename from aswb/2.3/tests/unittests/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributorTest.java
rename to aswb/tests/unittests/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributorTest.java
index ffe8267..2b49d8c 100644
--- a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributorTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/rendering/BlazeRenderErrorContributorTest.java
@@ -44,7 +44,6 @@
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.BlazeImportSettingsManagerLegacy;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.base.targetmaps.SourceToTargetMap;
@@ -103,12 +102,10 @@
projectServices.register(
AndroidResourceModuleRegistry.class, new AndroidResourceModuleRegistry());
- BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager(project);
- BlazeImportSettings settings = new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+ BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
+ BlazeImportSettings settings = new BlazeImportSettings("", "", "", "", BuildSystem.Blaze);
importSettingsManager.setImportSettings(settings);
projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
- projectServices.register(
- BlazeImportSettingsManagerLegacy.class, new BlazeImportSettingsManagerLegacy(project));
createPsiClassesAndSourceToTargetMap(projectServices);
@@ -345,14 +342,14 @@
}
private void createTargetMapWithGeneratedResources() {
- Label mainResourcesTarget = new Label("//com/google/example:main");
- Label dependencyGeneratedResourceTarget = new Label("//com/google/example:generated");
- Label dependencySourceResourceTarget = new Label("//com/google/example:source");
+ Label mainResourcesTarget = Label.create("//com/google/example:main");
+ Label dependencyGeneratedResourceTarget = Label.create("//com/google/example:generated");
+ Label dependencySourceResourceTarget = Label.create("//com/google/example:source");
Label transitiveGeneratedResourcesTarget =
- new Label("//com/google/example/transitive:generated");
- Label transitiveSourceResourceTarget = new Label("//com/google/example/transitive:source");
- Label unrelatedGeneratedResourceTarget = new Label("//com/google/unrelated:generated");
- Label unrelatedSourceResourceTarget = new Label("//com/google/unrelated:source");
+ Label.create("//com/google/example/transitive:generated");
+ Label transitiveSourceResourceTarget = Label.create("//com/google/example/transitive:source");
+ Label unrelatedGeneratedResourceTarget = Label.create("//com/google/unrelated:generated");
+ Label unrelatedSourceResourceTarget = Label.create("//com/google/unrelated:source");
ArtifactLocation mainGeneratedResource =
artifact("com/google/example/main/generated/res", false);
@@ -500,7 +497,7 @@
}
private void createTargetMapWithNonStandardAndroidManifestName() {
- Label mainResourceTarget = new Label("//com/google/example:main");
+ Label mainResourceTarget = Label.create("//com/google/example:main");
ArtifactLocation mainManifest = artifact("com/google/example/main/WeirdManifest.xml", true);
ArtifactLocation mainResource = artifact("com/google/example/main/res", true);
@@ -530,8 +527,8 @@
}
private void createTargetMapWithNonStandardAndroidManifestNameInDependency() {
- Label mainResourceTarget = new Label("//com/google/example:main");
- Label dependencyResourceTarget = new Label("//com/google/example:dependency");
+ Label mainResourceTarget = Label.create("//com/google/example:main");
+ Label dependencyResourceTarget = Label.create("//com/google/example:dependency");
ArtifactLocation mainManifest = artifact("com/google/example/main/AndroidManifest.xml", true);
ArtifactLocation mainResource = artifact("com/google/example/main/res", true);
@@ -582,11 +579,11 @@
}
private void createTargetMapWithMissingClassDependency() {
- Label parentTarget = new Label("//com/google/example:app");
- Label independentLibraryTarget = new Label("//com/google/example/independent:library");
- Label independentLibrary2Target = new Label("//com/google/example/independent:library2");
- Label dependentLibraryTarget = new Label("//com/google/example/dependent:library");
- Label resourcesTarget = new Label("//com/google/example:resources");
+ Label parentTarget = Label.create("//com/google/example:app");
+ Label independentLibraryTarget = Label.create("//com/google/example/independent:library");
+ Label independentLibrary2Target = Label.create("//com/google/example/independent:library2");
+ Label dependentLibraryTarget = Label.create("//com/google/example/dependent:library");
+ Label resourcesTarget = Label.create("//com/google/example:resources");
ArtifactLocation manifest = artifact("com/google/example/AndroidManifest.xml", true);
ArtifactLocation resources = artifact("com/google/example/res", true);
@@ -667,15 +664,15 @@
ImmutableMap<File, TargetKey> sourceToTarget =
ImmutableMap.of(
VfsUtilCore.virtualToIoFile(independentLibraryView),
- TargetKey.forPlainTarget(new Label("//com/google/example/independent:library")),
+ TargetKey.forPlainTarget(Label.create("//com/google/example/independent:library")),
VfsUtilCore.virtualToIoFile(independentLibraryView2),
- TargetKey.forPlainTarget(new Label("//com/google/example/independent:library")),
+ TargetKey.forPlainTarget(Label.create("//com/google/example/independent:library")),
VfsUtilCore.virtualToIoFile(independentLibrary2View),
- TargetKey.forPlainTarget(new Label("//com/google/example/independent:library2")),
+ TargetKey.forPlainTarget(Label.create("//com/google/example/independent:library2")),
VfsUtilCore.virtualToIoFile(dependentLibraryView),
- TargetKey.forPlainTarget(new Label("//com/google/example/dependent:library")),
+ TargetKey.forPlainTarget(Label.create("//com/google/example/dependent:library")),
VfsUtilCore.virtualToIoFile(resourceView),
- TargetKey.forPlainTarget(new Label("//com/google/example:resources")));
+ TargetKey.forPlainTarget(Label.create("//com/google/example:resources")));
projectServices.register(
JavaPsiFacade.class, new MockJavaPsiFacade(project, psiManager, classes));
diff --git a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/run/testrecorder/BlazeConfigurationsTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/run/testrecorder/BlazeConfigurationsTest.java
similarity index 91%
rename from aswb/2.3/tests/unittests/com/google/idea/blaze/android/run/testrecorder/BlazeConfigurationsTest.java
rename to aswb/tests/unittests/com/google/idea/blaze/android/run/testrecorder/BlazeConfigurationsTest.java
index 86c20cf..b48fe02 100644
--- a/aswb/2.3/tests/unittests/com/google/idea/blaze/android/run/testrecorder/BlazeConfigurationsTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/run/testrecorder/BlazeConfigurationsTest.java
@@ -23,7 +23,6 @@
import com.android.tools.idea.run.editor.ShowChooserTargetProvider;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.gct.testrecorder.run.TestRecorderRunConfigurationProxy;
import com.google.gct.testrecorder.run.TestRecorderRunConfigurationProxyProvider;
import com.google.gct.testrecorder.ui.TestRecorderAction;
@@ -33,6 +32,7 @@
import com.google.idea.blaze.base.BlazeTestCase;
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.bazel.WorkspaceRootProvider;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
import com.google.idea.blaze.base.model.BlazeVersionData;
@@ -151,7 +151,7 @@
BlazeCommandRunConfigurationType.getInstance()
.getFactory()
.createTemplateConfiguration(project);
- blazeConfiguration.setTarget(new Label("//label:android_binary_rule"));
+ blazeConfiguration.setTarget(Label.create("//label:android_binary_rule"));
BlazeAndroidBinaryRunConfigurationState configurationState =
((BlazeAndroidBinaryRunConfigurationHandler) blazeConfiguration.getHandler()).getState();
configurationState.setMode(BlazeAndroidBinaryRunConfigurationState.LAUNCH_SPECIFIC_ACTIVITY);
@@ -164,9 +164,9 @@
}
private void mockBlazeImportSettings(Container projectServices) {
- BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager(project);
+ BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
importSettingsManager.setImportSettings(
- new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze));
+ new BlazeImportSettings("", "", "", "", Blaze.BuildSystem.Blaze));
projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
}
@@ -178,12 +178,12 @@
BlazeCommandRunConfiguration blazeAndroidBinaryConfiguration =
configurationFactory.createTemplateConfiguration(project);
blazeAndroidBinaryConfiguration.setName("AndroidBinaryConfiguration");
- blazeAndroidBinaryConfiguration.setTarget(new Label("//label:android_binary_rule"));
+ blazeAndroidBinaryConfiguration.setTarget(Label.create("//label:android_binary_rule"));
BlazeCommandRunConfiguration blazeAndroidTestConfiguration =
configurationFactory.createTemplateConfiguration(project);
blazeAndroidTestConfiguration.setName("AndroidTestConfiguration");
- blazeAndroidTestConfiguration.setTarget(new Label("//label:android_test_rule"));
+ blazeAndroidTestConfiguration.setTarget(Label.create("//label:android_test_rule"));
runManager.addConfiguration(
runManager.createConfiguration(blazeAndroidBinaryConfiguration, configurationFactory),
@@ -192,7 +192,7 @@
runManager.createConfiguration(blazeAndroidTestConfiguration, configurationFactory), true);
}
- private class MockTargetFinder extends TargetFinder {
+ private static class MockTargetFinder extends TargetFinder {
@Override
public List<TargetIdeInfo> findTargets(Project project, Predicate<TargetIdeInfo> predicate) {
return null;
@@ -201,9 +201,9 @@
@Override
public TargetIdeInfo targetForLabel(Project project, final Label label) {
TargetIdeInfo.Builder builder = TargetIdeInfo.builder().setLabel(label);
- if (label.equals(new Label("//label:android_binary_rule"))) {
+ if (label.equals(Label.create("//label:android_binary_rule"))) {
builder.setKind(Kind.ANDROID_BINARY);
- } else if (label.equals(new Label("//label:android_test_rule"))) {
+ } else if (label.equals(Label.create("//label:android_test_rule"))) {
builder.setKind(Kind.ANDROID_TEST);
}
return builder.build();
@@ -236,7 +236,7 @@
@Override
public Module getModule() {
Label label = getLabel();
- if (label != null && label.equals(new Label("//label:android_binary_rule"))) {
+ if (label != null && label.equals(Label.create("//label:android_binary_rule"))) {
return mockModule;
}
@@ -244,13 +244,18 @@
}
}
- private class MockBuildSystemProvider implements BuildSystemProvider {
+ private static class MockBuildSystemProvider implements BuildSystemProvider {
@Override
public Blaze.BuildSystem buildSystem() {
return Blaze.BuildSystem.Blaze;
}
@Override
+ public String getBinaryPath() {
+ return "/usr/bin/blaze";
+ }
+
+ @Override
public WorkspaceRootProvider getWorkspaceRootProvider() {
return null;
}
@@ -266,6 +271,12 @@
return null;
}
+ @Nullable
+ @Override
+ public String getProjectViewDocumentationUrl() {
+ return null;
+ }
+
@Override
public boolean isBuildFile(String fileName) {
return false;
@@ -278,15 +289,15 @@
}
@Override
- public FileNameMatcher buildFileMatcher() {
- return null;
+ public ImmutableList<FileNameMatcher> buildLanguageFileTypeMatchers() {
+ return ImmutableList.of();
}
@Override
public void populateBlazeVersionData(
BuildSystem buildSystem,
WorkspaceRoot workspaceRoot,
- ImmutableMap<String, String> blazeInfo,
+ BlazeInfo blazeInfo,
BlazeVersionData.Builder builder) {}
}
}
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 c839293..e720a87 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
@@ -81,7 +81,7 @@
artifactLocation -> new File("/", artifactLocation.getRelativePath());
private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
- new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+ new BlazeImportSettings("", "", "", "", BuildSystem.Blaze);
private BlazeContext context;
private ErrorCollector errorCollector = new ErrorCollector();
@@ -95,8 +95,7 @@
BlazeExecutor blazeExecutor = new MockBlazeExecutor();
applicationServices.register(BlazeExecutor.class, blazeExecutor);
- projectServices.register(
- BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager());
BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
MockFileAttributeProvider mockFileAttributeProvider = new MockFileAttributeProvider();
@@ -221,7 +220,7 @@
assertThat(result.androidResourceModules)
.containsExactly(
AndroidResourceModule.builder(
- TargetKey.forPlainTarget(new Label("//java/apps/example:example_debug")))
+ TargetKey.forPlainTarget(Label.create("//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"))
@@ -231,7 +230,7 @@
.addTransitiveResourceDependency("//java/libraries/shared:shared")
.build(),
AndroidResourceModule.builder(
- TargetKey.forPlainTarget(new Label("//java/apps/example/lib0:lib0")))
+ TargetKey.forPlainTarget(Label.create("//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"))
@@ -239,7 +238,7 @@
.addTransitiveResourceDependency("//java/libraries/shared:shared")
.build(),
AndroidResourceModule.builder(
- TargetKey.forPlainTarget(new Label("//java/apps/example/lib1:lib1")))
+ TargetKey.forPlainTarget(Label.create("//java/apps/example/lib1:lib1")))
.addResourceAndTransitiveResource(source("java/apps/example/lib1/res"))
.addTransitiveResource(source("java/libraries/shared/res"))
.addTransitiveResourceDependency("//java/libraries/shared:shared")
@@ -468,7 +467,7 @@
.setKind("android_library")
.setAndroidInfo(
AndroidIdeInfo.builder()
- .setLegacyResources(new Label("//java/example:resources"))
+ .setLegacyResources(Label.create("//java/example:resources"))
.setManifestFile(source("java/example/AndroidManifest.xml"))
.addResource(source("java/example/res"))
.setGenerateResourceClass(true)
@@ -492,7 +491,7 @@
assertThat(result.androidResourceModules)
.containsExactly(
AndroidResourceModule.builder(
- TargetKey.forPlainTarget(new Label("//java/example:resources")))
+ TargetKey.forPlainTarget(Label.create("//java/example:resources")))
.addResourceAndTransitiveResource(source("java/example/res"))
.build());
}
@@ -588,7 +587,8 @@
assertThat(result.androidResourceModules)
.containsExactly(
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//java/example:lib")))
+ AndroidResourceModule.builder(
+ TargetKey.forPlainTarget(Label.create("//java/example:lib")))
.addResourceAndTransitiveResource(source("java/example/res"))
.build());
}
@@ -654,7 +654,8 @@
errorCollector.assertNoIssues();
assertThat(result.androidResourceModules)
.containsExactly(
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//java/example:lib")))
+ AndroidResourceModule.builder(
+ TargetKey.forPlainTarget(Label.create("//java/example:lib")))
.addResourceAndTransitiveResource(source("java/example/res"))
.addResourceAndTransitiveResource(gen("java/example/res"))
.build());
@@ -759,7 +760,7 @@
assertThat(result.androidResourceModules)
.containsExactly(
AndroidResourceModule.builder(
- TargetKey.forPlainTarget(new Label("//java/uninterestingdir:lib")))
+ TargetKey.forPlainTarget(Label.create("//java/uninterestingdir:lib")))
.addResourceAndTransitiveResource(source("java/uninterestingdir/res"))
.build());
}
diff --git a/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/model/idea/AndroidResourceModuleRegistryTest.java b/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/model/idea/AndroidResourceModuleRegistryTest.java
index 9a8e66c..f21c480 100644
--- a/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/model/idea/AndroidResourceModuleRegistryTest.java
+++ b/aswb/tests/unittests/com/google/idea/blaze/android/sync/importer/model/idea/AndroidResourceModuleRegistryTest.java
@@ -51,11 +51,13 @@
Module moduleTwo = mock(Module.class);
Module moduleThree = mock(Module.class);
AndroidResourceModule resourceModuleOne =
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo/bar:one"))).build();
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo/bar:one")))
+ .build();
AndroidResourceModule resourceModuleTwo =
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo/bar:two"))).build();
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo/bar:two")))
+ .build();
AndroidResourceModule resourceModuleThree =
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo/bar:three")))
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo/bar:three")))
.build();
registry.put(moduleOne, resourceModuleOne);
registry.put(moduleTwo, resourceModuleTwo);
@@ -76,9 +78,11 @@
public void testPutSameKeyDifferentValues() {
Module module = mock(Module.class);
AndroidResourceModule resourceModuleOne =
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo/bar:one"))).build();
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo/bar:one")))
+ .build();
AndroidResourceModule resourceModuleTwo =
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo/bar:two"))).build();
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo/bar:two")))
+ .build();
registry.put(module, resourceModuleOne);
registry.put(module, resourceModuleTwo);
assertThat(registry.get(module)).isEqualTo(resourceModuleTwo);
@@ -89,7 +93,8 @@
Module moduleOne = mock(Module.class);
Module moduleTwo = mock(Module.class);
AndroidResourceModule resourceModule =
- AndroidResourceModule.builder(TargetKey.forPlainTarget(new Label("//foo/bar:one"))).build();
+ AndroidResourceModule.builder(TargetKey.forPlainTarget(Label.create("//foo/bar:one")))
+ .build();
registry.put(moduleOne, resourceModule);
try {
registry.put(moduleTwo, resourceModule);
diff --git a/aswb/2.3/tests/utils/integration/com/google/idea/blaze/android/BlazeAndroidIntegrationTestCase.java b/aswb/tests/utils/integration/com/google/idea/blaze/android/AndroidIntegrationTestSetupRule.java
similarity index 68%
rename from aswb/2.3/tests/utils/integration/com/google/idea/blaze/android/BlazeAndroidIntegrationTestCase.java
rename to aswb/tests/utils/integration/com/google/idea/blaze/android/AndroidIntegrationTestSetupRule.java
index 74459a0..088e953 100644
--- a/aswb/2.3/tests/utils/integration/com/google/idea/blaze/android/BlazeAndroidIntegrationTestCase.java
+++ b/aswb/tests/utils/integration/com/google/idea/blaze/android/AndroidIntegrationTestSetupRule.java
@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.google.idea.blaze.android;
-import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import org.junit.rules.ExternalResource;
-/** Compatibility test class for Blaze Android integration tests. */
-public abstract class BlazeAndroidIntegrationTestCase extends BlazeIntegrationTestCase {}
+/** Runs before Android Studio integration tests. */
+public class AndroidIntegrationTestSetupRule extends ExternalResource {
+
+ @Override
+ protected void before() throws Throwable {
+ System.setProperty("android.studio.sdk.manager.disabled", "true");
+ }
+}
diff --git a/base/BUILD b/base/BUILD
index 850f1dd..7afe714 100644
--- a/base/BUILD
+++ b/base/BUILD
@@ -11,7 +11,7 @@
"//common/experiments",
"//common/formatter",
"//intellij_platform_sdk:plugin_api",
- "//proto_deps",
+ "//proto:proto_deps",
"//sdkcompat",
"@jsr305_annotations//jar",
],
@@ -46,7 +46,7 @@
":unit_test_utils",
"//base",
"//intellij_platform_sdk:plugin_api_for_tests",
- "//proto_deps",
+ "//proto:proto_deps",
"//testing:lib",
"@jsr305_annotations//jar",
"@junit//jar",
@@ -91,7 +91,7 @@
"//common/experiments",
"//common/experiments:unit_test_utils",
"//intellij_platform_sdk:plugin_api_for_tests",
- "//proto_deps",
+ "//proto:proto_deps",
"@jsr305_annotations//jar",
"@junit//jar",
],
@@ -110,7 +110,7 @@
":integration_test_utils",
":unit_test_utils",
"//intellij_platform_sdk:plugin_api_for_tests",
- "//proto_deps",
+ "//proto:proto_deps",
"@jsr305_annotations//jar",
"@junit//jar",
],
diff --git a/base/resources/binaries/bazel-buildifier b/base/resources/binaries/bazel-buildifier
index c7347bb..9b5f6b0 100755
--- a/base/resources/binaries/bazel-buildifier
+++ b/base/resources/binaries/bazel-buildifier
Binary files differ
diff --git a/base/src/META-INF/blaze-base.xml b/base/src/META-INF/blaze-base.xml
index 913bdb5..f472193 100644
--- a/base/src/META-INF/blaze-base.xml
+++ b/base/src/META-INF/blaze-base.xml
@@ -56,12 +56,20 @@
class="com.google.idea.blaze.base.settings.ui.OpenLocalProjectViewAction"
text="Open Local Project View File">
</action>
- <action class="com.google.idea.blaze.base.buildmap.OpenCorrespondingBuildFile"
- id="Blaze.OpenCorrespondingBuildFile"
+ <action id="Blaze.AddDirectoryToProjectView"
+ class="com.google.idea.blaze.base.settings.ui.AddDirectoryToProjectAction"
+ text="Add Directory To Project...">
+ </action>
+ <action id="Blaze.OpenCorrespondingBuildFile"
+ class="com.google.idea.blaze.base.buildmap.OpenCorrespondingBuildFile"
text="Open Corresponding BUILD File">
</action>
- <action class="com.google.idea.blaze.base.sync.actions.PartialSyncAction"
- id="Blaze.PartialSync"
+ <action id="Blaze.CopyBlazeTargetPathAction"
+ class="com.google.idea.blaze.base.actions.CopyBlazeTargetPathAction"
+ text="Copy BUILD target string">
+ </action>
+ <action id="Blaze.PartialSync"
+ class="com.google.idea.blaze.base.sync.actions.PartialSyncAction"
text="Partially Sync File"
icon="BlazeIcons.Blaze">
</action>
@@ -77,12 +85,15 @@
class="com.google.idea.blaze.base.ide.NewBlazeRuleAction"
text="New Rule"
popup="true"/>
+ <action id="Blaze.OpenWorkspaceFile"
+ class="com.google.idea.blaze.base.ide.OpenBlazeWorkspaceFileAction"
+ text="Open Workspace File..."
+ icon="BlazeIcons.Blaze">
+ <add-to-group group-id="FileOpenGroup" relative-to-action="OpenFile" anchor="after"/>
+ </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="Blaze.EditLocalProjectView"/>
- <reference id="Blaze.EditProjectView"/>
- <separator/>
<group id ="Blaze.SyncMenuGroup" text="Sync" popup="true">
<reference id="Blaze.IncrementalSyncProject"/>
<reference id="Blaze.FullSyncProject"/>
@@ -95,6 +106,11 @@
<reference id="MakeBlazeProject"/>
<reference id="MakeBlazeModule"/>
</group>
+ <group id="Blaze.Project" text="Project" popup="true">
+ <reference id="Blaze.EditLocalProjectView"/>
+ <reference id="Blaze.EditProjectView"/>
+ <reference id="Blaze.AddDirectoryToProjectView"/>
+ </group>
<!--Add popup groups anchored after this bookmark-->
<group id="Blaze.MenuGroupsBookmark"/>
<separator/>
@@ -123,6 +139,7 @@
<separator/>
<reference ref="Blaze.PartialSync"/>
<reference ref="Blaze.OpenCorrespondingBuildFile"/>
+ <reference ref="Blaze.CopyBlazeTargetPathAction"/>
</group>
</actions>
@@ -162,8 +179,8 @@
serviceImplementation="com.google.idea.blaze.base.buildmodifier.FileSystemModifierImpl"/>
<applicationService serviceInterface="com.google.idea.blaze.base.run.targetfinder.TargetFinder"
serviceImplementation="com.google.idea.blaze.base.run.targetfinder.TargetFinderImpl"/>
- <applicationService serviceInterface="com.google.idea.blaze.base.command.info.BlazeInfo"
- serviceImplementation="com.google.idea.blaze.base.command.info.BlazeInfoImpl"/>
+ <applicationService serviceInterface="com.google.idea.blaze.base.command.info.BlazeInfoRunner"
+ serviceImplementation="com.google.idea.blaze.base.command.info.BlazeInfoRunnerImpl"/>
<treeStructureProvider implementation="com.google.idea.blaze.base.treeview.BlazeTreeStructureProvider" id="blaze"/>
@@ -183,12 +200,14 @@
<projectService serviceInterface="com.google.idea.blaze.base.targetmaps.TransitiveDependencyMap"
serviceImplementation="com.google.idea.blaze.base.targetmaps.TransitiveDependencyMap"/>
<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"/>
+ <projectService serviceInterface="com.google.idea.blaze.base.sync.projectstructure.ModuleFinder"
+ serviceImplementation="com.google.idea.blaze.base.sync.projectstructure.ModuleFinderImpl"/>
+ <applicationService serviceImplementation="com.google.idea.blaze.base.sync.projectview.RelatedWorkspacePathFinder"/>
<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"/>
@@ -225,6 +244,9 @@
<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"/>
+ <filetype.stubBuilder filetype="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.stubs.ProjectViewFileStubBuilder"/>
+ <lang.documentationProvider language="projectview" implementationClass="com.google.idea.blaze.base.lang.projectview.documentation.ProjectViewDocumentationProvider"/>
+ <langCodeStyleSettingsProvider implementation="com.google.idea.blaze.base.lang.projectview.formatting.ProjectViewCodeStyleSettingsProvider"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
@@ -233,10 +255,11 @@
<!--<annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.LoadErrorAnnotator"/>-->
<annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.GlobErrorAnnotator"/>
<annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.BuiltInRuleAnnotator"/>
+ <annotator language="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.validation.LoadStatementAnnotator"/>
<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.BuildReferenceSearcher"/>
<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"/>
@@ -257,6 +280,7 @@
<filetype.stubBuilder filetype="BUILD" implementationClass="com.google.idea.blaze.base.lang.buildfile.stubs.BuildFileStubBuilder"/>
<editorNotificationProvider implementation="com.google.idea.blaze.base.lang.AdditionalLanguagesHelper"/>
<usageTypeProvider implementation="com.google.idea.blaze.base.lang.buildfile.findusages.BuildUsageTypeProvider"/>
+ <renameInputValidator implementation="com.google.idea.blaze.base.lang.buildfile.refactor.TargetRenameValidator"/>
</extensions>
<extensions defaultExtensionNs="com.intellij.lang">
@@ -289,6 +313,9 @@
<interface-class>com.google.idea.common.experiments.ExperimentService</interface-class>
<implementation-class>com.google.idea.blaze.base.experiments.BlazeExperimentService</implementation-class>
</component>
+ <component>
+ <implementation-class>com.google.idea.blaze.base.prefetch.PrefetchProjectInitializer</implementation-class>
+ </component>
</application-components>
<project-components>
@@ -323,9 +350,11 @@
<extensionPoint qualifiedName="com.google.idea.blaze.AspectStrategyProvider" interface="com.google.idea.blaze.base.sync.aspects.strategy.AspectStrategyProvider"/>
<extensionPoint qualifiedName="com.google.idea.blaze.DistributedExecutorSupport" interface="com.google.idea.blaze.base.run.DistributedExecutorSupport"/>
<extensionPoint qualifiedName="com.google.idea.blaze.FileStringParser" interface="com.google.idea.blaze.base.run.filter.FileResolver"/>
- <extensionPoint qualifiedName="com.google.idea.blaze.BlazeTestXmlFinderStrategy" interface="com.google.idea.blaze.base.run.testlogs.BlazeTestXmlFinderStrategy"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazeTestXmlFinderStrategy" interface="com.google.idea.blaze.base.run.testlogs.BlazeTestResultFinderStrategy"/>
<extensionPoint qualifiedName="com.google.idea.blaze.BlazeTestEventsHandler" interface="com.google.idea.blaze.base.run.smrunner.BlazeTestEventsHandler"/>
<extensionPoint qualifiedName="com.google.idea.blaze.AttributeSpecificStringLiteralReferenceProvider" interface="com.google.idea.blaze.base.lang.buildfile.references.AttributeSpecificStringLiteralReferenceProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.EventLogger" interface="com.google.idea.blaze.base.logging.EventLogger"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.ProjectViewDefaultValueProvider" interface="com.google.idea.blaze.base.projectview.section.ProjectViewDefaultValueProvider"/>
</extensionPoints>
<extensions defaultExtensionNs="com.google.idea.blaze">
@@ -339,13 +368,17 @@
<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"/>
- <TestTargetHeuristic implementation="com.google.idea.blaze.base.run.TargetNameHeuristic" order="first"/>
+ <TestTargetHeuristic implementation="com.google.idea.blaze.base.run.TargetNameHeuristic" order="first" id="TargetNameHeuristic"/>
+ <TestTargetHeuristic implementation="com.google.idea.blaze.base.run.TestTargetSourcesHeuristic"/>
<TestTargetHeuristic implementation="com.google.idea.blaze.base.run.TestSizeHeuristic" order="last" id="TestSizeHeuristic"/>
<RunConfigurationFactory implementation="com.google.idea.blaze.base.run.BlazeBuildTargetRunConfigurationFactory" order="last"/>
<AspectStrategyProvider implementation="com.google.idea.blaze.base.sync.aspects.strategy.AspectStrategyProviderBazel" order="last"/>
<FileStringParser implementation="com.google.idea.blaze.base.run.filter.StandardFileResolver" order="last"/>
- <BlazeTestXmlFinderStrategy implementation="com.google.idea.blaze.base.run.testlogs.TargetPathTestXmlFinderStrategy"/>
+ <BlazeTestXmlFinderStrategy implementation="com.google.idea.blaze.base.run.testlogs.TargetPathTestResultFinderStrategy"/>
<BlazeTestEventsHandler implementation="com.google.idea.blaze.base.run.smrunner.BlazeCompositeTestEventsHandler" order="last"/>
+ <ProjectViewDefaultValueProvider implementation="com.google.idea.blaze.base.projectview.section.sections.DirectorySection$DirectoriesProjectViewDefaultValueProvider"/>
+ <ProjectViewDefaultValueProvider implementation="com.google.idea.blaze.base.projectview.section.sections.TargetSection$TargetsProjectViewDefaultValueProvider"/>
+ <ProjectViewDefaultValueProvider implementation="com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection$AdditionalLanguagesDefaultValueProvider"/>
</extensions>
</idea-plugin>
diff --git a/base/src/com/google/idea/blaze/base/actions/BlazeBuildService.java b/base/src/com/google/idea/blaze/base/actions/BlazeBuildService.java
index 6b9e095..36a23e9 100644
--- a/base/src/com/google/idea/blaze/base/actions/BlazeBuildService.java
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeBuildService.java
@@ -37,7 +37,10 @@
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.BuildResult;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.sharding.BlazeBuildTargetSharder;
+import com.google.idea.blaze.base.sync.sharding.BlazeBuildTargetSharder.ShardedTargetsResult;
import com.google.idea.blaze.base.util.SaveUtil;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
@@ -113,20 +116,31 @@
.push(notificationScope);
WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
- BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
SaveUtil.saveAllFiles();
- BlazeIdeInterface.BuildResult buildResult =
- blazeIdeInterface.compileIdeArtifacts(
+ ShardedTargetsResult shardedTargets =
+ BlazeBuildTargetSharder.expandAndShardTargets(
project,
context,
workspaceRoot,
projectViewSet,
- blazeProjectData.blazeVersionData,
+ blazeProjectData.workspacePathResolver,
targets);
+ if (shardedTargets.buildResult.status == BuildResult.Status.FATAL_ERROR) {
+ return;
+ }
+ BuildResult buildResult =
+ BlazeIdeInterface.getInstance()
+ .compileIdeArtifacts(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ blazeProjectData.blazeVersionData,
+ shardedTargets.shardedTargets);
FileCaches.refresh(project);
- if (buildResult != BlazeIdeInterface.BuildResult.SUCCESS) {
+ if (buildResult.status != BuildResult.Status.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
index a124759..b049dee 100644
--- a/base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java
+++ b/base/src/com/google/idea/blaze/base/actions/BlazeMakeProjectAction.java
@@ -15,6 +15,8 @@
*/
package com.google.idea.blaze.base.actions;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.logging.EventLogger;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
@@ -22,6 +24,7 @@
@Override
protected void actionPerformedInBlazeProject(Project project, AnActionEvent e) {
+ EventLogger.getInstance().log(getClass(), "make", ImmutableMap.of());
BlazeBuildService.getInstance().buildProject(project);
}
}
diff --git a/base/src/com/google/idea/blaze/base/actions/CopyBlazeTargetPathAction.java b/base/src/com/google/idea/blaze/base/actions/CopyBlazeTargetPathAction.java
new file mode 100644
index 0000000..ffb49e9
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/actions/CopyBlazeTargetPathAction.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.lang.buildfile.psi.FuncallExpression;
+import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.common.actionhelper.ActionPresentationHelper;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.ide.CopyPasteManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import java.awt.datatransfer.StringSelection;
+import javax.annotation.Nullable;
+
+/** Copies a blaze target path into the clipboard */
+public class CopyBlazeTargetPathAction extends BlazeProjectAction {
+
+ @Override
+ protected void actionPerformedInBlazeProject(Project project, AnActionEvent e) {
+ Label label = getSelectedTarget(e);
+ if (label != null) {
+ CopyPasteManager.getInstance().setContents(new StringSelection(label.toString()));
+ }
+ }
+
+ @Override
+ protected void updateForBlazeProject(Project project, AnActionEvent e) {
+ Label label = getSelectedTarget(e);
+ ActionPresentationHelper.of(e).hideIf(label == null).commit();
+ }
+
+ @Nullable
+ private static Label getSelectedTarget(AnActionEvent e) {
+ PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT);
+ if (!(psiElement instanceof FuncallExpression)) {
+ return null;
+ }
+ return ((FuncallExpression) psiElement).resolveBuildLabel();
+ }
+}
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
index f9eed17..8df0ed0 100644
--- a/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java
+++ b/base/src/com/google/idea/blaze/base/async/executor/BlazeExecutor.java
@@ -28,8 +28,8 @@
import com.intellij.openapi.util.Computable;
import com.intellij.util.ui.UIUtil;
import java.util.concurrent.Callable;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Shared thread pool for blaze tasks. */
public abstract class BlazeExecutor {
@@ -59,7 +59,7 @@
@NotNull final String title,
@NotNull final Progressive progressive) {
return submitTask(
- project, title, true /* cancelable */, Modality.ALWAYS_BACKGROUND, progressive);
+ project, title, /* cancelable */ true, Modality.ALWAYS_BACKGROUND, progressive);
}
public static ListenableFuture<Void> submitTask(
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
index 8aa44a8..5357fdf 100644
--- a/base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java
+++ b/base/src/com/google/idea/blaze/base/async/process/LineProcessingOutputStream.java
@@ -15,11 +15,11 @@
*/
package com.google.idea.blaze.base.async.process;
-import com.google.common.collect.Lists;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.collect.ImmutableList;
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 {
@@ -31,25 +31,29 @@
*
* @return Whether line processing should continue
*/
- boolean processLine(@NotNull String line);
+ boolean processLine(String line);
}
- @NotNull private final StringBuffer stringBuffer = new StringBuffer();
+ private final StringBuffer stringBuffer = new StringBuffer();
private volatile boolean closed;
- @NotNull private final List<LineProcessor> lineProcessors;
+ private final ImmutableList<LineProcessor> lineProcessors;
- LineProcessingOutputStream(@NotNull LineProcessor... lineProcessors) {
- this.lineProcessors = Lists.newArrayList(lineProcessors);
+ LineProcessingOutputStream(ImmutableList<LineProcessor> lineProcessors) {
+ this.lineProcessors = lineProcessors;
}
- public static LineProcessingOutputStream of(@NotNull LineProcessor... lineProcessors) {
+ public static LineProcessingOutputStream of(LineProcessor... lineProcessors) {
+ return new LineProcessingOutputStream(ImmutableList.copyOf(lineProcessors));
+ }
+
+ public static LineProcessingOutputStream of(ImmutableList<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);
+ String text = new String(b, off, len, UTF_8);
stringBuffer.append(text);
while (true) {
diff --git a/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java b/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
index b3d4598..85296be 100644
--- a/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
+++ b/base/src/com/google/idea/blaze/base/bazel/BazelBuildSystemProvider.java
@@ -16,13 +16,15 @@
package com.google.idea.blaze.base.bazel;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.io.FileAttributeProvider;
import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
import com.google.idea.blaze.base.model.BlazeVersionData;
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.BlazeUserSettings;
import com.intellij.openapi.fileTypes.ExactFileNameMatcher;
+import com.intellij.openapi.fileTypes.ExtensionFileNameMatcher;
import com.intellij.openapi.fileTypes.FileNameMatcher;
import java.io.File;
import javax.annotation.Nullable;
@@ -35,6 +37,13 @@
return BuildSystem.Bazel;
}
+ @Nullable
+ @Override
+ public String getBinaryPath() {
+ BlazeUserSettings settings = BlazeUserSettings.getInstance();
+ return settings.getBazelBinaryPath();
+ }
+
@Override
public WorkspaceRootProvider getWorkspaceRootProvider() {
return BazelWorkspaceRootProvider.INSTANCE;
@@ -47,17 +56,20 @@
"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.build/docs/be/overview.html";
}
- // TODO: Update the methods below when https://github.com/bazelbuild/bazel/issues/552 lands.
+ @Override
+ public String getProjectViewDocumentationUrl() {
+ return "https://ij.bazel.build/docs/project-views.html";
+ }
+
@Override
public boolean isBuildFile(String fileName) {
- return fileName.equals("BUILD");
+ return fileName.equals("BUILD") || fileName.equals("BUILD.bazel");
}
@Nullable
@@ -65,22 +77,28 @@
public File findBuildFileInDirectory(File directory) {
FileAttributeProvider provider = FileAttributeProvider.getInstance();
File child = new File(directory, "BUILD");
- if (!provider.exists(child)) {
- return null;
+ if (provider.exists(child)) {
+ return child;
}
- return child;
+ child = new File(directory, "BUILD.bazel");
+ if (provider.exists(child)) {
+ return child;
+ }
+ return null;
}
@Override
- public FileNameMatcher buildFileMatcher() {
- return new ExactFileNameMatcher("BUILD");
+ public ImmutableList<FileNameMatcher> buildLanguageFileTypeMatchers() {
+ return ImmutableList.of(
+ new ExactFileNameMatcher("BUILD"), new ExactFileNameMatcher("BUILD.bazel"),
+ new ExtensionFileNameMatcher("bzl"), new ExactFileNameMatcher("WORKSPACE"));
}
@Override
public void populateBlazeVersionData(
BuildSystem buildSystem,
WorkspaceRoot workspaceRoot,
- ImmutableMap<String, String> blazeInfo,
+ BlazeInfo blazeInfo,
BlazeVersionData.Builder builder) {
if (buildSystem != BuildSystem.Bazel) {
return;
diff --git a/base/src/com/google/idea/blaze/base/bazel/BazelVersion.java b/base/src/com/google/idea/blaze/base/bazel/BazelVersion.java
index 44582cb..19be022 100644
--- a/base/src/com/google/idea/blaze/base/bazel/BazelVersion.java
+++ b/base/src/com/google/idea/blaze/base/bazel/BazelVersion.java
@@ -21,7 +21,6 @@
import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.intellij.openapi.util.text.StringUtil;
import java.io.Serializable;
-import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
@@ -77,7 +76,7 @@
return new BazelVersion(major, minor, bugfix);
}
- public static BazelVersion parseVersion(Map<String, String> blazeInfo) {
+ public static BazelVersion parseVersion(BlazeInfo blazeInfo) {
return parseVersion(blazeInfo.get(BlazeInfo.RELEASE));
}
diff --git a/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java b/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
index 61c7257..22392d4 100644
--- a/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
+++ b/base/src/com/google/idea/blaze/base/bazel/BuildSystemProvider.java
@@ -16,7 +16,7 @@
package com.google.idea.blaze.base.bazel;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.lang.buildfile.language.semantics.RuleDefinition;
import com.google.idea.blaze.base.model.BlazeVersionData;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
@@ -71,6 +71,16 @@
*/
BuildSystem buildSystem();
+ /** @return The location of the blaze/bazel binary. */
+ @Nullable
+ String getBinaryPath();
+
+ /** @return The location of the blaze/bazel binary to use for syncing. */
+ @Nullable
+ default String getSyncBinaryPath() {
+ return getBinaryPath();
+ }
+
WorkspaceRootProvider getWorkspaceRootProvider();
/** Directories containing artifacts produced during the build process. */
@@ -80,6 +90,10 @@
@Nullable
String getRuleDocumentationUrl(RuleDefinition rule);
+ /** The URL providing documentation for project view files, if one can be found. */
+ @Nullable
+ String getProjectViewDocumentationUrl();
+
/** Check if the given filename is a valid BUILD file name. */
boolean isBuildFile(String fileName);
@@ -101,12 +115,13 @@
return buildFile != null ? directory.getFileSystem().findFileByPath(buildFile.getPath()) : null;
}
- FileNameMatcher buildFileMatcher();
+ /** Returns the list of file types recognized as build system files. */
+ ImmutableList<FileNameMatcher> buildLanguageFileTypeMatchers();
/** Populates the passed builder with version data. */
void populateBlazeVersionData(
BuildSystem buildSystem,
WorkspaceRoot workspaceRoot,
- ImmutableMap<String, String> blazeInfo,
+ BlazeInfo blazeInfo,
BlazeVersionData.Builder builder);
}
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierDelegatingCodeStyleManager.java b/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierDelegatingCodeStyleManager.java
index cf4574a..ca0827d 100644
--- a/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierDelegatingCodeStyleManager.java
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/BuildifierDelegatingCodeStyleManager.java
@@ -78,7 +78,7 @@
private static boolean overrideFormatterForFile(PsiFile file) {
// don't format skylark extensions
return file instanceof BuildFile
- && ((BuildFile) file).getBlazeFileType() == BlazeFileType.BuildPackage;
+ && ((BuildFile) file).getBlazeFileType() != BlazeFileType.SkylarkExtension;
}
private void formatInternal(PsiFile file, Collection<TextRange> ranges) {
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
index f3586a2..96719c1 100644
--- a/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifier.java
@@ -19,8 +19,8 @@
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import java.io.File;
+import javax.annotation.Nullable;
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 {
diff --git a/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
index 0d398f9..7e873ee 100644
--- a/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
+++ b/base/src/com/google/idea/blaze/base/buildmodifier/FileSystemModifierImpl.java
@@ -20,8 +20,8 @@
import com.intellij.openapi.project.Project;
import java.io.File;
import java.io.IOException;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
class FileSystemModifierImpl extends FileSystemModifier {
diff --git a/base/src/com/google/idea/blaze/base/command/BlazeCommand.java b/base/src/com/google/idea/blaze/base/command/BlazeCommand.java
index a337472..d43aeaa 100644
--- a/base/src/com/google/idea/blaze/base/command/BlazeCommand.java
+++ b/base/src/com/google/idea/blaze/base/command/BlazeCommand.java
@@ -18,30 +18,21 @@
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 String binaryPath;
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;
+ private BlazeCommand(String binaryPath, BlazeCommandName name, ImmutableList<String> arguments) {
+ this.binaryPath = binaryPath;
this.name = name;
- this.blazeBinary = blazeBinary;
this.arguments = arguments;
}
@@ -50,27 +41,11 @@
}
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);
- }
+ return ImmutableList.<String>builder()
+ .add(binaryPath)
+ .add(name.toString())
+ .addAll(arguments)
+ .build();
}
@Override
@@ -78,21 +53,20 @@
return Joiner.on(' ').join(toList());
}
- public static Builder builder(BuildSystem buildSystem, BlazeCommandName name) {
- return new Builder(buildSystem, name);
+ public static Builder builder(String binaryPath, BlazeCommandName name) {
+ return new Builder(binaryPath, name);
}
/** Builder for a blaze command */
public static class Builder {
- private final BuildSystem buildSystem;
+ private final String binaryPath;
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;
+ public Builder(String binaryPath, BlazeCommandName name) {
+ this.binaryPath = binaryPath;
this.name = name;
// Tell forge what tool we used to call blaze so we can track usage.
addBlazeFlags(BlazeFlags.getToolTagFlag());
@@ -109,12 +83,7 @@
}
arguments.addAll(exeFlags.build());
- return new BlazeCommand(buildSystem, name, blazeBinary, arguments.build());
- }
-
- public Builder setBlazeBinary(@Nullable String blazeBinary) {
- this.blazeBinary = blazeBinary;
- return this;
+ return new BlazeCommand(binaryPath, name, arguments.build());
}
public Builder addTargets(TargetExpression... targets) {
diff --git a/base/src/com/google/idea/blaze/base/command/BlazeFlags.java b/base/src/com/google/idea/blaze/base/command/BlazeFlags.java
index 1f24f62..a44b056 100644
--- a/base/src/com/google/idea/blaze/base/command/BlazeFlags.java
+++ b/base/src/com/google/idea/blaze/base/command/BlazeFlags.java
@@ -21,6 +21,8 @@
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.google.idea.common.experiments.BoolExperiment;
+import com.intellij.execution.configurations.ParametersList;
import com.intellij.openapi.project.Project;
import com.intellij.util.PlatformUtils;
import java.util.List;
@@ -28,6 +30,9 @@
/** The collection of all the Bazel flag strings we use. */
public final class BlazeFlags {
+ private static final BoolExperiment macroExpandBuildFlags =
+ new BoolExperiment("macro.expand.blaze.flags", true);
+
// 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";
@@ -39,6 +44,7 @@
public static final String JAVA_BINARY_DEBUG = "--wrapper_script_flag=--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";
+ public static final String DISABLE_TEST_SHARDING = "--test_sharding_strategy=disabled";
// Filters the unit tests that are run (used with regexp for Java/Robolectric tests).
public static final String TEST_FILTER = "--test_filter";
// When used with mobile-install, deploys the an app incrementally.
@@ -48,9 +54,6 @@
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";
@@ -60,7 +63,7 @@
for (BuildFlagsProvider buildFlagsProvider : BuildFlagsProvider.EP_NAME.getExtensions()) {
buildFlagsProvider.addBuildFlags(buildSystem, projectViewSet, flags);
}
- flags.addAll(projectViewSet.listItems(BuildFlagsSection.KEY));
+ flags.addAll(expandBuildFlags(projectViewSet.listItems(BuildFlagsSection.KEY)));
return flags;
}
@@ -90,5 +93,17 @@
return TOOL_TAG + platformPrefix;
}
+ /** Expands any macros in the passed build flags. */
+ public static List<String> expandBuildFlags(List<String> flags) {
+ if (!macroExpandBuildFlags.getValue()) {
+ return flags;
+ }
+ // This built-in IntelliJ class will do macro expansion using
+ // both your enviroment and your Settings > Behavior > Path Variables
+ ParametersList parametersList = new ParametersList();
+ parametersList.addAll(flags);
+ return parametersList.getList();
+ }
+
private BlazeFlags() {}
}
diff --git a/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java b/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
index 2e40662..fcdfc70 100644
--- a/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
+++ b/base/src/com/google/idea/blaze/base/command/BuildFlagsProviderImpl.java
@@ -15,26 +15,19 @@
*/
package com.google.idea.blaze.base.command;
-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 experimentUseVersionWindowForDirtyNodeGc =
- new BoolExperiment("ide_build_info.use_version_window_for_dirty_node_gc", false);
-
@Override
public void addBuildFlags(
BuildSystem buildSystem, ProjectViewSet projectViewSet, List<String> flags) {
- if (experimentUseVersionWindowForDirtyNodeGc.getValue()) {
- flags.add(VERSION_WINDOW_FOR_DIRTY_NODE_GC);
- }
flags.add("--curses=no");
flags.add("--color=no");
+ flags.add("--noexperimental_ui");
+ flags.add("--noprogress_in_terminal_title");
}
}
diff --git a/base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java b/base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.java
deleted file mode 100644
index 8d512c0..0000000
--- a/base/src/com/google/idea/blaze/base/command/ExperimentalShowArtifactsLineProcessor.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.async.process.LineProcessingOutputStream;
-import java.io.File;
-import java.util.List;
-import java.util.function.Predicate;
-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 = ">>>";
-
- private final List<File> fileList;
- private final Predicate<String> filter;
- boolean insideBuildResult = false;
-
- public ExperimentalShowArtifactsLineProcessor(List<File> fileList) {
- this(fileList, (value) -> true);
- }
-
- public ExperimentalShowArtifactsLineProcessor(List<File> fileList, Predicate<String> filter) {
- this.fileList = fileList;
- this.filter = filter;
- }
-
- @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 (filter.test(fileName)) {
- 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/buildresult/BuildResultHelper.java b/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelper.java
new file mode 100644
index 0000000..9adf5e2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelper.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.buildresult;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream.LineProcessor;
+import com.google.idea.common.experiments.BoolExperiment;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.function.Predicate;
+
+/** Assists in getting build artifacts from a build operation. */
+public interface BuildResultHelper {
+ // This experiment does *not* work yet and should remain off
+ BoolExperiment USE_BEP = new BoolExperiment("use.bep", false);
+
+ /**
+ * Constructs a new build result helper.
+ *
+ * @param files A filter for the output artifacts you are interested in.
+ */
+ static BuildResultHelper forFiles(Predicate<String> files) {
+ return USE_BEP.getValue()
+ ? new BuildResultHelperBep(files)
+ : new BuildResultHelperStderr(files);
+ }
+
+ /**
+ * Returns the build flags necessary for the build result helper to work.
+ *
+ * <p>The user must add these flags to their build command.
+ */
+ List<String> getBuildFlags();
+
+ /**
+ * Returns an output stream to be passed to the external task's stderr.
+ *
+ * <p>The user must pipe blaze's stderr to this output stream.
+ *
+ * @param lineProcessors Any additional line processors you want on stderr output.
+ */
+ OutputStream stderr(LineProcessor... lineProcessors);
+
+ /**
+ * Returns the build result. May only be called once the build is complete, or no artifacts will
+ * be returned.
+ *
+ * @return The build artifacts from the build operation.
+ */
+ ImmutableList<File> getBuildArtifacts();
+}
diff --git a/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelperBep.java b/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelperBep.java
new file mode 100644
index 0000000..8a32e85
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelperBep.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.buildresult;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream.LineProcessor;
+import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEvent;
+import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
+import com.google.repackaged.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.IdCase;
+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.io.OutputStream;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Predicate;
+
+/**
+ * Build event protocol implementation to get build results.
+ *
+ * <p>The build even protocol (BEP for short) is a proto-based protocol used by bazel to communicate
+ * build events.
+ */
+class BuildResultHelperBep implements BuildResultHelper {
+ private static final Logger logger = Logger.getInstance(BuildResultHelperBep.class);
+ private final File outputFile;
+ private final Predicate<String> fileFilter;
+ private ImmutableList<File> result;
+
+ BuildResultHelperBep(Predicate<String> fileFilter) {
+ this.fileFilter = fileFilter;
+ File tempDir = new File(System.getProperty("java.io.tmpdir"));
+ String suffix = UUID.randomUUID().toString();
+ String fileName = "intellij-bep-" + suffix;
+ this.outputFile = new File(tempDir, fileName);
+ }
+
+ @Override
+ public List<String> getBuildFlags() {
+ return ImmutableList.of("--experimental_build_event_binary_file=" + outputFile.getPath());
+ }
+
+ @Override
+ public OutputStream stderr(LineProcessor... lineProcessors) {
+ return LineProcessingOutputStream.of(ImmutableList.copyOf(lineProcessors));
+ }
+
+ @Override
+ public ImmutableList<File> getBuildArtifacts() {
+ if (result == null) {
+ result = readResult();
+ }
+ return result;
+ }
+
+ private ImmutableList<File> readResult() {
+ ImmutableList.Builder<File> result = ImmutableList.builder();
+ try (InputStream inputStream = new BufferedInputStream(new FileInputStream(outputFile))) {
+ BuildEvent buildEvent;
+ while ((buildEvent = BuildEvent.parseDelimitedFrom(inputStream)) != null) {
+ BuildEventId buildEventId = buildEvent.getId();
+ // Note: This doesn't actually work. BEP does not issue these for actions
+ // that don't execute during the build, so we can't find the files
+ // for a no-op build the way we can for --experimental_show_artifacts
+ if (buildEventId.getIdCase() == IdCase.ACTION_COMPLETED) {
+ String output = buildEventId.getActionCompleted().getPrimaryOutput();
+ if (fileFilter.test(output)) {
+ result.add(new File(output));
+ }
+ }
+ }
+ } catch (IOException e) {
+ logger.error(e);
+ return ImmutableList.of();
+ }
+ if (!outputFile.delete()) {
+ logger.warn("Could not delete BEP output file: " + outputFile);
+ }
+ return result.build();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelperStderr.java b/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelperStderr.java
new file mode 100644
index 0000000..ef34dd6
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/buildresult/BuildResultHelperStderr.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.buildresult;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream.LineProcessor;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.function.Predicate;
+
+class BuildResultHelperStderr implements BuildResultHelper {
+ private final ImmutableList.Builder<File> buildArtifacts = ImmutableList.builder();
+ private final ExperimentalShowArtifactsLineProcessor experimentalShowArtifactsLineProcessor;
+ private ImmutableList<File> result;
+
+ BuildResultHelperStderr(Predicate<String> fileFilter) {
+ experimentalShowArtifactsLineProcessor =
+ new ExperimentalShowArtifactsLineProcessor(buildArtifacts, fileFilter);
+ }
+
+ @Override
+ public List<String> getBuildFlags() {
+ return ImmutableList.of(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS);
+ }
+
+ @Override
+ public OutputStream stderr(LineProcessor... lineProcessors) {
+ return LineProcessingOutputStream.of(
+ ImmutableList.<LineProcessor>builder()
+ .add(experimentalShowArtifactsLineProcessor)
+ .add(lineProcessors)
+ .build());
+ }
+
+ @Override
+ public ImmutableList<File> getBuildArtifacts() {
+ if (result == null) {
+ result = buildArtifacts.build();
+ }
+ return result;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/command/buildresult/ExperimentalShowArtifactsLineProcessor.java b/base/src/com/google/idea/blaze/base/command/buildresult/ExperimentalShowArtifactsLineProcessor.java
new file mode 100644
index 0000000..609867c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/buildresult/ExperimentalShowArtifactsLineProcessor.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.command.buildresult;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import java.io.File;
+import java.util.function.Predicate;
+import org.jetbrains.annotations.NotNull;
+
+/** Collects the output of --experimental_show_artifacts */
+class ExperimentalShowArtifactsLineProcessor implements LineProcessingOutputStream.LineProcessor {
+ private static final String OUTPUT_START = "Build artifacts:";
+ private static final String OUTPUT_MARKER = ">>>";
+
+ private final ImmutableList.Builder<File> fileList;
+ private final Predicate<String> filter;
+ private boolean afterBuildResult = false;
+
+ ExperimentalShowArtifactsLineProcessor(
+ ImmutableList.Builder<File> fileList, Predicate<String> filter) {
+ this.fileList = fileList;
+ this.filter = filter;
+ }
+
+ @Override
+ public boolean processLine(@NotNull String line) {
+ if (!afterBuildResult) {
+ afterBuildResult = line.equals(OUTPUT_START);
+ return !afterBuildResult;
+ }
+ if (!line.startsWith(OUTPUT_MARKER)) {
+ return true;
+ }
+ String fileName = line.substring(OUTPUT_MARKER.length());
+ if (filter.test(fileName)) {
+ fileList.add(new File(fileName));
+ }
+ return false;
+ }
+}
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
index 1d329aa..bf9d694 100644
--- a/base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfo.java
@@ -15,17 +15,17 @@
*/
package com.google.idea.blaze.base.command.info;
+import com.google.common.annotations.VisibleForTesting;
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.model.primitives.ExecutionRootPath;
import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.components.ServiceManager;
-import java.util.List;
-import javax.annotation.Nullable;
+import com.intellij.openapi.diagnostic.Logger;
+import java.io.File;
+import java.io.Serializable;
-/** Runs the blaze info command. The results may be cached in the workspace. */
-public abstract class BlazeInfo {
+/** The data output by blaze info. */
+public class BlazeInfo implements Serializable {
+ public static final long serialVersionUID = 2L;
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";
@@ -34,6 +34,8 @@
public static final String COMMAND_LOG = "command_log";
public static final String RELEASE = "release";
+ private static final Logger logger = Logger.getInstance(BlazeInfo.class);
+
public static String blazeBinKey(BuildSystem buildSystem) {
switch (buildSystem) {
case Blaze:
@@ -67,46 +69,74 @@
}
}
- public static BlazeInfo getInstance() {
- return ServiceManager.getService(BlazeInfo.class);
+ private final ImmutableMap<String, String> blazeInfoMap;
+
+ private final File executionRoot;
+ private final ExecutionRootPath blazeBinExecutionRootPath;
+ private final ExecutionRootPath blazeGenfilesExecutionRootPath;
+ private final File outputBase;
+
+ public BlazeInfo(BuildSystem buildSystem, ImmutableMap<String, String> blazeInfoMap) {
+ this.blazeInfoMap = blazeInfoMap;
+ this.executionRoot = new File(getOrThrow(blazeInfoMap, EXECUTION_ROOT_KEY).trim());
+ this.blazeBinExecutionRootPath =
+ ExecutionRootPath.createAncestorRelativePath(
+ executionRoot, new File(getOrThrow(blazeInfoMap, blazeBinKey(buildSystem))));
+ this.blazeGenfilesExecutionRootPath =
+ ExecutionRootPath.createAncestorRelativePath(
+ executionRoot, new File(getOrThrow(blazeInfoMap, blazeGenfilesKey(buildSystem))));
+ this.outputBase = new File(getOrThrow(blazeInfoMap, OUTPUT_BASE_KEY).trim());
+ logger.assertTrue(blazeBinExecutionRootPath != null);
+ logger.assertTrue(blazeGenfilesExecutionRootPath != null);
}
- /**
- * @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);
+ private static String getOrThrow(ImmutableMap<String, String> map, String key) {
+ String value = map.get(key);
+ if (value == null) {
+ throw new RuntimeException(String.format("Could not locate %s in info map", key));
+ }
+ return value;
+ }
- /**
- * @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);
+ public String get(String key) {
+ return blazeInfoMap.get(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);
+ public File getExecutionRoot() {
+ return executionRoot;
+ }
+
+ public ExecutionRootPath getBlazeBinExecutionRootPath() {
+ return blazeBinExecutionRootPath;
+ }
+
+ public ExecutionRootPath getBlazeGenfilesExecutionRootPath() {
+ return blazeGenfilesExecutionRootPath;
+ }
+
+ public File getGenfilesDirectory() {
+ return blazeGenfilesExecutionRootPath.getFileRootedAt(getExecutionRoot());
+ }
+
+ public File getBlazeBinDirectory() {
+ return blazeBinExecutionRootPath.getFileRootedAt(getExecutionRoot());
+ }
+
+ public File getOutputBase() {
+ return outputBase;
+ }
+
+ /** Creates a mock blaze info with the minimum information required for syncing. */
+ @VisibleForTesting
+ public static BlazeInfo createMockBlazeInfo(
+ String outputBase, String executionRoot, String blazeBin, String blazeGenFiles) {
+ BuildSystem buildSystem = BuildSystem.Bazel;
+ ImmutableMap.Builder<String, String> blazeInfoMap =
+ ImmutableMap.<String, String>builder()
+ .put(OUTPUT_BASE_KEY, outputBase)
+ .put(EXECUTION_ROOT_KEY, executionRoot)
+ .put(blazeBinKey(buildSystem), blazeBin)
+ .put(blazeGenfilesKey(buildSystem), blazeGenFiles);
+ return new BlazeInfo(buildSystem, blazeInfoMap.build());
+ }
}
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
index 39294c3..98aa7d3 100644
--- a/base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoException.java
@@ -17,33 +17,23 @@
import javax.annotation.concurrent.Immutable;
-/** Exception occuring during blaze infoy */
+/** Exception occuring during blaze info */
@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) {
+ public BlazeInfoException(int exitCode, String stdout) {
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;
+ return "blaze info failed with exit code: " + exitCode;
}
public String getStdout() {
return stdout;
}
-
- public String getStderr() {
- return stderr;
- }
}
diff --git a/base/src/com/google/idea/blaze/base/command/info/BlazeInfoRunner.java b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoRunner.java
new file mode 100644
index 0000000..fb29f7d
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoRunner.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.command.info;
+
+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;
+
+/** Runs the blaze info command. The results may be cached in the workspace. */
+public abstract class BlazeInfoRunner {
+
+ public static BlazeInfoRunner getInstance() {
+ return ServiceManager.getService(BlazeInfoRunner.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(
+ BlazeContext context,
+ String binaryPath,
+ 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(
+ BlazeContext context,
+ String binaryPath,
+ 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.
+ *
+ * @param blazeFlags The blaze flags that will be passed to Blaze.
+ * @return The blaze info data fields.
+ */
+ public abstract ListenableFuture<BlazeInfo> runBlazeInfo(
+ BlazeContext context,
+ BuildSystem buildSystem,
+ String binaryPath,
+ WorkspaceRoot workspaceRoot,
+ List<String> blazeFlags);
+}
diff --git a/base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoRunnerImpl.java
similarity index 74%
rename from base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java
rename to base/src/com/google/idea/blaze/base/command/info/BlazeInfoRunnerImpl.java
index 4b9fe6c..892da90 100644
--- a/base/src/com/google/idea/blaze/base/command/info/BlazeInfoImpl.java
+++ b/base/src/com/google/idea/blaze/base/command/info/BlazeInfoRunnerImpl.java
@@ -19,6 +19,8 @@
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.async.process.PrintOutputLineProcessor;
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;
@@ -29,77 +31,78 @@
import java.util.List;
import javax.annotation.Nullable;
-class BlazeInfoImpl extends BlazeInfo {
- private static final Logger logger = Logger.getInstance(BlazeInfoImpl.class);
+class BlazeInfoRunnerImpl extends BlazeInfoRunner {
+ private static final Logger logger = Logger.getInstance(BlazeInfoRunnerImpl.class);
@Override
public ListenableFuture<String> runBlazeInfo(
- @Nullable BlazeContext context,
- BuildSystem buildSystem,
+ BlazeContext context,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
List<String> blazeFlags,
String key) {
return BlazeExecutor.getInstance()
.submit(
() ->
- runBlazeInfo(buildSystem, workspaceRoot, key, blazeFlags, context)
+ runBlazeInfo(binaryPath, workspaceRoot, key, blazeFlags, context)
.toString()
.trim());
}
@Override
public ListenableFuture<byte[]> runBlazeInfoGetBytes(
- @Nullable BlazeContext context,
- BuildSystem buildSystem,
+ BlazeContext context,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
List<String> blazeFlags,
String key) {
return BlazeExecutor.getInstance()
.submit(
- () -> runBlazeInfo(buildSystem, workspaceRoot, key, blazeFlags, context).toByteArray());
+ () -> runBlazeInfo(binaryPath, workspaceRoot, key, blazeFlags, context).toByteArray());
}
@Override
- public ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(
- @Nullable BlazeContext context,
+ public ListenableFuture<BlazeInfo> runBlazeInfo(
+ BlazeContext context,
BuildSystem buildSystem,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
List<String> blazeFlags) {
return BlazeExecutor.getInstance()
.submit(
() -> {
String blazeInfoString =
- runBlazeInfo(buildSystem, workspaceRoot, null /* key */, blazeFlags, context)
+ runBlazeInfo(binaryPath, workspaceRoot, /* key */ null, blazeFlags, context)
.toString()
.trim();
- return parseBlazeInfoResult(blazeInfoString);
+ ImmutableMap<String, String> blazeInfoMap = parseBlazeInfoResult(blazeInfoString);
+ return new BlazeInfo(buildSystem, blazeInfoMap);
});
}
private static ByteArrayOutputStream runBlazeInfo(
- BuildSystem buildSystem,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
@Nullable String key,
List<String> blazeFlags,
- @Nullable BlazeContext context)
+ BlazeContext context)
throws BlazeInfoException {
- BlazeCommand.Builder builder = BlazeCommand.builder(buildSystem, BlazeCommandName.INFO);
+ BlazeCommand.Builder builder = BlazeCommand.builder(binaryPath, 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)
+ .stderr(LineProcessingOutputStream.of(new PrintOutputLineProcessor(context)))
.build()
.run();
if (exitCode != 0) {
- throw new BlazeInfoException(exitCode, stdout.toString(), stderr.toString());
+ throw new BlazeInfoException(exitCode, stdout.toString());
}
return stdout;
}
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
index 2bd7d57..2e40a53 100644
--- a/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleService.java
@@ -18,8 +18,8 @@
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Prints text to the blaze console. */
public interface BlazeConsoleService {
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
index ba5e3a6..5b4792b 100644
--- a/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleServiceImpl.java
@@ -19,8 +19,8 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Implementation for BlazeConsoleService */
public class BlazeConsoleServiceImpl implements BlazeConsoleService {
diff --git a/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java b/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
index d5c02c3..58162c5 100644
--- a/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
+++ b/base/src/com/google/idea/blaze/base/console/BlazeConsoleView.java
@@ -38,10 +38,10 @@
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import java.awt.BorderLayout;
+import javax.annotation.Nullable;
import javax.swing.JComponent;
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
class BlazeConsoleView implements Disposable {
diff --git a/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java b/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java
index 0142f06..052bb6e 100644
--- a/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java
+++ b/base/src/com/google/idea/blaze/base/filecache/FileDiffer.java
@@ -23,7 +23,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Provides a diffing service for a collection of files. */
public final class FileDiffer {
diff --git a/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java b/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
index 1f5d7c5..7317f31 100644
--- a/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
+++ b/base/src/com/google/idea/blaze/base/ide/NewBlazePackageDialog.java
@@ -38,11 +38,11 @@
import java.awt.GridBagLayout;
import java.io.File;
import java.util.List;
+import javax.annotation.Nullable;
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 logger = Logger.getInstance(NewBlazePackageDialog.class);
@@ -112,7 +112,7 @@
WorkspacePath newPackagePath = workspaceRoot.workspacePathFor(newPackageDirectory);
TargetName newTargetName = newRuleUI.getRuleName();
- Label newRule = new Label(newPackagePath, newTargetName);
+ Label newRule = Label.create(newPackagePath, newTargetName);
Kind ruleKind = newRuleUI.getSelectedRuleKind();
try {
parentDirectory.checkCreateSubdirectory(newPackageName);
diff --git a/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java b/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
index d77e25c..ae43540 100644
--- a/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
+++ b/base/src/com/google/idea/blaze/base/ide/NewBlazeRuleDialog.java
@@ -24,7 +24,6 @@
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;
@@ -37,8 +36,6 @@
import javax.swing.JPanel;
class NewBlazeRuleDialog extends DialogWrapper {
- private static final Logger logger = Logger.getInstance(NewBlazeRuleDialog.class);
-
private static final int UI_INDENT = 0;
private static final int TEXT_BOX_WIDTH = 40;
@@ -94,7 +91,7 @@
WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
WorkspacePath workspacePath =
workspaceRoot.workspacePathFor(new File(buildFile.getParent().getPath()));
- Label newRule = new Label(workspacePath, targetName);
+ Label newRule = Label.create(workspacePath, targetName);
BuildFileModifier buildFileModifier = BuildFileModifier.getInstance();
boolean success = buildFileModifier.addRule(project, context, newRule, ruleKind);
diff --git a/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java b/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
index 8f859fd..bf0c26a 100644
--- a/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
+++ b/base/src/com/google/idea/blaze/base/ide/NewRuleUI.java
@@ -27,9 +27,9 @@
import com.intellij.ui.components.JBTextField;
import java.util.Collection;
import java.util.List;
+import javax.annotation.Nullable;
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
final class NewRuleUI {
diff --git a/base/src/com/google/idea/blaze/base/ide/OpenBlazeWorkspaceFileAction.java b/base/src/com/google/idea/blaze/base/ide/OpenBlazeWorkspaceFileAction.java
new file mode 100644
index 0000000..68976c8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ide/OpenBlazeWorkspaceFileAction.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.BlazeProjectAction;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.ui.UiUtil;
+import com.google.idea.blaze.base.ui.WorkspaceFileTextField;
+import com.intellij.ide.actions.OpenFileAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.fileChooser.FileTextField;
+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 com.intellij.ui.components.JBLabel;
+import java.awt.GridBagLayout;
+import javax.annotation.Nullable;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+final class OpenBlazeWorkspaceFileAction extends BlazeProjectAction {
+
+ @Override
+ protected void actionPerformedInBlazeProject(Project project, AnActionEvent e) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return;
+ }
+ new OpenBlazeWorkspaceFileActionDialog(project, blazeProjectData.workspacePathResolver).show();
+ }
+
+ private static class OpenBlazeWorkspaceFileActionDialog extends DialogWrapper {
+
+ static final int PATH_FIELD_WIDTH = 40;
+ final Project project;
+
+ final JPanel component;
+ final FileTextField fileTextField;
+
+ OpenBlazeWorkspaceFileActionDialog(
+ Project project, WorkspacePathResolver workspacePathResolver) {
+ super(project, /* canBeParent */ false, IdeModalityType.PROJECT);
+ this.project = project;
+
+ component = new JPanel(new GridBagLayout());
+ FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileDescriptor();
+ fileTextField =
+ WorkspaceFileTextField.create(
+ workspacePathResolver, descriptor, PATH_FIELD_WIDTH, myDisposable);
+
+ component.add(new JBLabel("Path:"));
+ component.add(fileTextField.getField(), UiUtil.getFillLineConstraints(0));
+
+ UiUtil.fillBottom(component);
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return component;
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return fileTextField.getField();
+ }
+
+ @Nullable
+ @Override
+ protected ValidationInfo doValidate() {
+ VirtualFile selectedFile = fileTextField.getSelectedFile();
+ if (selectedFile == null || !selectedFile.exists()) {
+ return new ValidationInfo("File does not exist", fileTextField.getField());
+ } else if (selectedFile.isDirectory()) {
+ return new ValidationInfo("Directories can not be opened", fileTextField.getField());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected void doOKAction() {
+ OpenFileAction.openFile(fileTextField.getSelectedFile(), project);
+ super.doOKAction();
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/AndroidIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/AndroidIdeInfo.java
index 760fac7..68a7565 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/AndroidIdeInfo.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/AndroidIdeInfo.java
@@ -19,7 +19,7 @@
import com.google.idea.blaze.base.model.primitives.Label;
import java.io.Serializable;
import java.util.Collection;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Ide info specific to android rules. */
public final class AndroidIdeInfo implements Serializable {
diff --git a/base/src/com/google/idea/blaze/base/run/testlogs/CompletedTestTarget.java b/base/src/com/google/idea/blaze/base/ideinfo/AndroidSdkIdeInfo.java
similarity index 60%
rename from base/src/com/google/idea/blaze/base/run/testlogs/CompletedTestTarget.java
rename to base/src/com/google/idea/blaze/base/ideinfo/AndroidSdkIdeInfo.java
index bf0b33b..1a07184 100644
--- a/base/src/com/google/idea/blaze/base/run/testlogs/CompletedTestTarget.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/AndroidSdkIdeInfo.java
@@ -13,19 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.idea.blaze.base.run.testlogs;
+package com.google.idea.blaze.base.ideinfo;
-import com.google.idea.blaze.base.model.primitives.Label;
-import java.io.File;
+import java.io.Serializable;
-/** Information relating to a completed test target. */
-public class CompletedTestTarget {
+/** android_sdk ide info */
+public class AndroidSdkIdeInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
- public final File testResultXml;
- public final Label label;
+ public final ArtifactLocation androidJar;
- public CompletedTestTarget(File testResultXml, Label label) {
- this.testResultXml = testResultXml;
- this.label = label;
+ public AndroidSdkIdeInfo(ArtifactLocation androidJar) {
+ this.androidJar = androidJar;
}
}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java b/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
index a23ab9c..72dc07c 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/ArtifactLocation.java
@@ -22,9 +22,9 @@
/** Represents a blaze-produced artifact. */
public final class ArtifactLocation implements Serializable, Comparable<ArtifactLocation> {
- private static final long serialVersionUID = 4L;
+ private static final long serialVersionUID = 5L;
- public final String rootExecutionPathFragment;
+ private final String rootExecutionPathFragment;
public final String relativePath;
public final boolean isSource;
public final boolean isExternal;
@@ -37,7 +37,10 @@
this.isExternal = isExternal;
}
- /** Gets the path relative to the root path. */
+ /**
+ * The root-relative path. For external workspace artifacts, this is relative to the external
+ * workspace root.
+ */
public String getRelativePath() {
return relativePath;
}
@@ -50,10 +53,7 @@
return !isSource;
}
- /**
- * Returns rootExecutionPathFragment + relativePath. For source artifacts, this is simply
- * relativePath
- */
+ /** For main-workspace source artifacts, this is simply the workspace-relative path. */
public String getExecutionRootRelativePath() {
return Paths.get(rootExecutionPathFragment, relativePath).toString();
}
@@ -124,8 +124,8 @@
return ComparisonChain.start()
.compare(rootExecutionPathFragment, o.rootExecutionPathFragment)
.compare(relativePath, o.relativePath)
- .compare(isSource, o.isSource)
- .compare(isExternal, o.isExternal)
+ .compareFalseFirst(isSource, o.isSource)
+ .compareFalseFirst(isExternal, o.isExternal)
.result();
}
}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/CIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/CIdeInfo.java
index de80f8c..215033d 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/CIdeInfo.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/CIdeInfo.java
@@ -21,10 +21,12 @@
/** Sister class to {@link JavaIdeInfo} */
public class CIdeInfo implements Serializable {
- private static final long serialVersionUID = 6L;
+ private static final long serialVersionUID = 7L;
public final ImmutableList<ArtifactLocation> sources;
+ public final ImmutableList<String> localDefines;
+ public final ImmutableList<ExecutionRootPath> localIncludeDirectories;
// From the cpp compilation context provider.
// These should all be for the entire transitive closure.
public final ImmutableList<ExecutionRootPath> transitiveIncludeDirectories;
@@ -34,11 +36,15 @@
public CIdeInfo(
ImmutableList<ArtifactLocation> sources,
+ ImmutableList<String> localDefines,
+ ImmutableList<ExecutionRootPath> localIncludeDirectories,
ImmutableList<ExecutionRootPath> transitiveIncludeDirectories,
ImmutableList<ExecutionRootPath> transitiveQuoteIncludeDirectories,
ImmutableList<String> transitiveDefines,
ImmutableList<ExecutionRootPath> transitiveSystemIncludeDirectories) {
this.sources = sources;
+ this.localDefines = localDefines;
+ this.localIncludeDirectories = localIncludeDirectories;
this.transitiveIncludeDirectories = transitiveIncludeDirectories;
this.transitiveQuoteIncludeDirectories = transitiveQuoteIncludeDirectories;
this.transitiveDefines = transitiveDefines;
@@ -53,6 +59,9 @@
public static class Builder {
private final ImmutableList.Builder<ArtifactLocation> sources = ImmutableList.builder();
+ private final ImmutableList.Builder<String> localDefines = ImmutableList.builder();
+ private final ImmutableList.Builder<ExecutionRootPath> localIncludeDirectories =
+ ImmutableList.builder();
private final ImmutableList.Builder<ExecutionRootPath> transitiveIncludeDirectories =
ImmutableList.builder();
private final ImmutableList.Builder<ExecutionRootPath> transitiveQuoteIncludeDirectories =
@@ -66,6 +75,16 @@
return this;
}
+ public Builder addLocalDefines(Iterable<String> localDefines) {
+ this.localDefines.addAll(localDefines);
+ return this;
+ }
+
+ public Builder addLocalIncludeDirectories(Iterable<ExecutionRootPath> localIncludeDirectories) {
+ this.localIncludeDirectories.addAll(localIncludeDirectories);
+ return this;
+ }
+
public Builder addTransitiveIncludeDirectories(
Iterable<ExecutionRootPath> transitiveIncludeDirectories) {
this.transitiveIncludeDirectories.addAll(transitiveIncludeDirectories);
@@ -92,6 +111,8 @@
public CIdeInfo build() {
return new CIdeInfo(
sources.build(),
+ localDefines.build(),
+ localIncludeDirectories.build(),
transitiveIncludeDirectories.build(),
transitiveQuoteIncludeDirectories.build(),
transitiveDefines.build(),
@@ -106,6 +127,12 @@
+ " sources="
+ sources
+ "\n"
+ + " localDefines="
+ + localDefines
+ + "\n"
+ + " localIncludeDirectories="
+ + localIncludeDirectories
+ + "\n"
+ " transitiveIncludeDirectories="
+ transitiveIncludeDirectories
+ "\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
index f1c0174..5224256 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/CToolchainIdeInfo.java
@@ -20,7 +20,7 @@
import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
import java.io.Serializable;
-/** Sister class to {@link JavaIdeInfo} */
+/** Represents a cc_toolchain */
public class CToolchainIdeInfo implements Serializable {
private static final long serialVersionUID = 3L;
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/IntellijPluginDeployInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/IntellijPluginDeployInfo.java
deleted file mode 100644
index 426fa6b..0000000
--- a/base/src/com/google/idea/blaze/base/ideinfo/IntellijPluginDeployInfo.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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 javax.annotation.concurrent.Immutable;
-
-/** A special rule representing the files that need to be deployed for an IntelliJ plugin */
-@Immutable
-public class IntellijPluginDeployInfo implements Serializable {
- private static final long serialVersionUID = 1L;
-
- /** A single file for deployment */
- @Immutable
- public static class IntellijPluginDeployFile implements Serializable {
- private static final long serialVersionUID = 1L;
-
- /** The source file to deploy. */
- public final ArtifactLocation src;
- /** A plugins-directory relative location to deploy to. */
- public final String deployLocation;
-
- public IntellijPluginDeployFile(ArtifactLocation src, String deployLocation) {
- this.src = src;
- this.deployLocation = deployLocation;
- }
- }
-
- public final ImmutableList<IntellijPluginDeployFile> deployFiles;
-
- public IntellijPluginDeployInfo(ImmutableList<IntellijPluginDeployFile> deployFiles) {
- this.deployFiles = deployFiles;
- }
-}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/JavaIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/JavaIdeInfo.java
index 174db51..271e390 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/JavaIdeInfo.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/JavaIdeInfo.java
@@ -18,7 +18,7 @@
import com.google.common.collect.ImmutableList;
import java.io.Serializable;
import java.util.Collection;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Ide info specific to java rules. */
public final class JavaIdeInfo implements Serializable {
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java b/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
index f661e5a..6eaab56 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/LibraryArtifact.java
@@ -17,7 +17,7 @@
import com.google.common.base.Objects;
import java.io.Serializable;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Represents a jar artifact. */
public class LibraryArtifact implements Serializable {
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/TargetIdeInfo.java b/base/src/com/google/idea/blaze/base/ideinfo/TargetIdeInfo.java
index 34f2bc2..ecd44c5 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/TargetIdeInfo.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/TargetIdeInfo.java
@@ -27,7 +27,7 @@
/** Simple implementation of TargetIdeInfo. */
public final class TargetIdeInfo implements Serializable {
- private static final long serialVersionUID = 15L;
+ private static final long serialVersionUID = 17L;
public final TargetKey key;
public final Kind kind;
@@ -39,11 +39,11 @@
@Nullable public final CToolchainIdeInfo cToolchainIdeInfo;
@Nullable public final JavaIdeInfo javaIdeInfo;
@Nullable public final AndroidIdeInfo androidIdeInfo;
+ @Nullable public final AndroidSdkIdeInfo androidSdkIdeInfo;
@Nullable public final PyIdeInfo pyIdeInfo;
@Nullable public final TestIdeInfo testIdeInfo;
@Nullable public final ProtoLibraryLegacyInfo protoLibraryLegacyInfo;
@Nullable public final JavaToolchainIdeInfo javaToolchainIdeInfo;
- @Nullable public final IntellijPluginDeployInfo intellijPluginDeployInfo;
public TargetIdeInfo(
TargetKey key,
@@ -56,11 +56,11 @@
@Nullable CToolchainIdeInfo cToolchainIdeInfo,
@Nullable JavaIdeInfo javaIdeInfo,
@Nullable AndroidIdeInfo androidIdeInfo,
+ @Nullable AndroidSdkIdeInfo androidSdkIdeInfo,
@Nullable PyIdeInfo pyIdeInfo,
@Nullable TestIdeInfo testIdeInfo,
@Nullable ProtoLibraryLegacyInfo protoLibraryLegacyInfo,
- @Nullable JavaToolchainIdeInfo javaToolchainIdeInfo,
- @Nullable IntellijPluginDeployInfo intellijPluginDeployInfo) {
+ @Nullable JavaToolchainIdeInfo javaToolchainIdeInfo) {
this.key = key;
this.kind = kind;
this.buildFile = buildFile;
@@ -71,11 +71,11 @@
this.cToolchainIdeInfo = cToolchainIdeInfo;
this.javaIdeInfo = javaIdeInfo;
this.androidIdeInfo = androidIdeInfo;
+ this.androidSdkIdeInfo = androidSdkIdeInfo;
this.pyIdeInfo = pyIdeInfo;
this.testIdeInfo = testIdeInfo;
this.protoLibraryLegacyInfo = protoLibraryLegacyInfo;
this.javaToolchainIdeInfo = javaToolchainIdeInfo;
- this.intellijPluginDeployInfo = intellijPluginDeployInfo;
}
@Override
@@ -89,7 +89,7 @@
}
/** Returns whether this rule is one of the kinds. */
- public boolean kindIsOneOf(List<Kind> kinds) {
+ public boolean kindIsOneOf(Collection<Kind> kinds) {
if (kind != null) {
return kind.isOneOf(kinds);
}
@@ -122,7 +122,7 @@
private JavaToolchainIdeInfo javaToolchainIdeInfo;
public Builder setLabel(String label) {
- return setLabel(new Label(label));
+ return setLabel(Label.create(label));
}
public Builder setLabel(Label label) {
@@ -212,7 +212,7 @@
}
public Builder addDependency(String s) {
- return addDependency(new Label(s));
+ return addDependency(Label.create(s));
}
public Builder addDependency(Label label) {
@@ -222,7 +222,7 @@
}
public Builder addRuntimeDep(String s) {
- return addRuntimeDep(new Label(s));
+ return addRuntimeDep(Label.create(s));
}
public Builder addRuntimeDep(Label label) {
@@ -243,11 +243,11 @@
cToolchainIdeInfo,
javaIdeInfo,
androidIdeInfo,
+ null,
pyIdeInfo,
testIdeInfo,
protoLibraryLegacyInfo,
- javaToolchainIdeInfo,
- null);
+ javaToolchainIdeInfo);
}
}
}
diff --git a/base/src/com/google/idea/blaze/base/ideinfo/TargetKey.java b/base/src/com/google/idea/blaze/base/ideinfo/TargetKey.java
index d1e99a1..9803427 100644
--- a/base/src/com/google/idea/blaze/base/ideinfo/TargetKey.java
+++ b/base/src/com/google/idea/blaze/base/ideinfo/TargetKey.java
@@ -24,7 +24,7 @@
import java.io.Serializable;
import java.util.List;
-/** A key that uniquely idenfifies a target in the target map */
+/** A key that uniquely identifies a target in the target map */
public class TargetKey implements Serializable, Comparable<TargetKey> {
private static final long serialVersionUID = 3L;
diff --git a/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java b/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
index 2ebd868..55755ec 100644
--- a/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
+++ b/base/src/com/google/idea/blaze/base/issueparser/BlazeIssueParser.java
@@ -36,11 +36,11 @@
import java.util.regex.Pattern;
import javax.annotation.Nullable;
-
/** Parses blaze output for compile errors. */
public class BlazeIssueParser {
- private static class ParseResult {
+ /** Result from parsing the current line */
+ public static class ParseResult {
public static final ParseResult NEEDS_MORE_INPUT = new ParseResult(true, null);
@@ -117,9 +117,9 @@
/** Returns the file referenced by the target */
@Nullable
- public static File fileFromTarget(WorkspaceRoot workspaceRoot, String targetString) {
+ private static File fileFromTarget(WorkspaceRoot workspaceRoot, String targetString) {
Label label = Label.createIfValid(targetString);
- if (label == null) {
+ if (label == null || label.isExternal()) {
return null;
}
try {
@@ -132,7 +132,10 @@
}
/** Falls back to returning -1 if no integer can be parsed. */
- public static int parseOptionalInt(String intString) {
+ public static int parseOptionalInt(@Nullable String intString) {
+ if (intString == null) {
+ return -1;
+ }
try {
return Integer.parseInt(intString);
} catch (NumberFormatException e) {
@@ -215,6 +218,22 @@
}
}
+ static class SkylarkErrorParser extends SingleLineParser {
+ SkylarkErrorParser() {
+ super("^ERROR: (/.*?\\.bzl):([0-9]+):([0-9]+): (.*)$");
+ }
+
+ @Override
+ protected IssueOutput createIssue(Matcher matcher) {
+ File file = fileFromAbsolutePath(matcher.group(1));
+ return IssueOutput.error(matcher.group(4))
+ .inFile(file)
+ .onLine(Integer.parseInt(matcher.group(2)))
+ .inColumn(parseOptionalInt(matcher.group(3)))
+ .build();
+ }
+ }
+
static class LinelessBuildParser extends SingleLineParser {
LinelessBuildParser() {
super("^ERROR: (.*?):char offsets [0-9]+--[0-9]+: (.*)$");
diff --git a/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java b/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
index c3c5de2..a5588dc 100644
--- a/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
+++ b/base/src/com/google/idea/blaze/base/issueparser/IssueOutputLineProcessor.java
@@ -49,6 +49,7 @@
new BlazeIssueParser.CompileParser(workspaceRoot),
new BlazeIssueParser.TracebackParser(),
new BlazeIssueParser.BuildParser(),
+ new BlazeIssueParser.SkylarkErrorParser(),
new BlazeIssueParser.LinelessBuildParser(),
new BlazeIssueParser.ProjectViewLabelParser(projectViewSet),
new BlazeIssueParser.InvalidTargetProjectViewPackageParser(
diff --git a/base/src/com/google/idea/blaze/base/lang/AdditionalLanguagesHelper.java b/base/src/com/google/idea/blaze/base/lang/AdditionalLanguagesHelper.java
index 384e35b..a55996c 100644
--- a/base/src/com/google/idea/blaze/base/lang/AdditionalLanguagesHelper.java
+++ b/base/src/com/google/idea/blaze/base/lang/AdditionalLanguagesHelper.java
@@ -15,6 +15,7 @@
*/
package com.google.idea.blaze.base.lang;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.LanguageClass;
@@ -35,6 +36,7 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.EditorNotificationPanel;
import com.intellij.ui.EditorNotifications;
+import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
@@ -111,12 +113,15 @@
panel.setText(message);
panel.createActionLabel(
String.format("Enable %s support", langName),
- () -> enableLanguageSupport(project, language));
+ () -> {
+ enableLanguageSupport(project, ImmutableList.of(language));
+ suppressNotifications(language);
+ });
panel.createActionLabel("Don't show again", () -> suppressNotifications(language));
return panel;
}
- private void enableLanguageSupport(Project project, LanguageClass language) {
+ public static void enableLanguageSupport(Project project, List<LanguageClass> languages) {
ProjectViewEdit edit =
ProjectViewEdit.editLocalProjectView(
project,
@@ -126,7 +131,7 @@
builder.replace(
existingSection,
ListSection.update(AdditionalLanguagesSection.KEY, existingSection)
- .add(language));
+ .addAll(languages));
return true;
});
if (edit == null) {
@@ -137,8 +142,6 @@
}
edit.apply();
- suppressNotifications(language);
-
BlazeSyncManager.getInstance(project)
.requestProjectSync(
new BlazeSyncParams.Builder("Sync", BlazeSyncParams.SyncMode.INCREMENTAL)
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
index cc05ea4..cd01e0d 100644
--- 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
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.lang.buildfile.completion;
import com.google.idea.blaze.base.lang.buildfile.references.QuoteType;
+import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
@@ -42,9 +43,15 @@
this.wrapWithQuotes = quoteWrapping != QuoteType.NoQuotes;
}
+ private static boolean insertClosingQuotes() {
+ return CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE;
+ }
+
@Override
public String getLookupString() {
- return quoteWrapping.wrap(baseName);
+ return insertClosingQuotes()
+ ? quoteWrapping.wrap(baseName)
+ : quoteWrapping.quoteString + baseName;
}
@Nullable
@@ -75,19 +82,17 @@
/**
* 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) {
+ if (!wrapWithQuotes || !insertClosingQuotes()) {
super.handleInsert(context);
return;
}
Document document = context.getDocument();
context.commitDocument();
PsiElement suffix = context.getFile().findElementAt(context.getTailOffset());
- if (suffix.getText().startsWith(quoteWrapping.quoteString)) {
+ if (suffix != null && suffix.getText().startsWith(quoteWrapping.quoteString)) {
int offset = suffix.getTextOffset();
document.deleteString(offset, offset + 1);
context.commitDocument();
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
index 1b16003..1d84632 100644
--- 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
@@ -96,7 +96,7 @@
@Nullable
private static String getEnclosingFuncallName(PsiElement element) {
- FuncallExpression funcall = PsiUtils.getParentOfType(element, FuncallExpression.class);
+ FuncallExpression funcall = PsiUtils.getParentOfType(element, FuncallExpression.class, true);
return funcall != null ? funcall.getFunctionName() : null;
}
}
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
index c5a32e5..b9e6172 100644
--- 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
@@ -32,10 +32,13 @@
private final Map<String, LookupElement> results = Maps.newHashMap();
private final PsiElement originalElement;
private final QuoteType quoteType;
+ private final boolean allowPrivateSymbols;
- public CompletionResultsProcessor(PsiElement originalElement, QuoteType quoteType) {
+ public CompletionResultsProcessor(
+ PsiElement originalElement, QuoteType quoteType, boolean allowPrivateSymbols) {
this.originalElement = originalElement;
this.quoteType = quoteType;
+ this.allowPrivateSymbols = allowPrivateSymbols;
}
@Override
@@ -49,9 +52,11 @@
results.put(string, new LoadedSymbolReferenceLookupElement(loadedSymbol, string, quoteType));
} else if (buildElement instanceof PsiNamedElement) {
PsiNamedElement namedElement = (PsiNamedElement) buildElement;
- results.put(
- namedElement.getName(),
- new NamedBuildLookupElement((PsiNamedElement) buildElement, quoteType));
+ String name = namedElement.getName();
+ if (!allowPrivateSymbols && name != null && name.startsWith("_")) {
+ return true;
+ }
+ results.put(name, new NamedBuildLookupElement((PsiNamedElement) buildElement, quoteType));
}
return true;
}
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
index 61d40e9..0a5a958 100644
--- 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
@@ -20,7 +20,7 @@
import javax.annotation.Nullable;
import javax.swing.Icon;
-/** Code completion support for package paths. */
+/** Code completion support for file paths within BUILD file labels. */
public class FilePathLookupElement extends BuildLookupElement {
private final String itemText;
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
deleted file mode 100644
index d888efb..0000000
--- a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilterPatterns.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.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
index dc7dc46..0b9af98 100644
--- 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
@@ -16,8 +16,6 @@
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;
@@ -45,9 +43,6 @@
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
@@ -56,7 +51,7 @@
continue;
}
String ruleType = target.getFunctionName();
- if (ruleType == null || (spec != null && !spec.hasRule(ruleType))) {
+ if (ruleType == null) {
continue;
}
lookups.add(
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
index 8c96eec..6f1b195 100644
--- 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
@@ -24,6 +24,7 @@
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.model.primitives.Label;
import com.google.idea.blaze.base.settings.Blaze;
import com.intellij.codeInsight.documentation.DocumentationManagerProtocol;
import com.intellij.lang.documentation.AbstractDocumentationProvider;
@@ -77,11 +78,8 @@
return;
}
BuildFile buildFile = (BuildFile) file;
- String name = buildFile.getBuildLabel();
- if (name == null) {
- // fall back to qualitative description
- name = buildFile.getPresentableText();
- }
+ Label label = buildFile.getBuildLabel();
+ String name = label != null ? label.toString() : buildFile.getPresentableText();
if (linkToFile) {
builder
.append("<a href=\"")
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
index 8f01178..c28b741 100644
--- 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
@@ -46,7 +46,7 @@
return Access.Write;
}
if (expression instanceof ReferenceExpression) {
- if (PsiUtils.getParentOfType(expression, AugmentedAssignmentStatement.class) != null) {
+ if (PsiUtils.getParentOfType(expression, AugmentedAssignmentStatement.class, true) != null) {
return Access.ReadWrite;
}
}
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
index 7ef9399..a538b35 100644
--- 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
@@ -56,35 +56,32 @@
}
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;
- }
+ (ref1, 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();
+ 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;
- }
-
+ 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). */
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
index 34af8b9..994107e 100644
--- 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
@@ -20,7 +20,7 @@
import com.intellij.lang.CodeDocumentationAwareCommenter;
import com.intellij.psi.PsiComment;
import com.intellij.psi.tree.IElementType;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Supports (un)commenting lines via IntelliJ */
public class BuildCommenter implements CodeDocumentationAwareCommenter {
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
index b2295af..2562a55 100644
--- 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
@@ -21,8 +21,8 @@
import com.intellij.lang.Language;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Allows BUILD language-specific code style settings */
public class BuildLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider {
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
index b7a44c4..ab7ede4 100644
--- 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
@@ -15,7 +15,6 @@
*/
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;
@@ -31,17 +30,14 @@
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.VirtualFile;
-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.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
@@ -49,6 +45,7 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
import javax.annotation.Nullable;
/**
@@ -63,35 +60,16 @@
public final class UnixGlob {
private UnixGlob() {}
- private static List<File> globInternal(
+ private static Set<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);
- }
+ return visitor.glob(base, patterns, excludeDirectories, dirPred);
}
/**
@@ -113,58 +91,13 @@
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);
+ try {
+ return matches(pattern, str, null);
+ } catch (PatternSyntaxException e) {
+ return false;
+ }
}
/**
@@ -176,7 +109,7 @@
* @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) {
+ private static boolean matches(String pattern, String str, Cache<String, Pattern> patternCache) {
if (pattern.length() == 0 || str.length() == 0) {
return false;
}
@@ -278,8 +211,8 @@
/** Builder class for UnixGlob. */
public static class Builder {
private File base;
- private List<String> patterns;
- private List<String> excludes;
+ private final List<String> patterns = new ArrayList<>();
+ private final List<String> excludes = new ArrayList<>();
private boolean excludeDirectories;
private Predicate<File> pathFilter;
private ThreadPoolExecutor threadPool;
@@ -287,8 +220,6 @@
/** 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;
}
@@ -374,37 +305,29 @@
* @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);
+ Set<File> included = globInternal(base, patterns, excludeDirectories, pathFilter, threadPool);
+ Set<File> excluded = globInternal(base, excludes, excludeDirectories, pathFilter, threadPool);
+ included.removeAll(excluded);
+ return Ordering.<File>natural().immutableSortedCopy(included);
}
}
/** Adapts the result of the glob visitation as a Future. */
- private static class GlobFuture extends ForwardingListenableFuture<List<File>> {
+ private static class GlobFuture extends ForwardingListenableFuture<Set<File>> {
private final GlobVisitor visitor;
- private final SettableFuture<List<File>> delegate = SettableFuture.create();
+ private final SettableFuture<Set<File>> delegate = SettableFuture.create();
- public GlobFuture(GlobVisitor visitor) {
+ private GlobFuture(GlobVisitor visitor) {
this.visitor = visitor;
}
@Override
- public List<File> get() throws InterruptedException, ExecutionException {
+ public Set<File> get() throws InterruptedException, ExecutionException {
return super.get();
}
@Override
- protected ListenableFuture<List<File>> delegate() {
+ protected ListenableFuture<Set<File>> delegate() {
return delegate;
}
@@ -412,7 +335,7 @@
delegate.setException(exception);
}
- public void set(List<File> paths) {
+ public void set(Set<File> paths) {
delegate.set(paths);
}
@@ -423,7 +346,7 @@
return true;
}
- public void markCanceled() {
+ void markCanceled() {
super.cancel(true);
}
}
@@ -434,7 +357,7 @@
*/
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 Set<File> results = Sets.newConcurrentHashSet();
private final Cache<String, Pattern> cache =
CacheBuilder.newBuilder()
.build(
@@ -452,40 +375,34 @@
private final FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
private volatile boolean canceled = false;
- public GlobVisitor(ThreadPoolExecutor executor) {
+ private GlobVisitor(ThreadPoolExecutor executor) {
this.executor = executor;
this.result = new GlobFuture(this);
}
- public GlobVisitor() {
+ private 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.
+ * patterns} relative to {@code base}. 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.
+ * @throws IllegalArgumentException if any glob or exclude pattern 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)
+ private Set<File> glob(
+ File base, Collection<String> patterns, boolean excludeDirectories, Predicate<File> dirPred)
throws IOException, InterruptedException {
try {
- return globAsync(base, patterns, excludePatterns, excludeDirectories, dirPred).get();
+ return globAsync(base, patterns, excludeDirectories, dirPred).get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
Throwables.propagateIfPossible(cause, IOException.class);
@@ -493,40 +410,24 @@
}
}
- public Future<List<File>> globAsync(
- File base,
- Collection<String> patterns,
- Collection<String> excludePatterns,
- boolean excludeDirectories,
- Predicate<File> dirPred)
+ private Future<Set<File>> globAsync(
+ File base, Collection<String> patterns, boolean excludeDirectories, Predicate<File> dirPred)
throws IOException {
if (!fileAttributeProvider.exists(base) || patterns.isEmpty()) {
- return Futures.immediateFuture(Collections.emptyList());
+ return Futures.immediateFuture(Collections.emptySet());
}
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) {
+ for (String[] splitPattern : checkAndSplitPatterns(patterns)) {
queueGlob(
- base,
- baseIsDirectory,
- splitPattern,
- 0,
- excludeDirectories,
- splitExcludes,
- 0,
- results,
- cache,
- dirPred);
+ base, baseIsDirectory, splitPattern, 0, excludeDirectories, results, cache, dirPred);
}
} finally {
decrementAndCheckDone();
@@ -541,8 +442,6 @@
String[] patternParts,
int idx,
boolean excludeDirectories,
- List<String[]> excludePatterns,
- int excludeIdx,
Collection<File> results,
Cache<String, Pattern> cache,
Predicate<File> dirPred)
@@ -556,8 +455,6 @@
patternParts,
idx,
excludeDirectories,
- excludePatterns,
- excludeIdx,
results,
cache,
dirPred);
@@ -567,7 +464,7 @@
});
}
- protected void enqueue(final Runnable r) {
+ void enqueue(final Runnable r) {
pendingOps.incrementAndGet();
Runnable wrapped =
@@ -602,7 +499,7 @@
} else if (failure.get() != null) {
result.setException(failure.get());
} else {
- result.set(Ordering.<File>natural().immutableSortedCopy(results));
+ result.set(results);
}
}
}
@@ -621,8 +518,6 @@
String[] patternParts,
int idx,
boolean excludeDirectories,
- List<String[]> excludePatterns,
- int excludeIdx,
Collection<File> results,
Cache<String, Pattern> cache,
Predicate<File> dirPred)
@@ -633,8 +528,7 @@
}
if (idx == patternParts.length) { // Base case.
- if (!(excludeDirectories && baseIsDirectory)
- && !excludedOnMatch(base, excludePatterns, excludeIdx, cache)) {
+ if (!(excludeDirectories && baseIsDirectory)) {
results.add(base);
}
return;
@@ -645,8 +539,6 @@
return;
}
- List<String[]> relevantExcludes =
- getRelevantExcludes(base, excludePatterns, excludeIdx, cache);
final String pattern = patternParts[idx];
// ** is special: it can match nothing at all.
@@ -658,8 +550,6 @@
patternParts,
idx + 1,
excludeDirectories,
- excludePatterns,
- excludeIdx,
results,
cache,
dirPred);
@@ -675,16 +565,7 @@
}
queueGlob(
- child,
- childIsDir,
- patternParts,
- idx + 1,
- excludeDirectories,
- relevantExcludes,
- excludeIdx + 1,
- results,
- cache,
- dirPred);
+ child, childIsDir, patternParts, idx + 1, excludeDirectories, results, cache, dirPred);
return;
}
@@ -699,16 +580,7 @@
// Recurse without shifting the pattern.
if (childIsDir) {
queueGlob(
- child,
- childIsDir,
- patternParts,
- idx,
- excludeDirectories,
- relevantExcludes,
- excludeIdx + 1,
- results,
- cache,
- dirPred);
+ child, childIsDir, patternParts, idx, excludeDirectories, results, cache, dirPred);
}
}
if (matches(pattern, child.getName(), cache)) {
@@ -720,15 +592,12 @@
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)) {
+ if (idx + 1 == patternParts.length) {
results.add(child);
}
}
@@ -738,16 +607,7 @@
@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);
+ return FileAttributeProvider.getInstance().listFiles(file);
}
}
}
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
index 4c4a21c..a73c0a4 100644
--- 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
@@ -15,8 +15,9 @@
*/
package com.google.idea.blaze.base.lang.buildfile.language;
+import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
-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;
@@ -26,9 +27,11 @@
@Override
public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
- consumer.consume(
- BuildFileType.INSTANCE,
- BuildSystemProvider.defaultBuildSystem().buildFileMatcher(),
- new ExtensionFileNameMatcher("bzl"));
+ ImmutableList<FileNameMatcher> fileNameMatchers =
+ ImmutableList.<FileNameMatcher>builder()
+ .addAll(BuildSystemProvider.defaultBuildSystem().buildLanguageFileTypeMatchers())
+ .add()
+ .build();
+ consumer.consume(BuildFileType.INSTANCE, fileNameMatchers.toArray(new FileNameMatcher[0]));
}
}
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
index 67ff005..ecf79f8 100644
--- 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
@@ -107,13 +107,15 @@
}
}
+ /** Variable number of positional arguments: *args */
static class Star extends Argument {
public Star(ASTNode node) {
super(node);
}
}
- static class StarStar extends Argument {
+ /** Variable number of keyword arguments: **kwargs */
+ public static class StarStar extends Argument {
public StarStar(ASTNode node) {
super(node);
}
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
index fc0d2e1..b1e34eb 100644
--- 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
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.lang.buildfile.psi;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
import com.intellij.util.PlatformIcons;
import javax.annotation.Nullable;
import javax.swing.Icon;
@@ -36,7 +37,8 @@
/** Returns the RHS of the assignment */
@Nullable
public Expression getAssignedValue() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ PsiElement psi = childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ return psi instanceof Expression ? (Expression) psi : null;
}
@Override
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
index 5d2384d..c3a3eb0 100644
--- 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
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.lang.buildfile.psi;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
import javax.annotation.Nullable;
/** PSI element for an augmented assignment statement [expr += expr] */
@@ -28,13 +29,15 @@
/** Returns the LHS of the assignment */
@Nullable
public TargetExpression getLeftHandSideExpression() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ PsiElement psi = childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ return psi instanceof TargetExpression ? (TargetExpression) psi : null;
}
/** Returns the RHS of the assignment */
@Nullable
public Expression getAssignedValue() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ PsiElement psi = childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ return psi instanceof Expression ? (Expression) psi : null;
}
@Override
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
index 76a4387..3dab6d8 100644
--- 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
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.lang.buildfile.psi;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
import javax.annotation.Nullable;
/** PSI element for an binary operation expression [expr BIN_OP expr] */
@@ -33,12 +34,14 @@
/** Returns the LHS of the expression */
@Nullable
public Expression getLhs() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ PsiElement psi = childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ return psi instanceof Expression ? (Expression) psi : null;
}
/** Returns the RHS of the expression */
@Nullable
public Expression getRhs() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ PsiElement psi = childToPsi(BuildElementTypes.EXPRESSIONS, 1);
+ return psi instanceof Expression ? (Expression) psi : null;
}
}
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
index 35a67c5..7cfd64b 100644
--- 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
@@ -16,7 +16,6 @@
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;
@@ -41,8 +40,6 @@
@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
index 55f472d..700f4dc 100644
--- 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
@@ -16,7 +16,6 @@
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;
@@ -82,13 +81,14 @@
return psiElements;
}
+ /** Finds the n'th child of the specified type */
@Nullable
- protected <T extends BuildElement> T childToPsi(TokenSet filterSet, int index) {
+ protected PsiElement childToPsi(TokenSet filterSet, int index) {
final ASTNode[] nodes = getNode().getChildren(filterSet);
if (nodes.length <= index) {
return null;
}
- return (T) nodes[index].getPsi();
+ return nodes[index].getPsi();
}
@Nullable
@@ -159,13 +159,6 @@
@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;
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
index b9cc459..75c6417 100644
--- 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
@@ -15,26 +15,22 @@
*/
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.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.sync.workspace.WorkspaceHelper;
import com.intellij.extapi.psi.PsiFileBase;
-import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
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;
@@ -44,24 +40,17 @@
/** 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);
+ BuildPackage, // "BUILD", "BUILD.bazel"
+ Workspace, // the top-level WORKSPACE file
}
public static String getBuildFileString(Project project, String filePath) {
- WorkspacePath workspacePath = getWorkspacePath(project, PathUtil.getParentPath(filePath));
- if (workspacePath == null) {
+ Label label = WorkspaceHelper.getBuildLabel(project, new File(filePath));
+ if (label == null) {
return "BUILD file: " + filePath;
}
- String fileName = PathUtil.getFileName(filePath);
- if (fileName.startsWith("BUILD")) {
- return "//" + workspacePath + "/" + fileName;
- }
- return "//" + workspacePath + ":" + fileName;
+ String labelString = label.toString();
+ return labelString.replace(":__pkg__", "/" + PathUtil.getFileName(filePath));
}
public BuildFile(FileViewProvider viewProvider) {
@@ -78,6 +67,9 @@
if (fileName.startsWith("BUILD")) {
return BlazeFileType.BuildPackage;
}
+ if (fileName.equals("WORKSPACE")) {
+ return BlazeFileType.Workspace;
+ }
return BlazeFileType.SkylarkExtension;
}
@@ -117,37 +109,19 @@
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)
+ * The label 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() {
+ public Label getPackageLabel() {
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;
+ return parentPackage != null ? parentPackage.getPackageLabel() : null;
}
/** The path for this file, formatted as a BUILD label. */
@Nullable
- public String getBuildLabel() {
+ public Label getBuildLabel() {
BlazePackage containingPackage = getBlazePackage();
return containingPackage != null
? containingPackage.getBuildLabelForChild(getFilePath())
@@ -166,24 +140,6 @@
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()) {
@@ -195,11 +151,6 @@
}
@Nullable
- public TargetExpression findTopLevelVariable(String name) {
- return ResolveUtil.searchChildAssignmentStatements(this, name);
- }
-
- @Nullable
public FunctionStatement findLoadedFunction(String name) {
for (LoadStatement loadStatement : findChildrenByClass(LoadStatement.class)) {
for (LoadedSymbol loadedSymbol : loadStatement.getImportedSymbolElements()) {
@@ -293,6 +244,28 @@
}
@Override
+ public ItemPresentation getPresentation() {
+ final BuildFile element = this;
+ return new ItemPresentation() {
+ @Override
+ public String getPresentableText() {
+ return element.getName();
+ }
+
+ @Override
+ public String getLocationString() {
+ String label = getBuildFileString(element.getProject(), element.getFilePath());
+ return String.format("(%s)", label);
+ }
+
+ @Override
+ public Icon getIcon(boolean unused) {
+ return element.getIcon(0);
+ }
+ };
+ }
+
+ @Override
public String toString() {
return getBuildFileString(getProject(), getFilePath());
}
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
index e59d9a7..46701da 100644
--- 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
@@ -15,8 +15,7 @@
*/
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.BuildFile.BlazeFileType;
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;
@@ -106,8 +105,10 @@
@Nullable
public Label resolveBuildLabel() {
BuildFile containingFile = getContainingFile();
- if (containingFile == null
- || containingFile.getBlazeFileType() == BuildFile.BlazeFileType.SkylarkExtension) {
+ if (containingFile == null) {
+ return null;
+ }
+ if (containingFile.getBlazeFileType() != BlazeFileType.BuildPackage) {
return null;
}
return LabelUtils.createLabelFromRuleName(getBlazePackage(), getNameArgumentValue());
@@ -175,11 +176,6 @@
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);
}
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
index 0dce2fe..3865d64 100644
--- 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
@@ -19,8 +19,8 @@
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.util.PlatformIcons;
+import javax.annotation.Nullable;
import javax.swing.Icon;
-import org.jetbrains.annotations.Nullable;
/** PSI element for a function definition statement. */
public class FunctionStatement extends NamedBuildElement
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
index c873bb6..37298d2 100644
--- 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
@@ -19,8 +19,8 @@
import com.google.idea.blaze.base.lang.buildfile.lexer.TokenKind;
import com.intellij.icons.AllIcons;
import com.intellij.lang.ASTNode;
+import javax.annotation.Nullable;
import javax.swing.Icon;
-import org.jetbrains.annotations.Nullable;
/** PSI nodes for parameters in a function declaration */
public abstract class Parameter extends NamedBuildElement {
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
index 287402c..755231e 100644
--- 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
@@ -20,7 +20,7 @@
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiReference;
import com.intellij.psi.tree.IElementType;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** References a PsiNamedElement */
public class ReferenceExpression extends BuildElementImpl implements Expression {
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
index a334c00..63926ee 100644
--- 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
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.lang.buildfile.psi;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
import javax.annotation.Nullable;
/** A wrapper Statement class for return expressions. */
@@ -27,7 +28,8 @@
@Nullable
public Expression getReturnExpression() {
- return childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ PsiElement psi = childToPsi(BuildElementTypes.EXPRESSIONS, 0);
+ return psi instanceof Expression ? (Expression) psi : null;
}
@Override
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
index 027107e..933bd47 100644
--- 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
@@ -18,6 +18,7 @@
import com.google.idea.blaze.base.lang.buildfile.psi.Argument.Keyword;
import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
import com.google.idea.blaze.base.lang.buildfile.references.AttributeSpecificStringLiteralReferenceProvider;
+import com.google.idea.blaze.base.lang.buildfile.references.ExternalWorkspaceReferenceFragment;
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;
@@ -128,8 +129,11 @@
}
PsiReference primaryReference = getReference();
if (primaryReference instanceof LabelReference) {
+ LabelReference labelReference = (LabelReference) primaryReference;
return new PsiReference[] {
- primaryReference, new PackageReferenceFragment((LabelReference) primaryReference)
+ primaryReference,
+ new PackageReferenceFragment(labelReference),
+ new ExternalWorkspaceReferenceFragment(labelReference)
};
}
return primaryReference != null
@@ -159,7 +163,7 @@
/** If this string is an attribute value within a BUILD rule, return the attribute type. */
@Nullable
private String getParentAttributeName() {
- Keyword parentKeyword = PsiUtils.getParentOfType(this, Keyword.class);
+ Keyword parentKeyword = PsiUtils.getParentOfType(this, Keyword.class, true);
return parentKeyword != null ? parentKeyword.getName() : null;
}
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
index 405d0de..96a87ec 100644
--- 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
@@ -19,8 +19,8 @@
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiReference;
import com.intellij.util.PlatformIcons;
+import javax.annotation.Nullable;
import javax.swing.Icon;
-import org.jetbrains.annotations.Nullable;
/** References a PsiNamedElement */
public class TargetExpression extends NamedBuildElement implements Expression {
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
index 30d8c5e..213586b 100644
--- 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
@@ -67,13 +67,14 @@
* 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;
+ public static <T extends PsiElement> T getParentOfType(
+ PsiElement element, Class<T> psiClass, boolean strict) {
+ element = strict ? element.getParent() : element;
+ while (element != null && !(element instanceof PsiDirectory)) {
+ if (psiClass.isInstance(element)) {
+ return psiClass.cast(element);
}
- parent = parent.getParent();
+ element = element.getParent();
}
return null;
}
@@ -159,7 +160,7 @@
* Unwraps ParenthesizedExpression.<br>
* For other types, returns the input expression.
*/
- public static PsiElement getReferencedTarget(Expression expr) {
+ private static PsiElement getReferencedTarget(Expression expr) {
PsiElement element = expr;
while (true) {
PsiElement unwrapped = unwrap(element);
@@ -170,6 +171,7 @@
}
}
+ @Nullable
private static PsiElement unwrap(PsiElement expr) {
if (expr instanceof ParenthesizedExpression) {
return ((ParenthesizedExpression) expr).getContainedExpression();
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/quickfix/DeprecatedLoadQuickFix.java b/base/src/com/google/idea/blaze/base/lang/buildfile/quickfix/DeprecatedLoadQuickFix.java
new file mode 100644
index 0000000..2fdb3a3
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/quickfix/DeprecatedLoadQuickFix.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.base.lang.buildfile.quickfix;
+
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+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.references.LabelUtils;
+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.intellij.codeInsight.intention.HighPriorityAction;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.history.core.Paths;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Offer to convert deprecated statements to label format. */
+public class DeprecatedLoadQuickFix implements LocalQuickFix, HighPriorityAction {
+
+ public static final DeprecatedLoadQuickFix INSTANCE = new DeprecatedLoadQuickFix();
+
+ @Override
+ public String getFamilyName() {
+ return "Fix load statement format";
+ }
+
+ @Override
+ public String getName() {
+ return getFamilyName();
+ }
+
+ @Override
+ public void applyFix(Project project, ProblemDescriptor descriptor) {
+ PsiElement element = descriptor.getPsiElement();
+ if (element instanceof StringLiteral) {
+ fixLoadString(project, (StringLiteral) element);
+ }
+ }
+
+ private static void fixLoadString(Project project, StringLiteral importString) {
+ String contents = importString.getStringContents();
+ if (!contents.startsWith("/") || LabelUtils.isAbsolute(contents)) {
+ return;
+ }
+ WorkspaceRoot root = WorkspaceRoot.fromProjectSafe(project);
+ if (root == null) {
+ return;
+ }
+ WorkspacePath workspacePath = WorkspacePath.createIfValid(contents.substring(1));
+ if (workspacePath == null) {
+ return;
+ }
+ File file = root.fileForPath(workspacePath);
+ File parentPackageFile = findContainingPackage(project, file);
+ if (parentPackageFile == null) {
+ return;
+ }
+ WorkspacePath packagePath = root.workspacePathForSafe(parentPackageFile);
+ if (packagePath == null) {
+ return;
+ }
+ String relativePath =
+ Paths.relativeIfUnder(workspacePath.relativePath(), packagePath.relativePath());
+ if (relativePath == null) {
+ return;
+ }
+ String newString = "//" + packagePath + ":" + relativePath + ".bzl";
+
+ ASTNode node = importString.getNode();
+ node.replaceChild(
+ node.getFirstChildNode(), PsiUtils.createNewLabel(importString.getProject(), newString));
+ }
+
+ @Nullable
+ private static File findContainingPackage(Project project, File file) {
+ BuildSystemProvider provider = Blaze.getBuildSystemProvider(project);
+ file = file.getParentFile();
+ while (file != null) {
+ File buildFile = provider.findBuildFileInDirectory(file);
+ if (buildFile != null) {
+ return file;
+ }
+ file = file.getParentFile();
+ }
+ return null;
+ }
+}
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
index f85425d..ded303f 100644
--- 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
@@ -15,18 +15,24 @@
*/
package com.google.idea.blaze.base.lang.buildfile.refactor;
+import com.google.common.collect.ImmutableSet;
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;
+import java.util.stream.Collectors;
-/** Used for rename validation */
+/** Used for rename validation of elements which aren't string literals. */
public class BuildNamesValidator implements NamesValidator {
+ private static final ImmutableSet<String> KEYWORDS =
+ ImmutableSet.copyOf(
+ TokenKind.KEYWORDS.stream().map(TokenKind::toString).collect(Collectors.toSet()));
+
@Override
public boolean isKeyword(String s, Project project) {
- return false;
+ return KEYWORDS.contains(s);
}
@Override
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/TargetRenameValidator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/TargetRenameValidator.java
new file mode 100644
index 0000000..a46ccad
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/refactor/TargetRenameValidator.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 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.model.primitives.TargetName;
+import com.intellij.patterns.ElementPattern;
+import com.intellij.patterns.PlatformPatterns;
+import com.intellij.psi.PsiElement;
+import com.intellij.refactoring.rename.RenameInputValidator;
+import com.intellij.util.ProcessingContext;
+
+/** Overrides name validation for target names. */
+public class TargetRenameValidator implements RenameInputValidator {
+
+ @Override
+ public ElementPattern<? extends PsiElement> getPattern() {
+ // FuncallExpression is the owner of the target name.
+ return PlatformPatterns.psiElement(FuncallExpression.class);
+ }
+
+ @Override
+ public boolean isInputValid(String newName, PsiElement element, ProcessingContext context) {
+ return TargetName.validate(newName);
+ }
+}
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
index 9b72b1d..4738bdd 100644
--- 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
@@ -25,6 +25,7 @@
import com.google.idea.blaze.base.model.primitives.TargetName;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.workspace.WorkspaceHelper;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider;
import com.intellij.openapi.components.ServiceManager;
@@ -58,19 +59,19 @@
/** Finds the PSI element associated with the given label. */
@Nullable
public PsiElement resolveLabel(Label label) {
- return resolveLabel(label.blazePackage(), label.targetName(), false);
+ return resolveLabel(label, false);
}
/** Finds the PSI element associated with the given label. */
@Nullable
- public PsiElement resolveLabel(
- WorkspacePath packagePath, TargetName targetName, boolean excludeRules) {
- File packageDir = resolvePackage(packagePath);
+ public PsiElement resolveLabel(Label label, boolean excludeRules) {
+ File packageDir = WorkspaceHelper.resolveBlazePackage(project, label);
if (packageDir == null) {
return null;
}
- if (targetName.toString().equals("__pkg__")) {
+ String targetName = label.targetName().toString();
+ if (targetName.equals("__pkg__")) {
return findBuildFile(packageDir);
}
@@ -82,7 +83,7 @@
}
// try a direct file reference (e.g. ":a.java")
- File fullFile = new File(packageDir, targetName.toString());
+ File fullFile = new File(packageDir, targetName);
if (FileAttributeProvider.getInstance().exists(fullFile)) {
return resolveFile(fullFile);
}
@@ -90,9 +91,9 @@
return null;
}
- private FuncallExpression findRule(File packageDir, TargetName targetName) {
+ private FuncallExpression findRule(File packageDir, String targetName) {
BuildFile psiFile = findBuildFile(packageDir);
- return psiFile != null ? psiFile.findRule(targetName.toString()) : null;
+ return psiFile != null ? psiFile.findRule(targetName) : null;
}
@Nullable
@@ -190,7 +191,8 @@
}
private BuildLookupElement lookupForFile(VirtualFile file, FileLookupData lookupData) {
- WorkspacePath workspacePath = getWorkspaceRelativePath(file.getPath());
+ WorkspacePath workspacePath =
+ WorkspaceHelper.resolveWorkspacePath(project, new File(file.getPath()));
return lookupData.lookupElementForFile(project, file, workspacePath);
}
@@ -244,10 +246,4 @@
String rulePathParent = PathUtil.getParentPath(targetName.toString());
return new File(packageFile, rulePathParent);
}
-
- @Nullable
- public WorkspacePath getWorkspaceRelativePath(String absolutePath) {
- WorkspacePathResolver pathResolver = getWorkspacePathResolver();
- return pathResolver != null ? pathResolver.getWorkspacePath(new File(absolutePath)) : null;
- }
}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.java
new file mode 100644
index 0000000..521f432
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceFragment.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.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.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.lang.ASTNode;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFileSystemItem;
+import com.intellij.psi.PsiReferenceBase;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.ObjectUtils;
+import javax.annotation.Nullable;
+
+/** The external workspace component of a label (between '@' and '//') */
+public class ExternalWorkspaceReferenceFragment extends PsiReferenceBase<StringLiteral> {
+
+ public ExternalWorkspaceReferenceFragment(LabelReference labelReference) {
+ super(labelReference.getElement(), labelReference.getRangeInElement(), labelReference.isSoft());
+ }
+
+ @Override
+ public TextRange getRangeInElement() {
+ String rawText = myElement.getText();
+ boolean valid = LabelUtils.getExternalWorkspaceComponent(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 FuncallExpression resolve() {
+ String name = LabelUtils.getExternalWorkspaceComponent(myElement.getStringContents());
+ if (name == null) {
+ return null;
+ }
+ BuildFile workspaceFile = resolveProjectWorkspaceFile(myElement.getProject());
+ return workspaceFile != null ? workspaceFile.findRule(name) : null;
+ }
+
+ @Nullable
+ private static BuildFile resolveProjectWorkspaceFile(Project project) {
+ WorkspaceRoot projectRoot = WorkspaceRoot.fromProject(project);
+ if (projectRoot == null) {
+ return null;
+ }
+ PsiFileSystemItem workspaceFile =
+ BuildReferenceManager.getInstance(project)
+ .resolveFile(projectRoot.fileForPath(new WorkspacePath("WORKSPACE")));
+ return ObjectUtils.tryCast(workspaceFile, BuildFile.class);
+ }
+
+ @Override
+ public Object[] getVariants() {
+ return EMPTY_ARRAY;
+ }
+
+ @Override
+ public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
+ String oldString = myElement.getStringContents();
+ int slashesIndex = oldString.indexOf("//");
+ String newString =
+ String.format(
+ "@%s%s", newElementName, slashesIndex == -1 ? "" : oldString.substring(slashesIndex));
+ return handleRename(newString);
+ }
+
+ @Override
+ public PsiElement bindToElement(PsiElement element) throws IncorrectOperationException {
+ return myElement;
+ }
+
+ 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/FileLookupData.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java
index eabe428..36ae50c 100644
--- 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
@@ -19,6 +19,7 @@
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.Label;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.settings.Blaze;
import com.intellij.icons.AllIcons;
@@ -32,8 +33,8 @@
import com.intellij.util.PathUtil;
import com.intellij.util.PlatformIcons;
import icons.BlazeIcons;
+import javax.annotation.Nullable;
import javax.swing.Icon;
-import org.jetbrains.annotations.Nullable;
/** The data relevant to finding file lookups. */
public class FileLookupData {
@@ -89,11 +90,14 @@
StringLiteral element,
@Nullable BuildFile basePackage,
@Nullable VirtualFileFilter fileFilter) {
- String basePackagePath =
- basePackage != null ? basePackage.getWorkspaceRelativePackagePath() : null;
- if (basePackagePath == null) {
+ if (basePackage == null) {
return null;
}
+ Label packageLabel = basePackage.getPackageLabel();
+ if (packageLabel == null) {
+ return null;
+ }
+ String basePackagePath = packageLabel.blazePackage().relativePath();
String filePath = basePackagePath + "/" + LabelUtils.getRuleComponent(originalLabel);
return new FileLookupData(
originalLabel,
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
index 526e2ec..b3d69dd 100644
--- 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
@@ -31,7 +31,7 @@
public class FuncallReference extends PsiReferenceBase<FuncallExpression> {
public FuncallReference(FuncallExpression element, TextRange rangeInElement) {
- super(element, rangeInElement, /*soft*/ true);
+ super(element, rangeInElement, /* soft */ true);
}
@Nullable
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
index c3ddb46..1f349c1 100644
--- 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
@@ -17,7 +17,7 @@
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.bazel.BuildSystemProvider;
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;
@@ -25,7 +25,9 @@
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.google.idea.blaze.base.settings.Blaze;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
@@ -109,19 +111,19 @@
if (includes.isEmpty()) {
return ResolveResult.EMPTY_ARRAY;
}
-
+ Project project = element.getProject();
try {
List<File> files =
UnixGlob.forPath(containingDirectory)
.addPatterns(includes)
.addExcludes(excludes)
.setExcludeDirectories(directoriesExcluded)
- .setDirectoryFilter(directoryFilter(containingDirectory.getPath()))
+ .setDirectoryFilter(directoryFilter(project, containingDirectory.getPath()))
.glob();
+
List<ResolveResult> results = Lists.newArrayListWithCapacity(files.size());
for (File file : files) {
- PsiFileSystemItem psiFile =
- BuildReferenceManager.getInstance(element.getProject()).resolveFile(file);
+ PsiFileSystemItem psiFile = BuildReferenceManager.getInstance(project).resolveFile(file);
if (psiFile != null) {
results.add(new PsiElementResolveResult(psiFile));
}
@@ -133,14 +135,14 @@
}
}
- private static Predicate<File> directoryFilter(String base) {
+ /** Don't traverse sub-directories which are themselves blaze packages */
+ private static Predicate<File> directoryFilter(Project project, String base) {
+ BuildSystemProvider provider = Blaze.getBuildSystemProvider(project);
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);
+ return provider.findBuildFileInDirectory(file) == null;
};
}
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
index f1e6542..a3457bb 100644
--- 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
@@ -35,8 +35,7 @@
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;
+import javax.annotation.Nullable;
/** Converts a blaze label into an absolute path, then resolves that path to a PsiElements */
public class LabelReference extends PsiReferenceBase<StringLiteral> {
@@ -51,7 +50,7 @@
/* Possibilities:
* - target
* - data file (.java, .txt, etc.)
- * - glob contents (not yet handling globs)
+ * - glob contents
*/
return resolveTarget(myElement.getStringContents());
}
@@ -65,8 +64,8 @@
if (!validLabelLocation(myElement)) {
return null;
}
- if (!labelString.startsWith("//") && insideSkylarkExtension(myElement)) {
- return getReferenceManager().resolveLabel(label.blazePackage(), label.targetName(), true);
+ if (!LabelUtils.isAbsolute(labelString) && insideSkylarkExtension(myElement)) {
+ return getReferenceManager().resolveLabel(label, true);
}
return getReferenceManager().resolveLabel(label);
}
@@ -86,7 +85,6 @@
return true;
}
- @NotNull
@Override
public Object[] getVariants() {
if (!validLabelLocation(myElement)) {
@@ -110,7 +108,8 @@
}
String self = null;
if (referencedBuildFile == myElement.getContainingFile()) {
- FuncallExpression funcall = PsiUtils.getParentOfType(myElement, FuncallExpression.class);
+ FuncallExpression funcall =
+ PsiUtils.getParentOfType(myElement, FuncallExpression.class, true);
if (funcall != null) {
self = funcall.getName();
}
@@ -242,8 +241,7 @@
return null;
}
BlazePackage blazePackage = myElement.getBlazePackage();
- return LabelUtils.createLabelFromString(
- blazePackage != null ? blazePackage.buildFile : null, labelString);
+ return LabelUtils.createLabelFromString(blazePackage, labelString);
}
private static boolean skylarkExtensionReference(StringLiteral element) {
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
index db58991..cf3e8df 100644
--- 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
@@ -54,8 +54,8 @@
if (blazePackage == null || ruleName == null) {
return null;
}
- WorkspacePath packagePath = blazePackage.buildFile.getPackageWorkspacePath();
- return createLabelFromRuleName(packagePath, ruleName);
+ Label packageLabel = blazePackage.buildFile.getPackageLabel();
+ return packageLabel != null ? packageLabel.withTargetName(ruleName) : null;
}
public static Label createLabelFromRuleName(
@@ -67,36 +67,35 @@
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);
+ return Label.create(packagePath, name);
}
/**
- * Canonicalizes the label (to the form //packagePath:packageRelativeTarget). Returns null if the
- * string does not represent a valid label.
+ * Canonicalizes the label (to the form [@external_workspace]//packagePath:packageRelativeTarget).
+ * Returns null if the string does not represent a valid label.
*/
@Nullable
public static Label createLabelFromString(
- @Nullable BuildFile file, @Nullable String labelString) {
+ @Nullable BlazePackage blazePackage, @Nullable String labelString) {
if (labelString == null) {
return null;
}
int colonIndex = labelString.indexOf(':');
- if (labelString.startsWith("//")) {
+ if (isAbsolute(labelString)) {
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) {
+ // package-relative label of the form '[:]relativePath'
+ if (colonIndex > 0 || blazePackage == null) {
return null;
}
- String localPath = colonIndex == -1 ? labelString : labelString.substring(1);
- return Label.createIfValid("//" + packagePath.relativePath() + ":" + localPath);
+ Label packageLabel = blazePackage.getPackageLabel();
+ return packageLabel != null
+ ? packageLabel.withTargetName(labelString.substring(colonIndex + 1))
+ : null;
}
/** The blaze file referenced by the label. */
@@ -121,12 +120,33 @@
return labelString.startsWith(":") ? labelString.substring(1) : labelString;
}
+ /** For a label of the form '[@ext]//package/path:target/name', returns '//package/path' */
public static String getPackagePathComponent(String labelString) {
- if (!labelString.startsWith("//")) {
+ if (!isAbsolute(labelString)) {
+ return "";
+ }
+ int slashesIndex = labelString.indexOf("//");
+ if (slashesIndex == -1) {
return "";
}
int colonIndex = labelString.indexOf(':');
- return colonIndex == -1 ? labelString : labelString.substring(0, colonIndex);
+ return colonIndex == -1
+ ? labelString.substring(slashesIndex)
+ : labelString.substring(slashesIndex, colonIndex);
+ }
+
+ @Nullable
+ public static String getExternalWorkspaceComponent(String labelString) {
+ if (!labelString.startsWith("@")) {
+ return null;
+ }
+ int slashesIndex = labelString.indexOf("//");
+ return slashesIndex == -1 ? null : labelString.substring(1, slashesIndex);
+ }
+
+ /** Returns false for package-relative labels */
+ public static boolean isAbsolute(String labelString) {
+ return labelString.startsWith("//") || labelString.startsWith("@");
}
/** 'load' reference. Of the form [path][/ or :][extra_path/]file_name.bzl */
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
index 219d843..44fa77f 100644
--- 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
@@ -33,7 +33,7 @@
private final LabelReference bzlFileReference;
public LoadedSymbolReference(StringLiteral element, LabelReference bzlFileReference) {
- super(element, new TextRange(0, element.getTextLength()), /*soft*/ false);
+ super(element, new TextRange(0, element.getTextLength()), /* soft */ false);
this.bzlFileReference = bzlFileReference;
}
@@ -54,7 +54,7 @@
return EMPTY_ARRAY;
}
CompletionResultsProcessor processor =
- new CompletionResultsProcessor(myElement, myElement.getQuoteType());
+ new CompletionResultsProcessor(myElement, myElement.getQuoteType(), false);
((BuildFile) bzlFile).searchSymbolsInScope(processor, null);
return processor.getResults().toArray();
}
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
index 85808b1..08b3237 100644
--- 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
@@ -33,7 +33,7 @@
public class LocalReference extends PsiReferenceBase<ReferenceExpression> {
public LocalReference(ReferenceExpression element) {
- super(element, new TextRange(0, element.getTextLength()), /*soft*/ false);
+ super(element, new TextRange(0, element.getTextLength()), /* soft */ false);
}
@Nullable
@@ -49,7 +49,7 @@
@Override
public Object[] getVariants() {
CompletionResultsProcessor processor =
- new CompletionResultsProcessor(myElement, QuoteType.NoQuotes);
+ new CompletionResultsProcessor(myElement, QuoteType.NoQuotes, true);
ResolveUtil.searchInScope(myElement, processor);
return processor.getResults().toArray();
}
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
index 6dba496..746d4e5 100644
--- 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
@@ -18,6 +18,7 @@
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.Label;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
@@ -27,7 +28,7 @@
import com.intellij.util.PathUtil;
import javax.annotation.Nullable;
-/** The label component preceeding the colon. */
+/** The label component preceding the colon. */
public class PackageReferenceFragment extends PsiReferenceBase<StringLiteral> {
public PackageReferenceFragment(LabelReference labelReference) {
@@ -84,10 +85,11 @@
if (element.equals(resolve())) {
return myElement;
}
- WorkspacePath newPath = ((BuildFile) element).getPackageWorkspacePath();
- if (newPath == null) {
+ Label newPackageLabel = ((BuildFile) element).getPackageLabel();
+ if (newPackageLabel == null) {
return myElement;
}
+ String newPath = newPackageLabel.blazePackage().toString();
String labelString = myElement.getStringContents();
int colonIndex = labelString.indexOf(':');
if (colonIndex != -1) {
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
index 52ee6da..68ba606 100644
--- 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
@@ -34,7 +34,7 @@
public class TargetReference extends PsiReferenceBase<TargetExpression> {
public TargetReference(TargetExpression element) {
- super(element, new TextRange(0, element.getTextLength()), /*soft*/ true);
+ super(element, new TextRange(0, element.getTextLength()), /* soft */ true);
}
@Nullable
@@ -51,7 +51,7 @@
@Override
public Object[] getVariants() {
CompletionResultsProcessor processor =
- new CompletionResultsProcessor(myElement, QuoteType.NoQuotes);
+ new CompletionResultsProcessor(myElement, QuoteType.NoQuotes, true);
ResolveUtil.searchInScope(myElement, processor);
return processor.getResults().toArray();
}
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
index 6f1b102..94f2f48 100644
--- 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
@@ -15,10 +15,13 @@
*/
package com.google.idea.blaze.base.lang.buildfile.search;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
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.model.primitives.Label;
import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.workspace.WorkspaceHelper;
import com.intellij.history.core.Paths;
+import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PackagePrefixFileSystemItem;
import com.intellij.psi.PsiDirectory;
@@ -30,7 +33,10 @@
import java.util.Objects;
import javax.annotation.Nullable;
-/** Defines the files accessible by a given blaze package. */
+/**
+ * A Blaze package is a directory containing a BUILD file, plus all subdirectories which aren't
+ * themselves Blaze packages.
+ */
public class BlazePackage {
@Nullable
@@ -96,6 +102,11 @@
return new BlazePackageSearchScope(this, onlyBlazeFiles);
}
+ @Nullable
+ public Label getPackageLabel() {
+ return WorkspaceHelper.getBuildLabel(buildFile.getProject(), buildFile.getFile());
+ }
+
/**
* Returns the file path relative to this blaze package, or null if it does lie inside this
* package
@@ -108,19 +119,13 @@
/** 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) {
+ public Label getBuildLabelForChild(String filePath) {
+ Label parentPackage = getPackageLabel();
+ if (parentPackage == null) {
return null;
}
String relativePath = getPackageRelativePath(filePath);
- if (relativePath == null) {
- return null;
- }
- if (relativePath.isEmpty()) {
- return "//" + packagePath;
- }
- return "//" + packagePath + ":" + relativePath;
+ return parentPackage.withTargetName(relativePath);
}
/**
@@ -190,6 +195,29 @@
public String toString() {
return String.format(
"%s package: %s",
- Blaze.buildSystemName(buildFile.getProject()), buildFile.getPackageWorkspacePath());
+ Blaze.buildSystemName(buildFile.getProject()), buildFile.getPackageLabel());
+ }
+
+ public static boolean hasBlazePackageChild(PsiDirectory directory) {
+ ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(directory.getProject());
+ BuildSystemProvider buildSystemProvider = Blaze.getBuildSystemProvider(directory.getProject());
+ return hasBlazePackageChild(index, buildSystemProvider, directory);
+ }
+
+ private static boolean hasBlazePackageChild(
+ ProjectFileIndex index, BuildSystemProvider buildSystemProvider, PsiDirectory directory) {
+ if (!index.isInSourceContent(directory.getVirtualFile())) {
+ // only search project files
+ return false;
+ }
+ if (buildSystemProvider.findBuildFileInDirectory(directory.getVirtualFile()) != null) {
+ return true;
+ }
+ for (PsiDirectory child : directory.getSubdirectories()) {
+ if (hasBlazePackageChild(index, buildSystemProvider, child)) {
+ return true;
+ }
+ }
+ return false;
}
}
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
index d5f6606..841ad88 100644
--- 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
@@ -65,7 +65,7 @@
public String toString() {
return String.format(
"%s directory scope: %s",
- Blaze.buildSystemName(getProject()), blazePackage.buildFile.getPackageWorkspacePath());
+ Blaze.buildSystemName(getProject()), blazePackage.buildFile.getPackageLabel());
}
@Override
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/BuildReferenceSearcher.java
similarity index 78%
rename from base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java
rename to base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildReferenceSearcher.java
index 688cc95..d35fc90 100644
--- a/base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildLabelReferenceSearcher.java
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/search/BuildReferenceSearcher.java
@@ -20,11 +20,10 @@
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.NamedBuildElement;
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;
@@ -39,41 +38,45 @@
import java.util.List;
import javax.annotation.Nullable;
-/** String search for label references in BUILD files */
-public class BuildLabelReferenceSearcher extends QueryExecutorBase<PsiReference, SearchParameters> {
+/** String search for references in BUILD files */
+public class BuildReferenceSearcher extends QueryExecutorBase<PsiReference, SearchParameters> {
- public BuildLabelReferenceSearcher() {
+ public BuildReferenceSearcher() {
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 (element instanceof NamedBuildElement) {
+ String fnName = ((NamedBuildElement) 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();
+ FuncallExpression funcall = (FuncallExpression) element;
PsiFile localFile = element.getContainingFile();
- if (label == null || localFile == null) {
+ if (localFile == null) {
+ return;
+ }
+ Label label = funcall.resolveBuildLabel();
+ if (label == null) {
+ searchForExternalWorkspace(params, localFile, funcall);
return;
}
List<String> stringsToSearch = LabelUtils.getAllValidLabelStrings(label, true);
for (String string : stringsToSearch) {
- if (string.startsWith("//")) {
+ if (LabelUtils.isAbsolute(string)) {
searchForString(params, element, string);
} else {
// only a valid reference from local package -- restrict the search scope accordingly
@@ -117,17 +120,18 @@
/** 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) {
+ Label label = file.getBuildLabel();
+ if (label == null) {
return;
}
+ String labelString = label.toString();
List<String> stringsToSearch = Lists.newArrayList();
if (file.getBlazeFileType() == BlazeFileType.BuildPackage) {
- stringsToSearch.add("//" + workspacePath);
+ // remove ':__pkg__' component of label
+ stringsToSearch.add(labelString.split(":", 2)[0]);
} else {
- stringsToSearch.add("//" + workspacePath + ":" + file.getName());
- stringsToSearch.add(
- "//" + workspacePath + "/" + file.getName()); // deprecated load/subinclude format
+ stringsToSearch.add(labelString);
+ stringsToSearch.add(labelString.replace(':', '/')); // deprecated load/subinclude format
}
for (String string : stringsToSearch) {
searchForString(params, file, string);
@@ -161,4 +165,21 @@
}
params.getOptimizer().searchWord(string, scope, UsageSearchContext.IN_STRINGS, true, element);
}
+
+ private static void searchForExternalWorkspace(
+ SearchParameters params, PsiFile file, FuncallExpression funcall) {
+ if (!isBlazeWorkspaceFile(file)) {
+ return;
+ }
+ String name = funcall.getNameArgumentValue();
+ if (name != null) {
+ searchForString(params, funcall, "@" + name);
+ }
+ }
+
+ /** Is the file a blaze WORKSPACE file */
+ private static boolean isBlazeWorkspaceFile(PsiFile file) {
+ return file instanceof BuildFile
+ && ((BuildFile) file).getBlazeFileType() == BlazeFileType.Workspace;
+ }
}
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
index 73d1e58..4c4a53a 100644
--- 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
@@ -19,7 +19,7 @@
import com.intellij.psi.stubs.BinaryFileStubBuilder;
import com.intellij.psi.stubs.Stub;
import com.intellij.util.indexing.FileContent;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Empty stub builder to suppress errors when IntelliJ is looking for stubs. */
public class BuildFileStubBuilder implements BinaryFileStubBuilder {
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
index 0279a2f..4a0f12b 100644
--- 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
@@ -15,9 +15,10 @@
*/
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.BlazeFlags;
import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.command.info.BlazeInfoRunner;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.lang.buildfile.language.semantics.BuildLanguageSpec;
import com.google.idea.blaze.base.model.SyncState;
@@ -30,7 +31,6 @@
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.repackaged.devtools.build.lib.query2.proto.proto2api.Build;
@@ -53,7 +53,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
@Nullable WorkingSet workingSet,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
@@ -62,7 +62,7 @@
@Nullable SyncState previousSyncState) {
LanguageSpecResult spec =
- getBuildLanguageSpec(project, workspaceRoot, previousSyncState, context);
+ getBuildLanguageSpec(project, workspaceRoot, projectViewSet, previousSyncState, context);
if (spec != null) {
syncStateBuilder.put(LanguageSpecResult.class, spec);
}
@@ -72,6 +72,7 @@
private static LanguageSpecResult getBuildLanguageSpec(
Project project,
WorkspaceRoot workspace,
+ ProjectViewSet projectViewSet,
@Nullable SyncState previousSyncState,
BlazeContext parentContext) {
LanguageSpecResult oldResult =
@@ -84,7 +85,8 @@
parentContext,
(context) -> {
context.push(new TimingScope("BUILD language spec"));
- BuildLanguageSpec spec = parseLanguageSpec(project, workspace, context);
+ BuildLanguageSpec spec =
+ parseLanguageSpec(project, workspace, projectViewSet, context);
if (spec != null) {
return new LanguageSpecResult(spec, System.currentTimeMillis());
}
@@ -95,17 +97,20 @@
@Nullable
private static BuildLanguageSpec parseLanguageSpec(
- Project project, WorkspaceRoot workspace, BlazeContext context) {
+ Project project,
+ WorkspaceRoot workspace,
+ ProjectViewSet projectViewSet,
+ 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()
+ BlazeInfoRunner.getInstance()
.runBlazeInfoGetBytes(
context,
- Blaze.getBuildSystem(project),
+ Blaze.getBuildSystemProvider(project).getSyncBinaryPath(),
workspace,
- ImmutableList.of(),
+ BlazeFlags.buildFlags(project, projectViewSet),
BlazeInfo.BUILD_LANGUAGE);
return BuildLanguageSpec.fromProto(Build.BuildLanguage.parseFrom(future.get()));
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
index 84028f8..b4b9230 100644
--- 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
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.lang.buildfile.validation;
import com.google.idea.blaze.base.lang.buildfile.psi.BuildElementVisitor;
+import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
import com.intellij.psi.PsiElement;
@@ -39,7 +40,11 @@
}
}
- protected void markError(PsiElement element, String message) {
- getHolder().createErrorAnnotation(element, message);
+ protected Annotation markError(PsiElement element, String message) {
+ return getHolder().createErrorAnnotation(element, message);
+ }
+
+ protected Annotation markWarning(PsiElement element, String message) {
+ return getHolder().createWarningAnnotation(element, message);
}
}
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildElementValidation.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildElementValidation.java
index 138908c..d8a8206 100644
--- a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildElementValidation.java
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuildElementValidation.java
@@ -15,6 +15,7 @@
*/
package com.google.idea.blaze.base.lang.buildfile.validation;
+import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.lang.buildfile.psi.DictionaryLiteral;
import com.google.idea.blaze.base.lang.buildfile.psi.FunctionStatement;
import com.google.idea.blaze.base.lang.buildfile.psi.GlobExpression;
@@ -38,14 +39,21 @@
private static final EnumSet<Build.Attribute.Discriminator> LIST_TYPES =
EnumSet.of(
Discriminator.STRING_LIST,
+ Discriminator.DISTRIBUTION_SET,
Discriminator.LABEL_LIST,
Discriminator.OUTPUT_LIST,
Discriminator.FILESET_ENTRY_LIST,
Discriminator.INTEGER_LIST,
- Discriminator.LICENSE);
+ Discriminator.LICENSE,
+ Discriminator.SELECTOR_LIST);
private static final EnumSet<Build.Attribute.Discriminator> DICT_TYPES =
- EnumSet.of(Discriminator.LABEL_LIST_DICT, Discriminator.STRING_LIST_DICT);
+ EnumSet.of(
+ Discriminator.LABEL_LIST_DICT,
+ Discriminator.LABEL_KEYED_STRING_DICT,
+ Discriminator.STRING_DICT,
+ Discriminator.STRING_LIST_DICT,
+ Discriminator.LABEL_DICT_UNARY);
private static final EnumSet<Build.Attribute.Discriminator> STRING_TYPES =
EnumSet.of(
@@ -58,9 +66,20 @@
private static final EnumSet<Build.Attribute.Discriminator> INTEGER_TYPES =
EnumSet.of(Discriminator.INTEGER, Discriminator.BOOLEAN, Discriminator.TRISTATE);
+ // This enum list is duplicated several times through Bazel source code. In some places there are
+ // additional items not covered here. Don't show spurious errors when more items are added.
+ private static final EnumSet<Build.Attribute.Discriminator> HANDLED_TYPES =
+ EnumSet.copyOf(
+ ImmutableList.<Discriminator>builder()
+ .addAll(LIST_TYPES)
+ .addAll(DICT_TYPES)
+ .addAll(STRING_TYPES)
+ .addAll(INTEGER_TYPES)
+ .build());
+
/** Returns false iff we know with certainty that the element cannot resolve to the given type. */
public static boolean possiblyValidType(PsiElement element, Build.Attribute.Discriminator type) {
- if (type == Discriminator.UNKNOWN) {
+ if (!HANDLED_TYPES.contains(type)) {
return true;
}
if (element instanceof ListLiteral || element instanceof GlobExpression) {
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotator.java
index 48f8136..8fa0362 100644
--- a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotator.java
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotator.java
@@ -43,8 +43,16 @@
if (rule == null) {
return;
}
+ if (node.getReferencedElement() != null) {
+ // this has been locally overridden, so don't attempt validation
+ return;
+ }
Set<String> missingAttributes = new TreeSet<>(rule.mandatoryAttributes.keySet());
for (Argument arg : node.getArguments()) {
+ if (arg instanceof Argument.StarStar) {
+ missingAttributes.clear();
+ continue;
+ }
String name = arg.getName();
if (name == null) {
continue;
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
index c82d736..f039e31 100644
--- 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
@@ -20,16 +20,12 @@
/**
* 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) {
@@ -58,6 +54,7 @@
case '[':
case ']':
return "illegal character '" + c + "'";
+ default: // fall out
}
}
Iterable<String> segments = Splitter.on('/').split(pattern);
diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/LoadErrorAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/LoadErrorAnnotator.java
deleted file mode 100644
index c8ea27a..0000000
--- a/base/src/com/google/idea/blaze/base/lang/buildfile/validation/LoadErrorAnnotator.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.lang.buildfile.validation;
-
-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.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.LoadedSymbol;
-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;
-import java.util.Arrays;
-import javax.annotation.Nullable;
-
-/**
- * Error annotations for load statements, 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 LoadErrorAnnotator extends BuildAnnotator {
-
- @Override
- public void visitLoadStatement(LoadStatement node) {
- BuildElement[] children = node.buildElementChildren();
- // StringLiteral[] strings = node..getChildStrings();
- if (children.length == 0) {
- return;
- }
- PsiElement skylarkRef = getSkylarkRef(children[0]);
- if (skylarkRef == null) {
- markError(children[0], "Cannot find this Skylark module");
- return;
- }
- if (!(skylarkRef instanceof BuildFile)) {
- markError(children[0], children[0].getText() + " is not a Skylark module");
- return;
- }
-
- LoadedSymbol[] symbols =
- Arrays.stream(children)
- .filter(element -> element instanceof LoadedSymbol)
- .toArray(LoadedSymbol[]::new);
- if (symbols.length == 1) {
- markError(node, "No symbols imported from Skylark module");
- return;
- }
- BuildFile skylarkModule = (BuildFile) skylarkRef;
- for (int i = 0; i < symbols.length; i++) {
- String text = symbols[i].getSymbolString();
- if (text == null) {
- continue;
- }
- FunctionStatement fn = skylarkModule.findDeclaredFunction(text);
- if (fn == null) {
- markError(
- symbols[i],
- "Function '" + text + "' not found in Skylark module " + skylarkModule.getFileName());
- }
- }
- }
-
- @Nullable
- private static PsiElement getSkylarkRef(BuildElement firstChild) {
- if (firstChild instanceof StringLiteral) {
- return new LabelReference((StringLiteral) firstChild, false).resolve();
- }
- return null;
- }
-
- @Override
- public void visitFuncallExpression(FuncallExpression node) {
- FunctionStatement function = (FunctionStatement) node.getReferencedElement();
- if (function == null) {
- // likely a built-in rule.
- 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/LoadStatementAnnotator.java b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/LoadStatementAnnotator.java
new file mode 100644
index 0000000..c51ccc8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/buildfile/validation/LoadStatementAnnotator.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 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.LoadStatement;
+import com.google.idea.blaze.base.lang.buildfile.psi.LoadedSymbol;
+import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral;
+import com.google.idea.blaze.base.lang.buildfile.quickfix.DeprecatedLoadQuickFix;
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.lang.annotation.Annotation;
+import javax.annotation.Nullable;
+
+/** Adds warning/error annotations to load statements. */
+public class LoadStatementAnnotator extends BuildAnnotator {
+
+ @Override
+ public void visitLoadStatement(LoadStatement node) {
+ validateImportTarget(node.getImportPsiElement());
+ }
+
+ @Override
+ public void visitLoadedSymbol(LoadedSymbol node) {
+ StringLiteral loadedString = node.getImport();
+ if (loadedString == null) {
+ return;
+ }
+ String name = loadedString.getStringContents();
+ if (name.startsWith("_")) {
+ markError(node, String.format("Symbol '%s' is private and cannot be imported.", name));
+ }
+ }
+
+ private void validateImportTarget(@Nullable StringLiteral target) {
+ if (target == null) {
+ return;
+ }
+ String targetString = target.getStringContents();
+ if (targetString == null
+ || targetString.startsWith(":")
+ || targetString.startsWith("//")
+ || targetString.startsWith("@")
+ || targetString.length() < 2) {
+ return;
+ }
+ if (targetString.startsWith("/")) {
+ Annotation annotation =
+ markWarning(
+ target, "Deprecated load syntax; loaded Skylark module should by in label format.");
+ InspectionManager inspectionManager = InspectionManager.getInstance(target.getProject());
+ ProblemDescriptor descriptor =
+ inspectionManager.createProblemDescriptor(
+ target,
+ annotation.getMessage(),
+ DeprecatedLoadQuickFix.INSTANCE,
+ ProblemHighlightType.LIKE_DEPRECATED,
+ true);
+ annotation.registerFix(DeprecatedLoadQuickFix.INSTANCE, null, null, descriptor);
+ return;
+ }
+ markError(target, "Invalid load syntax: missing Skylark module.");
+ }
+}
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
index 75768dd..7ae6217 100644
--- 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
@@ -21,8 +21,8 @@
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.ide.structureView.impl.common.PsiTreeElementBase;
import java.util.Collection;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Handles nodes in Structure View. */
public class BuildStructureViewElement extends PsiTreeElementBase<BuildElement> {
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
index 4cf2f36..598372f 100644
--- 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
@@ -17,10 +17,14 @@
import static com.intellij.patterns.PlatformPatterns.psiElement;
+import com.google.common.collect.Ordering;
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.model.primitives.WorkspaceType;
import com.google.idea.blaze.base.projectview.section.sections.AdditionalLanguagesSection;
+import com.google.idea.blaze.base.sync.SyncCache;
+import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
import com.intellij.codeInsight.completion.AutoCompletionContext;
import com.intellij.codeInsight.completion.AutoCompletionDecision;
import com.intellij.codeInsight.completion.CompletionContributor;
@@ -30,8 +34,11 @@
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.openapi.project.Project;
import com.intellij.patterns.StandardPatterns;
import com.intellij.util.ProcessingContext;
+import java.util.List;
+import java.util.stream.Collectors;
/** Code completion for additional language types. */
public class AdditionalLanguagesCompletionContributor extends CompletionContributor {
@@ -62,10 +69,28 @@
CompletionParameters parameters,
ProcessingContext context,
CompletionResultSet result) {
- for (LanguageClass type : LanguageClass.values()) {
+ for (LanguageClass type :
+ availableAdditionalLanguages(parameters.getEditor().getProject())) {
result.addElement(LookupElementBuilder.create(type.getName()));
}
}
});
}
+
+ private static List<LanguageClass> availableAdditionalLanguages(Project project) {
+ List<LanguageClass> langs =
+ SyncCache.getInstance(project)
+ .get(
+ AdditionalLanguagesCompletionContributor.class,
+ (proj, projectData) ->
+ additionalLanguages(projectData.workspaceLanguageSettings.getWorkspaceType()));
+ return langs == null ? additionalLanguages(LanguageSupport.getDefaultWorkspaceType()) : langs;
+ }
+
+ private static List<LanguageClass> additionalLanguages(WorkspaceType workspaceType) {
+ return LanguageSupport.availableAdditionalLanguages(workspaceType)
+ .stream()
+ .sorted(Ordering.usingToString())
+ .collect(Collectors.toList());
+ }
}
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
index 88d8d2b..6020f31 100644
--- 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
@@ -43,7 +43,7 @@
import com.intellij.psi.PsiFile;
import com.intellij.util.ProcessingContext;
import java.util.List;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Completes project view section names. */
public class ProjectViewKeywordCompletionContributor extends CompletionContributor {
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/documentation/ProjectViewDocumentationProvider.java b/base/src/com/google/idea/blaze/base/lang/projectview/documentation/ProjectViewDocumentationProvider.java
new file mode 100644
index 0000000..fda1879
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/documentation/ProjectViewDocumentationProvider.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 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.documentation;
+
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.lang.projectview.psi.ProjectViewSection;
+import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.lang.documentation.AbstractDocumentationProvider;
+import com.intellij.lang.documentation.ExternalDocumentationProvider;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
+
+/** Provides quick docs for some .blazeproject elements. */
+public class ProjectViewDocumentationProvider extends AbstractDocumentationProvider
+ implements ExternalDocumentationProvider {
+
+ @Nullable
+ private static SectionParser getSection(PsiElement element) {
+ ProjectViewSection section = PsiUtils.getParentOfType(element, ProjectViewSection.class, false);
+ return section != null ? section.getSectionParser() : null;
+ }
+
+ @Nullable
+ @Override
+ public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
+ SectionParser section = getSection(element);
+ if (section == null) {
+ return null;
+ }
+ StringBuilder builder = new StringBuilder();
+ String quickDocs = section.quickDocs();
+ if (quickDocs != null) {
+ builder.append(wrapInTag("<p>" + section.quickDocs(), "code"));
+ }
+ String url = getUrlFor(element.getProject(), section, false);
+ if (url != null) {
+ builder.append(
+ String.format("<p><b>External documentation</b>:<br><a href=\"%s\">%s</a>", url, url));
+ }
+ return wrapInTag(wrapInTag(builder.toString(), "body"), "html");
+ }
+
+ private static String wrapInTag(String doc, String htmlTag) {
+ return String.format("<%s>%s</%s>", htmlTag, doc, htmlTag);
+ }
+
+ @Override
+ public boolean hasDocumentationFor(PsiElement element, PsiElement originalElement) {
+ return getUrlFor(element, false) != null;
+ }
+
+ @Override
+ public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
+ final String url = getUrlFor(element, true);
+ return url == null ? null : Collections.singletonList(url);
+ }
+
+ @Nullable
+ @Override
+ public String fetchExternalDocumentation(
+ Project project, PsiElement element, List<String> docUrls) {
+ return null;
+ }
+
+ @Override
+ public boolean canPromptToConfigureDocumentation(PsiElement element) {
+ return false;
+ }
+
+ @Override
+ public void promptToConfigureDocumentation(PsiElement element) {}
+
+ @Nullable
+ private static String getUrlFor(PsiElement element, boolean checkExistence) {
+ SectionParser section = getSection(element);
+ return section != null ? getUrlFor(element.getProject(), section, checkExistence) : null;
+ }
+
+ @Nullable
+ private static String getUrlFor(Project project, SectionParser section, boolean checkExistence) {
+ String baseDocsUrl = Blaze.getBuildSystemProvider(project).getProjectViewDocumentationUrl();
+ if (baseDocsUrl == null) {
+ return null;
+ }
+ String url = baseDocsUrl + "#" + section.getName();
+ if (checkExistence && !pageExists(url)) {
+ return baseDocsUrl;
+ }
+ return url;
+ }
+
+ private static boolean pageExists(String url) {
+ final HttpClient client = new HttpClient();
+ final HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
+ params.setSoTimeout(5 * 1000);
+ params.setConnectionTimeout(5 * 1000);
+
+ try {
+ final HeadMethod method = new HeadMethod(url);
+ final int rc = client.executeMethod(method);
+ if (rc == 404) {
+ return false;
+ }
+ } catch (IllegalArgumentException e) {
+ return false;
+ } catch (IOException e) {
+ // ignore
+ }
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public PsiElement getCustomDocumentationElement(
+ Editor editor, PsiFile file, @Nullable PsiElement contextElement) {
+ return PsiUtils.getParentOfType(contextElement, ProjectViewSection.class, false);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCodeStyleSettingsProvider.java b/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCodeStyleSettingsProvider.java
new file mode 100644
index 0000000..3df7613
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/formatting/ProjectViewCodeStyleSettingsProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 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.language.ProjectViewLanguage;
+import com.intellij.lang.Language;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
+import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
+import javax.annotation.Nullable;
+
+/** Allows blazeproject-specific code style settings */
+public class ProjectViewCodeStyleSettingsProvider extends LanguageCodeStyleSettingsProvider {
+
+ @Override
+ public Language getLanguage() {
+ return ProjectViewLanguage.INSTANCE;
+ }
+
+ @Override
+ public String getCodeSample(SettingsType settingsType) {
+ return "";
+ }
+
+ @Nullable
+ @Override
+ public CommonCodeStyleSettings getDefaultCommonSettings() {
+ CommonCodeStyleSettings defaultSettings =
+ new CommonCodeStyleSettings(ProjectViewLanguage.INSTANCE);
+ defaultSettings.LINE_COMMENT_AT_FIRST_COLUMN = false;
+ defaultSettings.LINE_COMMENT_ADD_SPACE = true;
+ CommonCodeStyleSettings.IndentOptions indentOptions = defaultSettings.initIndentOptions();
+ indentOptions.TAB_SIZE = 2;
+ indentOptions.INDENT_SIZE = 2;
+ indentOptions.CONTINUATION_INDENT_SIZE = 2;
+ return defaultSettings;
+ }
+}
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
index 09aaa68..33667ee 100644
--- 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
@@ -19,7 +19,7 @@
import com.intellij.lang.CodeDocumentationAwareCommenter;
import com.intellij.psi.PsiComment;
import com.intellij.psi.tree.IElementType;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Supports (un)commenting lines via IntelliJ */
public class ProjectViewCommenter implements CodeDocumentationAwareCommenter {
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
index d75547a..3d2ad2b 100644
--- 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
@@ -15,12 +15,22 @@
*/
package com.google.idea.blaze.base.lang.projectview.psi;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import javax.annotation.Nullable;
/** Psi element for list section. */
-public class ProjectViewPsiListSection extends ProjectViewPsiElement {
+public class ProjectViewPsiListSection extends ProjectViewSection {
public ProjectViewPsiListSection(ASTNode node) {
super(node);
}
+
+ @Nullable
+ @Override
+ public String getSectionName() {
+ PsiElement keyword = findChildByType(ProjectViewTokenType.LIST_KEYWORD);
+ return keyword != null ? keyword.getText() : null;
+ }
}
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
index 6f03ff4..19819a4 100644
--- 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
@@ -15,12 +15,22 @@
*/
package com.google.idea.blaze.base.lang.projectview.psi;
+import com.google.idea.blaze.base.lang.projectview.lexer.ProjectViewTokenType;
import com.intellij.lang.ASTNode;
+import com.intellij.psi.PsiElement;
+import javax.annotation.Nullable;
/** Psi element for scalar section. */
-public class ProjectViewPsiScalarSection extends ProjectViewPsiElement {
+public class ProjectViewPsiScalarSection extends ProjectViewSection {
public ProjectViewPsiScalarSection(ASTNode node) {
super(node);
}
+
+ @Nullable
+ @Override
+ public String getSectionName() {
+ PsiElement keyword = findChildByType(ProjectViewTokenType.SCALAR_KEYWORD);
+ return keyword != null ? keyword.getText() : null;
+ }
}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewSection.java b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewSection.java
new file mode 100644
index 0000000..9e275bf
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/psi/ProjectViewSection.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 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.projectview.section.SectionParser;
+import com.google.idea.blaze.base.projectview.section.sections.Sections;
+import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.navigation.NavigationItem;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Psi element for a list or scalar section. */
+public abstract class ProjectViewSection extends ProjectViewPsiElement implements NavigationItem {
+
+ public ProjectViewSection(ASTNode node) {
+ super(node);
+ }
+
+ @Override
+ public ItemPresentation getPresentation() {
+ final ProjectViewSection element = this;
+ return new ItemPresentation() {
+ @Override
+ public String getPresentableText() {
+ return getSectionName();
+ }
+
+ @Override
+ public String getLocationString() {
+ return null;
+ }
+
+ @Override
+ public Icon getIcon(boolean unused) {
+ return element.getIcon(0);
+ }
+ };
+ }
+
+ @Override
+ public String getName() {
+ return getSectionName();
+ }
+
+ @Nullable
+ protected abstract String getSectionName();
+
+ @Nullable
+ public SectionParser getSectionParser() {
+ String text = getSectionName();
+ if (text == null) {
+ return null;
+ }
+ for (SectionParser parser : Sections.getParsers()) {
+ if (text.equals(parser.getName())) {
+ return parser;
+ }
+ }
+ return null;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/lang/projectview/stubs/ProjectViewFileStubBuilder.java b/base/src/com/google/idea/blaze/base/lang/projectview/stubs/ProjectViewFileStubBuilder.java
new file mode 100644
index 0000000..dcf8917
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/lang/projectview/stubs/ProjectViewFileStubBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 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.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 javax.annotation.Nullable;
+
+/** Empty stub builder to suppress errors when IntelliJ is looking for stubs. */
+public class ProjectViewFileStubBuilder 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/logging/EventLogger.java b/base/src/com/google/idea/blaze/base/logging/EventLogger.java
new file mode 100644
index 0000000..02a930f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/logging/EventLogger.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.base.logging;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.util.Map;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Forwards the event logs to an applicable receiver extension or discard them if no applicable
+ * receivers exist.
+ */
+public interface EventLogger {
+ ExtensionPointName<EventLogger> EP_NAME =
+ new ExtensionPointName<>("com.google.idea.blaze.EventLogger");
+
+ static EventLogger getInstance() {
+ for (EventLogger logger : EP_NAME.getExtensions()) {
+ if (logger.isApplicable()) {
+ return logger;
+ }
+ }
+ return NullEventLogger.SINGLETON;
+ }
+
+ boolean isApplicable();
+
+ default void log(Class<?> loggingClass, String eventType, Map<String, String> keyValues) {
+ log(loggingClass, eventType, keyValues, null);
+ }
+
+ void log(
+ Class<?> loggingClass,
+ String eventType,
+ Map<String, String> keyValues,
+ @Nullable Long durationInNanos);
+}
diff --git a/base/src/com/google/idea/blaze/base/logging/NullEventLogger.java b/base/src/com/google/idea/blaze/base/logging/NullEventLogger.java
new file mode 100644
index 0000000..0546f7b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/logging/NullEventLogger.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.base.logging;
+
+import java.util.Map;
+import org.jetbrains.annotations.Nullable;
+
+/** No-op logger used when no logger is not available to receive logs. */
+public class NullEventLogger implements EventLogger {
+ static final NullEventLogger SINGLETON = new NullEventLogger();
+
+ private NullEventLogger() {}
+
+ @Override
+ public boolean isApplicable() {
+ return true;
+ }
+
+ @Override
+ public void log(
+ Class<?> loggingClass,
+ String eventType,
+ Map<String, String> keyValues,
+ @Nullable Long durationInNanos) {}
+}
diff --git a/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java b/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
index 77862fd..bba404b 100644
--- a/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
+++ b/base/src/com/google/idea/blaze/base/model/BlazeProjectData.java
@@ -15,13 +15,12 @@
*/
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.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.ideinfo.TargetMap;
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.WorkspacePathResolver;
import java.io.Serializable;
import javax.annotation.concurrent.Immutable;
@@ -29,12 +28,11 @@
/** The top-level object serialized to cache. */
@Immutable
public class BlazeProjectData implements Serializable {
- private static final long serialVersionUID = 27L;
+ private static final long serialVersionUID = 28L;
public final long syncTime;
public final TargetMap targetMap;
- public final ImmutableMap<String, String> blazeInfo;
- public final BlazeRoots blazeRoots;
+ public final BlazeInfo blazeInfo;
public final BlazeVersionData blazeVersionData;
public final WorkspacePathResolver workspacePathResolver;
public final ArtifactLocationDecoder artifactLocationDecoder;
@@ -45,19 +43,16 @@
public BlazeProjectData(
long syncTime,
TargetMap targetMap,
- ImmutableMap<String, String> blazeInfo,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
BlazeVersionData blazeVersionData,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
WorkspaceLanguageSettings workspaceLanguageSettings,
SyncState syncState,
- ImmutableMultimap<TargetKey, TargetKey> reverseDependencies,
- Object dummy) {
+ ImmutableMultimap<TargetKey, TargetKey> reverseDependencies) {
this.syncTime = syncTime;
this.targetMap = targetMap;
this.blazeInfo = blazeInfo;
- this.blazeRoots = blazeRoots;
this.blazeVersionData = blazeVersionData;
this.workspacePathResolver = workspacePathResolver;
this.artifactLocationDecoder = artifactLocationDecoder;
diff --git a/base/src/com/google/idea/blaze/base/model/BlazeVersionData.java b/base/src/com/google/idea/blaze/base/model/BlazeVersionData.java
index 1cbdbff..ded37ad 100644
--- a/base/src/com/google/idea/blaze/base/model/BlazeVersionData.java
+++ b/base/src/com/google/idea/blaze/base/model/BlazeVersionData.java
@@ -16,9 +16,9 @@
package com.google.idea.blaze.base.model;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableMap;
import com.google.idea.blaze.base.bazel.BazelVersion;
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import java.io.Serializable;
@@ -59,10 +59,12 @@
return bazelVersion != null && bazelVersion.isAtLeast(major, minor, bugfix);
}
+ public BuildSystem buildSystem() {
+ return bazelVersion != null ? BuildSystem.Bazel : BuildSystem.Blaze;
+ }
+
public static BlazeVersionData build(
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- ImmutableMap<String, String> blazeInfo) {
+ BuildSystem buildSystem, WorkspaceRoot workspaceRoot, BlazeInfo blazeInfo) {
Builder builder = new Builder();
for (BuildSystemProvider provider : BuildSystemProvider.EP_NAME.getExtensions()) {
provider.populateBlazeVersionData(buildSystem, workspaceRoot, blazeInfo, builder);
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
index 4c8d3f0..5e060b7 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/ExecutionRootPath.java
@@ -87,7 +87,7 @@
if (root.isAbsolute() != path.isAbsolute()) {
return null;
}
- if (!isAncestor(root.getPath(), path.getPath(), false /* strict */)) {
+ if (!isAncestor(root.getPath(), path.getPath(), /* strict */ false)) {
return null;
}
String relativePath = FileUtil.getRelativePath(root, path);
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
index eba71f9..b5fbda8 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/Kind.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/Kind.java
@@ -15,9 +15,11 @@
*/
package com.google.idea.blaze.base.model.primitives;
+import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
import java.util.Arrays;
-import java.util.List;
+import java.util.Collection;
/** Wrapper around a string for a blaze kind (android_library, android_test...) */
public enum Kind {
@@ -25,6 +27,7 @@
ANDROID_LIBRARY("android_library", LanguageClass.ANDROID),
ANDROID_TEST("android_test", LanguageClass.ANDROID),
ANDROID_ROBOLECTRIC_TEST("android_robolectric_test", LanguageClass.ANDROID),
+ ANDROID_SDK("android_sdk", LanguageClass.ANDROID),
JAVA_LIBRARY("java_library", LanguageClass.JAVA),
JAVA_TEST("java_test", LanguageClass.JAVA),
JAVA_BINARY("java_binary", LanguageClass.JAVA),
@@ -57,10 +60,16 @@
GO_APPENGINE_LIBRARY("go_appengine_library", LanguageClass.GO),
GO_WRAP_CC("go_wrap_cc", LanguageClass.GO),
INTELLIJ_PLUGIN_DEBUG_TARGET("intellij_plugin_debug_target", LanguageClass.JAVA),
+ SCALA_BINARY("scala_binary", LanguageClass.SCALA),
+ SCALA_LIBRARY("scala_library", LanguageClass.SCALA),
+ SCALA_MACRO_LIBRARY("scala_macro_library", LanguageClass.SCALA),
+ SCALA_TEST("scala_test", LanguageClass.SCALA),
;
static final ImmutableMap<String, Kind> STRING_TO_KIND = makeStringToKindMap();
+ static final ImmutableMultimap<LanguageClass, Kind> PER_LANGUAGES_KINDS = makePerLanguageMap();
+
private static ImmutableMap<String, Kind> makeStringToKindMap() {
ImmutableMap.Builder<String, Kind> result = ImmutableMap.builder();
for (Kind kind : Kind.values()) {
@@ -69,10 +78,22 @@
return result.build();
}
+ private static ImmutableMultimap<LanguageClass, Kind> makePerLanguageMap() {
+ ImmutableMultimap.Builder<LanguageClass, Kind> result = ImmutableMultimap.builder();
+ for (Kind kind : Kind.values()) {
+ result.put(kind.languageClass, kind);
+ }
+ return result.build();
+ }
+
public static Kind fromString(String kindString) {
return STRING_TO_KIND.get(kindString);
}
+ public static ImmutableCollection<Kind> allKindsForLanguage(LanguageClass language) {
+ return PER_LANGUAGES_KINDS.get(language);
+ }
+
private final String kind;
private final LanguageClass languageClass;
@@ -94,7 +115,7 @@
return isOneOf(Arrays.asList(kinds));
}
- public boolean isOneOf(List<Kind> kinds) {
+ public boolean isOneOf(Collection<Kind> kinds) {
for (Kind kind : kinds) {
if (this.equals(kind)) {
return true;
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
index c06f6a2..f86da52 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/Label.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/Label.java
@@ -23,7 +23,7 @@
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
-/** Wrapper around a string for a blaze label (//package:rule). */
+/** Wrapper around a string for a blaze label ([@external_workspace]//package:rule). */
@Immutable
public final class Label extends TargetExpression {
private static final Logger logger = Logger.getInstance(Label.class);
@@ -39,16 +39,31 @@
return null;
}
- public Label(String label) {
- super(label);
+ public static Label create(String label) {
List<BlazeValidationError> errors = Lists.newArrayList();
if (!validate(label, errors)) {
BlazeValidationError.throwError(errors);
}
+ return new Label(label);
}
- public Label(WorkspacePath packageName, TargetName newTargetName) {
- this("//" + packageName.toString() + ":" + newTargetName.toString());
+ public static Label create(WorkspacePath packageName, TargetName newTargetName) {
+ return create(null, packageName, newTargetName);
+ }
+
+ public static Label create(
+ @Nullable String externalWorkspaceName, WorkspacePath packagePath, TargetName targetName) {
+ String fullLabel =
+ String.format(
+ "%s//%s:%s",
+ externalWorkspaceName != null ? "@" + externalWorkspaceName : "",
+ packagePath,
+ targetName);
+ return new Label(fullLabel);
+ }
+
+ private Label(String label) {
+ super(label);
}
public static boolean validate(String label) {
@@ -81,6 +96,25 @@
return false;
}
+ public boolean isExternal() {
+ return toString().startsWith("@");
+ }
+
+ /**
+ * Returns the external workspace referenced by this label, or null if it's a main workspace
+ * label.
+ */
+ @Nullable
+ public String externalWorkspaceName() {
+ String label = toString();
+ if (!label.startsWith("@")) {
+ return null;
+ }
+ int slashesIndex = label.indexOf("//");
+ logger.assertTrue(slashesIndex >= 0);
+ return label.substring(1, slashesIndex);
+ }
+
/**
* Extract the target name from a label. The target name follows a colon at the end of the label.
*
@@ -106,7 +140,17 @@
return new WorkspacePath(labelStr.substring(startIndex, colonIndex));
}
- public static boolean validatePackagePath(String path) {
+ /** A new label with the same workspace and package paths, but a different target name. */
+ @Nullable
+ public Label withTargetName(@Nullable String targetName) {
+ if (targetName == null) {
+ return null;
+ }
+ TargetName target = TargetName.createIfValid(targetName);
+ return target != null ? Label.create(externalWorkspaceName(), blazePackage(), target) : null;
+ }
+
+ static boolean validatePackagePath(String path) {
return validatePackagePath(path, null);
}
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
index cf030a2..e9cb3a8 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/LanguageClass.java
@@ -29,7 +29,9 @@
TYPESCRIPT("typescript", ImmutableSet.of("ts", "ats")),
DART("dart", ImmutableSet.of("dart")),
GO("go", ImmutableSet.of("go")),
- PYTHON("python", ImmutableSet.of("py", "pyw"));
+ PYTHON("python", ImmutableSet.of("py", "pyw")),
+ SCALA("scala", ImmutableSet.of("scala")),
+ ;
private static final ImmutableMap<String, LanguageClass> RECOGNIZED_EXTENSIONS =
extensionToClassMap();
@@ -65,6 +67,11 @@
return null;
}
+ @Override
+ public String toString() {
+ return name;
+ }
+
/** Returns the LanguageClass associated with the given filename extension, if it's recognized. */
@Nullable
public static LanguageClass fromExtension(String filenameExtension) {
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
index ea3d847..4e36aab 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/TargetExpression.java
@@ -32,16 +32,21 @@
* it is not.
*/
public static TargetExpression fromString(String expression) {
- return Label.validate(expression) ? new Label(expression) : new TargetExpression(expression);
+ return Label.validate(expression) ? Label.create(expression) : new TargetExpression(expression);
}
- TargetExpression(String expression) {
+ protected 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;
}
+ /** Is this an excluded target expression (i.e. starts with '-')? */
+ public boolean isExcluded() {
+ return expression.startsWith("-");
+ }
+
@Override
public String toString() {
return expression;
@@ -63,8 +68,7 @@
/** All targets in all packages below the given path */
public static TargetExpression allFromPackageRecursive(WorkspacePath localPackage) {
- if (localPackage.relativePath().isEmpty()) {
- // localPackage is the workspace root
+ if (localPackage.isWorkspaceRoot()) {
return new TargetExpression("//...:all");
}
return new TargetExpression("//" + localPackage.relativePath() + "/...:all");
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
index 00ce9ee..b3cbbf0 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/WorkspacePath.java
@@ -18,9 +18,9 @@
import com.google.idea.blaze.base.ui.BlazeValidationError;
import java.io.Serializable;
import java.util.Collection;
+import javax.annotation.Nullable;
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.
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
index b4a0a13..53d156d 100644
--- a/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java
+++ b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java
@@ -108,7 +108,8 @@
private WorkspacePath workspacePathFor(String path) {
if (!isInWorkspace(path)) {
- throw new IllegalArgumentException("File is not under this workspace");
+ throw new IllegalArgumentException(
+ String.format("File '%s' is not under workspace %s", path, directory));
}
if (directory.getPath().length() == path.length()) {
return new WorkspacePath("");
diff --git a/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java b/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
index 17e6043..c59731b 100644
--- a/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
+++ b/base/src/com/google/idea/blaze/base/plugin/BlazeActionRemover.java
@@ -32,7 +32,7 @@
}
}
- private static void replaceAction(String actionId, AnAction newAction) {
+ public static void replaceAction(String actionId, AnAction newAction) {
ActionManager actionManager = ActionManager.getInstance();
AnAction oldAction = actionManager.getAction(actionId);
if (oldAction != null) {
diff --git a/base/src/com/google/idea/blaze/base/plugin/PluginUtils.java b/base/src/com/google/idea/blaze/base/plugin/PluginUtils.java
new file mode 100644
index 0000000..6156cbc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/plugin/PluginUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.collect.ImmutableSet;
+import com.intellij.ide.plugins.IdeaPluginDescriptor;
+import com.intellij.ide.plugins.PluginManager;
+import com.intellij.openapi.extensions.PluginId;
+import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginsAdvertiser;
+import com.intellij.openapi.util.EmptyRunnable;
+import com.intellij.pom.Navigatable;
+import com.intellij.pom.NavigatableAdapter;
+
+/** Utility methods for querying / manipulating other plugins. */
+public final class PluginUtils {
+
+ private PluginUtils() {}
+
+ /** If the plugin is already installed, enable it, otherwise both install and enable it. */
+ public static void installOrEnablePlugin(String pluginId) {
+ if (isPluginInstalled(pluginId)) {
+ PluginManager.enablePlugin(pluginId);
+ } else {
+ PluginsAdvertiser.installAndEnablePlugins(ImmutableSet.of(pluginId), EmptyRunnable.INSTANCE);
+ }
+ }
+
+ /** Returns a {@link Navigatable} which will install (if necessary) and enable the given plugin */
+ public static Navigatable installOrEnablePluginNavigable(String pluginId) {
+ return new NavigatableAdapter() {
+ @Override
+ public void navigate(boolean requestFocus) {
+ installOrEnablePlugin(pluginId);
+ }
+ };
+ }
+
+ public static boolean isPluginInstalled(String pluginId) {
+ return getPluginDescriptor(pluginId) != null;
+ }
+
+ public static boolean isPluginEnabled(String pluginId) {
+ IdeaPluginDescriptor descriptor = getPluginDescriptor(pluginId);
+ return descriptor != null && descriptor.isEnabled();
+ }
+
+ private static IdeaPluginDescriptor getPluginDescriptor(String pluginId) {
+ return PluginManager.getPlugin(PluginId.getId(pluginId));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java b/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java
index dcdc666..26c7491 100644
--- a/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchFileSource.java
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.prefetch;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.project.Project;
import java.io.File;
@@ -28,7 +29,10 @@
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);
+ Project project,
+ ProjectViewSet projectViewSet,
+ 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/PrefetchProjectInitializer.java b/base/src/com/google/idea/blaze/base/prefetch/PrefetchProjectInitializer.java
new file mode 100644
index 0000000..ed7b4cc
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchProjectInitializer.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.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.data.BlazeProjectDataManagerImpl;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.openapi.application.TransactionGuard;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.project.DumbModeTask;
+import com.intellij.openapi.project.DumbService;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.project.ProjectManagerAdapter;
+import com.intellij.util.TimeoutUtil;
+import java.io.IOException;
+import javax.annotation.Nullable;
+
+/** Run prefetching on project open, prior to initial indexing step. */
+public class PrefetchProjectInitializer extends ApplicationComponent.Adapter {
+
+ private static final Logger logger = Logger.getInstance(PrefetchProjectInitializer.class);
+
+ private static final BoolExperiment prefetchOnProjectOpen =
+ new BoolExperiment("prefetch.on.project.open2", true);
+
+ @Override
+ public void initComponent() {
+ ProjectManager projectManager = ProjectManager.getInstance();
+ projectManager.addProjectManagerListener(
+ new ProjectManagerAdapter() {
+ @Override
+ public void projectOpened(Project project) {
+ if (prefetchOnProjectOpen.getValue()) {
+ prefetchProjectFiles(project);
+ }
+ }
+ });
+ }
+
+ private static void prefetchProjectFiles(Project project) {
+ BlazeProjectData projectData = getBlazeProjectData(project);
+ if (projectData == null) {
+ return;
+ }
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectViewSet == null) {
+ return;
+ }
+ long start = System.currentTimeMillis();
+ ListenableFuture<?> future =
+ PrefetchService.getInstance().prefetchProjectFiles(project, projectViewSet, projectData);
+ TransactionGuard.submitTransaction(
+ project,
+ () -> {
+ DumbService.getInstance(project).queueTask(new PrefetchTask(future, start));
+ });
+ }
+
+ static class PrefetchTask extends DumbModeTask {
+ private final ListenableFuture<?> future;
+ private final long startTimeMillis;
+
+ private PrefetchTask(ListenableFuture<?> future, long startTimeMillis) {
+ this.future = future;
+ this.startTimeMillis = startTimeMillis;
+ }
+
+ @Override
+ public void performInDumbMode(ProgressIndicator indicator) {
+ indicator.setIndeterminate(true);
+ indicator.setText("Prefetching files...");
+ while (!future.isCancelled() && !future.isDone()) {
+ indicator.checkCanceled();
+ TimeoutUtil.sleep(100);
+ }
+ long end = System.currentTimeMillis();
+ logger.info(String.format("Initial prefetching took: %d ms", (end - startTimeMillis)));
+ }
+ }
+
+ @Nullable
+ private static BlazeProjectData getBlazeProjectData(Project project) {
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ if (importSettings == null) {
+ return null;
+ }
+ try {
+ return BlazeProjectDataManagerImpl.getImpl(project).loadProjectRoot(importSettings);
+ } catch (IOException e) {
+ // ignore: if we can't load the previous project data, we don't know what to prefetch
+ return null;
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java b/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
index fc5f5e2..726f970 100644
--- a/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchService.java
@@ -17,6 +17,7 @@
import com.google.common.util.concurrent.ListenableFuture;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import java.io.File;
@@ -31,5 +32,6 @@
/** Instructs all prefetchers to prefetch these files. */
ListenableFuture<?> prefetchFiles(Project project, Collection<File> files);
- ListenableFuture<?> prefetchProjectFiles(Project project, BlazeProjectData blazeProjectData);
+ ListenableFuture<?> prefetchProjectFiles(
+ Project project, ProjectViewSet projectViewSet, 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
index 8046db0..05e02a6 100644
--- a/base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java
+++ b/base/src/com/google/idea/blaze/base/prefetch/PrefetchServiceImpl.java
@@ -22,7 +22,6 @@
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;
@@ -47,11 +46,7 @@
@Override
public ListenableFuture<?> prefetchProjectFiles(
- Project project, BlazeProjectData blazeProjectData) {
- ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
- if (projectViewSet == null) {
- return Futures.immediateFuture(null);
- }
+ Project project, ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
BlazeImportSettings importSettings =
BlazeImportSettingsManager.getInstance(project).getImportSettings();
if (importSettings == null) {
@@ -68,7 +63,7 @@
files.add(workspaceRoot.fileForPath(workspacePath));
}
for (PrefetchFileSource fileSource : PrefetchFileSource.EP_NAME.getExtensions()) {
- fileSource.addFilesToPrefetch(project, blazeProjectData, files);
+ fileSource.addFilesToPrefetch(project, projectViewSet, blazeProjectData, files);
}
return prefetchFiles(project, files);
}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectView.java b/base/src/com/google/idea/blaze/base/projectview/ProjectView.java
index 8dfc6f3..4d09c18 100644
--- a/base/src/com/google/idea/blaze/base/projectview/ProjectView.java
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectView.java
@@ -17,11 +17,15 @@
import com.google.common.base.Objects;
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.SectionBuilder;
import com.google.idea.blaze.base.projectview.section.SectionKey;
import java.io.Serializable;
+import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
@@ -47,6 +51,32 @@
return result.build();
}
+ /** Returns all values from the given list section */
+ public <T> List<T> listItems(SectionKey<T, ListSection<T>> key) {
+ List<T> result = Lists.newArrayList();
+ for (ListSection<T> section : getSectionsOfType(key)) {
+ result.addAll(section.items());
+ }
+ 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 */
+ @Nullable
+ public <T> T getScalarValue(SectionKey<T, ScalarSection<T>> key, @Nullable T defaultValue) {
+ Collection<ScalarSection<T>> sections = getSectionsOfType(key);
+ if (sections.isEmpty()) {
+ return defaultValue;
+ } else {
+ return Iterables.getLast(sections).getValue();
+ }
+ }
+
public static Builder builder() {
return new Builder();
}
@@ -107,6 +137,11 @@
return this;
}
+ public <T> Builder remove(Section<T> section) {
+ sections.remove(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) {
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
index bab57dc..1635b84 100644
--- a/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewManagerImpl.java
@@ -28,8 +28,8 @@
import java.io.File;
import java.io.IOException;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Project view manager implementation. */
/** Stores mutable per-project user settings. */
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
index 1f3ed1f..e2e1211 100644
--- a/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewSet.java
@@ -63,7 +63,8 @@
}
/** Gets the last value from any scalar sections */
- public <T> T getScalarValue(SectionKey<T, ScalarSection<T>> key, T defaultValue) {
+ @Nullable
+ public <T> T getScalarValue(SectionKey<T, ScalarSection<T>> key, @Nullable T defaultValue) {
Collection<ScalarSection<T>> sections = getSections(key);
if (sections.isEmpty()) {
return defaultValue;
@@ -82,7 +83,7 @@
return result;
}
- public Collection<ProjectViewFile> getProjectViewFiles() {
+ public ImmutableList<ProjectViewFile> getProjectViewFiles() {
return projectViewFiles;
}
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
index 729b1d8..49a5d3b 100644
--- a/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewStorageManagerImpl.java
@@ -17,18 +17,16 @@
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 javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Project view storage implementation. */
final class ProjectViewStorageManagerImpl extends ProjectViewStorageManager {
- private static final Logger logger = Logger.getInstance(ProjectViewManagerImpl.class);
@Nullable
@Override
diff --git a/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java b/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
index 9b4b465..1d35932 100644
--- a/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
+++ b/base/src/com/google/idea/blaze/base/projectview/ProjectViewVerifier.java
@@ -29,11 +29,14 @@
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.LanguageSupport;
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import java.io.File;
import java.util.List;
+import javax.annotation.Nullable;
/** Verifies project views. */
public class ProjectViewVerifier {
@@ -48,6 +51,7 @@
/** Verifies the project view. Any errors are output to the context as issues. */
public static boolean verifyProjectView(
+ @Nullable Project project,
BlazeContext context,
WorkspacePathResolver workspacePathResolver,
ProjectViewSet projectViewSet,
@@ -56,10 +60,14 @@
return false;
}
for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- if (!syncPlugin.validateProjectView(context, projectViewSet, workspaceLanguageSettings)) {
+ if (!syncPlugin.validateProjectView(
+ project, context, projectViewSet, workspaceLanguageSettings)) {
return false;
}
}
+ if (!LanguageSupport.validateLanguageSettings(context, workspaceLanguageSettings)) {
+ return false;
+ }
warnAboutDeprecatedSections(context, projectViewSet);
if (!verifyIncludedPackagesExistOnDisk(context, workspacePathResolver, projectViewSet)) {
return false;
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
index a7b626a..6956bbb 100644
--- a/base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java
+++ b/base/src/com/google/idea/blaze/base/projectview/parser/ParseContext.java
@@ -15,6 +15,7 @@
*/
package com.google.idea.blaze.base.projectview.parser;
+import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.IssueOutput;
@@ -22,7 +23,7 @@
import com.google.idea.blaze.base.ui.BlazeValidationError;
import java.io.File;
import java.util.List;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Context for the project view parser. */
public class ParseContext {
@@ -55,7 +56,7 @@
this.context = context;
this.workspacePathResolver = workspacePathResolver;
this.file = file;
- this.lines = Lists.newArrayList(text.split("\n"));
+ this.lines = Lists.newArrayList(Splitter.on('\n').split(text));
this.currentLine = null;
this.currentLineIndex = -1;
consume();
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
index 2f4707f..5349ec2 100644
--- a/base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java
+++ b/base/src/com/google/idea/blaze/base/projectview/parser/ProjectViewParser.java
@@ -68,6 +68,11 @@
}
public void parseProjectView(String text) {
+ if (text.isEmpty()) {
+ ProjectView projectView = new ProjectView(ImmutableList.of());
+ projectViewFiles.add(new ProjectViewSet.ProjectViewFile(projectView, null));
+ return;
+ }
parseProjectView(new ParseContext(context, workspacePathResolver, null, text));
}
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
index bc1ed4a..9c7aafc 100644
--- a/base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java
+++ b/base/src/com/google/idea/blaze/base/projectview/section/LabelSectionParser.java
@@ -38,7 +38,7 @@
parseContext.addErrors(errors);
return null;
}
- return new Label(text);
+ return Label.create(text);
}
@Override
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
index 40ec7da..d3d9e06 100644
--- a/base/src/com/google/idea/blaze/base/projectview/section/ListSection.java
+++ b/base/src/com/google/idea/blaze/base/projectview/section/ListSection.java
@@ -19,7 +19,9 @@
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.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -82,7 +84,7 @@
/** Builder for list sections */
public static class Builder<T> extends SectionBuilder<T, ListSection<T>> {
- private final ImmutableList.Builder<ItemOrTextBlock<T>> items = ImmutableList.builder();
+ private final List<ItemOrTextBlock<T>> items = new ArrayList<>();
public Builder(SectionKey<T, ListSection<T>> sectionKey, @Nullable ListSection<T> section) {
super(sectionKey);
@@ -96,14 +98,26 @@
return this;
}
+ public final Builder<T> addAll(List<T> items) {
+ for (T item : items) {
+ add(item);
+ }
+ return this;
+ }
+
public final Builder<T> add(TextBlock textBlock) {
items.add(new ItemOrTextBlock<T>(textBlock));
return this;
}
+ public final Builder<T> remove(T item) {
+ items.remove(new ItemOrTextBlock<>(item));
+ return this;
+ }
+
@Override
public final ListSection<T> build() {
- return new ListSection<>(getSectionKey(), items.build());
+ return new ListSection<>(getSectionKey(), ImmutableList.copyOf(items));
}
}
}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/ProjectViewDefaultValueProvider.java b/base/src/com/google/idea/blaze/base/projectview/section/ProjectViewDefaultValueProvider.java
new file mode 100644
index 0000000..370295f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/ProjectViewDefaultValueProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.extensions.ExtensionPointName;
+
+/** Allows the adding default values to sections. Used during the wizard. */
+public interface ProjectViewDefaultValueProvider {
+ ExtensionPointName<ProjectViewDefaultValueProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.ProjectViewDefaultValueProvider");
+
+ ProjectView addProjectViewDefaultValue(
+ BuildSystem buildSystem, ProjectViewSet projectViewSet, ProjectView topLevelProjectView);
+
+ SectionKey<?, ?> getSectionKey();
+}
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
index 1e0f043..2c76bb6 100644
--- a/base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java
+++ b/base/src/com/google/idea/blaze/base/projectview/section/SectionParser.java
@@ -15,7 +15,6 @@
*/
package com.google.idea.blaze.base.projectview.section;
-import com.google.idea.blaze.base.projectview.ProjectView;
import com.google.idea.blaze.base.projectview.parser.ParseContext;
import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
import javax.annotation.Nullable;
@@ -52,9 +51,10 @@
return null;
}
- /** Allows the section to add a default value. Used during the wizard. */
- public ProjectView addProjectViewDefaultValue(ProjectView projectView) {
- return projectView;
+ /** A brief description of this section, used for in-IDE documentation. */
+ @Nullable
+ public String quickDocs() {
+ return null;
}
/** The type of item(s) in this section. */
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
index d9dc894..9e05e64 100644
--- 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
@@ -15,13 +15,21 @@
*/
package com.google.idea.blaze.base.projectview.section.sections;
+import com.google.common.collect.Ordering;
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.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.ProjectViewDefaultValueProvider;
import com.google.idea.blaze.base.projectview.section.SectionKey;
import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
+import java.util.Set;
import javax.annotation.Nullable;
/** Allows users to set the rule classes they want to be imported */
@@ -56,5 +64,45 @@
public ItemType getItemType() {
return ItemType.Other;
}
+
+ @Override
+ public String quickDocs() {
+ return "Additional languages to support in this project.";
+ }
+ }
+
+ static class AdditionalLanguagesDefaultValueProvider implements ProjectViewDefaultValueProvider {
+ @Override
+ public ProjectView addProjectViewDefaultValue(
+ BuildSystem buildSystem, ProjectViewSet projectViewSet, ProjectView topLevelProjectView) {
+ if (!topLevelProjectView.getSectionsOfType(KEY).isEmpty()) {
+ return topLevelProjectView;
+ }
+ Set<LanguageClass> additionalLanguages = availableAdditionalLanguages(projectViewSet);
+ if (additionalLanguages.isEmpty()) {
+ return topLevelProjectView;
+ }
+ ListSection.Builder<LanguageClass> builder = ListSection.builder(KEY);
+ builder.add(TextBlock.of(" # Uncomment any additional languages you want supported"));
+ additionalLanguages
+ .stream()
+ .sorted(Ordering.usingToString())
+ .map(lang -> " # " + lang.getName())
+ .forEach(string -> builder.add(TextBlock.of(string)));
+ builder.add(TextBlock.newLine());
+ return ProjectView.builder(topLevelProjectView).add(builder).build();
+ }
+
+ @Override
+ public SectionKey<?, ?> getSectionKey() {
+ return KEY;
+ }
+
+ private static Set<LanguageClass> availableAdditionalLanguages(ProjectViewSet projectView) {
+ WorkspaceType workspaceType =
+ projectView.getScalarValue(
+ WorkspaceTypeSection.KEY, LanguageSupport.getDefaultWorkspaceType());
+ return LanguageSupport.availableAdditionalLanguages(workspaceType);
+ }
}
}
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
index 588d289..51f0709 100644
--- 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
@@ -48,5 +48,10 @@
public ItemType getItemType() {
return ItemType.Other;
}
+
+ @Override
+ public String quickDocs() {
+ return "A set of flags that get passed to all build command invocations as arguments";
+ }
}
}
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
index cc1cb23..c470e37 100644
--- 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
@@ -18,12 +18,15 @@
import com.google.common.collect.Lists;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.projectview.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.ListSection;
import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.ProjectViewDefaultValueProvider;
import com.google.idea.blaze.base.projectview.section.SectionKey;
import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.google.idea.blaze.base.ui.BlazeValidationError;
import com.intellij.util.PathUtil;
import java.util.List;
@@ -69,16 +72,32 @@
}
@Override
- public ProjectView addProjectViewDefaultValue(ProjectView projectView) {
- if (!projectView.getSectionsOfType(KEY).isEmpty()) {
- return projectView;
+ public String quickDocs() {
+ return "A list of project directories that will be added as source.";
+ }
+ }
+
+ static class DirectoriesProjectViewDefaultValueProvider
+ implements ProjectViewDefaultValueProvider {
+ @Override
+ public ProjectView addProjectViewDefaultValue(
+ BuildSystem buildSystem, ProjectViewSet projectViewSet, ProjectView topLevelProjectView) {
+ if (!topLevelProjectView.getSectionsOfType(KEY).isEmpty()) {
+ return topLevelProjectView;
}
- return ProjectView.builder(projectView)
- .add(
- ListSection.builder(KEY)
- .add(TextBlock.of(" # Add the directories you want added as source here"))
- .add(TextBlock.newLine()))
- .build();
+ ListSection.Builder<DirectoryEntry> builder = ListSection.builder(KEY);
+ builder.add(TextBlock.of(" # Add the directories you want added as source here"));
+ if (buildSystem == BuildSystem.Bazel) {
+ builder.add(TextBlock.of(" # By default, we've added your entire workspace ('.')"));
+ builder.add(DirectoryEntry.include(new WorkspacePath(".")));
+ }
+ builder.add(TextBlock.newLine());
+ return ProjectView.builder(topLevelProjectView).add(builder).build();
+ }
+
+ @Override
+ public SectionKey<?, ?> getSectionKey() {
+ return KEY;
}
}
}
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
index e377b09..d054235 100644
--- 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
@@ -26,7 +26,7 @@
import com.google.idea.blaze.base.ui.BlazeValidationError;
import java.io.File;
import java.util.List;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** "import" section. */
public class ImportSection {
@@ -70,5 +70,10 @@
public ItemType getItemType() {
return ItemType.FileSystemItem;
}
+
+ @Override
+ public String quickDocs() {
+ return "Imports another project view.";
+ }
}
}
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/RunConfigurationsSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/RunConfigurationsSection.java
index 9ffda84..c3a8ef6 100644
--- a/base/src/com/google/idea/blaze/base/projectview/section/sections/RunConfigurationsSection.java
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/RunConfigurationsSection.java
@@ -59,5 +59,10 @@
public ItemType getItemType() {
return ItemType.FileSystemItem;
}
+
+ @Override
+ public String quickDocs() {
+ return "A list of XML files which will be imported as run configurations during sync.";
+ }
}
}
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
index 4d071a3..eda173f 100644
--- 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
@@ -36,7 +36,8 @@
ImportTargetOutputSection.PARSER,
ExcludeTargetSection.PARSER,
ExcludedSourceSection.PARSER,
- RunConfigurationsSection.PARSER);
+ RunConfigurationsSection.PARSER,
+ ShardBlazeBuildsSection.PARSER);
public static List<SectionParser> getParsers() {
List<SectionParser> parsers = Lists.newArrayList(PARSERS);
diff --git a/base/src/com/google/idea/blaze/base/projectview/section/sections/ShardBlazeBuildsSection.java b/base/src/com/google/idea/blaze/base/projectview/section/sections/ShardBlazeBuildsSection.java
new file mode 100644
index 0000000..0b75c8b
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/projectview/section/sections/ShardBlazeBuildsSection.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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 javax.annotation.Nullable;
+
+/** Set for particularly large projects to enable sharding blaze invocations during blaze sync. */
+public class ShardBlazeBuildsSection {
+ public static final SectionKey<Boolean, ScalarSection<Boolean>> KEY = SectionKey.of("shard_sync");
+ public static final SectionParser PARSER = new ShardBlazeSyncSectionParser();
+
+ private static class ShardBlazeSyncSectionParser extends ScalarSectionParser<Boolean> {
+ ShardBlazeSyncSectionParser() {
+ super(KEY, ':');
+ }
+
+ @Override
+ @Nullable
+ protected Boolean parseItem(ProjectViewParser parser, ParseContext parseContext, String text) {
+ if (text.equals("true")) {
+ return true;
+ }
+ if (text.equals("false")) {
+ return false;
+ }
+ parseContext.addError(
+ "'shard_sync' must be set to 'true' or 'false' (e.g. 'shard_sync: true')");
+ return null;
+ }
+
+ @Override
+ protected void printItem(StringBuilder sb, Boolean item) {
+ sb.append(item);
+ }
+
+ @Override
+ public ItemType getItemType() {
+ return ItemType.Other;
+ }
+
+ @Override
+ public String quickDocs() {
+ return "Allows sharding build invocations when syncing and compiling your project.";
+ }
+ }
+}
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
index cd69179..01e38c6 100644
--- 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
@@ -17,12 +17,16 @@
import com.google.idea.blaze.base.model.primitives.TargetExpression;
import com.google.idea.blaze.base.projectview.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.ListSection;
import com.google.idea.blaze.base.projectview.section.ListSectionParser;
+import com.google.idea.blaze.base.projectview.section.ProjectViewDefaultValueProvider;
import com.google.idea.blaze.base.projectview.section.SectionKey;
import com.google.idea.blaze.base.projectview.section.SectionParser;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import javax.annotation.Nullable;
/** "targets" section. */
public class TargetSection {
@@ -51,20 +55,35 @@
return ItemType.Label;
}
+ @Nullable
@Override
- public ProjectView addProjectViewDefaultValue(ProjectView projectView) {
- if (!projectView.getSectionsOfType(KEY).isEmpty()) {
- return projectView;
+ public String quickDocs() {
+ return "A list of build targets that will be included during sync. To resolve source files "
+ + "under a project directory, the source must be reachable from one of your targets.";
+ }
+ }
+
+ static class TargetsProjectViewDefaultValueProvider implements ProjectViewDefaultValueProvider {
+ @Override
+ public ProjectView addProjectViewDefaultValue(
+ BuildSystem buildSystem, ProjectViewSet projectViewSet, ProjectView topLevelProjectView) {
+ if (!topLevelProjectView.getSectionsOfType(KEY).isEmpty()) {
+ return topLevelProjectView;
}
- return ProjectView.builder(projectView)
- .add(
- ListSection.builder(KEY)
- .add(
- TextBlock.of(
- " # Add targets that reach the source code "
- + "that you want to resolve here"))
- .add(TextBlock.newLine()))
- .build();
+ ListSection.Builder<TargetExpression> builder = ListSection.builder(KEY);
+ builder.add(
+ TextBlock.of(" # Add targets that reach the source code that you want to resolve here"));
+ if (buildSystem == BuildSystem.Bazel) {
+ builder.add(TextBlock.of(" # By default, we've added all targets in your workspace"));
+ builder.add(TargetExpression.fromString("//..."));
+ }
+ builder.add(TextBlock.newLine());
+ return ProjectView.builder(topLevelProjectView).add(builder).build();
+ }
+
+ @Override
+ public SectionKey<?, ?> getSectionKey() {
+ return KEY;
}
}
}
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
index 44da7b0..309b765 100644
--- 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
@@ -24,5 +24,12 @@
/** 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);
+ public static final SectionParser PARSER =
+ new GlobSectionParser(KEY) {
+ @Override
+ public String quickDocs() {
+ return "A list of workspace-relative glob patterns. Determines which sources IntelliJ "
+ + "treats as test sources.";
+ }
+ };
}
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
index b12b781..1631179 100644
--- 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
@@ -137,5 +137,11 @@
public ItemType getItemType() {
return ItemType.Other;
}
+
+ @Nullable
+ @Override
+ public String quickDocs() {
+ return null;
+ }
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java
index 9448702..7f59707 100644
--- a/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java
+++ b/base/src/com/google/idea/blaze/base/run/BlazeCommandRunConfiguration.java
@@ -15,13 +15,18 @@
*/
package com.google.idea.blaze.base.run;
+import static java.util.stream.Collectors.toList;
+
import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
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.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.confighandler.BlazeCommandRunConfigurationHandler;
import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandlerProvider;
import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationRunner;
@@ -29,7 +34,10 @@
import com.google.idea.blaze.base.run.state.RunConfigurationStateEditor;
import com.google.idea.blaze.base.run.targetfinder.TargetFinder;
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.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
import com.google.idea.blaze.base.ui.UiUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
@@ -55,7 +63,6 @@
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.UIUtil;
import java.util.Collection;
-import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -496,17 +503,27 @@
}
private static Collection<String> getTargets(Project project) {
- List<String> result = Lists.newArrayList();
BlazeProjectData projectData =
BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (projectData != null) {
- for (TargetIdeInfo target : projectData.targetMap.targets()) {
- if (target.isPlainTarget()) {
- result.add(target.key.label.toString());
- }
- }
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (projectData == null || importSettings == null || projectViewSet == null) {
+ return ImmutableList.of();
}
- return result;
+ ImportRoots importRoots =
+ ImportRoots.builder(
+ WorkspaceRoot.fromImportSettings(importSettings), importSettings.getBuildSystem())
+ .add(projectViewSet)
+ .build();
+ return projectData
+ .targetMap
+ .targets()
+ .stream()
+ .filter(TargetIdeInfo::isPlainTarget)
+ .filter(target -> importRoots.importAsSource(target.key.label))
+ .map(target -> target.key.label.toString())
+ .collect(toList());
}
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java b/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
index 5a4daed..3b98ced 100644
--- a/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
+++ b/base/src/com/google/idea/blaze/base/run/BlazeRunConfiguration.java
@@ -16,7 +16,7 @@
package com.google.idea.blaze.base.run;
import com.google.idea.blaze.base.model.primitives.TargetExpression;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Marker interface for all run configurations */
public interface BlazeRunConfiguration {
diff --git a/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java b/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
index a1e0549..96be88d 100644
--- a/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
+++ b/base/src/com/google/idea/blaze/base/run/BlazeRunConfigurationSyncListener.java
@@ -34,6 +34,7 @@
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.openapi.project.Project;
import java.io.File;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -67,7 +68,7 @@
Set<Label> labelsWithConfigs = labelsWithConfigs(project);
Set<TargetExpression> targetExpressions =
- Sets.newHashSet(projectViewSet.listItems(TargetSection.KEY));
+ Sets.newLinkedHashSet(projectViewSet.listItems(TargetSection.KEY));
// We only auto-generate configurations for rules listed in the project view.
for (TargetExpression target : targetExpressions) {
if (!(target instanceof Label) || labelsWithConfigs.contains(target)) {
@@ -86,7 +87,7 @@
.listItems(RunConfigurationsSection.KEY)
.stream()
.map(pathResolver::resolveToFile)
- .collect(Collectors.toSet());
+ .collect(Collectors.toCollection(LinkedHashSet::new));
}
/** Collects a set of all the Blaze labels that have an associated run configuration. */
@@ -119,7 +120,7 @@
if (configurationFactory.handlesTarget(project, blazeProjectData, label)) {
final RunnerAndConfigurationSettings settings =
configurationFactory.createForTarget(project, runManager, label);
- runManager.addConfiguration(settings, false /* isShared */);
+ runManager.addConfiguration(settings, /* isShared */ false);
if (runManager.getSelectedConfiguration() == null) {
// TODO(joshgiles): Better strategy for picking initially selected config.
runManager.setSelectedConfiguration(settings);
diff --git a/base/src/com/google/idea/blaze/base/run/TargetNameHeuristic.java b/base/src/com/google/idea/blaze/base/run/TargetNameHeuristic.java
index c2cf40a..bf3cd6c 100644
--- a/base/src/com/google/idea/blaze/base/run/TargetNameHeuristic.java
+++ b/base/src/com/google/idea/blaze/base/run/TargetNameHeuristic.java
@@ -17,7 +17,9 @@
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.psi.PsiFile;
import java.io.File;
import javax.annotation.Nullable;
@@ -25,7 +27,12 @@
public class TargetNameHeuristic implements TestTargetHeuristic {
@Override
- public boolean matchesSource(TargetIdeInfo target, File sourceFile, @Nullable TestSize testSize) {
+ public boolean matchesSource(
+ Project project,
+ TargetIdeInfo target,
+ @Nullable PsiFile sourcePsiFile,
+ File sourceFile,
+ @Nullable TestSize testSize) {
String filePathWithoutExtension = FileUtil.getNameWithoutExtension(sourceFile.getPath());
String targetName = target.key.label.targetName().toString();
if (!filePathWithoutExtension.endsWith(targetName)) {
diff --git a/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java b/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java
index 67f899a..c30a55e 100644
--- a/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java
+++ b/base/src/com/google/idea/blaze/base/run/TestSizeHeuristic.java
@@ -18,6 +18,8 @@
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
import java.io.File;
import javax.annotation.Nullable;
@@ -25,7 +27,12 @@
public class TestSizeHeuristic implements TestTargetHeuristic {
@Override
- public boolean matchesSource(TargetIdeInfo target, File sourceFile, @Nullable TestSize testSize) {
+ public boolean matchesSource(
+ Project project,
+ TargetIdeInfo target,
+ @Nullable PsiFile sourcePsiFile,
+ 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;
diff --git a/base/src/com/google/idea/blaze/base/run/TestTargetHeuristic.java b/base/src/com/google/idea/blaze/base/run/TestTargetHeuristic.java
index 9f31b39..74a46e4 100644
--- a/base/src/com/google/idea/blaze/base/run/TestTargetHeuristic.java
+++ b/base/src/com/google/idea/blaze/base/run/TestTargetHeuristic.java
@@ -16,9 +16,10 @@
package com.google.idea.blaze.base.run;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
-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.ExtensionPointName;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -38,22 +39,18 @@
if (element == null) {
return null;
}
- File file = getContainingFile(element);
- if (file == null) {
- return null;
- }
- Collection<TargetIdeInfo> rules =
- TestTargetFinder.getInstance(element.getProject()).testTargetsForSourceFile(file);
- return chooseTestTargetForSourceFile(file, rules, null);
- }
-
- static File getContainingFile(PsiElement element) {
PsiFile psiFile = element.getContainingFile();
if (psiFile == null) {
return null;
}
VirtualFile vf = psiFile.getVirtualFile();
- return vf != null ? new File(vf.getPath()) : null;
+ File file = vf != null ? new File(vf.getPath()) : null;
+ if (file == null) {
+ return null;
+ }
+ Collection<TargetIdeInfo> rules =
+ TestTargetFinder.getInstance(element.getProject()).testTargetsForSourceFile(file);
+ return chooseTestTargetForSourceFile(element.getProject(), psiFile, file, rules, null);
}
/**
@@ -62,13 +59,19 @@
*/
@Nullable
static Label chooseTestTargetForSourceFile(
- File sourceFile, Collection<TargetIdeInfo> targets, @Nullable TestIdeInfo.TestSize testSize) {
+ Project project,
+ @Nullable PsiFile sourcePsiFile,
+ File sourceFile,
+ Collection<TargetIdeInfo> targets,
+ @Nullable TestSize testSize) {
for (TestTargetHeuristic filter : EP_NAME.getExtensions()) {
TargetIdeInfo match =
targets
.stream()
- .filter(target -> filter.matchesSource(target, sourceFile, testSize))
+ .filter(
+ target ->
+ filter.matchesSource(project, target, sourcePsiFile, sourceFile, testSize))
.findFirst()
.orElse(null);
@@ -81,5 +84,9 @@
/** Returns true if the rule and source file match, according to this heuristic. */
boolean matchesSource(
- TargetIdeInfo target, File sourceFile, @Nullable TestIdeInfo.TestSize testSize);
+ Project project,
+ TargetIdeInfo target,
+ @Nullable PsiFile sourcePsiFile,
+ File sourceFile,
+ @Nullable TestSize testSize);
}
diff --git a/base/src/com/google/idea/blaze/base/run/TestTargetSourcesHeuristic.java b/base/src/com/google/idea/blaze/base/run/TestTargetSourcesHeuristic.java
new file mode 100644
index 0000000..9a9fb9f
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/TestTargetSourcesHeuristic.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiFile;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/**
+ * Matches source files to test targets, if the source file is present in the test target's 'srcs'
+ * list. Only looks for exact matches.
+ */
+public class TestTargetSourcesHeuristic implements TestTargetHeuristic {
+
+ @Override
+ public boolean matchesSource(
+ Project project,
+ TargetIdeInfo target,
+ @Nullable PsiFile sourcePsiFile,
+ File sourceFile,
+ @Nullable TestSize testSize) {
+ BlazeProjectData projectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (projectData == null) {
+ return false;
+ }
+ ArtifactLocationDecoder decoder = projectData.artifactLocationDecoder;
+ for (ArtifactLocation src : target.sources) {
+ if (decoder.decode(src).equals(sourceFile)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/WithBrowserHyperlinkExecutionException.java b/base/src/com/google/idea/blaze/base/run/WithBrowserHyperlinkExecutionException.java
new file mode 100644
index 0000000..16b9c23
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/WithBrowserHyperlinkExecutionException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.intellij.execution.ExecutionException;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationListener;
+import com.intellij.ui.BrowserHyperlinkListener;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An {@link ExecutionException} containing a clickable browser hyperlink. It attempts to navigate
+ * to a URL formed from the hyperlink description verbatim.
+ */
+public class WithBrowserHyperlinkExecutionException extends ExecutionException
+ implements HyperlinkListener, NotificationListener {
+
+ public WithBrowserHyperlinkExecutionException(String string) {
+ super(string);
+ }
+
+ @Override
+ public final void hyperlinkUpdate(HyperlinkEvent e) {
+ if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ BrowserHyperlinkListener.INSTANCE.hyperlinkUpdate(e);
+ }
+ }
+
+ @Override
+ public final void hyperlinkUpdate(
+ @NotNull Notification notification, @NotNull HyperlinkEvent event) {
+ hyperlinkUpdate(event);
+ }
+}
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
index da3d641..6d8dcd7 100644
--- a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandler.java
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationHandler.java
@@ -72,7 +72,7 @@
@Override
@Nullable
public String getCommandName() {
- BlazeCommandName command = state.getCommand();
+ BlazeCommandName command = state.getCommandState().getCommand();
return command != null ? command.toString() : null;
}
diff --git a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationRunner.java b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationRunner.java
index 7c508e2..4605c17 100644
--- a/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationRunner.java
+++ b/base/src/com/google/idea/blaze/base/run/confighandler/BlazeCommandGenericRunConfigurationRunner.java
@@ -38,7 +38,6 @@
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.BoolExperiment;
import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
@@ -65,9 +64,6 @@
public final class BlazeCommandGenericRunConfigurationRunner
implements BlazeCommandRunConfigurationRunner {
- private static final BoolExperiment smRunnerUiEnabled =
- new BoolExperiment("use.smrunner.ui.general", true);
-
@Override
public RunProfileState getRunProfileState(Executor executor, ExecutionEnvironment environment) {
return new BlazeCommandRunProfileState(environment, ImmutableList.of());
@@ -152,9 +148,7 @@
new ScopedBlazeProcessHandler.ScopedProcessHandlerDelegate() {
@Override
public void onBlazeContextStart(BlazeContext context) {
- context
- .push(new IssuesScope(project))
- .push(new IdeaLogScope());
+ context.push(new IssuesScope(project)).push(new IdeaLogScope());
}
@Override
@@ -171,29 +165,28 @@
ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
assert projectViewSet != null;
+ String binaryPath =
+ handlerState.getBlazeBinaryState().getBlazeBinary() != null
+ ? handlerState.getBlazeBinaryState().getBlazeBinary()
+ : Blaze.getBuildSystemProvider(project).getBinaryPath();
+
BlazeCommand.Builder command =
- BlazeCommand.builder(Blaze.getBuildSystem(project), handlerState.getCommand())
- .setBlazeBinary(handlerState.getBlazeBinary())
+ BlazeCommand.builder(binaryPath, handlerState.getCommandState().getCommand())
.addTargets(configuration.getTarget())
.addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
.addBlazeFlags(testHandlerFlags)
- .addBlazeFlags(handlerState.getBlazeFlags())
- .addExeFlags(handlerState.getExeFlags());
+ .addBlazeFlags(handlerState.getBlazeFlagsState().getExpandedFlags())
+ .addExeFlags(handlerState.getExeFlagsState().getExpandedFlags());
- boolean runDistributed = handlerState.getRunOnDistributedExecutor();
command.addBlazeFlags(
DistributedExecutorSupport.getBlazeFlags(
- project, handlerState.getRunOnDistributedExecutor()));
- if (!runDistributed) {
- command.addBlazeFlags(BlazeFlags.TEST_OUTPUT_STREAMED);
- }
+ project, handlerState.getRunOnDistributedExecutorState().runOnDistributedExecutor));
return command.build();
}
private boolean canUseTestUi() {
- return smRunnerUiEnabled.getValue()
- && BlazeCommandName.TEST.equals(handlerState.getCommand())
- && !handlerState.getRunOnDistributedExecutor();
+ return BlazeCommandName.TEST.equals(handlerState.getCommandState().getCommand())
+ && !handlerState.getRunOnDistributedExecutorState().runOnDistributedExecutor;
}
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/filter/BlazeTargetFilter.java b/base/src/com/google/idea/blaze/base/run/filter/BlazeTargetFilter.java
index 1cf0e0c..2e4f9ea 100644
--- a/base/src/com/google/idea/blaze/base/run/filter/BlazeTargetFilter.java
+++ b/base/src/com/google/idea/blaze/base/run/filter/BlazeTargetFilter.java
@@ -15,6 +15,7 @@
*/
package com.google.idea.blaze.base.run.filter;
+import com.google.common.annotations.VisibleForTesting;
import com.google.idea.blaze.base.lang.buildfile.references.BuildReferenceManager;
import com.google.idea.blaze.base.lang.buildfile.references.LabelUtils;
import com.google.idea.blaze.base.model.primitives.Label;
@@ -23,14 +24,24 @@
import com.intellij.openapi.project.Project;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
+import java.util.ArrayList;
+import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Parse blaze targets in streamed output. */
public class BlazeTargetFilter implements Filter {
- private static final Pattern TARGET_PATTERN = Pattern.compile("//([^\\s:]*):(\\S*)");
+ // See Bazel's LabelValidator class. Whitespace character intentionally not included here.
+ private static final String PACKAGE_NAME_CHARS = "a-zA-Z0-9/\\-\\._$()";
+ private static final String TARGET_CHARS = "a-zA-Z0-9+,=~#()$_@\\-";
+
+ private static final String TARGET_REGEX =
+ String.format(
+ "(@[%s]*)?//[%s]*(:[%s]*)?", PACKAGE_NAME_CHARS, PACKAGE_NAME_CHARS, TARGET_CHARS);
+
+ @VisibleForTesting static final Pattern TARGET_PATTERN = Pattern.compile(TARGET_REGEX);
private final Project project;
@@ -42,20 +53,21 @@
@Override
public Result applyFilter(String line, int entireLength) {
Matcher matcher = TARGET_PATTERN.matcher(line);
- if (!matcher.find()) {
- return null;
+ List<ResultItem> results = new ArrayList<>();
+ while (matcher.find()) {
+ String labelString = matcher.group();
+ Label label = LabelUtils.createLabelFromString(null, labelString);
+ if (label == null) {
+ continue;
+ }
+ PsiElement psi = BuildReferenceManager.getInstance(project).resolveLabel(label);
+ if (!(psi instanceof NavigatablePsiElement)) {
+ continue;
+ }
+ HyperlinkInfo link = project -> ((NavigatablePsiElement) psi).navigate(true);
+ int offset = entireLength - line.length();
+ results.add(new ResultItem(matcher.start() + offset, matcher.end() + offset, link));
}
- String labelString = matcher.group();
- Label label = LabelUtils.createLabelFromString(null, labelString);
- if (label == null) {
- return null;
- }
- PsiElement psi = BuildReferenceManager.getInstance(project).resolveLabel(label);
- if (!(psi instanceof NavigatablePsiElement)) {
- return null;
- }
- HyperlinkInfo link = project -> ((NavigatablePsiElement) psi).navigate(true);
- int offset = entireLength - line.length();
- return new Result(matcher.start() + offset, matcher.end() + offset, link);
+ return results.isEmpty() ? null : new Result(results);
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/filter/StandardFileResolver.java b/base/src/com/google/idea/blaze/base/run/filter/StandardFileResolver.java
index 15a3d09..652c2a5 100644
--- a/base/src/com/google/idea/blaze/base/run/filter/StandardFileResolver.java
+++ b/base/src/com/google/idea/blaze/base/run/filter/StandardFileResolver.java
@@ -21,6 +21,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import java.io.File;
+import java.io.IOException;
import javax.annotation.Nullable;
/** Parses absolute and workspace-relative paths. */
@@ -31,7 +32,9 @@
public VirtualFile resolveToFile(Project project, String fileString) {
File file = new File(fileString);
if (file.isAbsolute()) {
- return VirtualFileSystemProvider.getInstance().getSystem().findFileByPath(file.getPath());
+ return VirtualFileSystemProvider.getInstance()
+ .getSystem()
+ .findFileByPath(getCanonicalPathSafe(file));
}
BlazeProjectData projectData =
BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
@@ -41,4 +44,16 @@
file = projectData.workspacePathResolver.resolveToFile(fileString);
return VirtualFileSystemProvider.getInstance().getSystem().findFileByPath(file.getPath());
}
+
+ /**
+ * Swallows {@link IOException}s, falling back to returning the absolute, possibly non-canonical
+ * path.
+ */
+ private static String getCanonicalPathSafe(File file) {
+ try {
+ return file.getCanonicalPath();
+ } catch (IOException e) {
+ return file.getAbsolutePath();
+ }
+ }
}
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
index 154a9be..d344018 100644
--- a/base/src/com/google/idea/blaze/base/run/producers/AllInPackageBlazeConfigurationProducer.java
+++ b/base/src/com/google/idea/blaze/base/run/producers/AllInPackageBlazeConfigurationProducer.java
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.run.producers;
import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.lang.buildfile.search.BlazePackage;
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;
@@ -61,7 +62,7 @@
if (handlerState == null) {
return false;
}
- handlerState.setCommand(BlazeCommandName.TEST);
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
configuration.setGeneratedName();
return true;
}
@@ -84,7 +85,7 @@
if (handlerState == null) {
return false;
}
- return Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)
+ return Objects.equals(handlerState.getCommandState().getCommand(), BlazeCommandName.TEST)
&& Objects.equals(
configuration.getTarget(), TargetExpression.allFromPackageRecursive(packagePath));
}
@@ -93,13 +94,11 @@
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;
- }
+ if (!(location instanceof PsiDirectory)) {
+ return null;
}
- return null;
+ PsiDirectory dir = (PsiDirectory) location;
+ return isInWorkspace(root, dir) && BlazePackage.hasBlazePackageChild(dir) ? dir : null;
}
@Nullable
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
index 60faff7..9a838ed 100644
--- a/base/src/com/google/idea/blaze/base/run/producers/BlazeBuildFileRunConfigurationProducer.java
+++ b/base/src/com/google/idea/blaze/base/run/producers/BlazeBuildFileRunConfigurationProducer.java
@@ -195,8 +195,9 @@
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
if (handlerState != null) {
// TODO move the old test rule functionality to a BlazeRunConfigurationFactory
- handlerState.setCommand(
- Kind.isTestRule(target.ruleType) ? BlazeCommandName.TEST : BlazeCommandName.BUILD);
+ BlazeCommandName command =
+ Kind.isTestRule(target.ruleType) ? BlazeCommandName.TEST : BlazeCommandName.BUILD;
+ handlerState.getCommandState().setCommand(command);
}
configuration.setGeneratedName();
}
diff --git a/base/src/com/google/idea/blaze/base/run/producers/BlazeFilterExistingRunConfigurationProducer.java b/base/src/com/google/idea/blaze/base/run/producers/BlazeFilterExistingRunConfigurationProducer.java
index feae47b..92089e4 100644
--- a/base/src/com/google/idea/blaze/base/run/producers/BlazeFilterExistingRunConfigurationProducer.java
+++ b/base/src/com/google/idea/blaze/base/run/producers/BlazeFilterExistingRunConfigurationProducer.java
@@ -59,14 +59,20 @@
}
BlazeCommandRunConfigurationCommonState handlerState =
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
- if (handlerState == null || !BlazeCommandName.TEST.equals(handlerState.getCommand())) {
+ if (handlerState == null
+ || !BlazeCommandName.TEST.equals(handlerState.getCommandState().getCommand())) {
return false;
}
// replace old test filter flag if present
- List<String> flags = new ArrayList<>(handlerState.getBlazeFlags());
+ List<String> flags = new ArrayList<>(handlerState.getBlazeFlagsState().getRawFlags());
flags.removeIf((flag) -> flag.startsWith(BlazeFlags.TEST_FILTER));
flags.add(testFilter);
- handlerState.setBlazeFlags(flags);
+
+ if (SmRunnerUtils.countSelectedTestCases(context) == 1
+ && !flags.contains(BlazeFlags.DISABLE_TEST_SHARDING)) {
+ flags.add(BlazeFlags.DISABLE_TEST_SHARDING);
+ }
+ handlerState.getBlazeFlagsState().setRawFlags(flags);
configuration.setName(configuration.getName() + " (filtered)");
configuration.setNameChangedByUser(true);
return true;
@@ -83,7 +89,7 @@
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
return handlerState != null
- && Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)
+ && Objects.equals(handlerState.getCommandState().getCommand(), BlazeCommandName.TEST)
&& Objects.equals(testFilter, handlerState.getTestFilterFlag());
}
diff --git a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeCompositeTestEventsHandler.java b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeCompositeTestEventsHandler.java
index 5d86bdf..21bf76a 100644
--- a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeCompositeTestEventsHandler.java
+++ b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeCompositeTestEventsHandler.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.smrunner.BlazeXmlSchema.TestSuite;
import com.intellij.execution.Location;
import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction;
import com.intellij.execution.testframework.sm.runner.SMTestLocator;
@@ -95,6 +96,12 @@
return null;
}
+ @Override
+ public boolean ignoreSuite(@Nullable Kind kind, TestSuite suite) {
+ BlazeTestEventsHandler handler = kind != null ? getHandlers().get(kind) : null;
+ return handler != null ? handler.ignoreSuite(kind, suite) : super.ignoreSuite(kind, suite);
+ }
+
/** Converts the testsuite name in the blaze test XML to a user-friendly format */
@Override
public String suiteDisplayName(@Nullable Kind kind, String rawName) {
diff --git a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeRerunFailedTestsAction.java b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeRerunFailedTestsAction.java
index 2522bab..578bb9b 100644
--- a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeRerunFailedTestsAction.java
+++ b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeRerunFailedTestsAction.java
@@ -80,13 +80,15 @@
throws ExecutionException {
BlazeCommandRunConfigurationCommonState handlerState =
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
- if (handlerState == null || !BlazeCommandName.TEST.equals(handlerState.getCommand())) {
+ if (handlerState == null
+ || !BlazeCommandName.TEST.equals(handlerState.getCommandState().getCommand())) {
return null;
}
Project project = getProject();
List<Location<?>> locations =
getFailedTests(project)
.stream()
+ .filter(AbstractTestProxy::isLeaf)
.map((test) -> toLocation(project, test))
.filter(Objects::nonNull)
.collect(Collectors.toList());
@@ -94,8 +96,9 @@
if (testFilter == null) {
return null;
}
- List<String> blazeFlags = setTestFilter(handlerState.getBlazeFlags(), testFilter);
- handlerState.setBlazeFlags(blazeFlags);
+ List<String> blazeFlags =
+ setTestFilter(handlerState.getBlazeFlagsState().getRawFlags(), testFilter);
+ handlerState.getBlazeFlagsState().setRawFlags(blazeFlags);
return configuration.getState(executor, environment);
}
diff --git a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeTestEventsHandler.java b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeTestEventsHandler.java
index 2f3286f..3ecdeea 100644
--- a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeTestEventsHandler.java
+++ b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeTestEventsHandler.java
@@ -44,18 +44,17 @@
/**
* Blaze/Bazel flags required for test UI.<br>
- * Forces local test execution, without sharding.
+ * Forces local test execution, without retries.
*/
public static ImmutableList<String> getBlazeFlags(Project project) {
ImmutableList.Builder<String> flags =
- ImmutableList.<String>builder()
- .add(
- "--test_sharding_strategy=disabled",
- "--runs_per_test=1",
- "--flaky_test_attempts=1");
+ ImmutableList.<String>builder().add("--runs_per_test=1", "--flaky_test_attempts=1");
if (Blaze.getBuildSystem(project) == BuildSystem.Blaze) {
flags.add("--test_strategy=local");
}
+ if (Blaze.getBuildSystem(project) == BuildSystem.Bazel) {
+ flags.add("--test_sharding_strategy=disabled");
+ }
return flags.build();
}
@@ -117,16 +116,16 @@
public String testLocationUrl(
@Nullable Kind kind, String parentSuite, String name, @Nullable String className) {
- String base = SmRunnerUtils.GENERIC_TEST_PROTOCOL + URLUtil.SCHEME_SEPARATOR + name;
+ String base = SmRunnerUtils.GENERIC_TEST_PROTOCOL + URLUtil.SCHEME_SEPARATOR;
if (Strings.isNullOrEmpty(className)) {
- return base;
+ return base + name;
}
- return base + SmRunnerUtils.TEST_NAME_PARTS_SPLITTER + className;
+ return base + className + SmRunnerUtils.TEST_NAME_PARTS_SPLITTER + name;
}
/** Whether to skip logging a {@link TestSuite}. */
- public boolean ignoreSuite(TestSuite suite) {
+ public boolean ignoreSuite(@Nullable Kind kind, TestSuite suite) {
// by default only include innermost 'testsuite' elements
- return suite.testSuites.isEmpty();
+ return !suite.testSuites.isEmpty();
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchema.java b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchema.java
index 4126bc8..f1f053a 100644
--- a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchema.java
+++ b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchema.java
@@ -18,6 +18,7 @@
import com.google.common.collect.Lists;
import java.io.InputStream;
import java.util.List;
+import java.util.Objects;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAttribute;
@@ -95,6 +96,40 @@
@XmlElement(name = "testcase")
List<TestCase> testCases = Lists.newArrayList();
+
+ /** Used to merge test suites from a single target, split across multiple shards */
+ private void addSuite(TestSuite suite) {
+ for (TestSuite existing : testSuites) {
+ if (Objects.equals(existing.name, suite.name)) {
+ existing.mergeWithSuite(suite);
+ return;
+ }
+ }
+ testSuites.add(suite);
+ }
+
+ private void mergeWithSuite(TestSuite suite) {
+ for (TestSuite child : suite.testSuites) {
+ addSuite(child);
+ }
+ testDecorators.addAll(suite.testDecorators);
+ testCases.addAll(suite.testCases);
+ tests += suite.tests;
+ failures += suite.failures;
+ errors += suite.errors;
+ skipped += suite.skipped;
+ disabled += suite.disabled;
+ time += suite.time;
+ }
+ }
+
+ /** Used to merge test suites from a single target, split across multiple shards */
+ static TestSuite mergeSuites(List<TestSuite> suites) {
+ TestSuite outer = new TestSuite();
+ for (TestSuite suite : suites) {
+ outer.addSuite(suite);
+ }
+ return outer;
}
static class TestCase {
diff --git a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlToTestEventsConverter.java b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlToTestEventsConverter.java
index 548557a..0cdee3b 100644
--- a/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlToTestEventsConverter.java
+++ b/base/src/com/google/idea/blaze/base/run/smrunner/BlazeXmlToTestEventsConverter.java
@@ -22,8 +22,8 @@
import com.google.idea.blaze.base.run.smrunner.BlazeXmlSchema.TestCase;
import com.google.idea.blaze.base.run.smrunner.BlazeXmlSchema.TestSuite;
import com.google.idea.blaze.base.run.targetfinder.TargetFinder;
-import com.google.idea.blaze.base.run.testlogs.BlazeTestXmlFinderStrategy;
-import com.google.idea.blaze.base.run.testlogs.CompletedTestTarget;
+import com.google.idea.blaze.base.run.testlogs.BlazeTestResultFinderStrategy;
+import com.google.idea.blaze.base.run.testlogs.BlazeTestResults;
import com.google.idea.sdkcompat.smrunner.SmRunnerCompatUtils;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.testframework.TestConsoleProperties;
@@ -37,9 +37,13 @@
import com.intellij.execution.testframework.sm.runner.events.TestSuiteStartedEvent;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
+import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import javax.annotation.Nullable;
import jetbrains.buildServer.messages.serviceMessages.ServiceMessageVisitor;
import jetbrains.buildServer.messages.serviceMessages.TestSuiteStarted;
@@ -87,14 +91,46 @@
onStartTesting();
getProcessor().onTestsReporterAttached();
- for (CompletedTestTarget testTarget : BlazeTestXmlFinderStrategy.locateTestXmlFiles(project)) {
- try (InputStream input = new FileInputStream(testTarget.testResultXml)) {
- parseXmlInput(getProcessor(), getKind(project, testTarget.label), input);
+ BlazeTestResults testResults = BlazeTestResultFinderStrategy.locateTestResults(project);
+ for (Label target : testResults.failedTargets) {
+ reportFailedTarget(target);
+ }
+ for (Label label : testResults.testXmlFiles.keySet()) {
+ processTestSuites(label, testResults.testXmlFiles.get(label));
+ }
+ }
+
+ private void reportFailedTarget(Label label) {
+ GeneralTestEventsProcessor processor = getProcessor();
+ TestSuiteStarted suiteStarted = new TestSuiteStarted(label.toString());
+ processor.onSuiteStarted(new TestSuiteStartedEvent(suiteStarted, null));
+ String targetName = label.targetName().toString();
+ processor.onTestStarted(new TestStartedEvent(targetName, null));
+ processor.onTestFailure(
+ SmRunnerCompatUtils.getTestFailedEvent(
+ targetName, "Target failed to build. See console output for details", null, 0));
+ processor.onTestFinished(new TestFinishedEvent(targetName, 0L));
+ processor.onSuiteFinished(new TestSuiteFinishedEvent(label.toString()));
+ }
+
+ /** Process all test XML files from a single test target. */
+ private void processTestSuites(Label label, Collection<File> files) {
+ Kind kind = getKind(project, label);
+ List<TestSuite> targetSuites = new ArrayList<>();
+ for (File file : files) {
+ try (InputStream input = new FileInputStream(file)) {
+ targetSuites.add(BlazeXmlSchema.parse(input));
} catch (Exception e) {
// ignore parsing errors -- most common cause is user cancellation, which we can't easily
// recognize.
}
}
+ if (targetSuites.isEmpty()) {
+ return;
+ }
+ TestSuite suite =
+ targetSuites.size() == 1 ? targetSuites.get(0) : BlazeXmlSchema.mergeSuites(targetSuites);
+ processTestSuite(getProcessor(), kind, suite);
}
@Nullable
@@ -103,19 +139,13 @@
return target != null ? target.kind : null;
}
- private void parseXmlInput(
- GeneralTestEventsProcessor processor, @Nullable Kind kind, InputStream input) {
- TestSuite testResult = BlazeXmlSchema.parse(input);
- processTestSuite(processor, kind, testResult);
- }
-
private void processTestSuite(
GeneralTestEventsProcessor processor, @Nullable Kind kind, TestSuite suite) {
if (!hasRunChild(suite)) {
return;
}
// only include the innermost 'testsuite' element
- boolean logSuite = !eventsHandler.ignoreSuite(suite);
+ boolean logSuite = !eventsHandler.ignoreSuite(kind, suite);
if (suite.name != null && logSuite) {
TestSuiteStarted suiteStarted =
new TestSuiteStarted(eventsHandler.suiteDisplayName(kind, suite.name));
diff --git a/base/src/com/google/idea/blaze/base/run/smrunner/SmRunnerUtils.java b/base/src/com/google/idea/blaze/base/run/smrunner/SmRunnerUtils.java
index b9e80ba..54f6595 100644
--- a/base/src/com/google/idea/blaze/base/run/smrunner/SmRunnerUtils.java
+++ b/base/src/com/google/idea/blaze/base/run/smrunner/SmRunnerUtils.java
@@ -33,8 +33,10 @@
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.search.GlobalSearchScope;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.swing.tree.TreePath;
@@ -88,6 +90,26 @@
}
public static List<Location<?>> getSelectedSmRunnerTreeElements(ConfigurationContext context) {
+ Project project = context.getProject();
+ List<SMTestProxy> tests = getSelectedTestProxies(context);
+ return tests
+ .stream()
+ .map(test -> (Location<?>) test.getLocation(project, GlobalSearchScope.allScope(project)))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ /** Counts all selected test cases, and their children, recursively */
+ public static int countSelectedTestCases(ConfigurationContext context) {
+ List<SMTestProxy> tests = getSelectedTestProxies(context);
+ Set<SMTestProxy> allTests = new HashSet<>(tests);
+ for (SMTestProxy test : tests) {
+ allTests.addAll(test.collectChildren());
+ }
+ return allTests.size();
+ }
+
+ private static List<SMTestProxy> getSelectedTestProxies(ConfigurationContext context) {
SMTRunnerTestTreeView treeView =
SMTRunnerTestTreeView.SM_TEST_RUNNER_VIEW.getData(context.getDataContext());
if (treeView == null) {
@@ -98,18 +120,16 @@
return ImmutableList.of();
}
return Arrays.stream(paths)
- .map((path) -> toLocation(context.getProject(), treeView, path))
+ .map((path) -> toTestProxy(treeView, path))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Nullable
- private static Location<?> toLocation(
- Project project, SMTRunnerTestTreeView treeView, TreePath path) {
+ private static SMTestProxy toTestProxy(SMTRunnerTestTreeView treeView, TreePath path) {
if (treeView.isPathSelected(path.getParentPath())) {
return null;
}
- SMTestProxy test = treeView.getSelectedTest(path);
- return test != null ? test.getLocation(project, GlobalSearchScope.allScope(project)) : null;
+ return treeView.getSelectedTest(path);
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonState.java b/base/src/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonState.java
index ef2ec8e..082f4be 100644
--- a/base/src/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonState.java
+++ b/base/src/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonState.java
@@ -23,7 +23,6 @@
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.openapi.project.Project;
import java.io.File;
-import java.util.List;
import javax.annotation.Nullable;
/**
@@ -49,46 +48,32 @@
addStates(command, blazeFlags, exeFlags, blazeBinary, runOnDistributedExecutor);
}
- @Nullable
- public BlazeCommandName getCommand() {
- return command.getCommand();
- }
-
/** @return The list of blaze flags that the user specified manually. */
- public List<String> getBlazeFlags() {
- return blazeFlags.getFlags();
+ public RunConfigurationFlagsState getBlazeFlagsState() {
+ return blazeFlags;
}
/** @return The list of executable flags the user specified manually. */
- public List<String> getExeFlags() {
- return exeFlags.getFlags();
+ public RunConfigurationFlagsState getExeFlagsState() {
+ return exeFlags;
}
- @Nullable
- public String getBlazeBinary() {
- return blazeBinary.getBlazeBinary();
+ public BlazeBinaryState getBlazeBinaryState() {
+ return blazeBinary;
}
- public void setCommand(@Nullable BlazeCommandName command) {
- this.command.setCommand(command);
+ public BlazeCommandState getCommandState() {
+ return command;
}
- public void setBlazeFlags(List<String> flags) {
- this.blazeFlags.setFlags(flags);
- }
-
- public void setExeFlags(List<String> flags) {
- this.exeFlags.setFlags(flags);
- }
-
- public void setBlazeBinary(@Nullable String blazeBinary) {
- this.blazeBinary.setBlazeBinary(blazeBinary);
+ public BlazeRunOnDistributedExecutorState getRunOnDistributedExecutorState() {
+ return runOnDistributedExecutor;
}
/** Searches through all blaze flags for the first one beginning with '--test_filter' */
@Nullable
public String getTestFilterFlag() {
- for (String flag : getBlazeFlags()) {
+ for (String flag : getBlazeFlagsState().getExpandedFlags()) {
if (flag.startsWith(BlazeFlags.TEST_FILTER)) {
return flag;
}
@@ -96,19 +81,11 @@
return null;
}
- public boolean getRunOnDistributedExecutor() {
- return runOnDistributedExecutor.runOnDistributedExecutor;
- }
-
- public void setRunOnDistributedExecutor(boolean runOnDistributedExecutor) {
- this.runOnDistributedExecutor.runOnDistributedExecutor = runOnDistributedExecutor;
- }
-
public void validate(String buildSystemName) throws RuntimeConfigurationException {
- if (getCommand() == null) {
+ if (getCommandState().getCommand() == null) {
throw new RuntimeConfigurationError("You must specify a command.");
}
- String blazeBinaryString = getBlazeBinary();
+ String blazeBinaryString = getBlazeBinaryState().getBlazeBinary();
if (blazeBinaryString != null && !(new File(blazeBinaryString).exists())) {
throw new RuntimeConfigurationError(buildSystemName + " binary does not exist");
}
@@ -135,7 +112,7 @@
// this editor needs to update based on state provided by other children.
if (runOnExecutorEditor != null) {
- boolean isTest = BlazeCommandName.TEST.equals(state.getCommand());
+ boolean isTest = BlazeCommandName.TEST.equals(state.getCommandState().getCommand());
runOnExecutorEditor.updateVisibility(isTest);
}
}
diff --git a/base/src/com/google/idea/blaze/base/run/state/RunConfigurationFlagsState.java b/base/src/com/google/idea/blaze/base/run/state/RunConfigurationFlagsState.java
index 87d306c..9cb8a3c 100644
--- a/base/src/com/google/idea/blaze/base/run/state/RunConfigurationFlagsState.java
+++ b/base/src/com/google/idea/blaze/base/run/state/RunConfigurationFlagsState.java
@@ -17,6 +17,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.command.BlazeFlags;
import com.google.idea.blaze.base.ui.UiUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
@@ -42,11 +43,17 @@
this.fieldLabel = fieldLabel;
}
- public List<String> getFlags() {
+ /** @return Flags subject to macro expansion. */
+ public List<String> getExpandedFlags() {
+ return BlazeFlags.expandBuildFlags(flags);
+ }
+
+ /** @return Raw flags that haven't been macro expanded */
+ public List<String> getRawFlags() {
return flags;
}
- public void setFlags(List<String> flags) {
+ public void setRawFlags(List<String> flags) {
this.flags = ImmutableList.copyOf(flags);
}
@@ -118,13 +125,13 @@
@Override
public void resetEditorFrom(RunConfigurationState genericState) {
RunConfigurationFlagsState state = (RunConfigurationFlagsState) genericState;
- flagsField.setText(makeFlagString(state.getFlags()));
+ flagsField.setText(makeFlagString(state.getRawFlags()));
}
@Override
public void applyEditorTo(RunConfigurationState genericState) {
RunConfigurationFlagsState state = (RunConfigurationFlagsState) genericState;
- state.setFlags(ParametersListUtil.parse(Strings.nullToEmpty(flagsField.getText())));
+ state.setRawFlags(ParametersListUtil.parse(Strings.nullToEmpty(flagsField.getText())));
}
@Override
diff --git a/base/src/com/google/idea/blaze/base/run/targetfinder/TargetFinder.java b/base/src/com/google/idea/blaze/base/run/targetfinder/TargetFinder.java
index cc88533..23a03a2 100644
--- a/base/src/com/google/idea/blaze/base/run/targetfinder/TargetFinder.java
+++ b/base/src/com/google/idea/blaze/base/run/targetfinder/TargetFinder.java
@@ -35,7 +35,7 @@
@Nullable
public TargetIdeInfo targetForLabel(Project project, final Label label) {
- return findTarget(project, target -> target.key.label.equals(label));
+ return findTarget(project, target -> target.key.label.equals(label) && target.isPlainTarget());
}
public ImmutableList<TargetIdeInfo> targetsOfKinds(Project project, final Kind... kinds) {
diff --git a/base/src/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParser.java b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParser.java
index 9993c83..6920313 100644
--- a/base/src/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParser.java
+++ b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParser.java
@@ -36,6 +36,8 @@
private static final Logger logger = Logger.getInstance(BlazeCommandLogParser.class);
private static final Pattern TEST_LOG = Pattern.compile("^(//[^\\s]*) .*? (PASSED|FAILED)");
+ private static final Pattern FAILED_TARGET =
+ Pattern.compile("^Target (//[^\\s]*) failed to build");
/** Finds log location and target label for all tests listed in the master log. */
public static ImmutableSet<Label> parseTestTargets(File commandLog) {
@@ -47,6 +49,25 @@
}
}
+ /** Finds the targets which failed to build */
+ public static ImmutableSet<Label> parseFailedTargets(File commandLog) {
+ try (Stream<String> stream = Files.lines(Paths.get(commandLog.getPath()))) {
+ return parseTestTargets(stream);
+ } catch (IOException e) {
+ logger.warn("Error parsing master log", e);
+ return ImmutableSet.of();
+ }
+ }
+
+ @VisibleForTesting
+ static ImmutableSet<Label> parseFailedTargets(Stream<String> lines) {
+ return ImmutableSet.copyOf(
+ lines
+ .map(BlazeCommandLogParser::parseBuildFailure)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet()));
+ }
+
@VisibleForTesting
static ImmutableSet<Label> parseTestTargets(Stream<String> lines) {
return ImmutableSet.copyOf(
@@ -65,4 +86,14 @@
}
return Label.createIfValid(match.group(1));
}
+
+ @Nullable
+ @VisibleForTesting
+ static Label parseBuildFailure(String line) {
+ Matcher match = FAILED_TARGET.matcher(line);
+ if (!match.find()) {
+ return null;
+ }
+ return Label.createIfValid(match.group(1));
+ }
}
diff --git a/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestResultFinderStrategy.java b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestResultFinderStrategy.java
new file mode 100644
index 0000000..cff8bd4
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestResultFinderStrategy.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.testlogs;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** A strategy for locating results from 'blaze test' invocation (e.g. output XML files). */
+public interface BlazeTestResultFinderStrategy {
+
+ ExtensionPointName<BlazeTestResultFinderStrategy> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BlazeTestXmlFinderStrategy");
+
+ /**
+ * Attempt to find all output test XML files produced by the most recent blaze invocation, grouped
+ * by target label.
+ */
+ @Nullable
+ static BlazeTestResults locateTestResults(Project project) {
+ BuildSystem buildSystem = Blaze.getBuildSystem(project);
+ for (BlazeTestResultFinderStrategy strategy : EP_NAME.getExtensions()) {
+ if (strategy.handlesBuildSystem(buildSystem)) {
+ return strategy.findTestResults(project);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Attempt to find test results corresponding to the most recent blaze invocation. Called after
+ * the 'blaze test' process completes.
+ */
+ @Nullable
+ BlazeTestResults findTestResults(Project project);
+
+ /** Results are taken from the first strategy handling a given build system */
+ boolean handlesBuildSystem(BuildSystem buildSystem);
+}
diff --git a/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestResults.java b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestResults.java
new file mode 100644
index 0000000..7d50bf2
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestResults.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.testlogs;
+
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.io.File;
+
+/** Results from a 'blaze test' invocation. */
+public class BlazeTestResults {
+
+ /** Output test XML files, grouped by target label. */
+ public final ImmutableMultimap<Label, File> testXmlFiles;
+ /** Targets which failed to build */
+ public final ImmutableSet<Label> failedTargets;
+
+ public BlazeTestResults(
+ ImmutableMultimap<Label, File> testXmlFiles, ImmutableSet<Label> failedTargets) {
+ this.testXmlFiles = testXmlFiles;
+ this.failedTargets = failedTargets;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestXmlFinderStrategy.java b/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestXmlFinderStrategy.java
deleted file mode 100644
index 174d512..0000000
--- a/base/src/com/google/idea/blaze/base/run/testlogs/BlazeTestXmlFinderStrategy.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2017 The Bazel Authors. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.testlogs;
-
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.settings.Blaze;
-import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.openapi.extensions.ExtensionPointName;
-import com.intellij.openapi.project.Project;
-
-/** A strategy for locating output test XML files. */
-public interface BlazeTestXmlFinderStrategy {
-
- ExtensionPointName<BlazeTestXmlFinderStrategy> EP_NAME =
- ExtensionPointName.create("com.google.idea.blaze.BlazeTestXmlFinderStrategy");
-
- /**
- * Attempt to find all output test XML files associated with the given run configuration. Called
- * after the 'blaze test' process completes.
- */
- static ImmutableList<CompletedTestTarget> locateTestXmlFiles(Project project) {
- BuildSystem buildSystem = Blaze.getBuildSystem(project);
- ImmutableList.Builder<CompletedTestTarget> output = ImmutableList.builder();
- for (BlazeTestXmlFinderStrategy strategy : EP_NAME.getExtensions()) {
- if (strategy.handlesBuildSystem(buildSystem)) {
- output.addAll(strategy.findTestXmlFiles(project));
- }
- }
- return output.build();
- }
-
- /**
- * Attempt to find all output test XML files associated with the given run configuration using a
- * particular strategy. Called after the 'blaze test' process completes.
- */
- ImmutableList<CompletedTestTarget> findTestXmlFiles(Project project);
-
- boolean handlesBuildSystem(BuildSystem buildSystem);
-}
diff --git a/base/src/com/google/idea/blaze/base/run/testlogs/TargetPathTestXmlFinderStrategy.java b/base/src/com/google/idea/blaze/base/run/testlogs/TargetPathTestResultFinderStrategy.java
similarity index 75%
rename from base/src/com/google/idea/blaze/base/run/testlogs/TargetPathTestXmlFinderStrategy.java
rename to base/src/com/google/idea/blaze/base/run/testlogs/TargetPathTestResultFinderStrategy.java
index ce5ec40..c18cc65 100644
--- a/base/src/com/google/idea/blaze/base/run/testlogs/TargetPathTestXmlFinderStrategy.java
+++ b/base/src/com/google/idea/blaze/base/run/testlogs/TargetPathTestResultFinderStrategy.java
@@ -15,7 +15,7 @@
*/
package com.google.idea.blaze.base.run.testlogs;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMultimap;
import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.Label;
@@ -24,15 +24,13 @@
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.intellij.openapi.project.Project;
import java.io.File;
-import java.util.Objects;
-import java.util.stream.Collectors;
import javax.annotation.Nullable;
/**
* Attempts to parse the list of test targets from the command log, then searches the corresponding
* path in the bazel-testlogs output tree.
*/
-public class TargetPathTestXmlFinderStrategy implements BlazeTestXmlFinderStrategy {
+public class TargetPathTestResultFinderStrategy implements BlazeTestResultFinderStrategy {
@Override
public boolean handlesBuildSystem(BuildSystem buildSystem) {
@@ -40,28 +38,30 @@
}
@Override
- public ImmutableList<CompletedTestTarget> findTestXmlFiles(Project project) {
+ public BlazeTestResults findTestResults(Project project) {
File testLogsDir = getTestLogsTree(project);
if (testLogsDir == null) {
- return ImmutableList.of();
+ return null;
}
File commandLog = getCommandLog(project);
if (commandLog == null) {
- return ImmutableList.of();
+ return null;
}
- return ImmutableList.copyOf(
- BlazeCommandLogParser.parseTestTargets(commandLog)
- .stream()
- .map((label) -> toKindAndTestXml(testLogsDir, label))
- .filter(Objects::nonNull)
- .collect(Collectors.toList()));
+ ImmutableMultimap.Builder<Label, File> output = ImmutableMultimap.builder();
+ for (Label label : BlazeCommandLogParser.parseTestTargets(commandLog)) {
+ File testXml = findTestXml(testLogsDir, label);
+ if (testXml != null) {
+ output.put(label, testXml);
+ }
+ }
+ return new BlazeTestResults(
+ output.build(), BlazeCommandLogParser.parseFailedTargets(commandLog));
}
@Nullable
- private static CompletedTestTarget toKindAndTestXml(File testLogsDir, Label label) {
+ private static File findTestXml(File testLogsDir, Label label) {
String labelPath = label.blazePackage() + File.separator + label.targetName();
- File testXml = new File(testLogsDir, labelPath + File.separator + "test.xml");
- return new CompletedTestTarget(testXml, label);
+ return new File(testLogsDir, labelPath + File.separator + "test.xml");
}
@Nullable
diff --git a/base/src/com/google/idea/blaze/base/scope/BlazeContext.java b/base/src/com/google/idea/blaze/base/scope/BlazeContext.java
index 316c05b..f502c10 100644
--- a/base/src/com/google/idea/blaze/base/scope/BlazeContext.java
+++ b/base/src/com/google/idea/blaze/base/scope/BlazeContext.java
@@ -20,8 +20,8 @@
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Scoped operation context. */
public class BlazeContext {
diff --git a/base/src/com/google/idea/blaze/base/scope/Scope.java b/base/src/com/google/idea/blaze/base/scope/Scope.java
index 4c0f12a..e288d8a 100644
--- a/base/src/com/google/idea/blaze/base/scope/Scope.java
+++ b/base/src/com/google/idea/blaze/base/scope/Scope.java
@@ -16,8 +16,9 @@
package com.google.idea.blaze.base.scope;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import javax.annotation.Nullable;
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 {
@@ -34,6 +35,9 @@
BlazeContext context = new BlazeContext(parentContext);
try {
return scopedFunction.execute(context);
+ } catch (ProcessCanceledException e) {
+ context.setCancelled();
+ throw e;
} catch (RuntimeException e) {
context.setHasError();
logger.error(e);
@@ -54,6 +58,9 @@
BlazeContext context = new BlazeContext(parentContext);
try {
scopedOperation.execute(context);
+ } catch (ProcessCanceledException e) {
+ context.setCancelled();
+ throw e;
} catch (RuntimeException e) {
context.setHasError();
logger.error(e);
diff --git a/base/src/com/google/idea/blaze/base/scope/ScopedTask.java b/base/src/com/google/idea/blaze/base/scope/ScopedTask.java
index 725bf2f..877cbe8 100644
--- a/base/src/com/google/idea/blaze/base/scope/ScopedTask.java
+++ b/base/src/com/google/idea/blaze/base/scope/ScopedTask.java
@@ -18,15 +18,15 @@
import com.google.idea.blaze.base.scope.scopes.ProgressIndicatorScope;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Progressive;
+import javax.annotation.Nullable;
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 */);
+ this(/* parentContext */ null);
}
public ScopedTask(@Nullable BlazeContext parentContext) {
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
index e3bc15a..8690be2 100644
--- a/base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java
+++ b/base/src/com/google/idea/blaze/base/scope/output/IssueOutput.java
@@ -19,8 +19,8 @@
import com.google.idea.blaze.base.scope.Output;
import com.intellij.pom.Navigatable;
import java.io.File;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** An issue in a blaze operation. */
public class IssueOutput implements Output {
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
index 1875f20..7128856 100644
--- a/base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/BlazeConsoleScope.java
@@ -28,8 +28,8 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Moves print output to the blaze console. */
public class BlazeConsoleScope implements BlazeScope {
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
index d3dcad0..bad8849 100644
--- a/base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java
+++ b/base/src/com/google/idea/blaze/base/scope/scopes/TimingScope.java
@@ -20,8 +20,8 @@
import com.google.idea.blaze.base.scope.BlazeScope;
import com.google.idea.blaze.base.scope.output.PrintOutput;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Prints timing information as output. */
public class TimingScope implements BlazeScope {
diff --git a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
index 7f0ea60..e19d578 100644
--- a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
+++ b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettings.java
@@ -16,13 +16,10 @@
package com.google.idea.blaze.base.settings;
import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
-import com.intellij.util.xmlb.annotations.Tag;
+import java.util.UUID;
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 = "";
@@ -46,17 +43,22 @@
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.locationHash = createLocationHash(projectName);
this.projectViewFile = projectViewFile;
this.buildSystem = buildSystem;
}
+ 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;
+ }
+
@SuppressWarnings("unused")
public String getWorkspaceRoot() {
return workspaceRoot;
diff --git a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
index a45b08e..093b18a 100644
--- a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
+++ b/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManager.java
@@ -21,8 +21,8 @@
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
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))
@@ -30,11 +30,7 @@
@Nullable private BlazeImportSettings importSettings;
- private Project project;
-
- public BlazeImportSettingsManager(@NotNull Project project) {
- this.project = project;
- }
+ public BlazeImportSettingsManager() {}
public static BlazeImportSettingsManager getInstance(Project project) {
return ServiceManager.getService(project, BlazeImportSettingsManager.class);
@@ -54,11 +50,6 @@
@Nullable
public BlazeImportSettings getImportSettings() {
- if (importSettings == null) {
- importSettings =
- BlazeImportSettingsManagerLegacy.getInstance(project).migrateImportSettings();
- }
-
return 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
deleted file mode 100644
index fec7d1d..0000000
--- a/base/src/com/google/idea/blaze/base/settings/BlazeImportSettingsManagerLegacy.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.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/ui/AddDirectoryToProjectAction.java b/base/src/com/google/idea/blaze/base/settings/ui/AddDirectoryToProjectAction.java
new file mode 100644
index 0000000..b9b1203
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/settings/ui/AddDirectoryToProjectAction.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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 static com.google.common.base.Preconditions.checkState;
+import static java.util.stream.Collectors.toCollection;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.actions.BlazeProjectAction;
+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.WorkspacePath;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+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.ListSection.Builder;
+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.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.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.google.idea.blaze.base.sync.projectview.RelatedWorkspacePathFinder;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.ui.WorkspaceFileTextField;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.fileChooser.FileTextField;
+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.openapi.vfs.VirtualFile;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.util.ui.SwingHelper;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.io.File;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.annotation.Nullable;
+import javax.swing.Box;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+final class AddDirectoryToProjectAction extends BlazeProjectAction {
+
+ private static final String WARNING_TEXT =
+ "This will add all blaze targets below this directory to your project. This could have a "
+ + "large impact on your project build times if the directory contains a lot of code or "
+ + "expensive genrule targets.";
+
+ @Override
+ protected void actionPerformedInBlazeProject(Project project, AnActionEvent e) {
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return;
+ }
+
+ new OpenBlazeWorkspaceFileActionDialog(project, blazeProjectData.workspacePathResolver).show();
+ }
+
+ private static class OpenBlazeWorkspaceFileActionDialog extends DialogWrapper {
+
+ static final int PATH_FIELD_WIDTH = 40;
+ final Project project;
+ final WorkspacePathResolver workspacePathResolver;
+ final JPanel component;
+ final FileTextField fileTextField;
+
+ OpenBlazeWorkspaceFileActionDialog(
+ Project project, WorkspacePathResolver workspacePathResolver) {
+ super(project, /* canBeParent */ false, IdeModalityType.PROJECT);
+ this.project = project;
+ this.workspacePathResolver = workspacePathResolver;
+
+ FileChooserDescriptor descriptor =
+ FileChooserDescriptorFactory.createSingleFolderDescriptor();
+ fileTextField =
+ WorkspaceFileTextField.create(
+ workspacePathResolver, descriptor, PATH_FIELD_WIDTH, myDisposable);
+ JBLabel directoryLabel =
+ new JBLabel("Directory:", AllIcons.Modules.SourceFolder, SwingConstants.LEFT);
+ JPanel directoryPanel =
+ SwingHelper.newHorizontalPanel(
+ Component.TOP_ALIGNMENT, directoryLabel, fileTextField.getField());
+
+ JBLabel warning =
+ new JBLabel(
+ "<html>" + WARNING_TEXT + "</html>",
+ AllIcons.General.BalloonWarning,
+ SwingConstants.LEFT);
+ warning.setPreferredSize(new Dimension(800, 100));
+ component =
+ SwingHelper.newLeftAlignedVerticalPanel(
+ directoryPanel, warning, Box.createVerticalGlue());
+
+ setTitle("Add Directory to Project");
+
+ init();
+ }
+
+ @Nullable
+ @Override
+ protected JComponent createCenterPanel() {
+ return component;
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return fileTextField.getField();
+ }
+
+ @Nullable
+ @Override
+ protected ValidationInfo doValidate() {
+ VirtualFile selectedFile = fileTextField.getSelectedFile();
+ if (selectedFile == null || !selectedFile.exists()) {
+ return new ValidationInfo("File does not exist", fileTextField.getField());
+ } else if (!selectedFile.isDirectory()) {
+ return new ValidationInfo("File is not a directory", fileTextField.getField());
+ }
+
+ WorkspacePath workspacePath =
+ workspacePathResolver.getWorkspacePath(new File(selectedFile.getPath()));
+ if (workspacePath == null) {
+ return new ValidationInfo("File is not in workspace", fileTextField.getField());
+ }
+
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ checkState(projectViewSet != null);
+
+ BlazeImportSettings importSettings =
+ BlazeImportSettingsManager.getInstance(project).getImportSettings();
+ checkState(importSettings != null);
+
+ ImportRoots importRoots =
+ ImportRoots.builder(
+ WorkspaceRoot.fromImportSettings(importSettings), importSettings.getBuildSystem())
+ .add(projectViewSet)
+ .build();
+
+ if (importRoots.containsWorkspacePath(workspacePath)) {
+ return new ValidationInfo("This directory is already included in your project");
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void doOKAction() {
+ VirtualFile selectedFile = fileTextField.getSelectedFile();
+ checkState(selectedFile != null);
+ WorkspacePath workspacePath =
+ workspacePathResolver.getWorkspacePath(new File(selectedFile.getPath()));
+ checkState(workspacePath != null);
+
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ checkState(projectViewSet != null);
+
+ Set<DirectoryEntry> existingDirectories =
+ ImmutableSet.copyOf(projectViewSet.listItems(DirectorySection.KEY));
+ Set<TargetExpression> existingTargets =
+ ImmutableSet.copyOf(projectViewSet.listItems(TargetSection.KEY));
+
+ Set<WorkspacePath> pathsToAdd = new LinkedHashSet<>();
+ pathsToAdd.add(workspacePath);
+ pathsToAdd.addAll(
+ RelatedWorkspacePathFinder.getInstance()
+ .findRelatedWorkspaceDirectories(workspacePathResolver, workspacePath));
+
+ Set<DirectoryEntry> newDirectories =
+ pathsToAdd
+ .stream()
+ .map(DirectoryEntry::include)
+ .filter(entry -> !existingDirectories.contains(entry))
+ .collect(toCollection(LinkedHashSet::new));
+
+ Set<TargetExpression> newTargets =
+ pathsToAdd
+ .stream()
+ .map(TargetExpression::allFromPackageRecursive)
+ .filter(entry -> !existingTargets.contains(entry))
+ .collect(toCollection(LinkedHashSet::new));
+
+ ProjectViewEdit edit =
+ ProjectViewEdit.editLocalProjectView(
+ project,
+ builder -> {
+ ListSection<DirectoryEntry> directories = builder.getLast(DirectorySection.KEY);
+ Builder<DirectoryEntry> directoriesUpdater =
+ ListSection.update(DirectorySection.KEY, directories);
+ newDirectories.forEach(directoriesUpdater::add);
+ builder.replace(directories, directoriesUpdater);
+
+ ListSection<TargetExpression> targets = builder.getLast(TargetSection.KEY);
+ Builder<TargetExpression> targetsUpdater =
+ ListSection.update(TargetSection.KEY, targets);
+ newTargets.forEach(targetsUpdater::add);
+ builder.replace(targets, targetsUpdater);
+
+ 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());
+
+ super.doOKAction();
+ }
+ }
+}
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
index 8e763f1..62370d2 100644
--- a/base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java
+++ b/base/src/com/google/idea/blaze/base/settings/ui/JPanelProvidingProject.java
@@ -37,6 +37,11 @@
this.project = project;
}
+ public JPanelProvidingProject(Project project) {
+ super();
+ this.project = project;
+ }
+
@Nullable
@Override
public Object getData(String dataId) {
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
index 5023368..ae6a917 100644
--- a/base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java
+++ b/base/src/com/google/idea/blaze/base/settings/ui/ProjectViewUi.java
@@ -133,7 +133,7 @@
return editor;
}
- public void fillUi(JPanel canvas, int indentLevel) {
+ public void fillUi(JPanel canvas) {
String tooltip =
"Enter a project view descriptor file."
+ (Blaze.defaultBuildSystem() == BuildSystem.Blaze
@@ -149,9 +149,9 @@
JBLabel labelsLabel = new JBLabel("Project View");
labelsLabel.setToolTipText(tooltip);
- canvas.add(labelsLabel, UiUtil.getFillLineConstraints(indentLevel));
+ canvas.add(labelsLabel, UiUtil.getFillLineConstraints(0));
- canvas.add(projectViewEditor.getComponent(), UiUtil.getFillLineConstraints(indentLevel));
+ canvas.add(projectViewEditor.getComponent(), UiUtil.getFillLineConstraints(0));
useShared = new JCheckBox(USE_SHARED_PROJECT_VIEW);
useShared.addActionListener(
@@ -162,7 +162,7 @@
}
updateTextAreasEnabled();
});
- canvas.add(useShared, UiUtil.getFillLineConstraints(indentLevel));
+ canvas.add(useShared, UiUtil.getFillLineConstraints(0));
}
public void init(
@@ -185,10 +185,7 @@
}
useShared.setSelected(useSharedProjectView);
-
- if (sharedProjectViewText == null) {
- useShared.setEnabled(false);
- }
+ useShared.setEnabled(sharedProjectViewText != null);
setDummyWorkspacePathResolverProvider(this.workspacePathResolver);
setProjectViewText(projectViewText);
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
index 6675f13..c79a9c9 100644
--- a/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncPlugin.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.BlazeVersionData;
@@ -30,7 +31,6 @@
import com.google.idea.blaze.base.sync.libraries.LibrarySource;
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.intellij.openapi.extensions.ExtensionPointName;
@@ -90,6 +90,12 @@
/** @return The set of supported languages under this workspace type. */
Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType);
+ /**
+ * @return The set of languages which are always active, regardless of which
+ * 'additional_languages' are requested.
+ */
+ Set<LanguageClass> getAlwaysActiveLanguages();
+
/** Installs any global SDKs */
void installSdks(BlazeContext context);
@@ -100,7 +106,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
@Nullable WorkingSet workingSet,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
@@ -160,6 +166,7 @@
* @return True for success, false for fatal error.
*/
boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings);
@@ -168,7 +175,7 @@
Collection<SectionParser> getSections();
@Nullable
- LibrarySource getLibrarySource(BlazeProjectData blazeProjectData);
+ LibrarySource getLibrarySource(ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData);
/** Convenience adapter to help stubbing out methods. */
class Adapter implements BlazeSyncPlugin {
@@ -196,6 +203,11 @@
}
@Override
+ public Set<LanguageClass> getAlwaysActiveLanguages() {
+ return ImmutableSet.of();
+ }
+
+ @Override
public void installSdks(BlazeContext context) {}
@Override
@@ -205,7 +217,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
@Nullable WorkingSet workingSet,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
@@ -259,6 +271,7 @@
@Override
public boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
@@ -272,7 +285,8 @@
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
return null;
}
}
diff --git a/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java b/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
index 9b6849f..a019ffd 100644
--- a/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
+++ b/base/src/com/google/idea/blaze/base/sync/BlazeSyncTask.java
@@ -16,8 +16,6 @@
package com.google.idea.blaze.base.sync;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -26,7 +24,9 @@
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.command.BlazeFlags;
import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.command.info.BlazeInfoRunner;
import com.google.idea.blaze.base.experiments.ExperimentScope;
import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.ideinfo.TargetKey;
@@ -65,21 +65,26 @@
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.aspects.BuildResult;
import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManagerImpl;
import com.google.idea.blaze.base.sync.libraries.BlazeLibraryCollector;
import com.google.idea.blaze.base.sync.libraries.LibraryEditor;
import com.google.idea.blaze.base.sync.projectstructure.ContentEntryEditor;
+import com.google.idea.blaze.base.sync.projectstructure.DirectoryStructure;
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.projectstructure.ModuleFinder;
import com.google.idea.blaze.base.sync.projectview.ImportRoots;
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.sharding.BlazeBuildTargetSharder;
+import com.google.idea.blaze.base.sync.sharding.BlazeBuildTargetSharder.ShardedTargetsResult;
+import com.google.idea.blaze.base.sync.sharding.ShardedTargetList;
+import com.google.idea.blaze.base.sync.sharding.SuggestEnablingShardingNotification;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoderImpl;
-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;
@@ -90,8 +95,8 @@
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Progressive;
import com.intellij.openapi.project.Project;
@@ -101,6 +106,7 @@
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFileManager;
import java.io.File;
+import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -153,6 +159,20 @@
});
}
+ @Nullable
+ private BlazeProjectData getOldProjectData(BlazeContext context) {
+ try {
+ return BlazeProjectDataManagerImpl.getImpl(project).loadProjectRoot(importSettings);
+ } catch (IOException e) {
+ logger.info(e);
+ context.output(
+ new StatusOutput(
+ String.format(
+ "Couldn't load previously cached project data; full sync will be needed")));
+ return null;
+ }
+ }
+
/** Returns true if sync successfully completed */
@VisibleForTesting
boolean syncProject(BlazeContext context) {
@@ -161,10 +181,7 @@
try {
SaveUtil.saveAllFiles();
BlazeProjectData oldBlazeProjectData =
- syncMode != SyncMode.FULL
- ? BlazeProjectDataManagerImpl.getImpl(project)
- .loadProjectRoot(context, importSettings)
- : null;
+ syncMode != SyncMode.FULL ? getOldProjectData(context) : null;
if (oldBlazeProjectData == null) {
syncMode = SyncMode.FULL;
}
@@ -183,8 +200,14 @@
onSyncComplete(project, context, projectViewSet, blazeProjectData, syncMode, syncResult);
}
} catch (AssertionError | Exception e) {
- logger.error(e);
- IssueOutput.error("Internal error: " + e.getMessage()).submit(context);
+ Throwable rootCause = e;
+ while (rootCause.getCause() != null) {
+ rootCause = rootCause.getCause();
+ }
+ if (!(rootCause instanceof ProcessCanceledException)) {
+ logger.error(e);
+ IssueOutput.error("Internal error: " + e.getMessage()).submit(context);
+ }
} finally {
afterSync(project, context, syncMode, syncResult);
}
@@ -208,16 +231,27 @@
return SyncResult.FAILURE;
}
- ListenableFuture<ImmutableMap<String, String>> blazeInfoFuture =
- BlazeInfo.getInstance()
- .runBlazeInfo(
- context, importSettings.getBuildSystem(), workspaceRoot, ImmutableList.of());
-
ListeningExecutorService executor = BlazeExecutor.getInstance().getExecutor();
+ WorkspacePathResolverAndProjectView workspacePathResolverAndProjectView =
+ computeWorkspacePathResolverAndProjectView(context, vcsHandler, executor);
+ if (workspacePathResolverAndProjectView == null) {
+ return SyncResult.FAILURE;
+ }
+ ProjectViewSet projectViewSet = workspacePathResolverAndProjectView.projectViewSet;
+
+ ListenableFuture<BlazeInfo> blazeInfoFuture =
+ BlazeInfoRunner.getInstance()
+ .runBlazeInfo(
+ context,
+ importSettings.getBuildSystem(),
+ Blaze.getBuildSystemProvider(project).getSyncBinaryPath(),
+ workspaceRoot,
+ BlazeFlags.buildFlags(project, projectViewSet));
+
ListenableFuture<WorkingSet> workingSetFuture =
vcsHandler.getWorkingSet(project, context, workspaceRoot, executor);
- ImmutableMap<String, String> blazeInfo =
+ BlazeInfo blazeInfo =
FutureUtil.waitForFuture(context, blazeInfoFuture)
.timed(Blaze.buildSystemName(project) + "Info")
.withProgressMessage(
@@ -228,24 +262,16 @@
if (blazeInfo == null) {
return SyncResult.FAILURE;
}
- BlazeRoots blazeRoots =
- BlazeRoots.build(importSettings.getBuildSystem(), workspaceRoot, blazeInfo);
BlazeVersionData blazeVersionData =
BlazeVersionData.build(importSettings.getBuildSystem(), workspaceRoot, blazeInfo);
- WorkspacePathResolverAndProjectView workspacePathResolverAndProjectView =
- computeWorkspacePathResolverAndProjectView(context, blazeRoots, vcsHandler, executor);
- if (workspacePathResolverAndProjectView == null) {
- return SyncResult.FAILURE;
- }
WorkspacePathResolver workspacePathResolver =
workspacePathResolverAndProjectView.workspacePathResolver;
ArtifactLocationDecoder artifactLocationDecoder =
- new ArtifactLocationDecoderImpl(blazeRoots, workspacePathResolver);
- ProjectViewSet projectViewSet = workspacePathResolverAndProjectView.projectViewSet;
+ new ArtifactLocationDecoderImpl(blazeInfo, workspacePathResolver);
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
if (workspaceLanguageSettings == null) {
return SyncResult.FAILURE;
}
@@ -255,7 +281,7 @@
}
if (!ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings)) {
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings)) {
return SyncResult.FAILURE;
}
@@ -304,6 +330,14 @@
printTargets(context, syncParams.title, syncParams.targetExpressions);
}
+ ShardedTargetsResult shardedTargetsResult =
+ BlazeBuildTargetSharder.expandAndShardTargets(
+ project, context, workspaceRoot, projectViewSet, workspacePathResolver, targets);
+ if (shardedTargetsResult.buildResult.status == BuildResult.Status.FATAL_ERROR) {
+ return SyncResult.FAILURE;
+ }
+ ShardedTargetList shardedTargets = shardedTargetsResult.shardedTargets;
+
boolean mergeWithOldState = !syncParams.addProjectViewTargets;
BlazeIdeInterface.IdeResult ideQueryResult =
getIdeQueryResult(
@@ -311,7 +345,7 @@
context,
projectViewSet,
blazeVersionData,
- targets,
+ shardedTargets,
workspaceLanguageSettings,
artifactLocationDecoder,
syncStateBuilder,
@@ -320,8 +354,12 @@
if (context.isCancelled()) {
return SyncResult.CANCELLED;
}
- if (ideQueryResult.targetMap == null || ideQueryResult.buildResult == BuildResult.FATAL_ERROR) {
+ if (ideQueryResult.targetMap == null
+ || ideQueryResult.buildResult.status == BuildResult.Status.FATAL_ERROR) {
context.setHasError();
+ if (ideQueryResult.buildResult.outOfMemory()) {
+ SuggestEnablingShardingNotification.suggestSharding(project, context);
+ }
return SyncResult.FAILURE;
}
@@ -333,9 +371,12 @@
BuildResult ideResolveResult =
resolveIdeArtifacts(
- project, context, workspaceRoot, projectViewSet, blazeVersionData, targets);
- if (ideResolveResult == BuildResult.FATAL_ERROR) {
+ project, context, workspaceRoot, projectViewSet, blazeVersionData, shardedTargets);
+ if (ideResolveResult.status == BuildResult.Status.FATAL_ERROR) {
context.setHasError();
+ if (ideResolveResult.outOfMemory()) {
+ SuggestEnablingShardingNotification.suggestSharding(project, context);
+ }
return SyncResult.FAILURE;
}
if (context.isCancelled()) {
@@ -353,7 +394,7 @@
workspaceRoot,
projectViewSet,
workspaceLanguageSettings,
- blazeRoots,
+ blazeInfo,
workingSet,
workspacePathResolver,
artifactLocationDecoder,
@@ -378,45 +419,66 @@
syncStartTime,
targetMap,
blazeInfo,
- blazeRoots,
blazeVersionData,
workspacePathResolver,
artifactLocationDecoder,
workspaceLanguageSettings,
syncStateBuilder.build(),
- reverseDependencies,
- null);
+ reverseDependencies);
FileCaches.onSync(project, context, projectViewSet, newBlazeProjectData, syncMode);
ListenableFuture<?> prefetch =
- PrefetchService.getInstance().prefetchProjectFiles(project, newBlazeProjectData);
+ PrefetchService.getInstance()
+ .prefetchProjectFiles(project, projectViewSet, newBlazeProjectData);
FutureUtil.waitForFuture(context, prefetch)
.withProgressMessage("Prefetching files...")
.timed("PrefetchFiles")
.onError("Prefetch failed")
.run();
+ ListenableFuture<DirectoryStructure> directoryStructureFuture =
+ DirectoryStructure.getRootDirectoryStructure(project, workspaceRoot, projectViewSet);
+
refreshVirtualFileSystem(context, newBlazeProjectData);
+ DirectoryStructure directoryStructure =
+ FutureUtil.waitForFuture(context, directoryStructureFuture)
+ .withProgressMessage("Computing directory structure...")
+ .timed("DirectoryStructure")
+ .onError("Directory structure computation failed")
+ .run()
+ .result();
+ if (directoryStructure == null) {
+ return SyncResult.FAILURE;
+ }
+
boolean success =
updateProject(
- context, projectViewSet, blazeVersionData, oldBlazeProjectData, newBlazeProjectData);
+ context,
+ projectViewSet,
+ blazeVersionData,
+ directoryStructure,
+ oldBlazeProjectData,
+ newBlazeProjectData);
if (!success) {
return SyncResult.FAILURE;
}
SyncResult syncResult = SyncResult.SUCCESS;
- if (ideInfoResult == BuildResult.BUILD_ERROR || ideResolveResult == BuildResult.BUILD_ERROR) {
+ if (ideInfoResult.status == BuildResult.Status.BUILD_ERROR
+ || ideResolveResult.status == BuildResult.Status.BUILD_ERROR) {
final String errorType =
- ideInfoResult == BuildResult.BUILD_ERROR ? "BUILD file errors" : "compilation errors";
+ ideInfoResult.status == BuildResult.Status.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.",
+ + "'Blaze > Sync > Expand Sync to Working Set' and try again.",
errorType);
context.output(PrintOutput.error(message));
IssueOutput.warn(message).submit(context);
@@ -457,10 +519,7 @@
}
private WorkspacePathResolverAndProjectView computeWorkspacePathResolverAndProjectView(
- BlazeContext context,
- BlazeRoots blazeRoots,
- BlazeVcsHandler vcsHandler,
- ListeningExecutorService executor) {
+ BlazeContext context, BlazeVcsHandler vcsHandler, ListeningExecutorService executor) {
context.output(new StatusOutput("Updating VCS..."));
for (int i = 0; i < 3; ++i) {
@@ -484,7 +543,7 @@
WorkspacePathResolver workspacePathResolver =
vcsWorkspacePathResolver != null
? vcsWorkspacePathResolver
- : new WorkspacePathResolverImpl(workspaceRoot, blazeRoots);
+ : new WorkspacePathResolverImpl(workspaceRoot);
ProjectViewSet projectViewSet =
ProjectViewManager.getInstance(project).reloadProjectView(context, workspacePathResolver);
@@ -580,7 +639,7 @@
BlazeContext parentContext,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets,
+ ShardedTargetList shardedTargets,
WorkspaceLanguageSettings workspaceLanguageSettings,
ArtifactLocationDecoder artifactLocationDecoder,
Builder syncStateBuilder,
@@ -601,7 +660,7 @@
workspaceRoot,
projectViewSet,
blazeVersionData,
- targets,
+ shardedTargets,
workspaceLanguageSettings,
artifactLocationDecoder,
syncStateBuilder,
@@ -616,7 +675,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targetExpressions) {
+ ShardedTargetList shardedTargets) {
return Scope.push(
parentContext,
context -> {
@@ -626,12 +685,12 @@
// We don't want IDE resolve errors to fail the whole sync
context.setPropagatesErrors(false);
- if (targetExpressions.isEmpty()) {
+ if (shardedTargets.isEmpty()) {
return BuildResult.SUCCESS;
}
BlazeIdeInterface blazeIdeInterface = BlazeIdeInterface.getInstance();
return blazeIdeInterface.resolveIdeArtifacts(
- project, context, workspaceRoot, projectViewSet, blazeVersionData, targetExpressions);
+ project, context, workspaceRoot, projectViewSet, blazeVersionData, shardedTargets);
});
}
@@ -639,6 +698,7 @@
BlazeContext parentContext,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
+ DirectoryStructure directoryStructure,
@Nullable BlazeProjectData oldBlazeProjectData,
BlazeProjectData newBlazeProjectData) {
return Scope.push(
@@ -656,19 +716,15 @@
() ->
ProjectRootManagerEx.getInstanceEx(this.project)
.mergeRootsChangesDuring(
- () -> {
- updateProjectSdk(
- context,
- projectViewSet,
- blazeVersionData,
- newBlazeProjectData);
- updateProjectStructure(
- context,
- importSettings,
- projectViewSet,
- newBlazeProjectData,
- oldBlazeProjectData);
- })));
+ () ->
+ updateProjectStructure(
+ context,
+ importSettings,
+ projectViewSet,
+ blazeVersionData,
+ directoryStructure,
+ newBlazeProjectData,
+ oldBlazeProjectData))));
} catch (Throwable e) {
IssueOutput.error("Internal error. Error: " + e).submit(context);
logger.error(e);
@@ -681,24 +737,20 @@
});
}
- private void updateProjectSdk(
- BlazeContext context,
- ProjectViewSet projectViewSet,
- BlazeVersionData blazeVersionData,
- BlazeProjectData newBlazeProjectData) {
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- syncPlugin.updateProjectSdk(
- project, context, projectViewSet, blazeVersionData, newBlazeProjectData);
- }
- }
-
private void updateProjectStructure(
BlazeContext context,
BlazeImportSettings importSettings,
ProjectViewSet projectViewSet,
+ BlazeVersionData blazeVersionData,
+ DirectoryStructure directoryStructure,
BlazeProjectData newBlazeProjectData,
@Nullable BlazeProjectData oldBlazeProjectData) {
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ syncPlugin.updateProjectSdk(
+ project, context, projectViewSet, blazeVersionData, newBlazeProjectData);
+ }
+
ModuleEditorImpl moduleEditor =
ModuleEditorProvider.getInstance().getModuleEditor(project, importSettings);
@@ -721,10 +773,17 @@
ModifiableRootModel workspaceModifiableModel = moduleEditor.editModule(workspaceModule);
ContentEntryEditor.createContentEntries(
- project, workspaceRoot, projectViewSet, newBlazeProjectData, workspaceModifiableModel);
+ project,
+ workspaceRoot,
+ projectViewSet,
+ newBlazeProjectData,
+ directoryStructure,
+ workspaceModifiableModel);
- List<BlazeLibrary> libraries = BlazeLibraryCollector.getLibraries(newBlazeProjectData);
- LibraryEditor.updateProjectLibraries(project, context, newBlazeProjectData, libraries);
+ List<BlazeLibrary> libraries =
+ BlazeLibraryCollector.getLibraries(projectViewSet, newBlazeProjectData);
+ LibraryEditor.updateProjectLibraries(
+ project, context, projectViewSet, newBlazeProjectData, libraries);
LibraryEditor.configureDependencies(workspaceModifiableModel, libraries);
for (BlazeSyncPlugin blazeSyncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
@@ -760,7 +819,7 @@
.runReadAction(
() -> {
Module workspaceModule =
- ModuleManager.getInstance(project)
+ ModuleFinder.getInstance(project)
.findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME);
for (BlazeSyncPlugin blazeSyncPlugin :
BlazeSyncPlugin.EP_NAME.getExtensions()) {
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
index c355d5d..34f952a 100644
--- a/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterface.java
@@ -18,15 +18,14 @@
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.model.BlazeVersionData;
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.sharding.ShardedTargetList;
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. */
@@ -36,22 +35,6 @@
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 TargetMap targetMap;
@@ -75,7 +58,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets,
+ ShardedTargetList shardedTargets,
WorkspaceLanguageSettings workspaceLanguageSettings,
ArtifactLocationDecoder artifactLocationDecoder,
SyncState.Builder syncStateBuilder,
@@ -93,7 +76,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets);
+ ShardedTargetList shardedTargets);
/**
* Attempts to compile the requested ide artifacts.
@@ -106,5 +89,5 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets);
+ ShardedTargetList shardedTargets);
}
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
index 12a09c5..18a884c 100644
--- a/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/BlazeIdeInterfaceAspectsImpl.java
@@ -15,10 +15,12 @@
*/
package com.google.idea.blaze.base.sync.aspects;
-import com.google.common.base.Objects;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+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;
@@ -26,25 +28,32 @@
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.bazel.BuildSystemProvider;
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.command.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.filecache.FileDiffer;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
+import com.google.idea.blaze.base.lang.AdditionalLanguagesHelper;
import com.google.idea.blaze.base.model.BlazeVersionData;
import com.google.idea.blaze.base.model.SyncState;
+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.LanguageClass;
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.projectview.section.sections.TargetSection;
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.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;
@@ -53,20 +62,31 @@
import com.google.idea.blaze.base.sync.aspects.strategy.AspectStrategy;
import com.google.idea.blaze.base.sync.aspects.strategy.AspectStrategyProvider;
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.sharding.ShardedTargetList;
+import com.google.idea.blaze.base.sync.sharding.WildcardTargetPattern;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.repackaged.devtools.intellij.ideinfo.IntellijIdeInfo;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.pom.NavigatableAdapter;
+import com.intellij.util.PathUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import javax.annotation.Nullable;
@@ -91,7 +111,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets,
+ ShardedTargetList shardedTargets,
WorkspaceLanguageSettings workspaceLanguageSettings,
ArtifactLocationDecoder artifactLocationDecoder,
SyncState.Builder syncStateBuilder,
@@ -108,22 +128,23 @@
// If the aspect strategy has changed, redo everything from scratch
final AspectStrategy aspectStrategy = getAspectStrategy(project, blazeVersionData);
if (prevState != null
- && !Objects.equal(prevState.aspectStrategyName, aspectStrategy.getName())) {
+ && !Objects.equals(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.targetMap : null, BuildResult.FATAL_ERROR);
+ getIdeInfo(project, context, workspaceRoot, projectViewSet, shardedTargets, aspectStrategy);
+ if (ideInfoResult.buildResult.status == BuildResult.Status.FATAL_ERROR) {
+ return new IdeResult(
+ prevState != null ? prevState.targetMap : null, ideInfoResult.buildResult);
}
// 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) {
+ if (ideInfoResult.buildResult.status == BuildResult.Status.BUILD_ERROR) {
mergeWithOldState = true;
}
- List<File> fileList = ideInfoResult.files;
+ Collection<File> fileList = ideInfoResult.files;
List<File> updatedFiles = Lists.newArrayList();
List<File> removedFiles = Lists.newArrayList();
ImmutableMap<File, Long> fileState =
@@ -149,13 +170,16 @@
return new IdeResult(prevState != null ? prevState.targetMap : null, BuildResult.FATAL_ERROR);
}
+ Set<Label> targets = getNonWildcardProjectViewTargets(projectViewSet);
+
State state =
updateState(
+ project,
context,
prevState,
fileState,
workspaceLanguageSettings,
- artifactLocationDecoder,
+ targets,
aspectStrategy,
updatedFiles,
removedFiles,
@@ -167,11 +191,38 @@
return new IdeResult(state.targetMap, ideInfoResult.buildResult);
}
- private static class IdeInfoResult {
- private final List<File> files;
- private final BuildResult buildResult;
+ private static Set<Label> getNonWildcardProjectViewTargets(ProjectViewSet projectViewSet) {
+ return projectViewSet
+ .listItems(TargetSection.KEY)
+ .stream()
+ .map(BlazeIdeInterfaceAspectsImpl::singleTargetLabel)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ }
- IdeInfoResult(List<File> files, BuildResult buildResult) {
+ @Nullable
+ private static Label singleTargetLabel(TargetExpression expression) {
+ if (WildcardTargetPattern.fromExpression(expression) != null) {
+ return null;
+ }
+ // convert to a valid Label format
+ String pattern = expression.toString();
+ if (!pattern.startsWith("//")) {
+ pattern = "//" + pattern;
+ }
+ int colonIndex = pattern.indexOf(':');
+ if (colonIndex == -1) {
+ // add the implicit rule name
+ pattern += ":" + PathUtil.getFileName(pattern);
+ }
+ return Label.createIfValid(pattern);
+ }
+
+ private static class IdeInfoResult {
+ final Collection<File> files;
+ final BuildResult buildResult;
+
+ IdeInfoResult(Collection<File> files, BuildResult buildResult) {
this.files = files;
this.buildResult = buildResult;
}
@@ -182,48 +233,70 @@
BlazeContext parentContext,
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
- List<TargetExpression> targets,
+ ShardedTargetList shardedTargets,
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);
- blazeCommandBuilder.addBlazeFlags(BlazeFlags.KEEP_GOING);
- blazeCommandBuilder
- .addBlazeFlags(BlazeFlags.EXPERIMENTAL_SHOW_ARTIFACTS)
- .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet));
-
- aspectStrategy.modifyIdeInfoCommand(blazeCommandBuilder);
-
- String fileExtension = aspectStrategy.getAspectOutputFileExtension();
- String gzFileExtension = fileExtension + ".gz";
- Predicate<String> fileFilter =
- fileName -> fileName.endsWith(fileExtension) || fileName.endsWith(gzFileExtension);
-
- int retVal =
- ExternalTask.builder(workspaceRoot)
- .addBlazeCommand(blazeCommandBuilder.build())
- .context(context)
- .stderr(
- LineProcessingOutputStream.of(
- new ExperimentalShowArtifactsLineProcessor(result, fileFilter),
- new IssueOutputLineProcessor(project, context, workspaceRoot)))
- .build()
- .run();
-
- BuildResult buildResult = BuildResult.fromExitCode(retVal);
- return new IdeInfoResult(result, buildResult);
+ Set<File> ideInfoFiles = new LinkedHashSet<>();
+ Function<Integer, String> progressMessage =
+ count ->
+ String.format(
+ "Building IDE info files for shard %s of %s...",
+ count, shardedTargets.shardedTargets.size());
+ Function<List<TargetExpression>, BuildResult> invocation =
+ targets -> {
+ IdeInfoResult result =
+ getIdeInfoForTargets(
+ project, context, workspaceRoot, projectViewSet, targets, aspectStrategy);
+ ideInfoFiles.addAll(result.files);
+ return result.buildResult;
+ };
+ BuildResult result =
+ shardedTargets.runShardedCommand(project, context, progressMessage, invocation);
+ return new IdeInfoResult(ideInfoFiles, result);
});
}
+ /** Runs blaze build with the aspect's ide-info output group for a given set of targets */
+ private static IdeInfoResult getIdeInfoForTargets(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> targets,
+ AspectStrategy aspectStrategy) {
+ String fileExtension = aspectStrategy.getAspectOutputFileExtension();
+ String gzFileExtension = fileExtension + ".gz";
+ Predicate<String> fileFilter =
+ fileName -> fileName.endsWith(fileExtension) || fileName.endsWith(gzFileExtension);
+ BuildResultHelper buildResultHelper = BuildResultHelper.forFiles(fileFilter);
+
+ BlazeCommand.Builder builder =
+ BlazeCommand.builder(getBinaryPath(project), BlazeCommandName.BUILD)
+ .addTargets(targets)
+ .addBlazeFlags(BlazeFlags.KEEP_GOING)
+ .addBlazeFlags(buildResultHelper.getBuildFlags())
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet));
+
+ aspectStrategy.modifyIdeInfoCommand(builder);
+
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(builder.build())
+ .context(context)
+ .stderr(
+ buildResultHelper.stderr(
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run();
+
+ BuildResult buildResult = BuildResult.fromExitCode(retVal);
+ return new IdeInfoResult(buildResultHelper.getBuildArtifacts(), buildResult);
+ }
+
private static class TargetFilePair {
private final File file;
private final TargetIdeInfo target;
@@ -236,11 +309,12 @@
@Nullable
static State updateState(
+ Project project,
BlazeContext parentContext,
@Nullable State prevState,
ImmutableMap<File, Long> fileState,
WorkspaceLanguageSettings workspaceLanguageSettings,
- ArtifactLocationDecoder artifactLocationDecoder,
+ Set<Label> nonWildcardProjectTargets,
AspectStrategy aspectStrategy,
List<File> newFiles,
List<File> removedFiles,
@@ -289,6 +363,7 @@
}
AtomicLong totalSizeLoaded = new AtomicLong(0);
+ Set<LanguageClass> ignoredLanguages = Sets.newConcurrentHashSet();
ListeningExecutorService executor = BlazeExecutor.getInstance().getExecutor();
@@ -300,11 +375,14 @@
() -> {
totalSizeLoaded.addAndGet(file.length());
try (InputStream inputStream = getAspectInputStream(file)) {
- IntellijIdeInfo.TargetIdeInfo ruleProto =
+ IntellijIdeInfo.TargetIdeInfo message =
aspectStrategy.readAspectFile(inputStream);
TargetIdeInfo target =
- IdeInfoFromProtobuf.makeTargetIdeInfo(
- workspaceLanguageSettings, ruleProto);
+ protoToTarget(
+ workspaceLanguageSettings,
+ nonWildcardProjectTargets,
+ message,
+ ignoredLanguages);
return new TargetFilePair(file, target);
}
}));
@@ -350,6 +428,8 @@
(100 * duplicateTargetLabels / targetMap.size()))));
}
+ warnIgnoredLanguages(project, context, ignoredLanguages);
+
state.targetMap = new TargetMap(ImmutableMap.copyOf(targetMap));
return Result.of(state);
});
@@ -361,6 +441,48 @@
return result.result;
}
+ @Nullable
+ private static TargetIdeInfo protoToTarget(
+ WorkspaceLanguageSettings languageSettings,
+ Set<Label> nonWildcardProjectTargets,
+ IntellijIdeInfo.TargetIdeInfo message,
+ Set<LanguageClass> ignoredLanguages) {
+ Kind kind = IdeInfoFromProtobuf.getKind(message);
+ if (kind == null) {
+ return null;
+ }
+ if (languageSettings.isLanguageActive(kind.getLanguageClass())) {
+ return IdeInfoFromProtobuf.makeTargetIdeInfo(message);
+ }
+ if (nonWildcardProjectTargets.contains(IdeInfoFromProtobuf.getKey(message).label)) {
+ ignoredLanguages.add(kind.getLanguageClass());
+ }
+ return null;
+ }
+
+ private static void warnIgnoredLanguages(
+ Project project, BlazeContext context, Set<LanguageClass> ignoredLangs) {
+ if (ignoredLangs.isEmpty()) {
+ return;
+ }
+ List<LanguageClass> sorted = new ArrayList<>(ignoredLangs);
+ sorted.sort(Ordering.usingToString());
+
+ String msg =
+ "Some project targets were ignored because the corresponding language support "
+ + "isn't enabled. Click here to enable support for: "
+ + Joiner.on(", ").join(sorted);
+ IssueOutput.warn(msg)
+ .navigatable(
+ new NavigatableAdapter() {
+ @Override
+ public void navigate(boolean requestFocus) {
+ AdditionalLanguagesHelper.enableLanguageSupport(project, sorted);
+ }
+ })
+ .submit(context);
+ }
+
private static InputStream getAspectInputStream(File file) throws IOException {
InputStream inputStream = new FileInputStream(file);
if (file.getName().endsWith(".gz")) {
@@ -376,9 +498,9 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets) {
+ ShardedTargetList shardedTargets) {
return resolveIdeArtifacts(
- project, context, workspaceRoot, projectViewSet, blazeVersionData, targets, false);
+ project, context, workspaceRoot, projectViewSet, blazeVersionData, shardedTargets, false);
}
@Override
@@ -388,14 +510,21 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets) {
+ ShardedTargetList shardedTargets) {
boolean ideCompile = hasIdeCompileOutputGroup(blazeVersionData);
return resolveIdeArtifacts(
- project, context, workspaceRoot, projectViewSet, blazeVersionData, targets, ideCompile);
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ blazeVersionData,
+ shardedTargets,
+ ideCompile);
}
private static boolean hasIdeCompileOutputGroup(BlazeVersionData blazeVersionData) {
- return blazeVersionData.bazelIsAtLeastVersion(0, 4, 4);
+ return blazeVersionData.buildSystem() == BuildSystem.Blaze
+ || blazeVersionData.bazelIsAtLeastVersion(0, 4, 4);
}
private static BuildResult resolveIdeArtifacts(
@@ -404,12 +533,39 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
+ ShardedTargetList shardedTargets,
+ boolean useIdeCompileOutputGroup) {
+
+ Function<Integer, String> progressMessage =
+ count ->
+ String.format(
+ "Building IDE resolve files for shard %s of %s...",
+ count, shardedTargets.shardedTargets.size());
+ Function<List<TargetExpression>, BuildResult> invocation =
+ targets ->
+ doResolveIdeArtifacts(
+ project,
+ context,
+ workspaceRoot,
+ projectViewSet,
+ blazeVersionData,
+ targets,
+ useIdeCompileOutputGroup);
+ return shardedTargets.runShardedCommand(project, context, progressMessage, invocation);
+ }
+
+ private static BuildResult doResolveIdeArtifacts(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeVersionData blazeVersionData,
List<TargetExpression> targets,
boolean useIdeCompileOutputGroup) {
AspectStrategy aspectStrategy = getAspectStrategy(project, blazeVersionData);
BlazeCommand.Builder blazeCommandBuilder =
- BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD)
+ BlazeCommand.builder(getBinaryPath(project), BlazeCommandName.BUILD)
.addTargets(targets)
.addBlazeFlags()
.addBlazeFlags(BlazeFlags.KEEP_GOING)
@@ -447,4 +603,9 @@
// Should never get here
throw new IllegalStateException("No aspect strategy found.");
}
+
+ private static String getBinaryPath(Project project) {
+ BuildSystemProvider buildSystemProvider = Blaze.getBuildSystemProvider(project);
+ return buildSystemProvider.getSyncBinaryPath();
+ }
}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/BuildResult.java b/base/src/com/google/idea/blaze/base/sync/aspects/BuildResult.java
new file mode 100644
index 0000000..d556be7
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/BuildResult.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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;
+
+/** The result of a blaze operation */
+public class BuildResult {
+
+ private static final int SUCCESS_EXIT_CODE = 0;
+ private static final int BUILD_ERROR_EXIT_CODE = 1;
+ // blaze server out-of-memory exit code
+ private static final int OOM_EXIT_CODE = 33;
+
+ /** The status of a blaze operation */
+ public enum Status {
+ SUCCESS, // Success
+ BUILD_ERROR, // Return code 1, a build error
+ FATAL_ERROR; // Some other failure
+
+ private static Status fromExitCode(int exitCode) {
+ if (exitCode == SUCCESS_EXIT_CODE) {
+ return SUCCESS;
+ } else if (exitCode == BUILD_ERROR_EXIT_CODE) {
+ return BUILD_ERROR;
+ }
+ return FATAL_ERROR;
+ }
+ }
+
+ public static final BuildResult SUCCESS = fromExitCode(SUCCESS_EXIT_CODE);
+ /** A general fatal error build result */
+ public static final BuildResult FATAL_ERROR = fromExitCode(-1);
+
+ public static BuildResult fromExitCode(int exitCode) {
+ return new BuildResult(exitCode);
+ }
+
+ /** Returns the 'worst' build result of the two. */
+ public static BuildResult combine(BuildResult first, BuildResult second) {
+ return fromExitCode(combineExitCode(first.exitCode, second.exitCode));
+ }
+
+ private final int exitCode;
+ public final Status status;
+
+ private BuildResult(int exitCode) {
+ this.exitCode = exitCode;
+ status = Status.fromExitCode(exitCode);
+ }
+
+ public boolean outOfMemory() {
+ return exitCode == OOM_EXIT_CODE;
+ }
+
+ private static int combineExitCode(int first, int second) {
+ if (first == OOM_EXIT_CODE || second == OOM_EXIT_CODE) {
+ // OOM errors treated specially, so preserve them.
+ return OOM_EXIT_CODE;
+ }
+ Status firstStatus = Status.fromExitCode(first);
+ Status secondStatus = Status.fromExitCode(second);
+ return firstStatus.ordinal() >= secondStatus.ordinal() ? first : second;
+ }
+}
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
index 8bf9585..a37991f 100644
--- a/base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/IdeInfoFromProtobuf.java
@@ -18,17 +18,18 @@
import static java.util.stream.Collectors.toList;
+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.idea.blaze.base.ideinfo.AndroidIdeInfo;
+import com.google.idea.blaze.base.ideinfo.AndroidSdkIdeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.CIdeInfo;
import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
import com.google.idea.blaze.base.ideinfo.Dependency;
import com.google.idea.blaze.base.ideinfo.Dependency.DependencyType;
-import com.google.idea.blaze.base.ideinfo.IntellijPluginDeployInfo;
-import com.google.idea.blaze.base.ideinfo.IntellijPluginDeployInfo.IntellijPluginDeployFile;
import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
import com.google.idea.blaze.base.ideinfo.JavaToolchainIdeInfo;
import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
@@ -40,8 +41,8 @@
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.repackaged.devtools.intellij.ideinfo.IntellijIdeInfo;
+import com.intellij.openapi.util.text.StringUtil;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
@@ -50,23 +51,12 @@
public class IdeInfoFromProtobuf {
@Nullable
- public static TargetIdeInfo makeTargetIdeInfo(
- WorkspaceLanguageSettings workspaceLanguageSettings, IntellijIdeInfo.TargetIdeInfo message) {
+ public static TargetIdeInfo makeTargetIdeInfo(IntellijIdeInfo.TargetIdeInfo message) {
Kind kind = getKind(message);
if (kind == null) {
return null;
}
- if (!workspaceLanguageSettings.isLanguageActive(kind.getLanguageClass())) {
- return null;
- }
-
- final TargetKey key;
- if (message.hasKey()) {
- key = makeTargetKey(message.getKey());
- } else {
- key = TargetKey.forPlainTarget(new Label(message.getLabel()));
- }
-
+ TargetKey key = getKey(message);
ArtifactLocation buildFile = getBuildFile(message);
final Collection<Dependency> dependencies;
@@ -107,6 +97,10 @@
if (message.hasAndroidIdeInfo()) {
androidIdeInfo = makeAndroidIdeInfo(message.getAndroidIdeInfo());
}
+ AndroidSdkIdeInfo androidSdkIdeInfo = null;
+ if (message.hasAndroidSdkIdeInfo()) {
+ androidSdkIdeInfo = makeAndroidSdkIdeInfo(message.getAndroidSdkIdeInfo());
+ }
PyIdeInfo pyIdeInfo = null;
if (message.hasPyIdeInfo()) {
pyIdeInfo = makePyIdeInfo(message.getPyIdeInfo());
@@ -125,11 +119,6 @@
if (message.hasJavaToolchainIdeInfo()) {
javaToolchainIdeInfo = makeJavaToolchainIdeInfo(message.getJavaToolchainIdeInfo());
}
- IntellijPluginDeployInfo intellijPluginDeployInfo = null;
- if (message.hasIntellijPluginDeployInfo()) {
- intellijPluginDeployInfo =
- makeIntellijPluginDeployInfo(message.getIntellijPluginDeployInfo());
- }
return new TargetIdeInfo(
key,
@@ -142,23 +131,23 @@
cToolchainIdeInfo,
javaIdeInfo,
androidIdeInfo,
+ androidSdkIdeInfo,
pyIdeInfo,
testIdeInfo,
protoLibraryLegacyInfo,
- javaToolchainIdeInfo,
- intellijPluginDeployInfo);
+ javaToolchainIdeInfo);
}
private static Collection<Dependency> makeDependencyListFromLabelList(
List<String> dependencyList, Dependency.DependencyType dependencyType) {
return dependencyList
.stream()
- .map(dep -> new Dependency(TargetKey.forPlainTarget(new Label(dep)), dependencyType))
+ .map(dep -> new Dependency(TargetKey.forPlainTarget(Label.create(dep)), dependencyType))
.collect(toList());
}
private static TargetKey makeTargetKey(IntellijIdeInfo.TargetKey key) {
- return TargetKey.forGeneralTarget(new Label(key.getLabel()), key.getAspectIdsList());
+ return TargetKey.forGeneralTarget(Label.create(key.getLabel()), key.getAspectIdsList());
}
private static Dependency makeDependency(IntellijIdeInfo.Dependency dep) {
@@ -194,10 +183,27 @@
makeExecutionRootPathList(cIdeInfo.getTransitiveQuoteIncludeDirectoryList());
List<ExecutionRootPath> transitiveSystemIncludeDirectories =
makeExecutionRootPathList(cIdeInfo.getTransitiveSystemIncludeDirectoryList());
+ List<String> coptDefines;
+ List<ExecutionRootPath> coptIncludeDirectories;
+ if (cIdeInfo.getTargetCoptList().isEmpty()) {
+ coptDefines = ImmutableList.of();
+ coptIncludeDirectories = ImmutableList.of();
+ } else {
+ UnfilteredCompilerOptions compilerOptions =
+ UnfilteredCompilerOptions.builder()
+ .registerSingleOrSplitOption("-D")
+ .registerSingleOrSplitOption("-I")
+ .build(cIdeInfo.getTargetCoptList());
+ coptDefines = compilerOptions.getExtractedOptionValues("-D");
+ coptIncludeDirectories =
+ makeExecutionRootPathList(compilerOptions.getExtractedOptionValues("-I"));
+ }
CIdeInfo.Builder builder =
CIdeInfo.builder()
.addSources(sources)
+ .addLocalDefines(coptDefines)
+ .addLocalIncludeDirectories(coptIncludeDirectories)
.addTransitiveIncludeDirectories(transitiveIncludeDirectories)
.addTransitiveQuoteIncludeDirectories(transitiveQuoteIncludeDirectories)
.addTransitiveDefines(cIdeInfo.getTransitiveDefineList())
@@ -222,8 +228,10 @@
ExecutionRootPath preprocessorExecutable =
new ExecutionRootPath(cToolchainIdeInfo.getPreprocessorExecutable());
- UnfilteredCompilerOptions unfilteredCompilerOptions =
- new UnfilteredCompilerOptions(cToolchainIdeInfo.getUnfilteredCompilerOptionList());
+ UnfilteredCompilerOptions compilerOptions =
+ UnfilteredCompilerOptions.builder()
+ .registerSingleOrSplitOption("-isystem")
+ .build(cToolchainIdeInfo.getUnfilteredCompilerOptionList());
CToolchainIdeInfo.Builder builder =
CToolchainIdeInfo.builder()
@@ -235,9 +243,9 @@
.setCppExecutable(cppExecutable)
.setPreprocessorExecutable(preprocessorExecutable)
.setTargetName(cToolchainIdeInfo.getTargetName())
- .addUnfilteredCompilerOptions(unfilteredCompilerOptions.getToolchainFlags())
+ .addUnfilteredCompilerOptions(compilerOptions.getUninterpretedOptions())
.addUnfilteredToolchainSystemIncludes(
- unfilteredCompilerOptions.getToolchainSysIncludes());
+ makeExecutionRootPathList(compilerOptions.getExtractedOptionValues("-isystem")));
return builder.build();
}
@@ -268,10 +276,15 @@
: null,
androidIdeInfo.getHasIdlSources(),
!Strings.isNullOrEmpty(androidIdeInfo.getLegacyResources())
- ? new Label(androidIdeInfo.getLegacyResources())
+ ? Label.create(androidIdeInfo.getLegacyResources())
: null);
}
+ private static AndroidSdkIdeInfo makeAndroidSdkIdeInfo(
+ IntellijIdeInfo.AndroidSdkIdeInfo androidSdkIdeInfo) {
+ return new AndroidSdkIdeInfo(makeArtifactLocation(androidSdkIdeInfo.getAndroidJar()));
+ }
+
private static PyIdeInfo makePyIdeInfo(IntellijIdeInfo.PyIdeInfo info) {
return PyIdeInfo.builder().addSources(makeArtifactLocationList(info.getSourcesList())).build();
}
@@ -334,21 +347,6 @@
javaToolchainIdeInfo.getSourceVersion(), javaToolchainIdeInfo.getTargetVersion());
}
- private static IntellijPluginDeployInfo makeIntellijPluginDeployInfo(
- IntellijIdeInfo.IntellijPluginDeployInfo intellijPluginDeployInfo) {
- return new IntellijPluginDeployInfo(
- ImmutableList.copyOf(
- intellijPluginDeployInfo
- .getDeployFilesList()
- .stream()
- .map(
- deployFile ->
- new IntellijPluginDeployFile(
- makeArtifactLocation(deployFile.getSrc()),
- deployFile.getDeployLocation()))
- .collect(toList())));
- }
-
private static Collection<LibraryArtifact> makeLibraryArtifactList(
List<IntellijIdeInfo.LibraryArtifact> jarsList) {
ImmutableList.Builder<LibraryArtifact> builder = ImmutableList.builder();
@@ -394,26 +392,46 @@
return builder.build();
}
+ @VisibleForTesting
@Nullable
- private static ArtifactLocation makeArtifactLocation(
- IntellijIdeInfo.ArtifactLocation pbArtifactLocation) {
- if (pbArtifactLocation == null) {
+ public static ArtifactLocation makeArtifactLocation(
+ @Nullable IntellijIdeInfo.ArtifactLocation location) {
+ if (location == null) {
return null;
}
+ String relativePath = location.getRelativePath();
+ String rootExecutionPathFragment = location.getRootExecutionPathFragment();
+ if (!location.getIsNewExternalVersion() && location.getIsExternal()) {
+ // fix up incorrect paths created with older aspect version
+ // Note: bazel always uses the '/' separator here, even on windows.
+ List<String> components = StringUtil.split(relativePath, "/");
+ if (components.size() > 2) {
+ relativePath = Joiner.on('/').join(components.subList(2, components.size()));
+ String prefix = components.get(0) + "/" + components.get(1);
+ rootExecutionPathFragment =
+ rootExecutionPathFragment.isEmpty() ? prefix : rootExecutionPathFragment + "/" + prefix;
+ }
+ }
return ArtifactLocation.builder()
- .setRootExecutionPathFragment(pbArtifactLocation.getRootExecutionPathFragment())
- .setRelativePath(pbArtifactLocation.getRelativePath())
- .setIsSource(pbArtifactLocation.getIsSource())
- .setIsExternal(pbArtifactLocation.getIsExternal())
+ .setRootExecutionPathFragment(rootExecutionPathFragment)
+ .setRelativePath(relativePath)
+ .setIsSource(location.getIsSource())
+ .setIsExternal(location.getIsExternal())
.build();
}
@Nullable
- private static Kind getKind(IntellijIdeInfo.TargetIdeInfo target) {
- String kindString = target.getKindString();
+ static Kind getKind(IntellijIdeInfo.TargetIdeInfo message) {
+ String kindString = message.getKindString();
if (!Strings.isNullOrEmpty(kindString)) {
return Kind.fromString(kindString);
}
return null;
}
+
+ static TargetKey getKey(IntellijIdeInfo.TargetIdeInfo message) {
+ return message.hasKey()
+ ? makeTargetKey(message.getKey())
+ : TargetKey.forPlainTarget(Label.create(message.getLabel()));
+ }
}
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
index 8509647..e76ead1 100644
--- a/base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/UnfilteredCompilerOptions.java
@@ -15,70 +15,173 @@
*/
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 com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
- * unfilteredCompilerOptions is a grab bag of options passed to the compiler. Do minimal parsing to
- * extract what we need.
+ * Parses any compiler options that were not extracted by the build system earlier. 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;
+ static class Builder {
+ private final BaseOptionParser baseOptionParser = new BaseOptionParser();
+ private final ImmutableMap.Builder<String, OptionParser> registeredParsers =
+ ImmutableMap.builder();
- public UnfilteredCompilerOptions(Iterable<String> unfilteredOptions) {
- List<String> toolchainSystemIncludePaths = Lists.newArrayList();
- toolchainFlags = Lists.newArrayList();
- splitUnfilteredCompilerOptions(unfilteredOptions, toolchainSystemIncludePaths, toolchainFlags);
+ /** Have the options parser handle the given one-or-two-token option (e.g., -Ifoo or -I foo). */
+ Builder registerSingleOrSplitOption(String optionName) {
+ registeredParsers.put(
+ optionName, new SingleOrSplitOptionParser(optionName, baseOptionParser));
+ return this;
+ }
- toolchainSysIncludes = Lists.newArrayList();
- for (String systemInclude : toolchainSystemIncludePaths) {
- toolchainSysIncludes.add(new ExecutionRootPath(systemInclude));
+ /** Parse the given options and build extracted compiler options */
+ UnfilteredCompilerOptions build(Iterable<String> unfilteredOptions) {
+ ImmutableMap<String, OptionParser> registered = registeredParsers.build();
+ baseOptionParser.setRegisteredOptionParsers(registered.values());
+ UnfilteredCompilerOptions options =
+ new UnfilteredCompilerOptions(baseOptionParser, registered);
+ options.parse(unfilteredOptions);
+ return options;
}
}
- public List<String> getToolchainFlags() {
- return toolchainFlags;
+ /** Make a new builder to register options to extract. */
+ static Builder builder() {
+ return new Builder();
}
- public List<ExecutionRootPath> getToolchainSysIncludes() {
- return toolchainSysIncludes;
+ private final OptionParser baseOptionParser;
+ private final ImmutableMap<String, OptionParser> registeredParsers;
+
+ private UnfilteredCompilerOptions(
+ OptionParser baseOptionParser, ImmutableMap<String, OptionParser> registeredParsers) {
+ this.baseOptionParser = baseOptionParser;
+ this.registeredParsers = registeredParsers;
}
- @VisibleForTesting
- static void splitUnfilteredCompilerOptions(
- Iterable<String> unfilteredOptions,
- List<String> toolchainSysIncludes,
- List<String> toolchainFlags) {
- NextOption nextOption = NextOption.FLAG;
+ private void parse(Iterable<String> unfilteredOptions) {
+ OptionParser nextOptionParser = baseOptionParser;
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;
+ nextOptionParser = nextOptionParser.parseValue(unfilteredOption);
+ }
+ }
+
+ /**
+ * Return the list of arguments that are not extracted (don't correspond to a registered option),
+ * in the original order.
+ */
+ List<String> getUninterpretedOptions() {
+ return baseOptionParser.values();
+ }
+
+ /**
+ * Return the extracted option values for the given registered option name. E.g., if -I is
+ * registered, and ["-foo", "-Ibar"] is parsed then getExtractedOptionValues("-I") returns
+ * ["bar"]. List is in the original order.
+ *
+ * @param optionName the name of a flag that was registered to be extracted
+ * @return option values corresponding to the flag.
+ */
+ List<String> getExtractedOptionValues(String optionName) {
+ OptionParser parser = registeredParsers.get(optionName);
+ Preconditions.checkNotNull(parser);
+ return parser.values();
+ }
+
+ private interface OptionParser {
+ /** Checks if the parser handles the next option value. */
+ boolean handlesOptionValue(String optionValue);
+
+ /**
+ * Parses the option and returns the next handler (assumes {@link #handlesOptionValue} is true).
+ */
+ OptionParser parseValue(String optionValue);
+
+ /** Return a list of option values captured by the parser. */
+ List<String> values();
+ }
+
+ /**
+ * A base option parser that defers to a list of more-specific registered flag parsers, before
+ * handling the flag itself.
+ */
+ private static class BaseOptionParser implements OptionParser {
+ private final List<String> values = new ArrayList<>();
+ private Collection<OptionParser> registeredOptionParsers;
+
+ void setRegisteredOptionParsers(Collection<OptionParser> registeredOptionParsers) {
+ this.registeredOptionParsers = registeredOptionParsers;
+ }
+
+ @Override
+ public boolean handlesOptionValue(String optionValue) {
+ return true;
+ }
+
+ @Override
+ public OptionParser parseValue(String optionValue) {
+ for (OptionParser registeredParser : registeredOptionParsers) {
+ if (registeredParser.handlesOptionValue(optionValue)) {
+ return registeredParser.parseValue(optionValue);
}
}
+ values.add(optionValue);
+ return this;
+ }
+
+ @Override
+ public List<String> values() {
+ return values;
+ }
+ }
+
+ /**
+ * A parser that handles flags that can be one or two tokens (e.g., "-Ihdrs", vs "-I", "hdrs").
+ */
+ private static class SingleOrSplitOptionParser implements OptionParser {
+ private final String optionName;
+ private final BaseOptionParser baseOptionParser;
+ private final List<String> values = new ArrayList<>();
+ private boolean consumeNext;
+
+ SingleOrSplitOptionParser(String optionName, BaseOptionParser baseOptionParser) {
+ this.optionName = optionName;
+ this.baseOptionParser = baseOptionParser;
+ }
+
+ @Override
+ public boolean handlesOptionValue(String optionValue) {
+ return consumeNext || optionValue.startsWith(optionName);
+ }
+
+ @Override
+ public OptionParser parseValue(String optionValue) {
+ if (consumeNext) {
+ consumeNext = false;
+ values.add(optionValue);
+ return baseOptionParser;
+ }
+ if (optionValue.equals(optionName)) {
+ consumeNext = true;
+ return this;
+ }
+ if (optionValue.startsWith(optionName)) {
+ values.add(optionValue.substring(optionName.length()));
+ return baseOptionParser;
+ }
+ Preconditions.checkState(
+ false, "Should check handlesOptionValue before attempting to parseValue");
+ return null;
+ }
+
+ @Override
+ public List<String> values() {
+ return values;
}
}
}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyNative.java b/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyNative.java
deleted file mode 100644
index 63787db..0000000
--- a/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyNative.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.sync.aspects.strategy;
-
-import com.google.idea.blaze.base.command.BlazeCommand;
-import com.google.repackaged.devtools.intellij.ideinfo.IntellijIdeInfo;
-import java.io.IOException;
-import java.io.InputStream;
-
-/** Aspect strategy for native. */
-public class AspectStrategyNative implements 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 void modifyIdeCompileCommand(BlazeCommand.Builder blazeCommandBuilder) {
- blazeCommandBuilder
- .addBlazeFlags("--aspects=AndroidStudioInfoAspect")
- .addBlazeFlags("--output_groups=ide-compile");
- }
-
- @Override
- public String getAspectOutputFileExtension() {
- return ".aswb-build";
- }
-
- @Override
- public IntellijIdeInfo.TargetIdeInfo readAspectFile(InputStream inputStream) throws IOException {
- return IntellijIdeInfo.TargetIdeInfo.parseFrom(inputStream);
- }
-}
diff --git a/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyProviderBazel.java b/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyProviderBazel.java
index 180ae9e..9c0faa4 100644
--- a/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyProviderBazel.java
+++ b/base/src/com/google/idea/blaze/base/sync/aspects/strategy/AspectStrategyProviderBazel.java
@@ -16,18 +16,11 @@
package com.google.idea.blaze.base.sync.aspects.strategy;
import com.google.idea.blaze.base.model.BlazeVersionData;
-import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.openapi.project.Project;
class AspectStrategyProviderBazel implements AspectStrategyProvider {
- private static final BoolExperiment useSkylarkAspect =
- new BoolExperiment("use.skylark.aspect.bazel.2", true);
-
@Override
public AspectStrategy getAspectStrategy(Project project, BlazeVersionData blazeVersionData) {
- boolean canUseSkylark =
- useSkylarkAspect.getValue() && blazeVersionData.bazelIsAtLeastVersion(0, 4, 4);
-
- return canUseSkylark ? new AspectStrategySkylark() : new AspectStrategyNative();
+ return new AspectStrategySkylark();
}
}
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
index bd4494f..2720611 100644
--- a/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java
+++ b/base/src/com/google/idea/blaze/base/sync/data/BlazeProjectDataManagerImpl.java
@@ -18,8 +18,6 @@
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.sync.BlazeSyncPlugin;
import com.google.idea.blaze.base.util.SerializationUtil;
@@ -52,15 +50,14 @@
}
@Nullable
- public BlazeProjectData loadProjectRoot(
- BlazeContext context, BlazeImportSettings importSettings) {
+ public BlazeProjectData loadProjectRoot(BlazeImportSettings importSettings) throws IOException {
BlazeProjectData projectData = blazeProjectData;
if (projectData != null) {
return projectData;
}
synchronized (this) {
projectData = blazeProjectData;
- return projectData != null ? projectData : loadProject(context, importSettings);
+ return projectData != null ? projectData : loadProject(importSettings);
}
}
@@ -71,29 +68,18 @@
}
@Nullable
- private synchronized BlazeProjectData loadProject(
- BlazeContext context, BlazeImportSettings importSettings) {
- BlazeProjectData blazeProjectData = null;
- try {
- File file = getCacheFile(project, importSettings);
+ private synchronized BlazeProjectData loadProject(BlazeImportSettings importSettings)
+ throws IOException {
+ 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)));
- logger.info(e);
+ 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());
- this.blazeProjectData = blazeProjectData;
+ blazeProjectData = (BlazeProjectData) SerializationUtil.loadFromDisk(file, classLoaders);
return blazeProjectData;
}
diff --git a/base/src/com/google/idea/blaze/base/sync/libraries/BlazeLibraryCollector.java b/base/src/com/google/idea/blaze/base/sync/libraries/BlazeLibraryCollector.java
index 9e029ed..c8e38db 100644
--- a/base/src/com/google/idea/blaze/base/sync/libraries/BlazeLibraryCollector.java
+++ b/base/src/com/google/idea/blaze/base/sync/libraries/BlazeLibraryCollector.java
@@ -16,21 +16,26 @@
package com.google.idea.blaze.base.sync.libraries;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.idea.blaze.base.model.BlazeLibrary;
import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/** Collects libraries from the sync data using all contributors. */
public class BlazeLibraryCollector {
- public static List<BlazeLibrary> getLibraries(BlazeProjectData blazeProjectData) {
- List<BlazeLibrary> result = Lists.newArrayList();
+ public static List<BlazeLibrary> getLibraries(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
+ // Use set to filter out duplicates.
+ Set<BlazeLibrary> result = Sets.newLinkedHashSet();
List<LibrarySource> librarySources = Lists.newArrayList();
for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- LibrarySource librarySource = syncPlugin.getLibrarySource(blazeProjectData);
+ LibrarySource librarySource = syncPlugin.getLibrarySource(projectViewSet, blazeProjectData);
if (librarySource != null) {
librarySources.add(librarySource);
}
diff --git a/base/src/com/google/idea/blaze/base/sync/libraries/LibraryEditor.java b/base/src/com/google/idea/blaze/base/sync/libraries/LibraryEditor.java
index 44969c3..cd59adb 100644
--- a/base/src/com/google/idea/blaze/base/sync/libraries/LibraryEditor.java
+++ b/base/src/com/google/idea/blaze/base/sync/libraries/LibraryEditor.java
@@ -20,6 +20,7 @@
import com.google.idea.blaze.base.model.BlazeLibrary;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.LibraryKey;
+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.sync.BlazeSyncPlugin;
@@ -45,6 +46,7 @@
public static void updateProjectLibraries(
Project project,
BlazeContext context,
+ ProjectViewSet projectViewSet,
BlazeProjectData blazeProjectData,
Collection<BlazeLibrary> libraries) {
Set<LibraryKey> intelliJLibraryState = Sets.newHashSet();
@@ -71,7 +73,7 @@
// Garbage collect unused libraries
List<LibrarySource> librarySources = Lists.newArrayList();
for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- LibrarySource librarySource = syncPlugin.getLibrarySource(blazeProjectData);
+ LibrarySource librarySource = syncPlugin.getLibrarySource(projectViewSet, blazeProjectData);
if (librarySource != null) {
librarySources.add(librarySource);
}
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
index 5b76a0c..b179a7d 100644
--- a/base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ContentEntryEditor.java
@@ -19,7 +19,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
-import com.google.idea.blaze.base.io.FileAttributeProvider;
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;
@@ -36,6 +35,7 @@
import java.io.File;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
/** Modifies content entries based on project data. */
public class ContentEntryEditor {
@@ -45,6 +45,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeProjectData blazeProjectData,
+ DirectoryStructure rootDirectoryStructure,
ModifiableRootModel modifiableRootModel) {
ImportRoots importRoots =
ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
@@ -60,9 +61,9 @@
List<ContentEntry> contentEntries = Lists.newArrayList();
for (WorkspacePath rootDirectory : rootDirectories) {
- File root = workspaceRoot.fileForPath(rootDirectory);
+ File rootFile = workspaceRoot.fileForPath(rootDirectory);
ContentEntry contentEntry =
- modifiableRootModel.addContentEntry(UrlUtil.pathToUrl(root.getPath()));
+ modifiableRootModel.addContentEntry(UrlUtil.pathToUrl(rootFile.getPath()));
contentEntries.add(contentEntry);
for (WorkspacePath exclude : excludesByRootDirectory.get(rootDirectory)) {
@@ -72,7 +73,7 @@
ImmutableMap<File, SourceFolder> sourceFolders =
provider.initializeSourceFolders(contentEntry);
- SourceFolder rootSource = sourceFolders.get(root);
+ SourceFolder rootSource = sourceFolders.get(rootFile);
walkFileSystem(
workspaceRoot,
testConfig,
@@ -81,7 +82,8 @@
provider,
sourceFolders,
rootSource,
- root);
+ rootDirectory,
+ rootDirectoryStructure.directories.get(rootDirectory));
}
}
@@ -93,20 +95,12 @@
SourceFolderProvider provider,
ImmutableMap<File, SourceFolder> sourceFolders,
SourceFolder parent,
- File file) {
- if (!FileAttributeProvider.getInstance().isDirectory(file)) {
- return;
- }
- WorkspacePath workspacePath;
- try {
- workspacePath = workspaceRoot.workspacePathFor(file);
- } catch (IllegalArgumentException e) {
- // stop at directories with unhandled characters.
- return;
- }
+ WorkspacePath workspacePath,
+ DirectoryStructure directoryStructure) {
if (excludedDirectories.contains(workspacePath)) {
return;
}
+ File file = workspaceRoot.fileForPath(workspacePath);
boolean isTest = testConfig.isTestSource(workspacePath.relativePath());
SourceFolder current = sourceFolders.get(new File(file.getPath()));
SourceFolder currentOrParent = current != null ? current : parent;
@@ -117,11 +111,8 @@
contentEntry.removeSourceFolder(current);
}
}
- File[] children = FileAttributeProvider.getInstance().listFiles(file);
- if (children == null) {
- return;
- }
- for (File child : children) {
+ for (Map.Entry<WorkspacePath, DirectoryStructure> child :
+ directoryStructure.directories.entrySet()) {
walkFileSystem(
workspaceRoot,
testConfig,
@@ -130,7 +121,8 @@
provider,
sourceFolders,
currentOrParent,
- child);
+ child.getKey(),
+ child.getValue());
}
}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/DirectoryStructure.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/DirectoryStructure.java
new file mode 100644
index 0000000..827e13e
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/DirectoryStructure.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.sync.projectstructure;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+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.FetchExecutor;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.projectview.ImportRoots;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+
+/**
+ * Directory structure representation used by {@link ContentEntryEditor}.
+ *
+ * <p>The purpose of this class is to pull out all file system operations out of the project
+ * structure commit step, as this step locks the UI.
+ */
+public class DirectoryStructure {
+
+ final ImmutableMap<WorkspacePath, DirectoryStructure> directories;
+
+ private DirectoryStructure(ImmutableMap<WorkspacePath, DirectoryStructure> directories) {
+ this.directories = directories;
+ }
+
+ public static ListenableFuture<DirectoryStructure> getRootDirectoryStructure(
+ Project project, WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
+ return FetchExecutor.EXECUTOR.submit(
+ () -> computeRootDirectoryStructure(project, workspaceRoot, projectViewSet));
+ }
+
+ private static DirectoryStructure computeRootDirectoryStructure(
+ Project project, WorkspaceRoot workspaceRoot, ProjectViewSet projectViewSet) {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, Blaze.getBuildSystem(project))
+ .add(projectViewSet)
+ .build();
+ Collection<WorkspacePath> rootDirectories = importRoots.rootDirectories();
+ ImmutableMap.Builder<WorkspacePath, DirectoryStructure> result = ImmutableMap.builder();
+ for (WorkspacePath rootDirectory : rootDirectories) {
+ walkDirectoryStructure(workspaceRoot, result, rootDirectory);
+ }
+ return new DirectoryStructure(result.build());
+ }
+
+ private static void walkDirectoryStructure(
+ WorkspaceRoot workspaceRoot,
+ ImmutableMap.Builder<WorkspacePath, DirectoryStructure> parent,
+ WorkspacePath workspacePath) {
+ File file = workspaceRoot.fileForPath(workspacePath);
+ if (!FileAttributeProvider.getInstance().isDirectory(file)) {
+ return;
+ }
+ ImmutableMap.Builder<WorkspacePath, DirectoryStructure> result = ImmutableMap.builder();
+ File[] children = FileAttributeProvider.getInstance().listFiles(file);
+ if (children != null) {
+ for (File child : children) {
+ WorkspacePath childWorkspacePath;
+ try {
+ childWorkspacePath = workspaceRoot.workspacePathFor(child);
+ } catch (IllegalArgumentException e) {
+ // stop at directories with unhandled characters.
+ continue;
+ }
+ walkDirectoryStructure(workspaceRoot, result, childWorkspacePath);
+ }
+ }
+ parent.put(workspacePath, new DirectoryStructure(result.build()));
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleFinder.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleFinder.java
new file mode 100644
index 0000000..2973200
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleFinder.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Service for looking up modules (might not be committed during tests). */
+public interface ModuleFinder {
+
+ static ModuleFinder getInstance(Project project) {
+ return ServiceManager.getService(project, ModuleFinder.class);
+ }
+
+ @Nullable
+ Module findModuleByName(String name);
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleFinderImpl.java b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleFinderImpl.java
new file mode 100644
index 0000000..36413f1
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectstructure/ModuleFinderImpl.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Default implementation of {@link ModuleFinder} */
+public class ModuleFinderImpl implements ModuleFinder {
+
+ private final Project project;
+
+ ModuleFinderImpl(Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public Module findModuleByName(String name) {
+ return ModuleManager.getInstance(project).findModuleByName(name);
+ }
+}
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
index c484df1..38568dc 100644
--- a/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java
@@ -23,16 +23,34 @@
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.projectview.section.sections.DirectoryEntry;
import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
+import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.google.idea.blaze.base.util.WorkspacePathUtil;
+import com.intellij.openapi.project.Project;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
import java.util.Collection;
import java.util.Set;
+import javax.annotation.Nullable;
/** The roots to import. Derived from project view. */
public final class ImportRoots {
+
+ /** Returns the ImportRoots for the project, or null if it's not a blaze project. */
+ @Nullable
+ public static ImportRoots forProjectSafe(Project project) {
+ WorkspaceRoot root = WorkspaceRoot.fromProjectSafe(project);
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ if (root == null || projectViewSet == null) {
+ return null;
+ }
+ return ImportRoots.builder(root, Blaze.getBuildSystem(project)).add(projectViewSet).build();
+ }
+
/** Builder for import roots */
public static class Builder {
private final ImmutableCollection.Builder<WorkspacePath> rootDirectoriesBuilder =
@@ -123,29 +141,27 @@
}
private boolean containsLabel(Label label) {
+ return !label.isExternal() && containsWorkspacePath(label.blazePackage());
+ }
+
+ public boolean containsWorkspacePath(WorkspacePath workspacePath) {
boolean included = false;
boolean excluded = false;
- for (WorkspacePath workspacePath : rootDirectories()) {
- included = included || matchesLabel(workspacePath, label);
+ for (WorkspacePath rootDirectory : rootDirectories()) {
+ included = included || isSubdirectory(rootDirectory, workspacePath);
}
- for (WorkspacePath workspacePath : excludeDirectories()) {
- excluded = excluded || matchesLabel(workspacePath, label);
+ for (WorkspacePath excludeDirectory : excludeDirectories()) {
+ excluded = excluded || isSubdirectory(excludeDirectory, workspacePath);
}
return included && !excluded;
}
- private static boolean matchesLabel(WorkspacePath workspacePath, Label label) {
- if (workspacePath.isWorkspaceRoot()) {
+ private static boolean isSubdirectory(WorkspacePath ancestor, WorkspacePath descendant) {
+ if (ancestor.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;
+ Path ancestorPath = FileSystems.getDefault().getPath(ancestor.relativePath());
+ Path descendantPath = FileSystems.getDefault().getPath(descendant.relativePath());
+ return descendantPath.startsWith(ancestorPath);
}
}
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
index da9ae7f..bae9239 100644
--- a/base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/LanguageSupport.java
@@ -15,7 +15,7 @@
*/
package com.google.idea.blaze.base.sync.projectview;
-import com.google.common.collect.Sets;
+import com.google.common.collect.ImmutableSet;
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;
@@ -25,57 +25,81 @@
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.Arrays;
import java.util.EnumSet;
import java.util.Set;
+import javax.annotation.Nullable;
/** Reads the user's language preferences from the project view. */
public class LanguageSupport {
private static final Logger logger = Logger.getInstance(LanguageSupport.class);
- public static WorkspaceLanguageSettings createWorkspaceLanguageSettings(
- BlazeContext context, ProjectViewSet projectViewSet) {
- WorkspaceType workspaceType = projectViewSet.getScalarValue(WorkspaceTypeSection.KEY);
- Set<WorkspaceType> supportedTypes = supportedWorkspaceTypes();
- if (workspaceType != null && !supportedTypes.contains(workspaceType)) {
- IssueOutput.error(
- String.format(
- "Workspace type '%s' is not supported by this plugin", workspaceType.getName()))
- .submit(context);
- return null;
- }
- if (workspaceType == null) {
- // if no workspace type is specified, prioritize by enum ordinal.
- for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
- WorkspaceType recommendedType = syncPlugin.getDefaultWorkspaceType();
- if (recommendedType != null
- && (workspaceType == null || workspaceType.ordinal() > recommendedType.ordinal())) {
- workspaceType = recommendedType;
- }
+ @Nullable
+ public static WorkspaceType getDefaultWorkspaceType() {
+ WorkspaceType workspaceType = null;
+ // prioritize by enum ordinal.
+ for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
+ WorkspaceType recommendedType = syncPlugin.getDefaultWorkspaceType();
+ if (recommendedType != null
+ && (workspaceType == null || workspaceType.ordinal() > recommendedType.ordinal())) {
+ workspaceType = recommendedType;
}
}
+ return workspaceType;
+ }
+
+ /**
+ * Derives {@link WorkspaceLanguageSettings} from the {@link ProjectViewSet}. Does no validation.
+ */
+ @Nullable
+ public static WorkspaceLanguageSettings createWorkspaceLanguageSettings(
+ ProjectViewSet projectViewSet) {
+ WorkspaceType workspaceType = projectViewSet.getScalarValue(WorkspaceTypeSection.KEY);
+ if (workspaceType == null) {
+ workspaceType = getDefaultWorkspaceType();
+ }
if (workspaceType == null) {
logger.error("Could not find workspace type."); // Should never happen
return null;
}
- Set<LanguageClass> activeLanguages = Sets.newHashSet(workspaceType.getLanguages());
- activeLanguages.addAll(projectViewSet.listItems(AdditionalLanguagesSection.KEY));
+ ImmutableSet.Builder<LanguageClass> activeLanguages =
+ ImmutableSet.<LanguageClass>builder()
+ .addAll(workspaceType.getLanguages())
+ .addAll(projectViewSet.listItems(AdditionalLanguagesSection.KEY))
+ .add(LanguageClass.GENERIC);
+ Arrays.stream(BlazeSyncPlugin.EP_NAME.getExtensions())
+ .forEach(plugin -> activeLanguages.addAll(plugin.getAlwaysActiveLanguages()));
+ return new WorkspaceLanguageSettings(workspaceType, activeLanguages.build());
+ }
+ public static boolean validateLanguageSettings(
+ BlazeContext context, WorkspaceLanguageSettings languageSettings) {
+ Set<WorkspaceType> supportedTypes = supportedWorkspaceTypes();
+ WorkspaceType workspaceType = languageSettings.getWorkspaceType();
+ if (!supportedTypes.contains(languageSettings.getWorkspaceType())) {
+ IssueOutput.error(
+ String.format(
+ "Workspace type '%s' is not supported by this plugin",
+ languageSettings.getWorkspaceType().getName()))
+ .submit(context);
+ return false;
+ }
Set<LanguageClass> supportedLanguages = supportedLanguagesForWorkspaceType(workspaceType);
Set<LanguageClass> availableLanguages = EnumSet.noneOf(LanguageClass.class);
for (WorkspaceType type : supportedTypes) {
availableLanguages.addAll(supportedLanguagesForWorkspaceType(type));
}
- for (LanguageClass languageClass : activeLanguages) {
+ for (LanguageClass languageClass : languageSettings.activeLanguages) {
if (!availableLanguages.contains(languageClass)) {
IssueOutput.error(
String.format(
"Language '%s' is not supported by this plugin", languageClass.getName()))
.submit(context);
- return null;
+ return false;
}
if (!supportedLanguages.contains(languageClass)) {
IssueOutput.error(
@@ -83,12 +107,10 @@
"Language '%s' is not supported for this plugin with workspace type: '%s'",
languageClass.getName(), workspaceType.getName()))
.submit(context);
- return null;
+ return false;
}
}
-
- activeLanguages.add(LanguageClass.GENERIC);
- return new WorkspaceLanguageSettings(workspaceType, activeLanguages);
+ return true;
}
/** The {@link WorkspaceType}s supported by this plugin */
@@ -105,7 +127,21 @@
Set<LanguageClass> supportedLanguages = EnumSet.noneOf(LanguageClass.class);
for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
supportedLanguages.addAll(syncPlugin.getSupportedLanguagesInWorkspace(type));
+ supportedLanguages.addAll(syncPlugin.getAlwaysActiveLanguages());
}
+ supportedLanguages.add(LanguageClass.GENERIC);
return supportedLanguages;
}
+
+ /** @return The valid 'additional_language' options for this workspace type */
+ public static Set<LanguageClass> availableAdditionalLanguages(WorkspaceType workspaceType) {
+ Set<LanguageClass> langs = LanguageSupport.supportedLanguagesForWorkspaceType(workspaceType);
+ langs.removeAll(workspaceType.getLanguages());
+ langs.remove(LanguageClass.GENERIC);
+
+ Arrays.stream(BlazeSyncPlugin.EP_NAME.getExtensions())
+ .forEach(plugin -> langs.removeAll(plugin.getAlwaysActiveLanguages()));
+
+ return langs;
+ }
}
diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/RelatedWorkspacePathFinder.java b/base/src/com/google/idea/blaze/base/sync/projectview/RelatedWorkspacePathFinder.java
new file mode 100644
index 0000000..9006605
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/RelatedWorkspacePathFinder.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.ImmutableSet;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.components.ServiceManager;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/** Utility class to find WorkspacePaths that are related */
+public final class RelatedWorkspacePathFinder {
+
+ private final FileAttributeProvider fileAttributeProvider;
+
+ RelatedWorkspacePathFinder(FileAttributeProvider fileAttributeProvider) {
+ this.fileAttributeProvider = fileAttributeProvider;
+ }
+
+ public static RelatedWorkspacePathFinder getInstance() {
+ return ServiceManager.getService(RelatedWorkspacePathFinder.class);
+ }
+
+ public ImmutableSet<WorkspacePath> findRelatedWorkspaceDirectories(
+ WorkspacePathResolver pathResolver, WorkspacePath workspacePath) {
+
+ Path path = Paths.get(workspacePath.relativePath());
+ Path testsPath = Paths.get("");
+
+ boolean foundTests = false;
+ for (Path element : path) {
+ if (!foundTests && element.toString().equals("java")) {
+ Path potentialTestsPath = testsPath.resolve("javatests");
+ if (exists(pathResolver.resolveToFile(potentialTestsPath.toString()))) {
+ testsPath = potentialTestsPath;
+ foundTests = true;
+ continue;
+ }
+ }
+
+ testsPath = testsPath.resolve(element);
+ }
+
+ if (!foundTests || !exists(pathResolver.resolveToFile(testsPath.toString()))) {
+ return ImmutableSet.of();
+ }
+
+ return ImmutableSet.of(new WorkspacePath(testsPath.toString()));
+ }
+
+ private boolean exists(File file) {
+ return fileAttributeProvider.exists(file);
+ }
+}
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
index 4ebde4d..5fdd67f 100644
--- a/base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java
+++ b/base/src/com/google/idea/blaze/base/sync/projectview/WorkspaceLanguageSettings.java
@@ -16,10 +16,12 @@
package com.google.idea.blaze.base.sync.projectview;
import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.primitives.Kind;
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 java.util.EnumSet;
import javax.annotation.concurrent.Immutable;
/** Contains the user's language preferences from the project view. */
@@ -28,10 +30,10 @@
private static final long serialVersionUID = 1L;
private final WorkspaceType workspaceType;
- private final Set<LanguageClass> activeLanguages;
+ final ImmutableSet<LanguageClass> activeLanguages;
public WorkspaceLanguageSettings(
- WorkspaceType workspaceType, Set<LanguageClass> activeLanguages) {
+ WorkspaceType workspaceType, ImmutableSet<LanguageClass> activeLanguages) {
this.workspaceType = workspaceType;
this.activeLanguages = activeLanguages;
}
@@ -57,6 +59,12 @@
return activeLanguages.contains(languageClass);
}
+ public EnumSet<Kind> getAvailableTargetKinds() {
+ EnumSet<Kind> kinds = EnumSet.allOf(Kind.class);
+ kinds.removeIf(kind -> !activeLanguages.contains(kind.getLanguageClass()));
+ return kinds;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/BlazeBuildTargetSharder.java b/base/src/com/google/idea/blaze/base/sync/sharding/BlazeBuildTargetSharder.java
new file mode 100644
index 0000000..8f2279c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/BlazeBuildTargetSharder.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import com.google.common.collect.ImmutableList;
+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.ShardBlazeBuildsSection;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.aspects.BuildResult;
+import com.google.idea.blaze.base.sync.sharding.WildcardTargetExpander.ExpandedTargetsResult;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.openapi.project.Project;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/** Utility methods for sharding blaze build invocations. */
+public class BlazeBuildTargetSharder {
+
+ private static final BoolExperiment allowSharding =
+ new BoolExperiment("blaze.build.sharding.allowed", true);
+
+ // number of packages per blaze query shard
+ static final int PACKAGE_SHARD_SIZE = 500;
+
+ // number of individual targets per blaze build shard
+ private static final int TARGET_SHARD_SIZE = 1000;
+
+ /** Result of expanding then sharding wildcard target patterns */
+ public static class ShardedTargetsResult {
+ public final ShardedTargetList shardedTargets;
+ public final BuildResult buildResult;
+
+ private ShardedTargetsResult(ShardedTargetList shardedTargets, BuildResult buildResult) {
+ this.shardedTargets = shardedTargets;
+ this.buildResult = buildResult;
+ }
+ }
+
+ /** Returns true if sharding can be enabled for this project, and is not already enabled */
+ static boolean canEnableSharding(Project project) {
+ if (!allowSharding.getValue()) {
+ return false;
+ }
+ ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
+ return projectViewSet != null && !shardingEnabled(projectViewSet);
+ }
+
+ private static boolean shardingEnabled(ProjectViewSet projectViewSet) {
+ if (!allowSharding.getValue()) {
+ return false;
+ }
+ return projectViewSet.getScalarValue(ShardBlazeBuildsSection.KEY, false);
+ }
+
+ /** Expand wildcard target patterns and partition the resulting target list. */
+ public static ShardedTargetsResult expandAndShardTargets(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspacePathResolver pathResolver,
+ List<TargetExpression> targets) {
+ if (!shardingEnabled(projectViewSet)) {
+ return new ShardedTargetsResult(
+ new ShardedTargetList(ImmutableList.of(targets)), BuildResult.SUCCESS);
+ }
+
+ List<WildcardTargetPattern> wildcardIncludes = getWildcardPatterns(targets);
+ if (wildcardIncludes.isEmpty()) {
+ return new ShardedTargetsResult(
+ new ShardedTargetList(ImmutableList.of(targets)), BuildResult.SUCCESS);
+ }
+ ExpandedTargetsResult expandedTargets =
+ expandWildcardTargets(
+ project, context, workspaceRoot, projectViewSet, pathResolver, targets);
+ if (expandedTargets.buildResult.status == BuildResult.Status.FATAL_ERROR) {
+ return new ShardedTargetsResult(
+ new ShardedTargetList(ImmutableList.of()), expandedTargets.buildResult);
+ }
+ return new ShardedTargetsResult(
+ shardTargets(expandedTargets.singleTargets, TARGET_SHARD_SIZE),
+ expandedTargets.buildResult);
+ }
+
+ /** Expand wildcard target patterns into individual blaze targets. */
+ private static ExpandedTargetsResult expandWildcardTargets(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspacePathResolver pathResolver,
+ List<TargetExpression> targets) {
+ if (!shardingEnabled(projectViewSet)) {
+ return new ExpandedTargetsResult(targets, BuildResult.SUCCESS);
+ }
+ List<WildcardTargetPattern> includes = getWildcardPatterns(targets);
+ if (includes.isEmpty()) {
+ return new ExpandedTargetsResult(targets, BuildResult.SUCCESS);
+ }
+ Map<TargetExpression, List<TargetExpression>> expandedTargets =
+ WildcardTargetExpander.expandToNonRecursiveWildcardTargets(
+ project, context, pathResolver, includes);
+ if (expandedTargets == null) {
+ return new ExpandedTargetsResult(ImmutableList.of(), BuildResult.FATAL_ERROR);
+ }
+
+ // replace original recursive targets with expanded list, retaining relative ordering
+ List<TargetExpression> fullList = new ArrayList<>();
+ for (TargetExpression target : targets) {
+ List<TargetExpression> expanded = expandedTargets.get(target);
+ if (expanded == null) {
+ fullList.add(target);
+ } else {
+ fullList.addAll(expanded);
+ }
+ }
+ return WildcardTargetExpander.expandToSingleTargets(
+ project, context, workspaceRoot, projectViewSet, fullList);
+ }
+
+ /**
+ * Partition targets list. Because order is important with respect to excluded targets, each shard
+ * has all subsequent excluded targets appended to it.
+ */
+ static ShardedTargetList shardTargets(List<TargetExpression> targets, int shardSize) {
+ if (targets.size() <= shardSize) {
+ return new ShardedTargetList(ImmutableList.of(targets));
+ }
+ List<List<TargetExpression>> output = new ArrayList<>();
+ for (int index = 0; index < targets.size(); index += shardSize) {
+ int endIndex = Math.min(targets.size(), index + shardSize);
+ List<TargetExpression> shard = new ArrayList<>(targets.subList(index, endIndex));
+ List<TargetExpression> remainingExcludes =
+ targets
+ .subList(endIndex, targets.size())
+ .stream()
+ .filter(TargetExpression::isExcluded)
+ .collect(Collectors.toList());
+ shard.addAll(remainingExcludes);
+ output.add(shard);
+ }
+ return new ShardedTargetList(output);
+ }
+
+ /** Returns the wildcard target patterns, ignoring exclude patterns (those starting with '-') */
+ private static List<WildcardTargetPattern> getWildcardPatterns(List<TargetExpression> targets) {
+ return targets
+ .stream()
+ .filter(t -> !t.isExcluded())
+ .map(WildcardTargetPattern::fromExpression)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ private BlazeBuildTargetSharder() {}
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/PackageLister.java b/base/src/com/google/idea/blaze/base/sync/sharding/PackageLister.java
new file mode 100644
index 0000000..d87d205
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/PackageLister.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+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.FutureUtil.FutureResult;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.prefetch.FetchExecutor;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.blaze.base.util.WorkspacePathUtil;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * Traverses blaze packages specified by wildcard target patterns, expanding to a set of
+ * single-package target patterns.
+ */
+class PackageLister {
+
+ private PackageLister() {}
+
+ /** The set of blaze packages to prefetch prior to traversing the directory tree. */
+ static Set<File> getDirectoriesToPrefetch(
+ WorkspacePathResolver pathResolver,
+ Collection<WildcardTargetPattern> includes,
+ Predicate<WorkspacePath> excluded) {
+ Set<WorkspacePath> prefetchPaths = new HashSet<>();
+ for (WildcardTargetPattern pattern : includes) {
+ WorkspacePath workspacePath = pattern.getBasePackage();
+ if (excluded.test(workspacePath)) {
+ continue;
+ }
+ prefetchPaths.add(workspacePath);
+ }
+ return WorkspacePathUtil.calculateMinimalWorkspacePaths(prefetchPaths)
+ .stream()
+ .map(pathResolver::resolveToFile)
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Expands all-in-package-recursive wildcard targets into all-in-single-package targets by
+ * traversing the file system, looking for child blaze packages.
+ *
+ * <p>Returns null if directory traversal failed or was cancelled.
+ */
+ @Nullable
+ static Map<TargetExpression, List<TargetExpression>> expandPackageTargets(
+ BuildSystemProvider provider,
+ BlazeContext context,
+ WorkspacePathResolver pathResolver,
+ Collection<WildcardTargetPattern> wildcardPatterns) {
+ List<ListenableFuture<Entry<TargetExpression, List<TargetExpression>>>> futures =
+ Lists.newArrayList();
+ for (WildcardTargetPattern pattern : wildcardPatterns) {
+ if (!pattern.isRecursive() || pattern.toString().startsWith("-")) {
+ continue;
+ }
+ File dir = pathResolver.resolveToFile(pattern.getBasePackage());
+ if (!FileAttributeProvider.getInstance().isDirectory(dir)) {
+ continue;
+ }
+ futures.add(
+ FetchExecutor.EXECUTOR.submit(
+ () -> {
+ List<TargetExpression> expandedTargets = new ArrayList<>();
+ traversePackageRecursively(provider, pathResolver, dir, expandedTargets);
+ return Maps.immutableEntry(pattern.originalPattern, expandedTargets);
+ }));
+ }
+ if (futures.isEmpty()) {
+ return ImmutableMap.of();
+ }
+ FutureResult<List<Entry<TargetExpression, List<TargetExpression>>>> result =
+ FutureUtil.waitForFuture(context, Futures.allAsList(futures))
+ .withProgressMessage("Expanding wildcard target patterns...")
+ .timed("ExpandWildcardTargets")
+ .onError("Expanding wildcard target patterns failed")
+ .run();
+ if (!result.success()) {
+ return null;
+ }
+ return result
+ .result()
+ .stream()
+ .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (x, y) -> x));
+ }
+
+ private static void traversePackageRecursively(
+ BuildSystemProvider provider,
+ WorkspacePathResolver pathResolver,
+ File dir,
+ List<TargetExpression> output) {
+ WorkspacePath path = pathResolver.getWorkspacePath(dir);
+ if (path == null) {
+ return;
+ }
+ if (provider.findBuildFileInDirectory(dir) != null) {
+ output.add(TargetExpression.allFromPackageNonRecursive(path));
+ }
+ File[] children = FileAttributeProvider.getInstance().listFiles(dir);
+ if (children == null) {
+ return;
+ }
+ for (File child : children) {
+ traversePackageRecursively(provider, pathResolver, child, output);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/QueryResultLineProcessor.java b/base/src/com/google/idea/blaze/base/sync/sharding/QueryResultLineProcessor.java
new file mode 100644
index 0000000..8d7a46a
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/QueryResultLineProcessor.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.async.process.LineProcessingOutputStream;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Collects the blaze targets output by 'blaze query --output label_kind "targets"' */
+class QueryResultLineProcessor implements LineProcessingOutputStream.LineProcessor {
+
+ static class RuleTypeAndLabel {
+ final String ruleType;
+ final String label;
+
+ private RuleTypeAndLabel(String ruleType, String label) {
+ this.ruleType = ruleType;
+ this.label = label;
+ }
+ }
+
+ private static final Pattern RULE_PATTERN = Pattern.compile("^([^\\s]*) rule ([^\\s]*)$");
+
+ private ImmutableList.Builder<TargetExpression> outputList;
+ private final Predicate<RuleTypeAndLabel> targetFilter;
+
+ /**
+ * @param outputList Parsed target expressions are added to this list
+ * @param targetFilter Ignore targets failing this predicate.
+ */
+ QueryResultLineProcessor(
+ ImmutableList.Builder<TargetExpression> outputList,
+ Predicate<RuleTypeAndLabel> targetFilter) {
+ this.outputList = outputList;
+ this.targetFilter = targetFilter;
+ }
+
+ @Override
+ public boolean processLine(String line) {
+ Matcher match = RULE_PATTERN.matcher(line);
+ if (!match.find()) {
+ return true;
+ }
+ String ruleType = match.group(1);
+ String label = match.group(2);
+ if (targetFilter.test(new RuleTypeAndLabel(ruleType, label))) {
+ outputList.add(TargetExpression.fromString(label));
+ }
+ return true;
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/ShardedTargetList.java b/base/src/com/google/idea/blaze/base/sync/sharding/ShardedTargetList.java
new file mode 100644
index 0000000..139c3b8
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/ShardedTargetList.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+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.StatusOutput;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.aspects.BuildResult;
+import com.intellij.openapi.project.Project;
+import java.util.List;
+import java.util.function.Function;
+
+/** Partitioned list of blaze targets. */
+public class ShardedTargetList {
+
+ public final List<List<TargetExpression>> shardedTargets;
+
+ public ShardedTargetList(List<List<TargetExpression>> shardedTargets) {
+ this.shardedTargets = shardedTargets;
+ }
+
+ public boolean isEmpty() {
+ return shardedTargets.stream().flatMap(List::stream).findFirst().orElse(null) == null;
+ }
+
+ /**
+ * Runs the provided blaze invocation on each target list shard, returning the combined {@link
+ * BuildResult}. Attempts to work around out of memory errors caused by lack of blaze garbage
+ * collection where possible.
+ */
+ public BuildResult runShardedCommand(
+ Project project,
+ BlazeContext context,
+ Function<Integer, String> progressMessage,
+ Function<List<TargetExpression>, BuildResult> invocation) {
+ if (isEmpty()) {
+ return BuildResult.SUCCESS;
+ }
+ if (shardedTargets.size() == 1) {
+ return invocation.apply(shardedTargets.get(0));
+ }
+ int progress = 0;
+ BuildResult output = null;
+ for (int i = 0; i < shardedTargets.size(); i++, progress++) {
+ context.output(new StatusOutput(progressMessage.apply(i + 1)));
+ BuildResult result = invocation.apply(shardedTargets.get(i));
+ if (result.outOfMemory() && progress > 0) {
+ // re-try now that blaze server has restarted
+ progress = 0;
+ IssueOutput.warn(retryOnOomMessage(project, i)).submit(context);
+ result = invocation.apply(shardedTargets.get(i));
+ }
+ output = output == null ? result : BuildResult.combine(output, result);
+ if (output.status == BuildResult.Status.FATAL_ERROR) {
+ return output;
+ }
+ }
+ return output;
+ }
+
+ private String retryOnOomMessage(Project project, int shardIndex) {
+ String buildSystem = Blaze.buildSystemName(project);
+ return String.format(
+ "%s server ran out of memory on shard %s of %s. This is generally caused by %s garbage "
+ + "collection bugs. Attempting to workaround by resuming with a clean %s server.",
+ buildSystem, shardIndex + 1, shardedTargets.size(), buildSystem, buildSystem);
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/SuggestEnablingShardingNotification.java b/base/src/com/google/idea/blaze/base/sync/sharding/SuggestEnablingShardingNotification.java
new file mode 100644
index 0000000..71f69c0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/SuggestEnablingShardingNotification.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import com.google.idea.blaze.base.projectview.ProjectViewEdit;
+import com.google.idea.blaze.base.projectview.section.ScalarSection;
+import com.google.idea.blaze.base.projectview.section.sections.ShardBlazeBuildsSection;
+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.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.BlazeSyncManager;
+import com.google.idea.blaze.base.sync.BlazeSyncParams;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationListener;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.pom.NavigatableAdapter;
+import com.intellij.xml.util.XmlStringUtil;
+import javax.swing.event.HyperlinkEvent;
+
+/** If blaze runs out of memory during sync, suggest that the user enables build sharding. */
+public class SuggestEnablingShardingNotification {
+
+ public static void suggestSharding(Project project, BlazeContext context) {
+ if (!BlazeBuildTargetSharder.canEnableSharding(project)) {
+ return;
+ }
+ String buildSystem = Blaze.buildSystemName(project);
+ String message =
+ String.format(
+ "The %1$s server ran out of memory during sync. This can occur for large projects. You "
+ + "can workaround this by <a href='fix'>sharding the %1$s build during sync</a>, "
+ + "or alternatively allocate more memory to %1$s",
+ buildSystem);
+ IssueOutput.error(message)
+ .navigatable(
+ new NavigatableAdapter() {
+ @Override
+ public void navigate(boolean requestFocus) {
+ enableShardingAndResync(project);
+ }
+ })
+ .submit(context);
+
+ Notification notification =
+ new Notification(
+ "Out of memory during sync",
+ buildSystem + " ran out of memory during sync",
+ XmlStringUtil.wrapInHtml(message),
+ NotificationType.ERROR,
+ new NotificationListener.Adapter() {
+ @Override
+ protected void hyperlinkActivated(
+ Notification notification, HyperlinkEvent hyperlinkEvent) {
+ notification.expire();
+ enableShardingAndResync(project);
+ }
+ });
+ notification.setImportant(true);
+ ApplicationManager.getApplication().invokeLater(() -> notification.notify(project));
+ }
+
+ private static void enableShardingAndResync(Project project) {
+ ProjectViewEdit edit =
+ ProjectViewEdit.editLocalProjectView(
+ project,
+ builder -> {
+ ScalarSection<Boolean> existingSection = builder.getLast(ShardBlazeBuildsSection.KEY);
+ builder.replace(
+ existingSection, ScalarSection.builder(ShardBlazeBuildsSection.KEY).set(true));
+ 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());
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/WildcardTargetExpander.java b/base/src/com/google/idea/blaze/base/sync/sharding/WildcardTargetExpander.java
new file mode 100644
index 0000000..396c1cf
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/WildcardTargetExpander.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.idea.blaze.base.async.FutureUtil;
+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.bazel.BuildSystemProvider;
+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.model.primitives.Kind;
+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.ProjectViewSet;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.output.StatusOutput;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.sync.aspects.BuildResult;
+import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
+import com.google.idea.blaze.base.sync.sharding.QueryResultLineProcessor.RuleTypeAndLabel;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** Expands wildcard target patterns into individual blaze targets. */
+public class WildcardTargetExpander {
+
+ private static final BoolExperiment filterByRuleType =
+ new BoolExperiment("blaze.build.filter.by.rule.type", true);
+
+ static class ExpandedTargetsResult {
+ final List<TargetExpression> singleTargets;
+ final BuildResult buildResult;
+
+ ExpandedTargetsResult(List<TargetExpression> singleTargets, BuildResult buildResult) {
+ this.singleTargets = singleTargets;
+ this.buildResult = buildResult;
+ }
+
+ static ExpandedTargetsResult merge(ExpandedTargetsResult first, ExpandedTargetsResult second) {
+ BuildResult buildResult = BuildResult.combine(first.buildResult, second.buildResult);
+ List<TargetExpression> targets =
+ ImmutableList.<TargetExpression>builder()
+ .addAll(first.singleTargets)
+ .addAll(second.singleTargets)
+ .build();
+ return new ExpandedTargetsResult(targets, buildResult);
+ }
+ }
+
+ /**
+ * Expand recursive wildcard blaze target patterns into single-package wildcard patterns, via a
+ * file system traversal.
+ *
+ * <p>Exclude target patterns (beginning with '-') are not expanded.
+ *
+ * <p>Returns null if operation failed or was cancelled.
+ */
+ @Nullable
+ static Map<TargetExpression, List<TargetExpression>> expandToNonRecursiveWildcardTargets(
+ Project project,
+ BlazeContext context,
+ WorkspacePathResolver pathResolver,
+ List<WildcardTargetPattern> wildcardPatterns) {
+
+ Set<WildcardTargetPattern> excludes =
+ wildcardPatterns
+ .stream()
+ .filter(WildcardTargetPattern::isExcluded)
+ .collect(Collectors.toSet());
+
+ Predicate<WorkspacePath> excludePredicate =
+ workspacePath ->
+ excludes.stream().anyMatch(pattern -> pattern.coversPackage(workspacePath));
+
+ List<WildcardTargetPattern> includes = new ArrayList<>(wildcardPatterns);
+ includes.removeAll(excludes);
+
+ Set<File> toPrefetch =
+ PackageLister.getDirectoriesToPrefetch(pathResolver, includes, excludePredicate);
+
+ ListenableFuture<?> prefetchFuture =
+ PrefetchService.getInstance().prefetchFiles(project, toPrefetch);
+ if (!FutureUtil.waitForFuture(context, prefetchFuture)
+ .withProgressMessage("Prefetching wildcard target pattern directories...")
+ .timed("PrefetchingWildcardTargetDirectories")
+ .onError("Prefetching wildcard target directories failed")
+ .run()
+ .success()) {
+ return null;
+ }
+
+ return PackageLister.expandPackageTargets(
+ Blaze.getBuildSystemProvider(project), context, pathResolver, includes);
+ }
+
+ /** Runs a sharded blaze query to expand wildcard targets to individual blaze targets */
+ static ExpandedTargetsResult expandToSingleTargets(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ List<TargetExpression> allTargets) {
+ ShardedTargetList shards =
+ BlazeBuildTargetSharder.shardTargets(
+ allTargets, BlazeBuildTargetSharder.PACKAGE_SHARD_SIZE);
+ ImmutableSet<String> handledRuleTypes = handledRuleTypes(projectViewSet);
+ ExpandedTargetsResult output = null;
+ for (int i = 0; i < shards.shardedTargets.size(); i++) {
+ List<TargetExpression> shard = shards.shardedTargets.get(i);
+ context.output(
+ new StatusOutput(
+ String.format(
+ "Expanding wildcard target patterns, shard %s of %s",
+ i + 1, shards.shardedTargets.size())));
+ ExpandedTargetsResult result =
+ queryIndividualTargets(project, context, workspaceRoot, handledRuleTypes, shard);
+ output = output == null ? result : ExpandedTargetsResult.merge(output, result);
+ if (output.buildResult == BuildResult.FATAL_ERROR) {
+ return output;
+ }
+ }
+ return output;
+ }
+
+ /** Runs a blaze query to expand the input target patterns to individual blaze targets. */
+ private static ExpandedTargetsResult queryIndividualTargets(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ImmutableSet<String> handledRuleTypes,
+ List<TargetExpression> targetPatterns) {
+ BlazeCommand.Builder builder =
+ BlazeCommand.builder(getBinaryPath(project), BlazeCommandName.QUERY)
+ .addBlazeFlags(BlazeFlags.KEEP_GOING)
+ .addBlazeFlags("--output=label_kind")
+ .addBlazeFlags(queryString(targetPatterns));
+
+ ImmutableList.Builder<TargetExpression> output = ImmutableList.builder();
+
+ // it's fine to include wildcards here; they're guaranteed not to clash with actual labels.
+ Set<String> explicitTargets =
+ targetPatterns.stream().map(TargetExpression::toString).collect(Collectors.toSet());
+ Predicate<RuleTypeAndLabel> filter =
+ !filterByRuleType.getValue()
+ ? t -> true
+ : t -> handledRuleTypes.contains(t.ruleType) || explicitTargets.contains(t.label);
+
+ int retVal =
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(builder.build())
+ .context(context)
+ .stdout(LineProcessingOutputStream.of(new QueryResultLineProcessor(output, filter)))
+ .stderr(LineProcessingOutputStream.of(new PrintOutputLineProcessor(context)))
+ .build()
+ .run();
+
+ BuildResult buildResult = BuildResult.fromExitCode(retVal);
+ return new ExpandedTargetsResult(output.build(), buildResult);
+ }
+
+ private static ImmutableSet<String> handledRuleTypes(ProjectViewSet projectViewSet) {
+ return ImmutableSet.copyOf(
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet)
+ .getAvailableTargetKinds()
+ .stream()
+ .map(Kind::toString)
+ .collect(Collectors.toList()));
+ }
+
+ private static String queryString(List<TargetExpression> targets) {
+ StringBuilder builder = new StringBuilder();
+ for (TargetExpression target : targets) {
+ boolean excluded = target.isExcluded();
+ if (builder.length() == 0) {
+ if (excluded) {
+ continue; // an excluded target at the start of the list has no effect
+ }
+ builder.append(target);
+ } else {
+ if (excluded) {
+ builder.append(" - ");
+ // trim leading '-'
+ String excludedTarget = target.toString();
+ builder.append(excludedTarget, 1, excludedTarget.length());
+ } else {
+ builder.append(" + ");
+ builder.append(target);
+ }
+ }
+ }
+ return builder.toString();
+ }
+
+ private static String getBinaryPath(Project project) {
+ BuildSystemProvider buildSystemProvider = Blaze.getBuildSystemProvider(project);
+ return buildSystemProvider.getSyncBinaryPath();
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/sync/sharding/WildcardTargetPattern.java b/base/src/com/google/idea/blaze/base/sync/sharding/WildcardTargetPattern.java
new file mode 100644
index 0000000..663825c
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/sharding/WildcardTargetPattern.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import javax.annotation.Nullable;
+
+/** A blaze wildcard target pattern. */
+public class WildcardTargetPattern {
+
+ private static final String ALL_PACKAGES_RECURSIVE_SUFFIX = "/...";
+ private static final ImmutableList<String> ALL_TARGETS_IN_SUFFIXES =
+ ImmutableList.of("*", "all-targets");
+ private static final String ALL_RULES_IN_SUFFIX = "all";
+
+ /** Returns null if the target is not a valid wildcard target pattern. */
+ @Nullable
+ public static WildcardTargetPattern fromExpression(TargetExpression target) {
+ String pattern = target.toString();
+ int colonIndex = pattern.lastIndexOf(':');
+ String packagePart = colonIndex < 0 ? pattern : pattern.substring(0, colonIndex);
+ String targetPart = colonIndex < 0 ? "" : pattern.substring(colonIndex + 1);
+
+ if (packagePart.startsWith("-")) {
+ packagePart = packagePart.substring(1);
+ }
+ packagePart = StringUtil.trimStart(packagePart, "//");
+
+ if (packagePart.endsWith(ALL_PACKAGES_RECURSIVE_SUFFIX)) {
+ WorkspacePath basePackageDir =
+ WorkspacePath.createIfValid(
+ StringUtil.trimEnd(packagePart, ALL_PACKAGES_RECURSIVE_SUFFIX));
+ if (basePackageDir == null) {
+ return null;
+ }
+ if (targetPart.isEmpty() || targetPart.equals(ALL_RULES_IN_SUFFIX)) {
+ return new WildcardTargetPattern(target, basePackageDir, true, true);
+ }
+ if (ALL_TARGETS_IN_SUFFIXES.contains(targetPart)) {
+ return new WildcardTargetPattern(target, basePackageDir, true, false);
+ }
+ return null; // ignore invalid patterns -- blaze will give us a better error later.
+ }
+
+ WorkspacePath packageDir = WorkspacePath.createIfValid(packagePart);
+ if (packageDir == null) {
+ return null;
+ }
+ if (targetPart.equals(ALL_RULES_IN_SUFFIX)) {
+ return new WildcardTargetPattern(target, packageDir, false, true);
+ }
+ if (ALL_TARGETS_IN_SUFFIXES.contains(targetPart)) {
+ return new WildcardTargetPattern(target, packageDir, false, false);
+ }
+ // not a wildcard target pattern
+ return null;
+ }
+
+ public final TargetExpression originalPattern;
+ private final WorkspacePath packageDir;
+ private final boolean recursive;
+ private final boolean rulesOnly;
+
+ private WildcardTargetPattern(
+ TargetExpression originalPattern,
+ WorkspacePath packageDir,
+ boolean recursive,
+ boolean rulesOnly) {
+ this.originalPattern = originalPattern;
+ this.packageDir = packageDir;
+ this.recursive = recursive;
+ this.rulesOnly = rulesOnly;
+ }
+
+ /** The base blaze package this target pattern refers to */
+ public WorkspacePath getBasePackage() {
+ return packageDir;
+ }
+
+ /** Whether the target pattern includes all packages below the base package. */
+ public boolean isRecursive() {
+ return recursive;
+ }
+
+ /** Whether the target pattern includes all targets, or only rules */
+ public boolean rulesOnly() {
+ return rulesOnly;
+ }
+
+ public boolean coversPackage(WorkspacePath packagePath) {
+ if (!recursive) {
+ return packagePath.equals(packageDir);
+ }
+ return FileUtil.isAncestor(packageDir.relativePath(), packagePath.relativePath(), false);
+ }
+
+ /** Is this an excluded target pattern (i.e. starts with '-')? */
+ public boolean isExcluded() {
+ return originalPattern.isExcluded();
+ }
+
+ @Override
+ public String toString() {
+ return originalPattern.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof WildcardTargetPattern
+ && originalPattern.equals(((WildcardTargetPattern) obj).originalPattern);
+ }
+
+ @Override
+ public int hashCode() {
+ return originalPattern.hashCode();
+ }
+}
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
index ee60cd7..5f74602 100644
--- a/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java
+++ b/base/src/com/google/idea/blaze/base/sync/status/BlazeSyncStatusImpl.java
@@ -37,8 +37,8 @@
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicBoolean;
+import javax.annotation.Nullable;
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.
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderImpl.java b/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderImpl.java
index 92ff6b8..1e3216a 100644
--- a/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderImpl.java
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/ArtifactLocationDecoderImpl.java
@@ -15,30 +15,35 @@
*/
package com.google.idea.blaze.base.sync.workspace;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.intellij.openapi.util.io.FileUtil;
import java.io.File;
+import java.nio.file.Paths;
/** Decodes intellij_ide_info.proto ArtifactLocation file paths */
public class ArtifactLocationDecoderImpl implements ArtifactLocationDecoder {
private static final long serialVersionUID = 1L;
- private final BlazeRoots blazeRoots;
+ private final BlazeInfo blazeInfo;
private final WorkspacePathResolver pathResolver;
- public ArtifactLocationDecoderImpl(BlazeRoots blazeRoots, WorkspacePathResolver pathResolver) {
- this.blazeRoots = blazeRoots;
+ public ArtifactLocationDecoderImpl(BlazeInfo blazeInfo, WorkspacePathResolver pathResolver) {
+ this.blazeInfo = blazeInfo;
this.pathResolver = pathResolver;
}
@Override
public File decode(ArtifactLocation artifactLocation) {
- if (artifactLocation.isSource) {
- if (artifactLocation.isExternal) {
- return new File(blazeRoots.externalSourceRoot, artifactLocation.relativePath);
- }
- File root = pathResolver.findPackageRoot(artifactLocation.relativePath);
- return new File(root, artifactLocation.relativePath);
+ if (artifactLocation.isSource && !artifactLocation.isExternal) {
+ return pathResolver.resolveToFile(artifactLocation.relativePath);
}
- return new File(blazeRoots.executionRoot, artifactLocation.getExecutionRootRelativePath());
+ String path =
+ Paths.get(
+ blazeInfo.getExecutionRoot().getPath(),
+ artifactLocation.getExecutionRootRelativePath())
+ .toString();
+ // doesn't require file-system operations -- no attempt to resolve symlinks.
+ return new File(FileUtil.toCanonicalPath(path));
}
}
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
deleted file mode 100644
index c66d024..0000000
--- a/base/src/com/google/idea/blaze/base/sync/workspace/BlazeRoots.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2016 The Bazel Authors. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-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.settings.Blaze.BuildSystem;
-import com.intellij.openapi.diagnostic.Logger;
-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 logger = Logger.getInstance(BlazeRoots.class);
-
- public static BlazeRoots build(
- BuildSystem buildSystem,
- WorkspaceRoot workspaceRoot,
- ImmutableMap<String, String> blazeInfo) {
- return build(
- workspaceRoot,
- getOrThrow(buildSystem, blazeInfo, BlazeInfo.EXECUTION_ROOT_KEY),
- getOrThrow(buildSystem, blazeInfo, BlazeInfo.PACKAGE_PATH_KEY),
- getOrThrow(buildSystem, blazeInfo, BlazeInfo.blazeBinKey(buildSystem)),
- getOrThrow(buildSystem, blazeInfo, BlazeInfo.blazeGenfilesKey(buildSystem)),
- getOrThrow(buildSystem, blazeInfo, BlazeInfo.OUTPUT_BASE_KEY));
- }
-
- private static BlazeRoots build(
- WorkspaceRoot workspaceRoot,
- String execRootString,
- String packagePathString,
- String blazeBinRoot,
- String blazeGenfilesRoot,
- String externalSourceRoot) {
- 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));
- File externalSourceRootFile = new File(externalSourceRoot.trim());
- logger.assertTrue(blazeBinExecutionRootPath != null);
- logger.assertTrue(blazeGenfilesExecutionRootPath != null);
- return new BlazeRoots(
- executionRoot,
- packagePaths,
- blazeBinExecutionRootPath,
- blazeGenfilesExecutionRootPath,
- externalSourceRootFile);
- }
-
- 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 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;
- public final File externalSourceRoot;
-
- @VisibleForTesting
- public BlazeRoots(
- File executionRoot,
- List<File> packagePaths,
- ExecutionRootPath blazeBinExecutionRootPath,
- ExecutionRootPath blazeGenfilesExecutionRootPath,
- File externalSourceRoot) {
- this.executionRoot = executionRoot;
- this.packagePaths = packagePaths;
- this.blazeBinExecutionRootPath = blazeBinExecutionRootPath;
- this.blazeGenfilesExecutionRootPath = blazeGenfilesExecutionRootPath;
- this.externalSourceRoot = externalSourceRoot;
- }
-
- public File getGenfilesDirectory() {
- return blazeGenfilesExecutionRootPath.getFileRootedAt(executionRoot);
- }
-
- public File getBlazeBinDirectory() {
- return blazeBinExecutionRootPath.getFileRootedAt(executionRoot);
- }
-
- public boolean isOutputArtifact(ExecutionRootPath path) {
- return ExecutionRootPath.isAncestor(blazeGenfilesExecutionRootPath, path, false)
- || ExecutionRootPath.isAncestor(blazeBinExecutionRootPath, path, false);
- }
-}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolver.java b/base/src/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolver.java
index c6b7eef..c1b3f29 100644
--- a/base/src/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolver.java
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolver.java
@@ -16,11 +16,12 @@
package com.google.idea.blaze.base.sync.workspace;
import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
-import com.intellij.openapi.util.io.FileUtil;
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import java.io.File;
-import java.util.List;
/**
* Converts execution-root-relative paths to absolute files with a minimum of file system calls
@@ -31,15 +32,29 @@
*/
public class ExecutionRootPathResolver {
- private final BlazeRoots blazeRoots;
+ private final ImmutableList<String> buildArtifactDirectories;
+ private final File executionRoot;
private final WorkspacePathResolver workspacePathResolver;
public ExecutionRootPathResolver(
- BlazeRoots blazeRoots, WorkspacePathResolver workspacePathResolver) {
- this.blazeRoots = blazeRoots;
+ BuildSystem buildSystem,
+ WorkspaceRoot workspaceRoot,
+ File executionRoot,
+ WorkspacePathResolver workspacePathResolver) {
+ this.buildArtifactDirectories = buildArtifactDirectories(buildSystem, workspaceRoot);
+ this.executionRoot = executionRoot;
this.workspacePathResolver = workspacePathResolver;
}
+ private static ImmutableList<String> buildArtifactDirectories(
+ BuildSystem buildSystem, WorkspaceRoot workspaceRoot) {
+ BuildSystemProvider provider = BuildSystemProvider.getBuildSystemProvider(buildSystem);
+ if (provider == null) {
+ provider = BuildSystemProvider.defaultBuildSystem();
+ }
+ return provider.buildArtifactDirectories(workspaceRoot);
+ }
+
/**
* This method should be used for directories. Returns all workspace files corresponding to the
* given execution-root-relative path. If the file does not exist inside the workspace (e.g. for
@@ -53,19 +68,21 @@
WorkspacePath workspacePath = new WorkspacePath(path.getAbsoluteOrRelativeFile().getPath());
return workspacePathResolver.resolveToIncludeDirectories(workspacePath);
}
- return ImmutableList.of(path.getFileRootedAt(blazeRoots.executionRoot));
+ return ImmutableList.of(path.getFileRootedAt(executionRoot));
}
private boolean isInWorkspace(ExecutionRootPath path) {
- boolean inOutputDir =
- ExecutionRootPath.isAncestor(blazeRoots.blazeBinExecutionRootPath, path, false)
- || ExecutionRootPath.isAncestor(blazeRoots.blazeGenfilesExecutionRootPath, path, false)
- || isExternalWorkspacePath(path);
- return !inOutputDir;
+ String firstPathComponent = getFirstPathComponent(path.getAbsoluteOrRelativeFile().getPath());
+ return !buildArtifactDirectories.contains(firstPathComponent)
+ && !isExternalWorkspacePath(firstPathComponent);
}
- private static boolean isExternalWorkspacePath(ExecutionRootPath path) {
- List<String> pathComponents = FileUtil.splitPath(path.getAbsoluteOrRelativeFile().getPath());
- return pathComponents.size() > 1 && "external".equals(pathComponents.get(0));
+ private static String getFirstPathComponent(String path) {
+ int index = path.indexOf(File.separatorChar);
+ return index == -1 ? path : path.substring(0, index);
+ }
+
+ private static boolean isExternalWorkspacePath(String firstPathComponent) {
+ return firstPathComponent.equals("external");
}
}
diff --git a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java
new file mode 100644
index 0000000..81ade09
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspaceHelper.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.collect.ImmutableMap;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+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.TargetName;
+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.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.SyncCache;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** External-workspace-aware resolution of workspace paths. */
+public class WorkspaceHelper {
+
+ private static class Workspace {
+ private final WorkspaceRoot root;
+ @Nullable private final String externalWorkspaceName;
+
+ private Workspace(WorkspaceRoot root, @Nullable String externalWorkspaceName) {
+ this.root = root;
+ this.externalWorkspaceName = externalWorkspaceName;
+ }
+ }
+
+ @Nullable
+ public static WorkspaceRoot resolveExternalWorkspace(Project project, String workspaceName) {
+ Map<String, WorkspaceRoot> externalWorkspaces = getExternalWorkspaceRoots(project);
+ return externalWorkspaces != null ? externalWorkspaces.get(workspaceName) : null;
+ }
+
+ /** Resolves the parent blaze package corresponding to this label. */
+ @Nullable
+ public static File resolveBlazePackage(Project project, Label label) {
+ if (!label.isExternal()) {
+ WorkspacePathResolver pathResolver =
+ WorkspacePathResolverProvider.getInstance(project).getPathResolver();
+ return pathResolver != null ? pathResolver.resolveToFile(label.blazePackage()) : null;
+ }
+ Map<String, WorkspaceRoot> externalWorkspaces = getExternalWorkspaceRoots(project);
+ if (externalWorkspaces == null) {
+ return null;
+ }
+ WorkspaceRoot root = externalWorkspaces.get(label.externalWorkspaceName());
+ return root != null ? root.fileForPath(label.blazePackage()) : null;
+ }
+
+ @Nullable
+ public static WorkspacePath resolveWorkspacePath(Project project, File absoluteFile) {
+ Workspace workspace = resolveWorkspace(project, absoluteFile);
+ return workspace != null ? workspace.root.workspacePathForSafe(absoluteFile) : null;
+ }
+
+ /** Converts a file to the corresponding BUILD label for this project, if valid. */
+ @Nullable
+ public static Label getBuildLabel(Project project, File absoluteFile) {
+ Workspace workspace = resolveWorkspace(project, absoluteFile);
+ if (workspace == null) {
+ return null;
+ }
+ WorkspacePath workspacePath = workspace.root.workspacePathForSafe(absoluteFile);
+ if (workspacePath == null) {
+ return null;
+ }
+ return deriveLabel(project, workspace, workspacePath);
+ }
+
+ @Nullable
+ private static Workspace resolveWorkspace(Project project, File absoluteFile) {
+ WorkspacePathResolver pathResolver =
+ WorkspacePathResolverProvider.getInstance(project).getPathResolver();
+ if (pathResolver == null) {
+ return null;
+ }
+
+ // try project workspace first
+ WorkspaceRoot root = pathResolver.findWorkspaceRoot(absoluteFile);
+ if (root != null) {
+ return new Workspace(root, null);
+ }
+
+ Map<String, WorkspaceRoot> externalWorkspaces = getExternalWorkspaceRoots(project);
+ if (externalWorkspaces == null) {
+ return null;
+ }
+ for (Entry<String, WorkspaceRoot> entry : externalWorkspaces.entrySet()) {
+ root = entry.getValue();
+ WorkspacePath workspacePath = root.workspacePathForSafe(absoluteFile);
+ if (workspacePath != null) {
+ return new Workspace(root, entry.getKey());
+ }
+ }
+ return null;
+ }
+
+ private static Label deriveLabel(
+ Project project, Workspace workspace, WorkspacePath workspacePath) {
+ BuildSystemProvider provider = Blaze.getBuildSystemProvider(project);
+ File file = workspace.root.fileForPath(workspacePath);
+ if (provider.isBuildFile(file.getName())) {
+ return Label.create(
+ workspace.externalWorkspaceName,
+ workspace.root.workspacePathFor(file.getParentFile()),
+ TargetName.create("__pkg__"));
+ }
+ WorkspacePath packagePath = getPackagePath(provider, workspace.root, workspacePath);
+ if (packagePath == null) {
+ return null;
+ }
+ TargetName targetName =
+ TargetName.createIfValid(
+ FileUtil.getRelativePath(workspace.root.fileForPath(packagePath), file));
+ return targetName != null
+ ? Label.create(workspace.externalWorkspaceName, packagePath, targetName)
+ : null;
+ }
+
+ private static WorkspacePath getPackagePath(
+ BuildSystemProvider provider, WorkspaceRoot root, WorkspacePath workspacePath) {
+ File file = root.fileForPath(workspacePath).getParentFile();
+ while (file != null && FileUtil.isAncestor(root.directory(), file, false)) {
+ if (provider.findBuildFileInDirectory(file) != null) {
+ return root.workspacePathFor(file);
+ }
+ file = file.getParentFile();
+ }
+ return null;
+ }
+
+ @Nullable
+ private static synchronized Map<String, WorkspaceRoot> getExternalWorkspaceRoots(
+ Project project) {
+ if (Blaze.getBuildSystem(project) == BuildSystem.Blaze) {
+ return ImmutableMap.of();
+ }
+ return SyncCache.getInstance(project)
+ .get(WorkspaceHelper.class, WorkspaceHelper::enumerateExternalWorkspaces);
+ }
+
+ @SuppressWarnings("unused")
+ private static Map<String, WorkspaceRoot> enumerateExternalWorkspaces(
+ Project project, BlazeProjectData blazeProjectData) {
+ FileAttributeProvider provider = FileAttributeProvider.getInstance();
+ File[] children = provider.listFiles(getExternalSourceRoot(blazeProjectData));
+ if (children == null) {
+ return ImmutableMap.of();
+ }
+ return Arrays.stream(children)
+ .filter(provider::isDirectory)
+ .collect(Collectors.toMap(File::getName, WorkspaceRoot::new));
+ }
+
+ @VisibleForTesting
+ public static File getExternalSourceRoot(BlazeProjectData projectData) {
+ return new File(projectData.blazeInfo.getOutputBase(), "external");
+ }
+}
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
index 128ca91..7392630 100644
--- a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolver.java
@@ -17,6 +17,7 @@
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 java.io.Serializable;
import javax.annotation.Nullable;
@@ -47,6 +48,13 @@
File findPackageRoot(String relativePath);
/**
+ * Finds the workspace root directory that an absolute file lies under. Returns null if the file
+ * is not in a known workspace.
+ */
+ @Nullable
+ WorkspaceRoot findWorkspaceRoot(File absoluteFile);
+
+ /**
* Given a resolved, absolute file, returns the corresponding {@link WorkspacePath}. Returns null
* if the file is not in the workspace.
*/
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
index ac131c1..bccb969 100644
--- a/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java
+++ b/base/src/com/google/idea/blaze/base/sync/workspace/WorkspacePathResolverImpl.java
@@ -16,31 +16,19 @@
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.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 static final long serialVersionUID = 3L;
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
@@ -50,19 +38,7 @@
@Override
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 first in package path, even though it might not exist
- return packagePaths.get(0);
+ return workspaceRoot.directory();
}
@Nullable
@@ -70,4 +46,10 @@
public WorkspacePath getWorkspacePath(File absoluteFile) {
return workspaceRoot.workspacePathForSafe(absoluteFile);
}
+
+ @Nullable
+ @Override
+ public WorkspaceRoot findWorkspaceRoot(File absoluteFile) {
+ return workspaceRoot.isInWorkspace(absoluteFile) ? workspaceRoot : null;
+ }
}
diff --git a/base/src/com/google/idea/blaze/base/targetmaps/SourceToTargetMapImpl.java b/base/src/com/google/idea/blaze/base/targetmaps/SourceToTargetMapImpl.java
index 4d4a28f..19e8383 100644
--- a/base/src/com/google/idea/blaze/base/targetmaps/SourceToTargetMapImpl.java
+++ b/base/src/com/google/idea/blaze/base/targetmaps/SourceToTargetMapImpl.java
@@ -74,7 +74,7 @@
.get(SourceToTargetMapImpl.class, SourceToTargetMapImpl::computeSourceToTargetMap);
}
- @Nullable
+ @SuppressWarnings("unused")
private static ImmutableMultimap<File, TargetKey> computeSourceToTargetMap(
Project project, BlazeProjectData blazeProjectData) {
ArtifactLocationDecoder artifactLocationDecoder = blazeProjectData.artifactLocationDecoder;
diff --git a/base/src/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMap.java b/base/src/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMap.java
index f973c8d..b2a31ba 100644
--- a/base/src/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMap.java
+++ b/base/src/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMap.java
@@ -16,6 +16,7 @@
package com.google.idea.blaze.base.targetmaps;
import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
@@ -26,6 +27,7 @@
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
+import java.util.Collection;
import java.util.List;
import java.util.Queue;
import java.util.Set;
@@ -53,11 +55,16 @@
return getTransitiveDependencies(targetKey, blazeProjectData.targetMap);
}
- private static ImmutableCollection<TargetKey> getTransitiveDependencies(
+ public static ImmutableCollection<TargetKey> getTransitiveDependencies(
TargetKey targetKey, TargetMap targetMap) {
+ return getTransitiveDependencies(ImmutableList.of(targetKey), targetMap);
+ }
+
+ public static ImmutableCollection<TargetKey> getTransitiveDependencies(
+ Collection<TargetKey> targetKeys, TargetMap targetMap) {
Queue<TargetKey> targetsToVisit = Queues.newArrayDeque();
Set<TargetKey> transitiveDependencies = Sets.newHashSet();
- targetsToVisit.add(targetKey);
+ targetsToVisit.addAll(targetKeys);
while (!targetsToVisit.isEmpty()) {
TargetIdeInfo currentTarget = targetMap.get(targetsToVisit.remove());
if (currentTarget == null) {
diff --git a/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java b/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
index 764e3b0..712c1fc 100644
--- a/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
+++ b/base/src/com/google/idea/blaze/base/treeview/BlazeTreeStructureProvider.java
@@ -36,8 +36,8 @@
import java.io.File;
import java.util.Collection;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* Modifies the project view:
@@ -147,6 +147,9 @@
@Override
public boolean isShowExcludedFiles() {
+ if (original instanceof ProjectViewSettings) {
+ return ((ProjectViewSettings) original).isShowExcludedFiles();
+ }
return true;
}
};
diff --git a/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java b/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
index 452ae82..f79fffc 100644
--- a/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
+++ b/base/src/com/google/idea/blaze/base/ui/BlazeValidationError.java
@@ -18,9 +18,9 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import java.util.Collection;
+import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** An error occuring during a blaze validation */
@Immutable
diff --git a/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java b/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
index 4200003..b6bc270 100644
--- a/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
+++ b/base/src/com/google/idea/blaze/base/ui/BlazeValidationResult.java
@@ -15,7 +15,7 @@
*/
package com.google.idea.blaze.base.ui;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Pair of (success, validation error) */
public class BlazeValidationResult {
diff --git a/base/src/com/google/idea/blaze/base/ui/WorkspaceFileTextField.java b/base/src/com/google/idea/blaze/base/ui/WorkspaceFileTextField.java
new file mode 100644
index 0000000..87a45a0
--- /dev/null
+++ b/base/src/com/google/idea/blaze/base/ui/WorkspaceFileTextField.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.ImmutableMap;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileTextField;
+import com.intellij.openapi.fileChooser.ex.FileTextFieldImpl;
+import com.intellij.openapi.fileChooser.ex.LocalFsFinder.FileChooserFilter;
+import com.intellij.openapi.fileChooser.ex.LocalFsFinder.IoFile;
+import com.intellij.openapi.fileChooser.ex.LocalFsFinder.VfsFile;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.components.JBTextField;
+import java.io.File;
+import javax.annotation.Nullable;
+import javax.swing.JTextField;
+
+/** A text field that auto-completes paths in the workspace root. */
+// This outer class basically a copy of FileTextFieldImpl.Vfs but we can't use that directly because
+// we need to specify our own custom Finder.
+public final class WorkspaceFileTextField extends FileTextFieldImpl {
+
+ private WorkspaceFileTextField(
+ WorkspacePathResolver pathResolver,
+ JTextField textField,
+ LookupFilter filter,
+ Disposable parent) {
+ super(textField, new WorkspaceFinder(pathResolver), filter, ImmutableMap.of(), parent);
+ }
+
+ public static FileTextField create(
+ WorkspacePathResolver pathResolver,
+ FileChooserDescriptor descriptor,
+ int columns,
+ Disposable parent) {
+ JTextField textField = new WorkspacePathTextField(pathResolver, columns);
+ return new WorkspaceFileTextField(
+ pathResolver, textField, new FileChooserFilter(descriptor, /* showHidden */ true), parent);
+ }
+
+ @Nullable
+ @Override
+ public VirtualFile getSelectedFile() {
+ LookupFile lookupFile = getFile();
+ return lookupFile != null ? ((VfsFile) lookupFile).getFile() : null;
+ }
+
+ private static class WorkspaceFinder implements Finder {
+
+ private final WorkspacePathResolver pathResolver;
+
+ private WorkspaceFinder(WorkspacePathResolver pathResolver) {
+ this.pathResolver = pathResolver;
+ }
+
+ @Nullable
+ @Override
+ public LookupFile find(String path) {
+ File file = new File(normalize(path));
+ VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file);
+ if (vFile != null) {
+ return new VfsFile(/* unused LocalFsFinder */ null, vFile);
+ } else if (file.isAbsolute()) {
+ return new IoFile(new File(path));
+ }
+ return null;
+ }
+
+ @Override
+ public String normalize(String path) {
+ File file = new File(path);
+ if (!file.isAbsolute()) {
+ file = pathResolver.resolveToFile(path);
+ }
+
+ return file.getAbsolutePath();
+ }
+
+ @Override
+ public String getSeparator() {
+ return File.separator;
+ }
+ }
+
+ // FileTextFieldImpl calls setText with the absolute path after every filename autocomplete. But
+ // we don't want to swap in the absolute path, we'd rather just show the path relative to the
+ // workspace root. So we override setText().
+ private static class WorkspacePathTextField extends JBTextField {
+
+ final WorkspacePathResolver pathResolver;
+
+ WorkspacePathTextField(WorkspacePathResolver pathResolver, int columns) {
+ super(columns);
+ this.pathResolver = pathResolver;
+ }
+
+ @Override
+ public void setText(String path) {
+ WorkspacePath workspacePath = pathResolver.getWorkspacePath(new File(path));
+ if (workspacePath == null) {
+ super.setText(path);
+ return;
+ }
+
+ String relativePath = workspacePath.relativePath();
+ if (path.endsWith(File.separator) && !relativePath.endsWith(File.separator)) {
+ relativePath += File.separator;
+ }
+ super.setText(relativePath);
+ }
+ }
+}
diff --git a/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java b/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
index e923236..f4bbfda 100644
--- a/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
+++ b/base/src/com/google/idea/blaze/base/util/PackagePrefixCalculator.java
@@ -24,9 +24,16 @@
public static String packagePrefixOf(@NotNull WorkspacePath workspacePath) {
int skipIndex = 0;
+ // For Bazel-style projects.
skipIndex = skipIndex == 0 ? skip(workspacePath, "java/") : skipIndex;
skipIndex = skipIndex == 0 ? skip(workspacePath, "javatests/") : skipIndex;
+ // For Maven-style projects.
+ skipIndex = skipIndex == 0 ? skip(workspacePath, "src/main/java/") : skipIndex;
+ skipIndex = skipIndex == 0 ? skip(workspacePath, "src/test/java/") : skipIndex;
+ skipIndex = skipIndex == 0 ? skip(workspacePath, "src/main/scala/") : skipIndex;
+ skipIndex = skipIndex == 0 ? skip(workspacePath, "src/test/scala/") : skipIndex;
+
return workspacePath.relativePath().substring(skipIndex).replace('/', '.');
}
diff --git a/base/src/com/google/idea/blaze/base/util/SerializationUtil.java b/base/src/com/google/idea/blaze/base/util/SerializationUtil.java
index f098673..ea689da 100644
--- a/base/src/com/google/idea/blaze/base/util/SerializationUtil.java
+++ b/base/src/com/google/idea/blaze/base/util/SerializationUtil.java
@@ -17,7 +17,6 @@
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;
@@ -26,12 +25,11 @@
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Utils for serialization. */
public class SerializationUtil {
- private static final Logger logger = Logger.getInstance(SerializationUtil.class.getName());
public static void saveToDisk(@NotNull File file, @NotNull Serializable serializable)
throws IOException {
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
index 16648e6..578af51 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeNewProjectBuilder.java
@@ -36,7 +36,6 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
-import java.util.UUID;
/** Contains the state to build a new project throughout the new project wizard process. */
public final class BlazeNewProjectBuilder {
@@ -218,7 +217,6 @@
workspaceRoot.directory().getPath(),
projectName,
projectDataDirectory,
- createLocationHash(projectName),
projectViewFile.getPath(),
buildSystem);
@@ -226,10 +224,4 @@
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/BlazeSelectProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
index 353ecb4..51229f0 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectProjectViewOption.java
@@ -37,9 +37,9 @@
return false;
}
- /** Returns the default project name */
- default String getDefaultProjectName(String workspaceName) {
- return workspaceName;
+ /** Returns the directory we're importing from, if applicable. */
+ default String getImportDirectory() {
+ return null;
}
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
index 11bf115..3c9a601 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeSelectWorkspaceOption.java
@@ -34,6 +34,9 @@
/** @return the name of the workspace. Used to generate default project names. */
String getWorkspaceName();
+ /** @return the name of the 'branch', if applicable */
+ String getBranchName();
+
BuildSystem getBuildSystemForWorkspace();
void commit() throws BlazeProjectCommitException;
diff --git a/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
index 2184d14..0ff0440 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/BlazeWizardUserSettingsStorage.java
@@ -19,7 +19,7 @@
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Stores wizard user settings between runs. */
@State(name = "BlazeWizardUserSettings", storages = @Storage("blaze.wizard.settings.xml"))
diff --git a/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
index 341d023..577f290 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/GenerateFromBuildFileSelectProjectViewOption.java
@@ -15,6 +15,8 @@
*/
package com.google.idea.blaze.base.wizard2;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.common.base.Strings;
import com.google.idea.blaze.base.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.model.primitives.TargetExpression;
@@ -27,6 +29,7 @@
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.sync.projectview.RelatedWorkspacePathFinder;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.blaze.base.ui.BlazeValidationResult;
import com.google.idea.blaze.base.ui.UiUtil;
@@ -41,6 +44,8 @@
import com.intellij.ui.TextFieldWithStoredHistory;
import java.awt.Dimension;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
import javax.annotation.Nullable;
import javax.swing.JButton;
import javax.swing.JComponent;
@@ -91,15 +96,26 @@
@Override
public BlazeValidationResult validate() {
- if (getBuildFilePath().isEmpty()) {
+ String buildFilePath = getBuildFilePath();
+ if (buildFilePath.isEmpty()) {
return BlazeValidationResult.failure("BUILD file field cannot be empty.");
}
+ if (!WorkspacePath.validate(buildFilePath)) {
+ return BlazeValidationResult.failure(
+ "Invalid BUILD file path: specify a path relative to the workspace root.");
+ }
WorkspacePathResolver workspacePathResolver =
builder.getWorkspaceOption().getWorkspacePathResolver();
- File file = workspacePathResolver.resolveToFile(new WorkspacePath(getBuildFilePath()));
+ File file = workspacePathResolver.resolveToFile(new WorkspacePath(buildFilePath));
if (!file.exists()) {
return BlazeValidationResult.failure("BUILD file does not exist.");
}
+ BuildSystemProvider buildSystemProvider =
+ BuildSystemProvider.getBuildSystemProvider(builder.getBuildSystem());
+ checkState(buildSystemProvider != null);
+ if (!buildSystemProvider.isBuildFile(file.getName())) {
+ return BlazeValidationResult.failure("File must be a BUILD file.");
+ }
return BlazeValidationResult.success();
}
@@ -120,9 +136,9 @@
}
@Override
- public String getDefaultProjectName(String workspaceName) {
+ public String getImportDirectory() {
File buildFileParent = new File(getBuildFilePath()).getParentFile();
- return buildFileParent != null ? buildFileParent.getName() : workspaceName;
+ return buildFileParent != null ? buildFileParent.getName() : null;
}
@Override
@@ -134,54 +150,31 @@
private static String guessProjectViewFromLocation(
WorkspacePathResolver workspacePathResolver, WorkspacePath workspacePath) {
- WorkspacePath mainModuleWorkspaceRelativePath = workspacePath;
- WorkspacePath testModuleWorkspaceRelativePath =
- guessTestRelativePath(workspacePathResolver, mainModuleWorkspaceRelativePath);
+ List<WorkspacePath> workspacePaths = new ArrayList<>();
+ workspacePaths.add(workspacePath);
+ workspacePaths.addAll(
+ RelatedWorkspacePathFinder.getInstance()
+ .findRelatedWorkspaceDirectories(workspacePathResolver, workspacePath));
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));
- }
+ workspacePaths.forEach(
+ path -> {
+ directorySectionBuilder.add(DirectoryEntry.include(path));
+ targetSectionBuilder.add(TargetExpression.allFromPackageRecursive(path));
+ });
return ProjectViewParser.projectViewToString(
ProjectView.builder()
.add(directorySectionBuilder)
.add(TextBlockSection.of(TextBlock.newLine()))
.add(targetSectionBuilder)
+ .add(TextBlockSection.of(TextBlock.newLine()))
.build());
}
- @Nullable
- private static WorkspacePath guessTestRelativePath(
- WorkspacePathResolver workspacePathResolver, 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 =
- workspacePathResolver.resolveToFile(new WorkspacePath(testBuildFileRelativePath));
- if (testBuildFile.exists()) {
- return new WorkspacePath(testBuildFileRelativePath);
- }
- }
- return null;
- }
-
private String getBuildFilePath() {
return buildFilePathField.getText().trim();
}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java b/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
index fe43d1c..14a07e0 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/ImportFromWorkspaceProjectViewOption.java
@@ -109,11 +109,11 @@
}
@Override
- public String getDefaultProjectName(String workspaceName) {
+ public String getImportDirectory() {
File projectViewFile = new File(getProjectViewPath());
File projectViewDirectory = projectViewFile.getParentFile();
if (projectViewDirectory == null) {
- return workspaceName;
+ return null;
}
return projectViewDirectory.getName();
}
diff --git a/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java b/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
index 51af079..de9d125 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/UseExistingBazelWorkspaceOption.java
@@ -117,6 +117,11 @@
}
@Override
+ public String getBranchName() {
+ return null;
+ }
+
+ @Override
public BlazeValidationResult validate() {
if (getDirectory().isEmpty()) {
return BlazeValidationResult.failure("Please select a workspace");
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
index e936db3..5b652d8 100644
--- a/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java
+++ b/base/src/com/google/idea/blaze/base/wizard2/ui/BlazeEditProjectViewControl.java
@@ -15,6 +15,8 @@
*/
package com.google.idea.blaze.base.wizard2.ui;
+import static java.util.stream.Collectors.toList;
+
import com.google.common.collect.Lists;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
@@ -26,15 +28,21 @@
import com.google.idea.blaze.base.projectview.ProjectViewStorageManager;
import com.google.idea.blaze.base.projectview.ProjectViewVerifier;
import com.google.idea.blaze.base.projectview.parser.ProjectViewParser;
+import com.google.idea.blaze.base.projectview.section.ProjectViewDefaultValueProvider;
import com.google.idea.blaze.base.projectview.section.ScalarSection;
+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.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.Sections;
+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.OutputSink.Propagation;
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.IssueOutput.Category;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
import com.google.idea.blaze.base.settings.ui.JPanelProvidingProject;
import com.google.idea.blaze.base.settings.ui.ProjectViewUi;
import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
@@ -50,6 +58,7 @@
import com.google.idea.blaze.base.wizard2.ProjectDataDirectoryValidator;
import com.google.idea.common.experiments.BoolExperiment;
import com.intellij.ide.RecentProjectsManager;
+import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.diagnostic.Logger;
@@ -66,13 +75,15 @@
import java.awt.GridBagLayout;
import java.io.File;
import java.io.IOException;
+import java.util.Comparator;
import java.util.List;
-import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import javax.swing.ButtonGroup;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import javax.swing.JRadioButton;
import javax.swing.JTextField;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** The UI control to collect project settings when importing a Blaze project. */
public final class BlazeEditProjectViewControl {
@@ -83,6 +94,8 @@
private static final BoolExperiment allowAddprojectViewDefaultValues =
new BoolExperiment("allow.add.project.view.default.values", true);
+ private static final String LAST_WORKSPACE_MODE_PROPERTY =
+ "blaze.edit.project.view.control.last.workspace.mode";
private final JPanel component;
private final String buildSystemName;
@@ -90,14 +103,27 @@
private TextFieldWithBrowseButton projectDataDirField;
private JTextField projectNameField;
+ private JRadioButton workspaceDefaultNameOption;
+ private JRadioButton branchDefaultNameOption;
+ private JRadioButton importDirectoryDefaultNameOption;
private HashCode paramsHash;
private WorkspaceRoot workspaceRoot;
private WorkspacePathResolver workspacePathResolver;
+ private BlazeSelectWorkspaceOption workspaceOption;
+ private BlazeSelectProjectViewOption projectViewOption;
+ private boolean isInitialising;
+ private boolean defaultWorkspaceNameModeExplicitlySet;
+
+ private enum InferDefaultNameMode {
+ FromWorkspace,
+ FromBranch,
+ FromImportDirectory,
+ }
public BlazeEditProjectViewControl(BlazeNewProjectBuilder builder, Disposable parentDisposable) {
this.projectViewUi = new ProjectViewUi(parentDisposable);
JPanel component = new JPanelProvidingProject(ProjectViewUi.getProject(), new GridBagLayout());
- fillUi(component, 0);
+ fillUi(component);
update(builder);
UiUtil.fillBottom(component);
this.component = component;
@@ -108,12 +134,12 @@
return component;
}
- private void fillUi(JPanel canvas, int indentLevel) {
+ private void fillUi(JPanel canvas) {
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);
+ // Add pixels so we have room for our extra fields
+ minSize.setSize(minSize.width, minSize.height + 180);
canvas.setMinimumSize(minSize);
canvas.setPreferredSize(minSize);
@@ -131,7 +157,7 @@
projectDataDirField.setToolTipText(dataDirToolTipText);
projectDataDirLabel.setToolTipText(dataDirToolTipText);
- canvas.add(projectDataDirLabel, UiUtil.getLabelConstraints(indentLevel));
+ canvas.add(projectDataDirLabel, UiUtil.getLabelConstraints(0));
canvas.add(projectDataDirField, UiUtil.getFillLineConstraints(0));
JLabel projectNameLabel = new JLabel("Project name:");
@@ -139,17 +165,39 @@
final String projectNameToolTipText = "Project display name.";
projectNameField.setToolTipText(projectNameToolTipText);
projectNameLabel.setToolTipText(projectNameToolTipText);
- canvas.add(projectNameLabel, UiUtil.getLabelConstraints(indentLevel));
+ canvas.add(projectNameLabel, UiUtil.getLabelConstraints(0));
canvas.add(projectNameField, UiUtil.getFillLineConstraints(0));
- projectViewUi.fillUi(canvas, indentLevel);
+ JLabel defaultNameLabel = new JLabel("Infer name from:");
+ workspaceDefaultNameOption = new JRadioButton("Workspace");
+ branchDefaultNameOption = new JRadioButton("Branch");
+ importDirectoryDefaultNameOption = new JRadioButton("Import Directory");
+
+ workspaceDefaultNameOption.setToolTipText("Infer default name from the workspace name");
+ branchDefaultNameOption.setToolTipText(
+ "Infer default name from the current branch of your workspace");
+ importDirectoryDefaultNameOption.setToolTipText(
+ "Infer default name from the directory used to import your project view");
+
+ workspaceDefaultNameOption.addItemListener(e -> inferDefaultNameModeSelectionChanged());
+ branchDefaultNameOption.addItemListener(e -> inferDefaultNameModeSelectionChanged());
+ importDirectoryDefaultNameOption.addItemListener(e -> inferDefaultNameModeSelectionChanged());
+ ButtonGroup buttonGroup = new ButtonGroup();
+ buttonGroup.add(workspaceDefaultNameOption);
+ buttonGroup.add(branchDefaultNameOption);
+ buttonGroup.add(importDirectoryDefaultNameOption);
+ canvas.add(defaultNameLabel, UiUtil.getLabelConstraints(0));
+ canvas.add(workspaceDefaultNameOption, UiUtil.getLabelConstraints(0));
+ canvas.add(branchDefaultNameOption, UiUtil.getLabelConstraints(0));
+ canvas.add(importDirectoryDefaultNameOption, UiUtil.getLabelConstraints(0));
+ canvas.add(new JPanel(), UiUtil.getFillLineConstraints(0));
+
+ projectViewUi.fillUi(canvas);
}
public void update(BlazeNewProjectBuilder builder) {
- BlazeSelectWorkspaceOption workspaceOption = builder.getWorkspaceOption();
- BlazeSelectProjectViewOption projectViewOption = builder.getProjectViewOption();
- String defaultProjectName =
- projectViewOption.getDefaultProjectName(workspaceOption.getWorkspaceName());
+ this.workspaceOption = builder.getWorkspaceOption();
+ this.projectViewOption = builder.getProjectViewOption();
WorkspaceRoot workspaceRoot = workspaceOption.getWorkspaceRoot();
WorkspacePath workspacePath = projectViewOption.getSharedProjectView();
String initialProjectViewText = projectViewOption.getInitialProjectViewText();
@@ -161,7 +209,6 @@
HashCode hashCode =
Hashing.md5()
.newHasher()
- .putUnencodedChars(defaultProjectName)
.putUnencodedChars(workspaceRoot.toString())
.putUnencodedChars(workspacePath != null ? workspacePath.toString() : "")
.putUnencodedChars(initialProjectViewText != null ? initialProjectViewText : "")
@@ -171,18 +218,22 @@
// If any params have changed, reinit the control
if (!hashCode.equals(paramsHash)) {
this.paramsHash = hashCode;
+ this.isInitialising = true;
init(
- defaultProjectName,
+ workspaceOption.getBuildSystemForWorkspace(),
workspaceRoot,
workspacePathResolver,
workspacePath,
initialProjectViewText,
allowAddDefaultValues);
+ this.isInitialising = false;
}
}
private static String modifyInitialProjectView(
- String initialProjectViewText, WorkspacePathResolver workspacePathResolver) {
+ BuildSystem buildSystem,
+ String initialProjectViewText,
+ WorkspacePathResolver workspacePathResolver) {
BlazeContext context = new BlazeContext();
ProjectViewParser projectViewParser = new ProjectViewParser(context, workspacePathResolver);
projectViewParser.parseProjectView(initialProjectViewText);
@@ -192,14 +243,23 @@
return initialProjectViewText;
}
ProjectView projectView = projectViewFile.projectView;
- for (SectionParser sectionParser : Sections.getParsers()) {
- projectView = sectionParser.addProjectViewDefaultValue(projectView);
+
+ // Sort default value providers to match the section order
+ List<SectionKey> sectionKeys =
+ Sections.getParsers().stream().map(SectionParser::getSectionKey).collect(toList());
+ List<ProjectViewDefaultValueProvider> defaultValueProviders =
+ Lists.newArrayList(ProjectViewDefaultValueProvider.EP_NAME.getExtensions());
+ defaultValueProviders.sort(
+ Comparator.comparingInt(val -> sectionKeys.indexOf(val.getSectionKey())));
+ for (ProjectViewDefaultValueProvider defaultValueProvider : defaultValueProviders) {
+ projectView =
+ defaultValueProvider.addProjectViewDefaultValue(buildSystem, projectViewSet, projectView);
}
return ProjectViewParser.projectViewToString(projectView);
}
private void init(
- String defaultProjectName,
+ BuildSystem buildSystem,
WorkspaceRoot workspaceRoot,
WorkspacePathResolver workspacePathResolver,
@Nullable WorkspacePath sharedProjectView,
@@ -207,14 +267,13 @@
boolean allowAddDefaultValues) {
if (allowAddDefaultValues && initialProjectViewText != null) {
initialProjectViewText =
- modifyInitialProjectView(initialProjectViewText, workspacePathResolver);
+ modifyInitialProjectView(buildSystem, initialProjectViewText, workspacePathResolver);
}
-
this.workspaceRoot = workspaceRoot;
this.workspacePathResolver = workspacePathResolver;
- projectNameField.setText(defaultProjectName);
- String defaultDataDir = getDefaultProjectDataDirectory(defaultProjectName);
- projectDataDirField.setText(defaultDataDir);
+
+ updateDefaultProjectNameUiState();
+ updateDefaultProjectName();
String projectViewText = "";
File sharedProjectViewFile = null;
@@ -246,6 +305,82 @@
false /* allowEditShared - not allowed during import */);
}
+ private void updateDefaultProjectNameUiState() {
+ workspaceDefaultNameOption.setEnabled(true);
+ branchDefaultNameOption.setEnabled(workspaceOption.getBranchName() != null);
+ importDirectoryDefaultNameOption.setEnabled(projectViewOption.getImportDirectory() != null);
+
+ InferDefaultNameMode inferDefaultNameMode = InferDefaultNameMode.FromImportDirectory;
+ try {
+ String lastModeString =
+ PropertiesComponent.getInstance().getValue(LAST_WORKSPACE_MODE_PROPERTY);
+ if (lastModeString != null) {
+ inferDefaultNameMode = InferDefaultNameMode.valueOf(lastModeString);
+ }
+ } catch (IllegalArgumentException e) {
+ // Ignore
+ }
+ switch (inferDefaultNameMode) {
+ case FromWorkspace:
+ workspaceDefaultNameOption.setSelected(true);
+ break;
+ case FromBranch:
+ if (workspaceOption.getBranchName() != null) {
+ branchDefaultNameOption.setSelected(true);
+ } else {
+ workspaceDefaultNameOption.setSelected(true);
+ }
+ break;
+ case FromImportDirectory:
+ if (projectViewOption.getImportDirectory() != null) {
+ importDirectoryDefaultNameOption.setSelected(true);
+ } else {
+ workspaceDefaultNameOption.setSelected(true);
+ }
+ break;
+ default:
+ throw new AssertionError("Illegal workspace name mode");
+ }
+ }
+
+ private InferDefaultNameMode getInferDefaultNameMode() {
+ if (workspaceDefaultNameOption.isSelected()) {
+ return InferDefaultNameMode.FromWorkspace;
+ } else if (branchDefaultNameOption.isSelected()) {
+ return InferDefaultNameMode.FromBranch;
+ } else if (importDirectoryDefaultNameOption.isSelected()) {
+ return InferDefaultNameMode.FromImportDirectory;
+ }
+ return InferDefaultNameMode.FromWorkspace;
+ }
+
+ private void inferDefaultNameModeSelectionChanged() {
+ if (!isInitialising) {
+ updateDefaultProjectName();
+ this.defaultWorkspaceNameModeExplicitlySet = true;
+ }
+ }
+
+ private void updateDefaultProjectName() {
+ String defaultProjectName = getDefaultName(getInferDefaultNameMode());
+ projectNameField.setText(defaultProjectName);
+ String defaultDataDir = getDefaultProjectDataDirectory(defaultProjectName);
+ projectDataDirField.setText(defaultDataDir);
+ }
+
+ private String getDefaultName(InferDefaultNameMode inferDefaultNameMode) {
+ switch (inferDefaultNameMode) {
+ case FromWorkspace:
+ return workspaceOption.getWorkspaceName();
+ case FromBranch:
+ return workspaceOption.getBranchName();
+ case FromImportDirectory:
+ return projectViewOption.getImportDirectory();
+ default:
+ throw new AssertionError("Invalid workspace name mode.");
+ }
+ }
+
private static String getDefaultProjectDataDirectory(String projectName) {
File defaultDataDirectory = new File(getDefaultProjectsDirectory());
File desiredLocation = new File(defaultDataDirectory, projectName);
@@ -347,6 +482,16 @@
+ "Please report a bug.");
}
+ List<DirectoryEntry> directories = projectViewSet.listItems(DirectorySection.KEY);
+ if (directories.isEmpty()) {
+ String msg = "Add some directories to index in the 'directories' section.";
+ if (projectViewSet.listItems(TargetSection.KEY).isEmpty()) {
+ msg += "\nTargets are also generally required to resolve sources.";
+ }
+ return BlazeValidationResult.failure(msg);
+ }
+
+
return BlazeValidationResult.success();
}
@@ -382,12 +527,12 @@
syncPlugin.installSdks(context);
}
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
if (workspaceLanguageSettings == null) {
return false;
}
return ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ null, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
}
}
@@ -397,7 +542,7 @@
issues
.stream()
.filter(issue -> issue.getCategory() == IssueOutput.Category.ERROR)
- .collect(Collectors.toList());
+ .collect(toList());
if (!errors.isEmpty()) {
StringBuilder errorMessage = new StringBuilder();
@@ -452,4 +597,12 @@
.setProjectName(projectName)
.setProjectDataDirectory(projectDataDirectory);
}
+
+ public void commit() {
+ if (defaultWorkspaceNameModeExplicitlySet) {
+ InferDefaultNameMode inferDefaultNameMode = getInferDefaultNameMode();
+ PropertiesComponent.getInstance()
+ .setValue(LAST_WORKSPACE_MODE_PROPERTY, inferDefaultNameMode.toString());
+ }
+ }
}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierTest.java
new file mode 100644
index 0000000..691dc74
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/actions/BuildFileModifierTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 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.idea.blaze.base.buildmodifier.BuildFileModifier;
+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.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.scope.BlazeContext;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link BuildFileModifier}. */
+@RunWith(JUnit4.class)
+public class BuildFileModifierTest extends BuildFileIntegrationTestCase {
+
+ @Test
+ public void testAddNewTarget() {
+ BuildFile buildFile =
+ createBuildFile(new WorkspacePath("BUILD"), "java_library(name = 'existing')", "");
+ BuildFileModifier.getInstance()
+ .addRule(getProject(), new BlazeContext(), Label.create("//:new_target"), Kind.JAVA_TEST);
+ assertFileContents(
+ buildFile,
+ "java_library(name = 'existing')",
+ "java_test(",
+ " name = \"new_target\"",
+ ")");
+ }
+}
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
index a13d261..a592d4e 100644
--- 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
@@ -20,6 +20,7 @@
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.model.primitives.WorkspacePath;
+import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.vfs.VirtualFile;
import org.junit.Test;
@@ -44,6 +45,30 @@
}
@Test
+ public void testInsertPairQuoteOptionRespected() {
+ boolean old = CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE;
+ try {
+ CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE = false;
+ BuildFile file = createBuildFile(new WorkspacePath("java/BUILD"), "'//");
+ Editor editor = editorTest.openFileInEditor(file);
+ editorTest.setCaretPosition(editor, 0, "'//".length());
+
+ assertThat(editorTest.completeIfUnique()).isTrue();
+ assertFileContents(file, "'//java");
+
+ CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE = true;
+ file = createBuildFile(new WorkspacePath("foo/BUILD"), "'//j");
+ editor = editorTest.openFileInEditor(file);
+ editorTest.setCaretPosition(editor, 0, "'//j".length());
+
+ assertThat(editorTest.completeIfUnique()).isTrue();
+ assertFileContents(file, "'//java'");
+ } finally {
+ CodeInsightSettings.getInstance().AUTOINSERT_PAIR_QUOTE = old;
+ }
+ }
+
+ @Test
public void testUniqueMultiSegmentDirectoryCompleted() {
BuildFile file = createBuildFile(new WorkspacePath("java/com/google/BUILD"), "'//'");
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
index 980da4d..ce2388b 100644
--- 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
@@ -17,11 +17,17 @@
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.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -49,6 +55,28 @@
}
@Test
+ public void testCustomRuleCompletion() {
+ MockBuildLanguageSpecProvider specProvider = new MockBuildLanguageSpecProvider();
+ setBuildLanguageSpecRules(specProvider, "java_library");
+ registerApplicationService(BuildLanguageSpecProvider.class, specProvider);
+
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "custom_rule(name = 'lib')",
+ "java_library(",
+ " name = 'test',",
+ " deps = [':']");
+
+ Editor editor = editorTest.openFileInEditor(file);
+ editorTest.setCaretPosition(editor, 3, " deps = [':".length());
+
+ LookupElement[] completionItems = testFixture.completeBasic();
+ assertThat(completionItems).hasLength(1);
+ assertThat(completionItems[0].toString()).isEqualTo("':lib'");
+ }
+
+ @Test
public void testIgnoreContainingTarget() {
BuildFile file =
createBuildFile(
@@ -160,4 +188,28 @@
assertThat(completionItems).asList().contains("'//java:root_rule'");
assertThat(completionItems).asList().doesNotContain("'//java/com/google:other_rule'");
}
+
+ private static void setBuildLanguageSpecRules(
+ MockBuildLanguageSpecProvider specProvider, 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 = new BuildLanguageSpec(ImmutableMap.of());
+
+ 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/SkylarkExtensionSymbolCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/SkylarkExtensionSymbolCompletionTest.java
index 44f3cb9..7a297ac 100644
--- 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
@@ -96,4 +96,18 @@
assertThat(editorTest.completeIfUnique()).isTrue();
assertFileContents(file, "load(':skylark.bzl', 'function')");
}
+
+ @Test
+ public void testPrivateSymbolsNotAutocompleted() {
+ workspace.createFile(
+ new WorkspacePath("skylark.bzl"),
+ "_local = 1",
+ "GLOBAL_VAR = 2",
+ "def _local_fn():stmt",
+ "def global_fn():stmt");
+ createAndSetCaret(new WorkspacePath("BUILD"), "load(':skylark.bzl', '<caret>')");
+
+ String[] options = editorTest.getCompletionItemsAsStrings();
+ assertThat(options).asList().containsExactly("'GLOBAL_VAR'", "'global_fn'");
+ }
}
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
index f50dbf2..9964a22 100644
--- 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
@@ -61,7 +61,7 @@
PsiElement ref = references[0].getElement();
assertThat(ref).isInstanceOf(StringLiteral.class);
- assertThat(PsiUtils.getParentOfType(ref, Argument.Keyword.class)).isEqualTo(arg);
+ assertThat(PsiUtils.getParentOfType(ref, Argument.Keyword.class, true)).isEqualTo(arg);
}
@Test
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalWorkspaceFindUsagesTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalWorkspaceFindUsagesTest.java
new file mode 100644
index 0000000..aec776f
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/findusages/ExternalWorkspaceFindUsagesTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 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.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.workspace.WorkspaceHelper;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiReference;
+import java.io.File;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test that references to external workspaces appear in 'find usages' results. */
+@RunWith(JUnit4.class)
+public class ExternalWorkspaceFindUsagesTest extends BuildFileIntegrationTestCase {
+
+ @Override
+ protected BuildSystem buildSystem() {
+ return BuildSystem.Bazel;
+ }
+
+ @Test
+ public void testFindUsagesFromWorkspaceFile() {
+ BuildFile workspaceBuildFile =
+ createBuildFile(
+ new WorkspacePath("WORKSPACE"),
+ "maven_jar(",
+ " name = 'javax_inject',",
+ " artifact = 'javax.inject:javax.inject:1',",
+ " sha1 = '6975da39a7040257bd51d21a231b76c915872d38',",
+ ")");
+ BuildFile refFile1 =
+ createBuildFile(
+ new WorkspacePath("java/com/foo/BUILD"),
+ "java_library(name = 'javax_inject', exports = ['@javax_inject//jar'])");
+
+ BuildFile refFile2 =
+ createBuildFile(
+ new WorkspacePath("java/com/bar/build_defs.bzl"),
+ "DEP = '@javax_inject//invalid:nonsense'");
+
+ FuncallExpression target = workspaceBuildFile.findRule("javax_inject");
+ StringLiteral ref1 =
+ PsiUtils.findFirstChildOfClassRecursive(
+ refFile1.findRule("javax_inject").getKeywordArgument("exports"), StringLiteral.class);
+ StringLiteral ref2 = PsiUtils.findFirstChildOfClassRecursive(refFile2, StringLiteral.class);
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(2);
+ assertThat(Arrays.stream(references).map(PsiReference::getElement).collect(Collectors.toList()))
+ .containsExactly(ref1, ref2);
+ }
+
+ @Test
+ public void testFindUsagesFromExternalWorkspaceFile() {
+ BuildFile workspaceBuildFile =
+ createBuildFile(
+ new WorkspacePath("BUILD"),
+ "java_library(",
+ " name = 'lib',",
+ " exports = ['@junit//:jar'],",
+ ")");
+ BuildFile externalFile =
+ (BuildFile)
+ createFileInExternalWorkspace(
+ "junit",
+ new WorkspacePath("BUILD"),
+ "java_import(",
+ " name = 'jar',",
+ " jars = ['junit-4.11.jar'],",
+ ")");
+
+ FuncallExpression target = externalFile.findRule("jar");
+ assertThat(target).isNotNull();
+
+ Argument.Keyword arg = workspaceBuildFile.findRule("lib").getKeywordArgument("exports");
+ StringLiteral label = PsiUtils.findFirstChildOfClassRecursive(arg, StringLiteral.class);
+ assertThat(label).isNotNull();
+
+ PsiReference[] references = FindUsages.findAllReferences(target);
+ assertThat(references).hasLength(1);
+ assertThat(references[0].getElement()).isEqualTo(label);
+ }
+
+ private PsiFile createFileInExternalWorkspace(
+ String workspaceName, WorkspacePath path, String... contents) {
+ String filePath =
+ Paths.get(getExternalSourceRoot().getPath(), workspaceName, path.relativePath()).toString();
+ return fileSystem.createPsiFile(filePath, contents);
+ }
+
+ private File getExternalSourceRoot() {
+ return WorkspaceHelper.getExternalSourceRoot(
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData());
+ }
+}
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
index 220c8f2..d46c259 100644
--- 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
@@ -61,14 +61,16 @@
assertThat(funcall).isNotNull();
PsiElement firstRef = references[0].getElement();
- assertThat(PsiUtils.getParentOfType(firstRef, FuncallExpression.class)).isEqualTo(funcall);
+ assertThat(PsiUtils.getParentOfType(firstRef, FuncallExpression.class, true))
+ .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);
+ assertThat(PsiUtils.getParentOfType(secondRef, FunctionStatement.class, true))
+ .isEqualTo(function);
}
// the case where a symbol is the target of multiple assignment statements
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/quickfix/DeprecatedLoadQuickFixTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/quickfix/DeprecatedLoadQuickFixTest.java
new file mode 100644
index 0000000..4223a4d
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/quickfix/DeprecatedLoadQuickFixTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.base.lang.buildfile.quickfix;
+
+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.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.psi.PsiElement;
+import com.intellij.testFramework.MockProblemDescriptor;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link DeprecatedLoadQuickFix}. */
+@RunWith(JUnit4.class)
+public class DeprecatedLoadQuickFixTest extends BuildFileIntegrationTestCase {
+
+ @Test
+ public void testParentDirectoryHasNoBuildFile() {
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load('/java/com/google/subdir/build_defs', 'symbol')");
+
+ StringLiteral string = PsiUtils.findFirstChildOfClassRecursive(file, StringLiteral.class);
+ applyQuickFix(string);
+
+ assertThat(string.getStringContents()).isEqualTo("//java/com/google:subdir/build_defs.bzl");
+ }
+
+ @Test
+ public void testBlazePackageIsParentDirectory() {
+ workspace.createPsiFile(new WorkspacePath("foo/bar/BUILD"));
+ workspace.createPsiFile(new WorkspacePath("foo/bar/build_defs.bzl"));
+
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"), "load('/foo/bar/build_defs', 'symbol')");
+
+ StringLiteral string = PsiUtils.findFirstChildOfClassRecursive(file, StringLiteral.class);
+ applyQuickFix(string);
+
+ assertThat(string.getStringContents()).isEqualTo("//foo/bar:build_defs.bzl");
+ }
+
+ @Test
+ public void testNormalLoadStatementUntouched() {
+ workspace.createPsiFile(new WorkspacePath("foo/bar/BUILD"));
+ workspace.createPsiFile(new WorkspacePath("foo/bar/build_defs.bzl"));
+
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load('//foo/bar:build_defs.bzl', 'symbol')");
+
+ StringLiteral string = PsiUtils.findFirstChildOfClassRecursive(file, StringLiteral.class);
+ String prevString = string.getStringContents();
+ applyQuickFix(string);
+ assertThat(string.getStringContents()).isEqualTo(prevString);
+ }
+
+ @Test
+ public void testRelativeLoadStatementUntouched() {
+ workspace.createPsiFile(new WorkspacePath("foo/bar/build_defs.bzl"));
+ BuildFile file =
+ createBuildFile(new WorkspacePath("foo/bar/BUILD"), "load(':build_defs.bzl', 'symbol')");
+
+ StringLiteral string = PsiUtils.findFirstChildOfClassRecursive(file, StringLiteral.class);
+ String prevString = string.getStringContents();
+ applyQuickFix(string);
+ assertThat(string.getStringContents()).isEqualTo(prevString);
+ }
+
+ private void applyQuickFix(StringLiteral string) {
+ WriteCommandAction.runWriteCommandAction(
+ getProject(),
+ () -> DeprecatedLoadQuickFix.INSTANCE.applyFix(getProject(), descriptorForPsi(string)));
+ }
+
+ private static ProblemDescriptor descriptorForPsi(PsiElement psi) {
+ return new MockProblemDescriptor(
+ psi, "mock", ProblemHighlightType.LIKE_DEPRECATED, DeprecatedLoadQuickFix.INSTANCE);
+ }
+}
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
index 71f8962..7db4d29 100644
--- 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
@@ -36,6 +36,7 @@
import com.intellij.refactoring.move.moveClassesOrPackages.MoveDirectoryWithClassesProcessor;
import com.intellij.refactoring.rename.RenameDialog;
import com.intellij.refactoring.rename.RenamePsiElementProcessor;
+import com.intellij.refactoring.rename.RenameUtil;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@@ -115,6 +116,32 @@
}
@Test
+ public void testTargetRenameValidation() {
+ BuildFile file =
+ createBuildFile(new WorkspacePath("com/google/foo/BUILD"), "rule_type(name = \"target\")");
+ FuncallExpression target =
+ PsiUtils.findFirstChildOfClassRecursive(file, FuncallExpression.class);
+
+ assertThat(RenameUtil.isValidName(getProject(), target, "name-with_allowed,meta=chars+-./@~"))
+ .isTrue();
+ assertThat(RenameUtil.isValidName(getProject(), target, "name:withColon")).isFalse();
+ assertThat(RenameUtil.isValidName(getProject(), target, "/start-with-slash")).isFalse();
+ assertThat(RenameUtil.isValidName(getProject(), target, "up-level-ref/../etc")).isFalse();
+ }
+
+ @Test
+ public void testFunctionRenameValidation() {
+ BuildFile file =
+ createBuildFile(new WorkspacePath("com/google/foo/BUILD"), "def fn_name():", " return");
+ FunctionStatement fn = PsiUtils.findFirstChildOfClassRecursive(file, FunctionStatement.class);
+
+ assertThat(RenameUtil.isValidName(getProject(), fn, "name-with-dash")).isFalse();
+ assertThat(RenameUtil.isValidName(getProject(), fn, "name:withColon")).isFalse();
+ assertThat(RenameUtil.isValidName(getProject(), fn, "return")).isFalse();
+ assertThat(RenameUtil.isValidName(getProject(), fn, "name_with_underscore")).isTrue();
+ }
+
+ @Test
public void testRenameSkylarkExtension() {
BuildFile extFile =
createBuildFile(
@@ -237,6 +264,37 @@
}
@Test
+ public void testRenameExternalWorkspaceTarget() {
+ BuildFile workspaceFile =
+ createBuildFile(
+ new WorkspacePath("WORKSPACE"),
+ "maven_jar(",
+ " name = \"javax\",",
+ " artifact = \"javax.inject:javax.inject:1\",",
+ " sha1 = \"6975da39a7040257bd51d21a231b76c915872d38\",",
+ ")");
+ BuildFile referencingFile =
+ createBuildFile(
+ new WorkspacePath("java/com/foo/BUILD"),
+ "java_library(name = \"javax_inject\", exports = [\"@javax//jar\"])");
+
+ FuncallExpression targetRule =
+ PsiUtils.findFirstChildOfClassRecursive(workspaceFile, FuncallExpression.class);
+ testFixture.renameElement(targetRule, "v2_lib");
+
+ assertFileContents(
+ workspaceFile,
+ "maven_jar(",
+ " name = \"v2_lib\",",
+ " artifact = \"javax.inject:javax.inject:1\",",
+ " sha1 = \"6975da39a7040257bd51d21a231b76c915872d38\",",
+ ")");
+
+ assertFileContents(
+ referencingFile, "java_library(name = \"javax_inject\", exports = [\"@v2_lib//jar\"])");
+ }
+
+ @Test
public void testRenameSuggestionForBuildFile() {
BuildFile buildFile = createBuildFile(new WorkspacePath("java/com/google/BUILD"));
RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(buildFile);
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceTest.java
new file mode 100644
index 0000000..6e2a045
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/ExternalWorkspaceReferenceTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 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.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.workspace.WorkspaceHelper;
+import com.intellij.psi.PsiFile;
+import java.io.File;
+import java.nio.file.Paths;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests that labels referencing external workspaces are correctly resolved. */
+@RunWith(JUnit4.class)
+public class ExternalWorkspaceReferenceTest extends BuildFileIntegrationTestCase {
+
+ @Override
+ protected BuildSystem buildSystem() {
+ return BuildSystem.Bazel;
+ }
+
+ @Test
+ public void testExternalWorkspaceTargetReference() {
+ BuildFile workspaceBuildFile =
+ createBuildFile(
+ new WorkspacePath("BUILD"),
+ "java_library(",
+ " name = 'lib',",
+ " exports = ['@junit//:jar'],",
+ ")");
+ BuildFile externalBuildFile =
+ (BuildFile)
+ createFileInExternalWorkspace(
+ "junit",
+ new WorkspacePath("BUILD"),
+ "java_import(",
+ " name = 'jar',",
+ " jars = ['junit-4.11.jar'],",
+ ")");
+
+ FuncallExpression target = externalBuildFile.findRule("jar");
+ assertThat(target).isNotNull();
+
+ Argument.Keyword arg = workspaceBuildFile.findRule("lib").getKeywordArgument("exports");
+ StringLiteral label = PsiUtils.findFirstChildOfClassRecursive(arg, StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(target);
+ }
+
+ @Test
+ public void testLocalTargetReferenceWithinExternalWorkspaceResolves() {
+ BuildFile externalFile =
+ (BuildFile)
+ createFileInExternalWorkspace(
+ "junit",
+ new WorkspacePath("BUILD"),
+ "java_import(",
+ " name = 'jar',",
+ " jars = ['junit-4.11.jar'],",
+ ")",
+ "java_library(",
+ " name = 'lib',",
+ " srcs = [':jar'],",
+ ")");
+ FuncallExpression target = externalFile.findRule("jar");
+ assertThat(target).isNotNull();
+
+ Argument.Keyword arg = externalFile.findRule("lib").getKeywordArgument("srcs");
+ StringLiteral label = PsiUtils.findFirstChildOfClassRecursive(arg, StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(target);
+ }
+
+ @Test
+ public void testFileReferenceWithinExternalWorkspaceResolves() {
+ BuildFile externalFile =
+ (BuildFile)
+ createFileInExternalWorkspace(
+ "junit",
+ new WorkspacePath("BUILD"),
+ "java_import(",
+ " name = 'target',",
+ " jars = ['junit-4.11.jar'],",
+ ")");
+ PsiFile jarFile = createFileInExternalWorkspace("junit", new WorkspacePath("junit-4.11.jar"));
+ FuncallExpression target = externalFile.findRule("target");
+ StringLiteral label =
+ PsiUtils.findFirstChildOfClassRecursive(
+ target.getKeywordArgument("jars"), StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(jarFile);
+ }
+
+ @Test
+ public void testReferenceToWorkspaceFileContents() {
+ BuildFile workspaceFile =
+ createBuildFile(
+ new WorkspacePath("WORKSPACE"),
+ "maven_jar(",
+ " name = 'w3c_css_sac',",
+ " artifact = 'org.w3c.css:sac:1.3',",
+ " sha1 = 'cdb2dcb4e22b83d6b32b93095f644c3462739e82',",
+ ")");
+ BuildFile referencingFile =
+ createBuildFile(
+ new WorkspacePath("java/com/google/pkg/BUILD"),
+ "rule(",
+ " name = 'other',",
+ " dep = '@w3c_css_sac//jar'",
+ ")");
+ FuncallExpression target = workspaceFile.findRule("w3c_css_sac");
+ assertThat(target).isNotNull();
+
+ FuncallExpression other = referencingFile.findRule("other");
+ StringLiteral label =
+ PsiUtils.findFirstChildOfClassRecursive(
+ other.getKeywordArgument("dep"), StringLiteral.class);
+ assertThat(label.getReferencedElement()).isEqualTo(target);
+ }
+
+ private PsiFile createFileInExternalWorkspace(
+ String workspaceName, WorkspacePath path, String... contents) {
+ String filePath =
+ Paths.get(getExternalSourceRoot().getPath(), workspaceName, path.relativePath()).toString();
+ return fileSystem.createPsiFile(filePath, contents);
+ }
+
+ private File getExternalSourceRoot() {
+ return WorkspaceHelper.getExternalSourceRoot(
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData());
+ }
+}
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
index cc9f04c..303ab02 100644
--- 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
@@ -137,8 +137,7 @@
PsiFile foo = workspace.createPsiFile(new WorkspacePath("java/com/google/Foo.java"));
BuildFile file =
createBuildFile(
- new WorkspacePath("java/com/google/BUILD"),
- "glob(" + " ['**/*']," + " exclude = ['BUILD'])");
+ new WorkspacePath("java/com/google/BUILD"), "glob(['**/*'], exclude = ['BUILD'])");
GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
List<PsiElement> references = multiResolve(glob);
@@ -147,6 +146,20 @@
}
@Test
+ public void testExcludeDirectories2() {
+ workspace.createDirectory(new WorkspacePath("java/com/google/tests"));
+ workspace.createPsiFile(new WorkspacePath("java/com/google/tests/Test.java"));
+ workspace.createPsiFile(new WorkspacePath("java/com/google/Foo.java"));
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"), "glob(['**/*'], exclude = ['**/*'])");
+
+ GlobExpression glob = PsiUtils.findFirstChildOfClassRecursive(file, GlobExpression.class);
+ List<PsiElement> references = multiResolve(glob);
+ assertThat(references).isEmpty();
+ }
+
+ @Test
public void testFilesInSubpackagesExcluded() {
BuildFile pkg =
createBuildFile(new WorkspacePath("java/com/google/BUILD"), "glob(['**/*.java'])");
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
index b14f4b7..7eb16c0 100644
--- 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
@@ -177,7 +177,7 @@
assertThat(references).hasLength(1);
PsiElement element = references[0].getElement();
- FuncallExpression rule = PsiUtils.getParentOfType(element, FuncallExpression.class);
+ FuncallExpression rule = PsiUtils.getParentOfType(element, FuncallExpression.class, true);
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
index b43f778..5cf33ab 100644
--- 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
@@ -17,14 +17,26 @@
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.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.LoadedSymbol;
+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.google.idea.blaze.base.lang.buildfile.search.FindUsages;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiReference;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -67,7 +79,7 @@
// BuildFile buildFile = createBuildFile(
// "java/com/google/tools/BUILD",
// "load(",
- // "\"//java/com/google/build_defs.bzl\",",
+ // "\"/java/com/google/build_defs.bzl\",",
// "\"function\"",
// ")");
//
@@ -119,6 +131,71 @@
}
@Test
+ public void testLoadedSymbolReference() {
+ BuildFile extFile =
+ createBuildFile(new WorkspacePath("java/com/google/tools/build_defs.bzl"), "CONSTANT = 1");
+
+ BuildFile buildFile =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"CONSTANT\"",
+ ")",
+ "NEW_CONSTANT = CONSTANT");
+
+ TargetExpression target =
+ PsiUtils.findFirstChildOfClassRecursive(extFile, TargetExpression.class);
+ ReferenceExpression ref =
+ PsiUtils.findFirstChildOfClassRecursive(buildFile, ReferenceExpression.class);
+ LoadedSymbol loadElement =
+ PsiUtils.findFirstChildOfClassRecursive(buildFile, LoadedSymbol.class);
+
+ assertThat(target).isNotNull();
+ assertThat(ref.getReferencedElement()).isEqualTo(target);
+ assertThat(loadElement.getImport().getReferencedElement()).isEqualTo(target);
+
+ assertThat(
+ Arrays.stream(FindUsages.findAllReferences(target))
+ .map(PsiReference::getElement)
+ .collect(Collectors.toList()))
+ .containsExactly(ref, loadElement.getImport());
+ }
+
+ @Test
+ public void testOverridenBuiltInSymbolReference() {
+ setBuiltInRuleNames("java_library");
+ BuildFile extFile =
+ createBuildFile(
+ new WorkspacePath("java/com/google/tools/build_defs.bzl"), "java_library = rule()");
+
+ BuildFile buildFile =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load(",
+ "\"//java/com/google/tools:build_defs.bzl\",",
+ "\"java_library\"",
+ ")",
+ "java_library(name = 'name')");
+
+ TargetExpression target =
+ PsiUtils.findFirstChildOfClassRecursive(extFile, TargetExpression.class);
+ FuncallExpression funcall = buildFile.firstChildOfClass(FuncallExpression.class);
+ LoadedSymbol loadElement =
+ PsiUtils.findFirstChildOfClassRecursive(buildFile, LoadedSymbol.class);
+
+ assertThat(target).isNotNull();
+ assertThat(funcall.getReferencedElement()).isEqualTo(target);
+ assertThat(loadElement.getImport().getReferencedElement()).isEqualTo(target);
+
+ assertThat(
+ Arrays.stream(FindUsages.findAllReferences(target))
+ .map(PsiReference::getElement)
+ .collect(Collectors.toList()))
+ .containsExactly(funcall, loadElement.getImport());
+ }
+
+ @Test
public void testFuncallReference() {
BuildFile extFile =
createBuildFile(
@@ -181,4 +258,30 @@
assertThat(function).isNotNull();
assertThat(funcall.getReferencedElement()).isEqualTo(function);
}
+
+ private void setBuiltInRuleNames(String... ruleNames) {
+ ImmutableMap.Builder<String, RuleDefinition> rules = ImmutableMap.builder();
+ for (String name : ruleNames) {
+ rules.put(name, new RuleDefinition(name, ImmutableMap.of(), null));
+ }
+ MockBuildLanguageSpecProvider specProvider = new MockBuildLanguageSpecProvider();
+ specProvider.setRules(rules.build());
+ registerApplicationService(BuildLanguageSpecProvider.class, specProvider);
+ specProvider.setRules(rules.build());
+ }
+
+ private static class MockBuildLanguageSpecProvider implements BuildLanguageSpecProvider {
+
+ BuildLanguageSpec languageSpec = new BuildLanguageSpec(ImmutableMap.of());
+
+ 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/references/PackageReferenceTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/PackageReferenceTest.java
index afb3760..6f09694 100644
--- 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
@@ -25,6 +25,8 @@
import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.intellij.psi.PsiReference;
+import java.util.Arrays;
+import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -76,8 +78,7 @@
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);
+ assertThat(Arrays.stream(references).map(PsiReference::resolve).collect(Collectors.toList()))
+ .containsAllOf(libTarget, buildFile1);
}
}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotatorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotatorTest.java
index 28eece6..baf2d39 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotatorTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/BuiltInRuleAnnotatorTest.java
@@ -55,6 +55,9 @@
private static final AttributeDefinition NEVERLINK_ATTRIBUTE =
new AttributeDefinition("neverlink", Discriminator.BOOLEAN, false, null, null);
+ private static final AttributeDefinition VALUES_ATTRIBUTE =
+ new AttributeDefinition("values", Discriminator.STRING_DICT, true, null, null);
+
private static final RuleDefinition JAVA_TEST =
new RuleDefinition(
"java_test",
@@ -62,6 +65,12 @@
"name", NAME_ATTRIBUTE, "srcs", SRCS_ATTRIBUTE, "neverlink", NEVERLINK_ATTRIBUTE),
null);
+ private static final RuleDefinition CONFIG_SETTING =
+ new RuleDefinition(
+ "config_setting",
+ ImmutableMap.of("name", NAME_ATTRIBUTE, "values", VALUES_ATTRIBUTE),
+ null);
+
private MockBuildLanguageSpecProvider specProvider;
@Before
@@ -95,6 +104,33 @@
}
@Test
+ public void testNoErrorsForValidStringDict() {
+ specProvider.setRules(ImmutableMap.of(CONFIG_SETTING.name, CONFIG_SETTING));
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "config_setting(",
+ " name = 'setting',",
+ " values = {'key1', 'value1', 'key2', 'value2'},",
+ ")");
+ assertNoErrors(file);
+ }
+
+ @Test
+ public void testErrorForInvalidDict() {
+ specProvider.setRules(ImmutableMap.of(CONFIG_SETTING.name, CONFIG_SETTING));
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "config_setting(",
+ " name = 'setting',",
+ " values = 1,",
+ ")");
+ assertHasError(
+ file, "Invalid value for attribute 'values'. Expected a value of type 'STRING_DICT'");
+ }
+
+ @Test
public void testGlobTreatedAsList() {
specProvider.setRules(ImmutableMap.of(JAVA_TEST.name, JAVA_TEST));
BuildFile file =
@@ -239,6 +275,35 @@
assertNoErrors(file);
}
+ @Test
+ public void testNoMissingMandatoryArgErrorIfKwargsPresent() {
+ specProvider.setRules(ImmutableMap.of(JAVA_TEST.name, JAVA_TEST));
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "def java_test(srcs=[], **kwargs):",
+ " native.java_test(srcs = srcs, **kwargs)");
+ assertNoErrors(file);
+ }
+
+ @Test
+ public void testNoMissingAttributeErrorsForOverriddenBuiltIns() {
+ specProvider.setRules(ImmutableMap.of(JAVA_TEST.name, JAVA_TEST));
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/foo/BUILD"),
+ "java_test(name = 'test', srcs = [':src'], extra_arg = [])");
+ assertHasError(file, "Unrecognized attribute 'extra_arg' for rule type 'java_test'");
+
+ file =
+ createBuildFile(
+ new WorkspacePath("java/com/bar/BUILD"),
+ "def java_test(srcs=[], **kwargs, extra_arg=[]):",
+ " native.java_test(srcs = srcs, **kwargs)",
+ "java_test(name = 'test', srcs = [':src'], extra_arg = [])");
+ assertNoErrors(file);
+ }
+
private void setRules(String... ruleNames) {
ImmutableMap.Builder<String, RuleDefinition> rules = ImmutableMap.builder();
for (String name : ruleNames) {
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/LoadStatementAnnotatorTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/LoadStatementAnnotatorTest.java
new file mode 100644
index 0000000..ce2f332
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/validation/LoadStatementAnnotatorTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 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.BuildElement;
+import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+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.lang.annotation.HighlightSeverity;
+import com.intellij.psi.PsiFile;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link LoadStatementAnnotator}. */
+@RunWith(JUnit4.class)
+public class LoadStatementAnnotatorTest extends BuildFileIntegrationTestCase {
+
+ @Test
+ public void testNoWarningsInNormalLoad() {
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load('//tools/ide/build_test.bzl', 'build_test')",
+ "load(':local_file.bzl', 'symbol')");
+ assertNoAnnotations(file);
+ }
+
+ @Test
+ public void testNoWarningsInExternalLoad() {
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load('@tools//ide:build_test.bzl', 'build_test')");
+ assertNoAnnotations(file);
+ }
+
+ @Test
+ public void testNoWarningsWhenTyping() {
+ BuildFile file = createBuildFile(new WorkspacePath("java/com/google/BUILD"), "load('/')");
+ assertNoAnnotations(file);
+ }
+
+ @Test
+ public void testWarningForDeprecatedFormat() {
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"),
+ "load('/tools/ide/build_test.bzl', 'build_test')");
+ assertHasAnnotation(
+ file,
+ "Deprecated load syntax; loaded Skylark module should by in label format.",
+ HighlightSeverity.WARNING);
+ }
+
+ @Test
+ public void testErrorForUnrecognizedFormat() {
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"), "load('not a skylark label', 'symbol')");
+ assertHasAnnotation(
+ file, "Invalid load syntax: missing Skylark module.", HighlightSeverity.ERROR);
+ }
+
+ @Test
+ public void testErrorForPrivateSymbols() {
+ BuildFile file =
+ createBuildFile(
+ new WorkspacePath("java/com/google/BUILD"), "load(':skylark.bzl', '_local_symbol')");
+ assertHasAnnotation(
+ file, "Symbol '_local_symbol' is private and cannot be imported.", HighlightSeverity.ERROR);
+ }
+
+ private void assertNoAnnotations(BuildFile file) {
+ assertThat(validateFile(file)).isEmpty();
+ }
+
+ private void assertHasAnnotation(BuildFile file, String message, HighlightSeverity type) {
+ assertThat(
+ validateFile(file)
+ .stream()
+ .filter(ann -> ann.getSeverity().equals(type))
+ .map(Annotation::getMessage)
+ .collect(Collectors.toList()))
+ .contains(message);
+ }
+
+ private List<Annotation> validateFile(BuildFile file) {
+ LoadStatementAnnotator annotator = createAnnotator(file);
+ PsiUtils.findAllChildrenOfClassRecursive(file, BuildElement.class)
+ .forEach(element -> element.accept(annotator));
+ return annotationHolder;
+ }
+
+ private LoadStatementAnnotator createAnnotator(PsiFile file) {
+ annotationHolder = new AnnotationHolderImpl(new AnnotationSession(file));
+ return new LoadStatementAnnotator() {
+ @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
index 99390e2..edf97b7 100644
--- 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
@@ -19,7 +19,6 @@
import com.google.common.base.Joiner;
import com.google.idea.blaze.base.lang.projectview.completion.ProjectViewKeywordCompletionContributor;
-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.WorkspaceType;
import com.google.idea.blaze.base.projectview.section.SectionParser;
@@ -126,20 +125,6 @@
}
@Test
- public void testAdditionalLanguagesCompletion() {
- setInput("additional_languages:", " <caret>");
-
- String[] types = editorTest.getCompletionItemsAsStrings();
-
- assertThat(types)
- .asList()
- .containsAllIn(
- Arrays.stream(LanguageClass.values())
- .map(LanguageClass::getName)
- .collect(Collectors.toList()));
- }
-
- @Test
public void testUniqueDirectoryCompleted() {
setInput("import <caret>");
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
index b6b1c80..42be3e9 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationGenericHandlerIntegrationTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationGenericHandlerIntegrationTest.java
@@ -84,10 +84,10 @@
BlazeCommandRunConfigurationCommonState state =
(BlazeCommandRunConfigurationCommonState) configuration.getHandler().getState();
- state.setCommand(COMMAND);
- state.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- state.setExeFlags(ImmutableList.of("--exeFlag1"));
- state.setBlazeBinary("/usr/bin/blaze");
+ state.getCommandState().setCommand(COMMAND);
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getExeFlagsState().setRawFlags(ImmutableList.of("--exeFlag1"));
+ state.getBlazeBinaryState().setBlazeBinary("/usr/bin/blaze");
Element element = new Element("test");
configuration.writeExternal(element);
@@ -101,10 +101,12 @@
BlazeCommandRunConfigurationCommonState readState =
(BlazeCommandRunConfigurationCommonState) readConfiguration.getHandler().getState();
- assertThat(readState.getCommand()).isEqualTo(COMMAND);
- assertThat(readState.getBlazeFlags()).containsExactly("--flag1", "--flag2").inOrder();
- assertThat(readState.getExeFlags()).containsExactly("--exeFlag1");
- assertThat(readState.getBlazeBinary()).isEqualTo("/usr/bin/blaze");
+ assertThat(readState.getCommandState().getCommand()).isEqualTo(COMMAND);
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("--flag1", "--flag2")
+ .inOrder();
+ assertThat(readState.getExeFlagsState().getRawFlags()).containsExactly("--exeFlag1");
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary()).isEqualTo("/usr/bin/blaze");
}
@Test
@@ -129,10 +131,10 @@
BlazeCommandRunConfigurationCommonState state =
(BlazeCommandRunConfigurationCommonState) configuration.getHandler().getState();
- state.setCommand(COMMAND);
- state.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- state.setExeFlags(ImmutableList.of("--exeFlag1"));
- state.setBlazeBinary("/usr/bin/blaze");
+ state.getCommandState().setCommand(COMMAND);
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getExeFlagsState().setRawFlags(ImmutableList.of("--exeFlag1"));
+ state.getBlazeBinaryState().setBlazeBinary("/usr/bin/blaze");
editor.resetFrom(configuration);
BlazeCommandRunConfiguration readConfiguration =
@@ -145,10 +147,14 @@
BlazeCommandRunConfigurationCommonState readState =
(BlazeCommandRunConfigurationCommonState) readConfiguration.getHandler().getState();
- assertThat(readState.getCommand()).isEqualTo(state.getCommand());
- assertThat(readState.getBlazeFlags()).isEqualTo(state.getBlazeFlags());
- assertThat(readState.getExeFlags()).isEqualTo(state.getExeFlags());
- assertThat(readState.getBlazeBinary()).isEqualTo(state.getBlazeBinary());
+ assertThat(readState.getCommandState().getCommand())
+ .isEqualTo(state.getCommandState().getCommand());
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(state.getBlazeFlagsState().getRawFlags());
+ assertThat(readState.getExeFlagsState().getRawFlags())
+ .isEqualTo(state.getExeFlagsState().getRawFlags());
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary())
+ .isEqualTo(state.getBlazeBinaryState().getBlazeBinary());
Disposer.dispose(editor);
}
@@ -175,10 +181,10 @@
BlazeCommandRunConfigurationCommonState readState =
(BlazeCommandRunConfigurationCommonState) readConfiguration.getHandler().getState();
- readState.setCommand(COMMAND);
- readState.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- readState.setExeFlags(ImmutableList.of("--exeFlag1"));
- readState.setBlazeBinary("/usr/bin/blaze");
+ readState.getCommandState().setCommand(COMMAND);
+ readState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
+ readState.getExeFlagsState().setRawFlags(ImmutableList.of("--exeFlag1"));
+ readState.getBlazeBinaryState().setBlazeBinary("/usr/bin/blaze");
editor.applyEditorTo(readConfiguration);
@@ -187,10 +193,14 @@
.isInstanceOf(BlazeCommandGenericRunConfigurationHandler.class);
readState = (BlazeCommandRunConfigurationCommonState) readConfiguration.getHandler().getState();
- assertThat(readState.getCommand()).isEqualTo(state.getCommand());
- assertThat(readState.getBlazeFlags()).isEqualTo(state.getBlazeFlags());
- assertThat(readState.getExeFlags()).isEqualTo(state.getExeFlags());
- assertThat(readState.getBlazeBinary()).isEqualTo(state.getBlazeBinary());
+ assertThat(readState.getCommandState().getCommand())
+ .isEqualTo(state.getCommandState().getCommand());
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(state.getBlazeFlagsState().getRawFlags());
+ assertThat(readState.getExeFlagsState().getRawFlags())
+ .isEqualTo(state.getExeFlagsState().getRawFlags());
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary())
+ .isEqualTo(state.getBlazeBinaryState().getBlazeBinary());
Disposer.dispose(editor);
}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationRunManagerImplTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationRunManagerImplTest.java
index d1e3b7f..715cbc0 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationRunManagerImplTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationRunManagerImplTest.java
@@ -77,7 +77,7 @@
@Test
public void loadStateAndGetStateShouldMatch() {
- final Label label = new Label("//package:rule");
+ final Label label = Label.create("//package:rule");
configuration.setTarget(label);
final Element element = runManager.getState();
@@ -94,7 +94,7 @@
@Test
public void loadStateAndGetStateElementShouldMatch() {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
- configuration.setTarget(new Label("//package:rule"));
+ configuration.setTarget(Label.create("//package:rule"));
final Element initialElement = runManager.getState();
runManager.loadState(initialElement);
@@ -107,14 +107,14 @@
@Test
public void loadStateAndGetStateElementShouldMatchAfterChangeAndRevert() {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
- final Label label = new Label("//package:rule");
+ final Label label = Label.create("//package:rule");
configuration.setTarget(label);
final Element initialElement = runManager.getState();
runManager.loadState(initialElement);
final BlazeCommandRunConfiguration modifiedConfiguration =
(BlazeCommandRunConfiguration) runManager.getAllConfigurations()[0];
- modifiedConfiguration.setTarget(new Label("//new:label"));
+ modifiedConfiguration.setTarget(Label.create("//new:label"));
final Element modifiedElement = runManager.getState();
assertThat(xmlOutputter.outputString(modifiedElement))
@@ -135,7 +135,7 @@
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
final BlazeCommandRunConfigurationSettingsEditor editor =
new BlazeCommandRunConfigurationSettingsEditor(configuration);
- configuration.setTarget(new Label("//package:rule"));
+ configuration.setTarget(Label.create("//package:rule"));
final Element initialElement = runManager.getState();
editor.resetFrom(configuration);
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
index 61b71f5..66984ae 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationSettingsEditorTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationSettingsEditorTest.java
@@ -51,7 +51,7 @@
public void testEditorApplyToAndResetFromMatches() throws ConfigurationException {
BlazeCommandRunConfigurationSettingsEditor editor =
new BlazeCommandRunConfigurationSettingsEditor(configuration);
- Label label = new Label("//package:rule");
+ Label label = Label.create("//package:rule");
configuration.setTarget(label);
editor.resetFrom(configuration);
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/TestTargetHeuristicTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/TestTargetHeuristicTest.java
index 6cd2d7c..9732eda 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/run/TestTargetHeuristicTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/TestTargetHeuristicTest.java
@@ -19,12 +19,19 @@
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
import com.google.idea.blaze.base.model.primitives.Label;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
import java.io.File;
import java.util.Collection;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -33,9 +40,16 @@
@RunWith(JUnit4.class)
public class TestTargetHeuristicTest extends BlazeIntegrationTestCase {
+ @Before
+ public final void doSetup() {
+ BlazeProjectData blazeProjectData = MockBlazeProjectDataBuilder.builder(workspaceRoot).build();
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(blazeProjectData));
+ }
+
@Test
- public void testTestSizeMatched() throws Exception {
- File source = new File("java/com/foo/FooTest.java");
+ public void testTestSizeMatched() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
Collection<TargetIdeInfo> targets =
ImmutableList.of(
TargetIdeInfo.builder()
@@ -49,24 +63,48 @@
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
.build());
Label match =
- TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, TestSize.SMALL);
- assertThat(match).isEqualTo(new Label("//foo:test2"));
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ getProject(), null, source, targets, TestSize.SMALL);
+ assertThat(match).isEqualTo(Label.create("//foo:test2"));
}
@Test
- public void testTargetNameMatched() throws Exception {
- File source = new File("java/com/foo/FooTest.java");
+ public void testTargetSourcesMatched() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ Collection<TargetIdeInfo> targets =
+ ImmutableList.of(
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/bar/OtherTest.java"))
+ .build(),
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/foo/FooTest.java"))
+ .build());
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ getProject(), null, source, targets, null);
+ assertThat(match).isEqualTo(Label.create("//foo:test2"));
+ }
+
+ @Test
+ public void testTargetNameMatched() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
Collection<TargetIdeInfo> targets =
ImmutableList.of(
TargetIdeInfo.builder().setLabel("//foo:FirstTest").setKind("java_test").build(),
TargetIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, null);
- assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ getProject(), null, source, targets, null);
+ assertThat(match).isEqualTo(Label.create("//foo:FooTest"));
}
@Test
- public void testNoMatchFallBackToFirstTarget() throws Exception {
- File source = new File("java/com/foo/FooTest.java");
+ public void testNoMatchFallBackToFirstTarget() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
ImmutableList<TargetIdeInfo> targets =
ImmutableList.of(
TargetIdeInfo.builder()
@@ -80,13 +118,14 @@
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
.build());
Label match =
- TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, TestSize.LARGE);
- assertThat(match).isEqualTo(new Label("//bar:BarTest"));
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ getProject(), null, source, targets, TestSize.LARGE);
+ assertThat(match).isEqualTo(Label.create("//bar:BarTest"));
}
@Test
- public void testTargetNameCheckedBeforeTestSize() throws Exception {
- File source = new File("java/com/foo/FooTest.java");
+ public void testTargetNameCheckedBeforeTestSize() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
ImmutableList<TargetIdeInfo> targets =
ImmutableList.of(
TargetIdeInfo.builder()
@@ -100,7 +139,35 @@
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
.build());
Label match =
- TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, TestSize.SMALL);
- assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ getProject(), null, source, targets, TestSize.SMALL);
+ assertThat(match).isEqualTo(Label.create("//foo:FooTest"));
+ }
+
+ @Test
+ public void testTargetSourcesCheckedBeforeTestSize() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ Collection<TargetIdeInfo> targets =
+ ImmutableList.of(
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
+ .addSource(sourceRoot("java/com/bar/OtherTest.java"))
+ .build(),
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
+ .addSource(sourceRoot("java/com/foo/FooTest.java"))
+ .build());
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ getProject(), null, source, targets, TestSize.SMALL);
+ assertThat(match).isEqualTo(Label.create("//foo:test2"));
+ }
+
+ private static ArtifactLocation sourceRoot(String relativePath) {
+ return ArtifactLocation.builder().setRelativePath(relativePath).setIsSource(true).build();
}
}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/exporter/RunConfigurationSerializerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/exporter/RunConfigurationSerializerTest.java
index 775e65f..0a28d06 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/run/exporter/RunConfigurationSerializerTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/exporter/RunConfigurationSerializerTest.java
@@ -80,7 +80,7 @@
@Test
public void testRunConfigurationUnalteredBySerializationRoundTrip() throws InvalidDataException {
- configuration.setTarget(new Label("//package:rule"));
+ configuration.setTarget(Label.create("//package:rule"));
configuration.setKeepInSync(true);
final Element initialElement = runManager.getState();
@@ -99,7 +99,7 @@
@Test
public void testSetKeepInSyncWhenImporting() throws InvalidDataException {
- configuration.setTarget(new Label("//package:rule"));
+ configuration.setTarget(Label.create("//package:rule"));
configuration.setKeepInSync(false);
Element element = RunConfigurationSerializer.writeToXml(configuration);
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/producer/AllInPackageBlazeConfigurationProducerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/producer/AllInPackageBlazeConfigurationProducerTest.java
new file mode 100644
index 0000000..7063c58
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/producer/AllInPackageBlazeConfigurationProducerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.producer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+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.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producers.AllInPackageBlazeConfigurationProducer;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.psi.PsiDirectory;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link AllInPackageBlazeConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class AllInPackageBlazeConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
+
+ @Test
+ public void testProducedFromPsiDirectory() {
+ PsiDirectory directory =
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ workspace.createPsiFile(
+ new WorkspacePath("java/com/google/test/BUILD"), "java_test(name='unit_tests'");
+
+ ConfigurationContext context = createContextFromPsi(directory);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(AllInPackageBlazeConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test/...:all"));
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testDirectoryWithoutBlazePackageChildIsIgnored() {
+ PsiDirectory directory =
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+
+ ConfigurationContext context = createContextFromPsi(directory);
+
+ AllInPackageBlazeConfigurationProducer producer = new AllInPackageBlazeConfigurationProducer();
+ assertThat(producer.createConfigurationFromContext(context)).isNull();
+
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test/child_dir"));
+ workspace.createPsiFile(new WorkspacePath("java/com/google/test/child_dir/BUILD"));
+
+ assertThat(producer.createConfigurationFromContext(context)).isNotNull();
+ }
+}
diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/run/producer/BlazeBuildFileRunConfigurationProducerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/run/producer/BlazeBuildFileRunConfigurationProducerTest.java
new file mode 100644
index 0000000..dcf3e6b
--- /dev/null
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/run/producer/BlazeBuildFileRunConfigurationProducerTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.producer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+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.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producers.BlazeBuildFileRunConfigurationProducer;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.psi.PsiFile;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link BlazeBuildFileRunConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class BlazeBuildFileRunConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
+
+ @Test
+ public void testProducedFromFuncallExpression() {
+ PsiFile buildFile =
+ workspace.createPsiFile(
+ new WorkspacePath("java/com/google/test/BUILD"), "java_test(name='unit_tests'");
+
+ FuncallExpression target =
+ PsiUtils.findFirstChildOfClassRecursive(buildFile, FuncallExpression.class);
+ assertThat(target).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(target);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeBuildFileRunConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:unit_tests"));
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testProducedWhenInsideFuncallExpression() {
+ PsiFile buildFile =
+ workspace.createPsiFile(
+ new WorkspacePath("java/com/google/test/BUILD"), "java_test(name='unit_tests'");
+
+ StringLiteral nameString =
+ PsiUtils.findFirstChildOfClassRecursive(buildFile, StringLiteral.class);
+ assertThat(nameString).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(nameString);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeBuildFileRunConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:unit_tests"));
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+}
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
index 84bf00f..df9a08f 100644
--- a/base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java
+++ b/base/tests/integrationtests/com/google/idea/blaze/base/sync/ImportRootsTest.java
@@ -87,8 +87,18 @@
.add(new DirectoryEntry(new WorkspacePath(""), true))
.build();
- assertThat(importRoots.importAsSource(new Label("//:target"))).isTrue();
- assertThat(importRoots.importAsSource(new Label("//foo/bar:target"))).isTrue();
+ assertThat(importRoots.importAsSource(Label.create("//:target"))).isTrue();
+ assertThat(importRoots.importAsSource(Label.create("//foo/bar:target"))).isTrue();
+ }
+
+ @Test
+ public void testExternalWorkspaceLabelsNotIncludedUnderWorkspaceRoot() {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(new DirectoryEntry(new WorkspacePath(""), true))
+ .build();
+
+ assertThat(importRoots.importAsSource(Label.create("@lib//:target"))).isFalse();
}
@Test
@@ -138,4 +148,55 @@
.build();
assertThat(importRoots.excludeDirectories()).containsExactly(new WorkspacePath("root"));
}
+
+ @Test
+ public void testContainsWorkspacePath_samePath() throws Exception {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(DirectoryEntry.include(new WorkspacePath("root")))
+ .build();
+
+ assertThat(importRoots.containsWorkspacePath(new WorkspacePath("root"))).isTrue();
+ }
+
+ @Test
+ public void testContainsWorkspacePath_subdirectory() throws Exception {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(DirectoryEntry.include(new WorkspacePath("root")))
+ .build();
+
+ assertThat(importRoots.containsWorkspacePath(new WorkspacePath("root/subdir"))).isTrue();
+ }
+
+ @Test
+ public void testContainsWorkspacePath_differentRoot() throws Exception {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(DirectoryEntry.include(new WorkspacePath("root")))
+ .build();
+
+ assertThat(importRoots.containsWorkspacePath(new WorkspacePath("otherroot"))).isFalse();
+ }
+
+ @Test
+ public void testContainsWorkspacePath_similarRoot() throws Exception {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(DirectoryEntry.include(new WorkspacePath("root")))
+ .build();
+
+ assertThat(importRoots.containsWorkspacePath(new WorkspacePath("root2/subdir"))).isFalse();
+ }
+
+ @Test
+ public void testContainsWorkspacePath_excludedParentsAreHandled() throws Exception {
+ ImportRoots importRoots =
+ ImportRoots.builder(workspaceRoot, BuildSystem.Blaze)
+ .add(DirectoryEntry.include(new WorkspacePath("root")))
+ .add(DirectoryEntry.exclude(new WorkspacePath("root/a")))
+ .build();
+
+ assertThat(importRoots.containsWorkspacePath(new WorkspacePath("root/a/b"))).isFalse();
+ }
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/actions/BlazeBuildServiceTest.java b/base/tests/unittests/com/google/idea/blaze/base/actions/BlazeBuildServiceTest.java
index cce3237..23e40c8 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/actions/BlazeBuildServiceTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/actions/BlazeBuildServiceTest.java
@@ -59,9 +59,9 @@
@Override
protected void initTest(Container applicationServices, Container projectServices) {
- BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager(project);
+ BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
importSettingsManager.setImportSettings(
- new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze));
+ new BlazeImportSettings("", "", "", "", Blaze.BuildSystem.Blaze));
projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
ProjectView view =
@@ -91,7 +91,7 @@
@Test
public void testBuildFile() {
ImmutableCollection<Label> labels =
- ImmutableList.of(new Label("//foo:bar"), new Label("//foo:baz"));
+ ImmutableList.of(Label.create("//foo:bar"), Label.create("//foo:baz"));
List<TargetExpression> targets = Lists.newArrayList(labels);
service.buildFile(project, "Foo.java", labels);
verify(service).buildTargetExpressions(eq(project), eq(targets), eq(viewSet), any());
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
index 64b6894..30f41fa 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/command/BlazeCommandTest.java
@@ -21,7 +21,6 @@
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;
@@ -47,8 +46,8 @@
@Test
public void addedFlagsShouldGoAtStart() {
List<String> flagsCommand =
- BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"))
+ BlazeCommand.builder("/usr/bin/blaze", BlazeCommandName.RUN)
+ .addTargets(Label.create("//a:b"))
.addBlazeFlags("--flag1", "--flag2")
.addExeFlags("--exeFlag1", "--exeFlag2")
.build()
@@ -60,8 +59,8 @@
@Test
public void targetsShouldGoAfterBlazeFlagsAndDoubleHyphen() {
List<String> command =
- BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"), new Label("//c:d"))
+ BlazeCommand.builder("/usr/bin/blaze", BlazeCommandName.RUN)
+ .addTargets(Label.create("//a:b"), Label.create("//c:d"))
.addBlazeFlags("--flag1", "--flag2")
.addExeFlags("--exeFlag1", "--exeFlag2")
.build()
@@ -75,8 +74,8 @@
@Test
public void exeFlagsShouldGoLast() {
List<String> command =
- BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
- .addTargets(new Label("//a:b"), new Label("//c:d"))
+ BlazeCommand.builder("/usr/bin/blaze", BlazeCommandName.RUN)
+ .addTargets(Label.create("//a:b"), Label.create("//c:d"))
.addBlazeFlags("--flag1", "--flag2")
.addExeFlags("--exeFlag1", "--exeFlag2")
.build()
@@ -88,9 +87,9 @@
@Test
public void maintainUserOrderingOfTargets() {
List<String> command =
- BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.RUN)
+ BlazeCommand.builder("/usr/bin/blaze", BlazeCommandName.RUN)
.addTargets(
- new Label("//a:b"), TargetExpression.fromString("-//e:f"), new Label("//c:d"))
+ Label.create("//a:b"), TargetExpression.fromString("-//e:f"), Label.create("//c:d"))
.addBlazeFlags("--flag1", "--flag2")
.addExeFlags("--exeFlag1", "--exeFlag2")
.build()
@@ -116,7 +115,7 @@
@Test
public void binaryAndCommandShouldComeFirst() {
List<String> command =
- BlazeCommand.builder(BuildSystem.Blaze, BlazeCommandName.BUILD)
+ BlazeCommand.builder("/usr/bin/blaze", BlazeCommandName.BUILD)
.addBlazeFlags("--flag")
.addExeFlags("--exeFlag")
.build()
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
index 437822a..6ed7193 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/issueparser/BlazeIssueParserTest.java
@@ -77,6 +77,7 @@
new BlazeIssueParser.CompileParser(workspaceRoot),
new BlazeIssueParser.TracebackParser(),
new BlazeIssueParser.BuildParser(),
+ new BlazeIssueParser.SkylarkErrorParser(),
new BlazeIssueParser.LinelessBuildParser(),
new BlazeIssueParser.ProjectViewLabelParser(projectViewSet),
new BlazeIssueParser.InvalidTargetProjectViewPackageParser(
@@ -150,6 +151,22 @@
}
@Test
+ public void testParseSkylarkError() {
+ BlazeIssueParser blazeIssueParser = new BlazeIssueParser(parsers);
+ IssueOutput issue =
+ blazeIssueParser.parseIssue(
+ "ERROR: /root/third_party/bazel/tools/ide/intellij_info_impl.bzl:42:12: "
+ + "Variable artifact_location is read only");
+ assertNotNull(issue);
+ assertThat(issue.getFile().getPath())
+ .isEqualTo("/root/third_party/bazel/tools/ide/intellij_info_impl.bzl");
+ assertThat(issue.getLine()).isEqualTo(42);
+ assertThat(issue.getColumn()).isEqualTo(12);
+ assertThat(issue.getMessage()).isEqualTo("Variable artifact_location is read only");
+ assertThat(issue.getCategory()).isEqualTo(IssueOutput.Category.ERROR);
+ }
+
+ @Test
public void testParseLinelessBuildError() {
BlazeIssueParser blazeIssueParser = new BlazeIssueParser(parsers);
IssueOutput issue =
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
index 2ef9472..2f2457b 100644
--- 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
@@ -23,8 +23,8 @@
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Utilities for deep equals testing. */
@VisibleForTesting
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
index 4ceb066..9227a6b 100644
--- 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
@@ -68,4 +68,47 @@
assertThat(Label.validate("foo")).isFalse();
assertThat(Label.validate("foo:bar")).isFalse();
}
+
+ @Test
+ public void testFactoryMethod() {
+ String fullLabel = "//package/path:target/name";
+ Label label = Label.create(fullLabel);
+ assertThat(label.toString()).isEqualTo(fullLabel);
+ assertThat(label.blazePackage()).isEqualTo(new WorkspacePath("package/path"));
+ assertThat(label.targetName()).isEqualTo(TargetName.create("target/name"));
+ }
+
+ @Test
+ public void testFactoryMethodExternalWorkspace() {
+ String fullLabel = "@ext_workspace//package/path:target/name";
+ Label label = Label.create(fullLabel);
+ assertThat(label.toString()).isEqualTo(fullLabel);
+ assertThat(label.externalWorkspaceName()).isEqualTo("ext_workspace");
+ assertThat(label.blazePackage()).isEqualTo(new WorkspacePath("package/path"));
+ assertThat(label.targetName()).isEqualTo(TargetName.create("target/name"));
+ }
+
+ @Test
+ public void testConstructor() {
+ String externalWorkspaceName = "ext_workspace";
+ WorkspacePath packagePath = new WorkspacePath("package/path");
+ TargetName targetName = TargetName.create("target/name");
+
+ Label label = Label.create(externalWorkspaceName, packagePath, targetName);
+ assertThat(label.toString()).isEqualTo("@ext_workspace//package/path:target/name");
+ assertThat(label.externalWorkspaceName()).isEqualTo(externalWorkspaceName);
+ assertThat(label.blazePackage()).isEqualTo(packagePath);
+ assertThat(label.targetName()).isEqualTo(targetName);
+ }
+
+ @Test
+ public void testConstructorExternalWorkspace() {
+ WorkspacePath packagePath = new WorkspacePath("package/path");
+ TargetName targetName = TargetName.create("target/name");
+
+ Label label = Label.create(packagePath, targetName);
+ assertThat(label.toString()).isEqualTo("//package/path:target/name");
+ assertThat(label.blazePackage()).isEqualTo(packagePath);
+ assertThat(label.targetName()).isEqualTo(targetName);
+ }
}
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
index 7758293..9f1ad20 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewSetTest.java
@@ -40,6 +40,7 @@
import com.google.idea.blaze.base.projectview.section.sections.ImportTargetOutputSection;
import com.google.idea.blaze.base.projectview.section.sections.RunConfigurationsSection;
import com.google.idea.blaze.base.projectview.section.sections.Sections;
+import com.google.idea.blaze.base.projectview.section.sections.ShardBlazeBuildsSection;
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;
@@ -83,9 +84,10 @@
.add(ListSection.builder(BuildFlagsSection.KEY).add("--android_sdk=abcd"))
.add(
ListSection.builder(ImportTargetOutputSection.KEY)
- .add(new Label("//test:test")))
+ .add(Label.create("//test:test")))
.add(
- ListSection.builder(ExcludeTargetSection.KEY).add(new Label("//test:test")))
+ ListSection.builder(ExcludeTargetSection.KEY)
+ .add(Label.create("//test:test")))
.add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.JAVA))
.add(
ListSection.builder(AdditionalLanguagesSection.KEY).add(LanguageClass.JAVA))
@@ -93,6 +95,7 @@
.add(
ListSection.builder(RunConfigurationsSection.KEY)
.add(new WorkspacePath("test")))
+ .add(ScalarSection.builder(ShardBlazeBuildsSection.KEY).set(false))
.build())
.build();
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
index fe15957..1b2e31c 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/projectview/ProjectViewVerifierTest.java
@@ -15,6 +15,7 @@
*/
package com.google.idea.blaze.base.projectview;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.idea.blaze.base.BlazeTestCase;
@@ -35,6 +36,7 @@
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
import java.io.File;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
@@ -60,7 +62,20 @@
protected void initTest(
@NotNull Container applicationServices, @NotNull Container projectServices) {
super.initTest(applicationServices, projectServices);
- registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+ ExtensionPointImpl<BlazeSyncPlugin> ep =
+ registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+ ep.registerExtension(
+ new BlazeSyncPlugin.Adapter() {
+ @Override
+ public ImmutableList<WorkspaceType> getSupportedWorkspaceTypes() {
+ return ImmutableList.of(WorkspaceType.JAVA);
+ }
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ return ImmutableSet.of(LanguageClass.JAVA);
+ }
+ });
fileAttributeProvider = new MockFileAttributeProvider(workspaceRoot);
applicationServices.register(FileAttributeProvider.class, fileAttributeProvider);
@@ -86,7 +101,7 @@
.build();
fileAttributeProvider.addProjectView(projectViewSet);
ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
errorCollector.assertNoIssues();
}
@@ -108,7 +123,7 @@
.build();
fileAttributeProvider.addProjectView(projectViewSet);
ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
errorCollector.assertIssues(
"java/com/google/android/apps/example is included, "
+ "but that contradicts java/com/google/android/apps/example which was excluded");
@@ -132,7 +147,7 @@
.build();
fileAttributeProvider.addProjectView(projectViewSet);
ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
errorCollector.assertIssues(
"java/com/google/android/apps/example is included, "
+ "but that contradicts java/com/google/android/apps which was excluded");
@@ -157,7 +172,7 @@
.build();
fileAttributeProvider.addProjectView(projectViewSet);
ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
errorCollector.assertNoIssues();
}
@@ -175,7 +190,7 @@
.build())
.build();
ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
errorCollector.assertIssues(
String.format(
"Directory '%s' specified in project view not found.",
@@ -197,7 +212,7 @@
.build();
fileAttributeProvider.addFile(new WorkspacePath("java/com/google/android/apps/example"));
ProjectViewVerifier.verifyProjectView(
- context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
+ project, context, workspacePathResolver, projectViewSet, workspaceLanguageSettings);
errorCollector.assertIssues(
String.format(
"Directory '%s' specified in project view is a file.",
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
index 08fea57..52ed8cf 100644
--- 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
@@ -48,8 +48,8 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
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
index 2f1cac6..f0047bd 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/BlazeCommandRunConfigurationTest.java
@@ -43,7 +43,7 @@
@RunWith(JUnit4.class)
public class BlazeCommandRunConfigurationTest extends BlazeTestCase {
private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
- new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze);
+ new BlazeImportSettings("", "", "", "", Blaze.BuildSystem.Blaze);
private final BlazeCommandRunConfigurationType type = new BlazeCommandRunConfigurationType();
private BlazeCommandRunConfiguration configuration;
@@ -54,8 +54,7 @@
super.initTest(applicationServices, projectServices);
applicationServices.register(UISettings.class, new UISettings());
- projectServices.register(
- BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager());
BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
applicationServices.register(ExperimentService.class, new MockExperimentService());
@@ -71,7 +70,7 @@
@Test
public void readAndWriteShouldMatch() throws Exception {
- Label label = new Label("//package:rule");
+ Label label = Label.create("//package:rule");
configuration.setTarget(label);
Element element = new Element("test");
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
index 2923947..70a85be 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/RuleNameHeuristicTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/RuleNameHeuristicTest.java
@@ -46,7 +46,8 @@
File source = new File("java/com/foo/FooTest.java");
TargetIdeInfo target =
TargetIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build();
- assertThat(new TargetNameHeuristic().matchesSource(target, source, null)).isTrue();
+ assertThat(new TargetNameHeuristic().matchesSource(project, target, null, source, null))
+ .isTrue();
}
@Test
@@ -54,7 +55,8 @@
File source = new File("java/com/foo/FooTest.java");
TargetIdeInfo target =
TargetIdeInfo.builder().setLabel("//foo:foo/FooTest").setKind("java_test").build();
- assertThat(new TargetNameHeuristic().matchesSource(target, source, null)).isTrue();
+ assertThat(new TargetNameHeuristic().matchesSource(project, target, null, source, null))
+ .isTrue();
}
@Test
@@ -62,7 +64,8 @@
File source = new File("java/com/foo/BarFooTest.java");
TargetIdeInfo target =
TargetIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build();
- assertThat(new TargetNameHeuristic().matchesSource(target, source, null)).isFalse();
+ assertThat(new TargetNameHeuristic().matchesSource(project, target, null, source, null))
+ .isFalse();
}
@Test
@@ -70,7 +73,8 @@
File source = new File("java/com/foo/FooTest.java");
TargetIdeInfo target =
TargetIdeInfo.builder().setLabel("//foo:bar/FooTest").setKind("java_test").build();
- assertThat(new TargetNameHeuristic().matchesSource(target, source, null)).isFalse();
+ assertThat(new TargetNameHeuristic().matchesSource(project, target, null, source, null))
+ .isFalse();
}
@Test
@@ -78,7 +82,8 @@
File source = new File("java/com/foo/FooTest.java");
TargetIdeInfo target =
TargetIdeInfo.builder().setLabel("//foo:ForTest").setKind("java_test").build();
- assertThat(new TargetNameHeuristic().matchesSource(target, source, null)).isFalse();
+ assertThat(new TargetNameHeuristic().matchesSource(project, target, null, source, null))
+ .isFalse();
}
@Test
@@ -88,8 +93,9 @@
ImmutableList.of(
TargetIdeInfo.builder().setLabel("//foo:FirstTest").setKind("java_test").build(),
TargetIdeInfo.builder().setLabel("//bar:OtherTest").setKind("java_test").build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, null);
- assertThat(match).isEqualTo(new Label("//foo:FirstTest"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(project, null, source, targets, null);
+ assertThat(match).isEqualTo(Label.create("//foo:FirstTest"));
}
@Test
@@ -99,8 +105,9 @@
ImmutableList.of(
TargetIdeInfo.builder().setLabel("//bar:FirstTest").setKind("java_test").build(),
TargetIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, null);
- assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(project, null, source, targets, null);
+ assertThat(match).isEqualTo(Label.create("//foo:FooTest"));
}
@Test
@@ -111,7 +118,8 @@
TargetIdeInfo.builder().setLabel("//bar:OtherTest").setKind("java_test").build(),
TargetIdeInfo.builder().setLabel("//foo:FooTest").setKind("java_test").build(),
TargetIdeInfo.builder().setLabel("//bar/foo:FooTest").setKind("java_test").build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, targets, null);
- assertThat(match).isEqualTo(new Label("//foo:FooTest"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(project, null, source, targets, null);
+ assertThat(match).isEqualTo(Label.create("//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
index 99ce084..9df7417 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/TestSizeHeuristicTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/TestSizeHeuristicTest.java
@@ -51,7 +51,9 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
.build();
- assertThat(new TestSizeHeuristic().matchesSource(target, source, TestSize.MEDIUM)).isTrue();
+ assertThat(
+ new TestSizeHeuristic().matchesSource(project, target, null, source, TestSize.MEDIUM))
+ .isTrue();
}
@Test
@@ -63,7 +65,8 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
.build();
- assertThat(new TestSizeHeuristic().matchesSource(target, source, TestSize.SMALL)).isFalse();
+ assertThat(new TestSizeHeuristic().matchesSource(project, target, null, source, TestSize.SMALL))
+ .isFalse();
}
@Test
@@ -75,7 +78,7 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
.build();
- assertThat(new TestSizeHeuristic().matchesSource(target, source, null)).isTrue();
+ assertThat(new TestSizeHeuristic().matchesSource(project, target, null, source, null)).isTrue();
target =
TargetIdeInfo.builder()
@@ -83,7 +86,8 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.MEDIUM))
.build();
- assertThat(new TestSizeHeuristic().matchesSource(target, source, null)).isFalse();
+ assertThat(new TestSizeHeuristic().matchesSource(project, target, null, source, null))
+ .isFalse();
}
@Test
@@ -106,8 +110,10 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.ENORMOUS))
.build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
- assertThat(match).isEqualTo(new Label("//foo:test1"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ project, null, source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(Label.create("//foo:test1"));
}
@Test
@@ -125,8 +131,10 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
.build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
- assertThat(match).isEqualTo(new Label("//foo:test2"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ project, null, source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(Label.create("//foo:test2"));
}
@Test
@@ -149,7 +157,9 @@
.setKind("java_test")
.setTestInfo(TestIdeInfo.builder().setTestSize(TestSize.SMALL))
.build());
- Label match = TestTargetHeuristic.chooseTestTargetForSourceFile(source, rules, TestSize.SMALL);
- assertThat(match).isEqualTo(new Label("//foo:test2"));
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ project, null, source, rules, TestSize.SMALL);
+ assertThat(match).isEqualTo(Label.create("//foo:test2"));
}
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/TestTargetSourcesHeuristicTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/TestTargetSourcesHeuristicTest.java
new file mode 100644
index 0000000..0663264
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/TestTargetSourcesHeuristicTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+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.sync.data.BlazeProjectDataManager;
+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;
+
+/** Unit tests for {@link TestTargetSourcesHeuristic}. */
+@RunWith(JUnit4.class)
+public class TestTargetSourcesHeuristicTest extends BlazeTestCase {
+
+ private final WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/"));
+
+ @Override
+ protected void initTest(Container applicationServices, Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+
+ BlazeProjectData blazeProjectData = MockBlazeProjectDataBuilder.builder(workspaceRoot).build();
+ projectServices.register(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(blazeProjectData));
+
+ ExtensionPointImpl<TestTargetHeuristic> ep =
+ registerExtensionPoint(TestTargetHeuristic.EP_NAME, TestTargetHeuristic.class);
+ ep.registerExtension(new TestTargetSourcesHeuristic());
+ }
+
+ @Test
+ public void testPredicateNoSources() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ TargetIdeInfo target =
+ TargetIdeInfo.builder().setLabel("//foo:test").setKind("java_test").build();
+ assertThat(new TestTargetSourcesHeuristic().matchesSource(project, target, null, source, null))
+ .isFalse();
+ }
+
+ @Test
+ public void testPredicateNoMatchingSource() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ TargetIdeInfo target =
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/bar/OtherTest.java"))
+ .build();
+ assertThat(new TestTargetSourcesHeuristic().matchesSource(project, target, null, source, null))
+ .isFalse();
+ }
+
+ @Test
+ public void testPredicateMatchingSource() {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ TargetIdeInfo target =
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/bar/OtherTest.java"))
+ .addSource(sourceRoot("java/com/foo/FooTest.java"))
+ .build();
+ assertThat(new TestTargetSourcesHeuristic().matchesSource(project, target, null, source, null))
+ .isTrue();
+ }
+
+ @Test
+ public void testFilterNoMatchesFallBackToFirstRule() throws Exception {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ ImmutableList<TargetIdeInfo> rules =
+ ImmutableList.of(
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/bar/OtherTest.java"))
+ .build(),
+ TargetIdeInfo.builder().setLabel("//foo:test2").setKind("java_test").build());
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(project, null, source, rules, null);
+ assertThat(match).isEqualTo(Label.create("//foo:test1"));
+ }
+
+ @Test
+ public void testFilterOneMatch() throws Exception {
+ File source = workspaceRoot.fileForPath(new WorkspacePath("java/com/foo/FooTest.java"));
+ ImmutableList<TargetIdeInfo> rules =
+ ImmutableList.of(
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test1")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/bar/OtherTest.java"))
+ .build(),
+ TargetIdeInfo.builder()
+ .setLabel("//foo:test2")
+ .setKind("java_test")
+ .addSource(sourceRoot("java/com/foo/FooTest.java"))
+ .build());
+ Label match =
+ TestTargetHeuristic.chooseTestTargetForSourceFile(project, null, source, rules, null);
+ assertThat(match).isEqualTo(Label.create("//foo:test2"));
+ }
+
+ private static ArtifactLocation sourceRoot(String relativePath) {
+ return ArtifactLocation.builder().setRelativePath(relativePath).setIsSource(true).build();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/filter/BlazeTargetFilterTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/filter/BlazeTargetFilterTest.java
new file mode 100644
index 0000000..4563886
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/filter/BlazeTargetFilterTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.filter;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.idea.blaze.base.run.filter.BlazeTargetFilter.TARGET_PATTERN;
+
+import java.util.regex.Matcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link BlazeTargetFilter}. */
+@RunWith(JUnit4.class)
+public class BlazeTargetFilterTest {
+
+ @Test
+ public void testSimpleTarget() {
+ String line = "Something //package:target_name something else";
+ Matcher matcher = TARGET_PATTERN.matcher(line);
+ assertThat(matcher.find()).isTrue();
+ assertThat(matcher.group()).isEqualTo("//package:target_name");
+ }
+
+ @Test
+ public void testExternalWorkspaceTarget() {
+ String line = "Something @ext//package:target_name something else";
+ Matcher matcher = TARGET_PATTERN.matcher(line);
+ assertThat(matcher.find()).isTrue();
+ assertThat(matcher.group()).isEqualTo("@ext//package:target_name");
+ }
+
+ @Test
+ public void testQuotedTarget() {
+ String line = "Something '//package:target_name' something else";
+ Matcher matcher = TARGET_PATTERN.matcher(line);
+ assertThat(matcher.find()).isTrue();
+ assertThat(matcher.group()).isEqualTo("//package:target_name");
+ }
+
+ @Test
+ public void testUnusualCharsInTarget() {
+ String line = "Something //Package-._$():T0+,=~#target_@name something else";
+ Matcher matcher = TARGET_PATTERN.matcher(line);
+ assertThat(matcher.find()).isTrue();
+ assertThat(matcher.group()).isEqualTo("//Package-._$():T0+,=~#target_@name");
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchemaTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchemaTest.java
index 5c7dc35..2ed69f5 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchemaTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/smrunner/BlazeXmlSchemaTest.java
@@ -24,6 +24,7 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -68,4 +69,51 @@
TestSuite parsed = BlazeXmlSchema.parse(stream);
assertThat(parsed).isNotNull();
}
+
+ @Test
+ public void testMergeShardedTests() {
+ TestSuite shard1 =
+ parseXml(
+ "<?xml version='1.0' encoding='UTF-8'?>",
+ "<testsuites>",
+ " <testsuite name='com.google.ConfigTest' time='10' tests='2' failures='1'>",
+ " <testcase name='testCase1' time='2.1' status='run' result='completed'/>",
+ " <testcase name='testCase2' time='7.9' status='run' result='completed'>",
+ " <failure message='failed'/>",
+ " </testcase>",
+ " </testsuite>",
+ "</testsuites>");
+ TestSuite shard2 =
+ parseXml(
+ "<?xml version='1.0' encoding='UTF-8'?>",
+ "<testsuites>",
+ " <testsuite name='com.google.ConfigTest' time='5' tests='2' failures='1'>",
+ " <testcase name='testCase3' time='1' status='run' result='completed'/>",
+ " <testcase name='testCase4' time='4' status='run' result='completed'>",
+ " <failure message='failed'/>",
+ " </testcase>",
+ " </testsuite>",
+ "</testsuites>");
+ TestSuite mergedOuter = BlazeXmlSchema.mergeSuites(ImmutableList.of(shard1, shard2));
+ assertThat(mergedOuter.testSuites).hasSize(1);
+ TestSuite mergedInner = mergedOuter.testSuites.get(0).testSuites.get(0);
+ assertThat(mergedInner.name).isEqualTo("com.google.ConfigTest");
+ assertThat(mergedInner.time).isEqualTo(15d);
+ assertThat(mergedInner.tests).isEqualTo(4);
+ assertThat(mergedInner.failures).isEqualTo(2);
+ assertThat(mergedInner.testCases).hasSize(4);
+ assertThat(
+ mergedInner
+ .testCases
+ .stream()
+ .map(testCase -> testCase.name)
+ .collect(Collectors.toList()))
+ .containsExactly("testCase1", "testCase2", "testCase3", "testCase4");
+ }
+
+ private static TestSuite parseXml(String... lines) {
+ InputStream stream =
+ new ByteArrayInputStream(Joiner.on('\n').join(lines).getBytes(StandardCharsets.UTF_8));
+ return BlazeXmlSchema.parse(stream);
+ }
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonStateTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonStateTest.java
index 5598b49..5aa8521 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonStateTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/state/BlazeCommandRunConfigurationCommonStateTest.java
@@ -37,7 +37,7 @@
@RunWith(JUnit4.class)
public class BlazeCommandRunConfigurationCommonStateTest extends BlazeTestCase {
private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
- new BlazeImportSettings("", "", "", "", "", Blaze.BuildSystem.Blaze);
+ new BlazeImportSettings("", "", "", "", Blaze.BuildSystem.Blaze);
private static final BlazeCommandName COMMAND = BlazeCommandName.fromString("command");
private BlazeCommandRunConfigurationCommonState state;
@@ -47,8 +47,7 @@
super.initTest(applicationServices, projectServices);
applicationServices.register(UISettings.class, new UISettings());
- projectServices.register(
- BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager());
BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
registerExtensionPoint(DistributedExecutorSupport.EP_NAME, DistributedExecutorSupport.class);
@@ -58,10 +57,10 @@
@Test
public void readAndWriteShouldMatch() throws Exception {
- state.setCommand(COMMAND);
- state.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- state.setExeFlags(ImmutableList.of("--exeFlag1"));
- state.setBlazeBinary("/usr/bin/blaze");
+ state.getCommandState().setCommand(COMMAND);
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getExeFlagsState().setRawFlags(ImmutableList.of("--exeFlag1"));
+ state.getBlazeBinaryState().setBlazeBinary("/usr/bin/blaze");
Element element = new Element("test");
state.writeExternal(element);
@@ -69,10 +68,12 @@
new BlazeCommandRunConfigurationCommonState(Blaze.getBuildSystem(project));
readState.readExternal(element);
- assertThat(readState.getCommand()).isEqualTo(COMMAND);
- assertThat(readState.getBlazeFlags()).containsExactly("--flag1", "--flag2").inOrder();
- assertThat(readState.getExeFlags()).containsExactly("--exeFlag1");
- assertThat(readState.getBlazeBinary()).isEqualTo("/usr/bin/blaze");
+ assertThat(readState.getCommandState().getCommand()).isEqualTo(COMMAND);
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("--flag1", "--flag2")
+ .inOrder();
+ assertThat(readState.getExeFlagsState().getRawFlags()).containsExactly("--exeFlag1");
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary()).isEqualTo("/usr/bin/blaze");
}
@Test
@@ -83,16 +84,24 @@
new BlazeCommandRunConfigurationCommonState(Blaze.getBuildSystem(project));
readState.readExternal(element);
- assertThat(readState.getCommand()).isEqualTo(state.getCommand());
- assertThat(readState.getBlazeFlags()).isEqualTo(state.getBlazeFlags());
- assertThat(readState.getExeFlags()).isEqualTo(state.getExeFlags());
- assertThat(readState.getBlazeBinary()).isEqualTo(state.getBlazeBinary());
+ assertThat(readState.getCommandState().getCommand())
+ .isEqualTo(state.getCommandState().getCommand());
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(state.getBlazeFlagsState().getRawFlags());
+ assertThat(readState.getExeFlagsState().getRawFlags())
+ .isEqualTo(state.getExeFlagsState().getRawFlags());
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary())
+ .isEqualTo(state.getBlazeBinaryState().getBlazeBinary());
}
@Test
public void readShouldOmitEmptyFlags() throws Exception {
- state.setBlazeFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
- state.setExeFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
+ state
+ .getBlazeFlagsState()
+ .setRawFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
+ state
+ .getExeFlagsState()
+ .setRawFlags(Lists.newArrayList("hi ", "", "I'm", " ", "\t", "Josh\r\n", "\n"));
Element element = new Element("test");
state.writeExternal(element);
@@ -100,18 +109,22 @@
new BlazeCommandRunConfigurationCommonState(Blaze.getBuildSystem(project));
readState.readExternal(element);
- assertThat(readState.getBlazeFlags()).containsExactly("hi", "I'm", "Josh").inOrder();
- assertThat(readState.getExeFlags()).containsExactly("hi", "I'm", "Josh").inOrder();
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .containsExactly("hi", "I'm", "Josh")
+ .inOrder();
+ assertThat(readState.getExeFlagsState().getRawFlags())
+ .containsExactly("hi", "I'm", "Josh")
+ .inOrder();
}
@Test
public void repeatedWriteShouldNotChangeElement() throws Exception {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getCompactFormat());
- state.setCommand(COMMAND);
- state.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- state.setExeFlags(ImmutableList.of("--exeFlag1"));
- state.setBlazeBinary("/usr/bin/blaze");
+ state.getCommandState().setCommand(COMMAND);
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getExeFlagsState().setRawFlags(ImmutableList.of("--exeFlag1"));
+ state.getBlazeBinaryState().setBlazeBinary("/usr/bin/blaze");
Element firstWrite = new Element("test");
state.writeExternal(firstWrite);
@@ -126,20 +139,24 @@
public void editorApplyToAndResetFromShouldMatch() throws Exception {
RunConfigurationStateEditor editor = state.getEditor(project);
- state.setCommand(COMMAND);
- state.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
- state.setExeFlags(ImmutableList.of("--exeFlag1", "--exeFlag2"));
- state.setBlazeBinary("/usr/bin/blaze");
+ state.getCommandState().setCommand(COMMAND);
+ state.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
+ state.getExeFlagsState().setRawFlags(ImmutableList.of("--exeFlag1", "--exeFlag2"));
+ state.getBlazeBinaryState().setBlazeBinary("/usr/bin/blaze");
editor.resetEditorFrom(state);
BlazeCommandRunConfigurationCommonState readState =
new BlazeCommandRunConfigurationCommonState(Blaze.getBuildSystem(project));
editor.applyEditorTo(readState);
- assertThat(readState.getCommand()).isEqualTo(state.getCommand());
- assertThat(readState.getBlazeFlags()).isEqualTo(state.getBlazeFlags());
- assertThat(readState.getExeFlags()).isEqualTo(state.getExeFlags());
- assertThat(readState.getBlazeBinary()).isEqualTo(state.getBlazeBinary());
+ assertThat(readState.getCommandState().getCommand())
+ .isEqualTo(state.getCommandState().getCommand());
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(state.getBlazeFlagsState().getRawFlags());
+ assertThat(readState.getExeFlagsState().getRawFlags())
+ .isEqualTo(state.getExeFlagsState().getRawFlags());
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary())
+ .isEqualTo(state.getBlazeBinaryState().getBlazeBinary());
}
@Test
@@ -151,9 +168,13 @@
new BlazeCommandRunConfigurationCommonState(Blaze.getBuildSystem(project));
editor.applyEditorTo(readState);
- assertThat(readState.getCommand()).isEqualTo(state.getCommand());
- assertThat(readState.getBlazeFlags()).isEqualTo(state.getBlazeFlags());
- assertThat(readState.getExeFlags()).isEqualTo(state.getExeFlags());
- assertThat(readState.getBlazeBinary()).isEqualTo(state.getBlazeBinary());
+ assertThat(readState.getCommandState().getCommand())
+ .isEqualTo(state.getCommandState().getCommand());
+ assertThat(readState.getBlazeFlagsState().getRawFlags())
+ .isEqualTo(state.getBlazeFlagsState().getRawFlags());
+ assertThat(readState.getExeFlagsState().getRawFlags())
+ .isEqualTo(state.getExeFlagsState().getRawFlags());
+ assertThat(readState.getBlazeBinaryState().getBlazeBinary())
+ .isEqualTo(state.getBlazeBinaryState().getBlazeBinary());
}
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/state/RunConfigurationFlagStateTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/state/RunConfigurationFlagStateTest.java
index 730ac3b..ec3daeb 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/state/RunConfigurationFlagStateTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/state/RunConfigurationFlagStateTest.java
@@ -32,26 +32,26 @@
// not putting them back when converting back to a string.
ImmutableList<String> flags = ImmutableList.of("--flag=\\\"Hello_world!\\\"", "--flag2");
RunConfigurationFlagsState state = new RunConfigurationFlagsState("tag", "field");
- state.setFlags(flags);
+ state.setRawFlags(flags);
RunConfigurationStateEditor editor = state.getEditor(null);
editor.resetEditorFrom(state);
editor.applyEditorTo(state);
- assertThat(state.getFlags()).isEqualTo(flags);
+ assertThat(state.getRawFlags()).isEqualTo(flags);
}
@Test
public void testQuotesRetainedAfterReserialization() {
ImmutableList<String> flags = ImmutableList.of("\"--flag=test\"");
RunConfigurationFlagsState state = new RunConfigurationFlagsState("tag", "field");
- state.setFlags(flags);
+ state.setRawFlags(flags);
RunConfigurationStateEditor editor = state.getEditor(null);
editor.resetEditorFrom(state);
editor.applyEditorTo(state);
- assertThat(state.getFlags()).isEqualTo(flags);
+ assertThat(state.getRawFlags()).isEqualTo(flags);
}
@Test
@@ -64,12 +64,12 @@
"--test_filter=com.google.idea.blaze.base.run.state.RunConfigurationFlagStateTest#",
"--define=ij_product=intellij-latest");
RunConfigurationFlagsState state = new RunConfigurationFlagsState("tag", "field");
- state.setFlags(flags);
+ state.setRawFlags(flags);
RunConfigurationStateEditor editor = state.getEditor(null);
editor.resetEditorFrom(state);
editor.applyEditorTo(state);
- assertThat(state.getFlags()).isEqualTo(flags);
+ assertThat(state.getRawFlags()).isEqualTo(flags);
}
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParserTest.java b/base/tests/unittests/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParserTest.java
index e3e63ad..cc7ca2c 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParserTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/run/testlogs/BlazeCommandLogParserTest.java
@@ -31,13 +31,23 @@
@Test
public void testParseTestXmlLine() {
assertThat(BlazeCommandLogParser.parseTestTarget("//path/to:target PASSED in 5.3s"))
- .isEqualTo(new Label("//path/to:target"));
+ .isEqualTo(Label.create("//path/to:target"));
assertThat(BlazeCommandLogParser.parseTestTarget("//path/to:target FAILED in 5.3s"))
- .isEqualTo(new Label("//path/to:target"));
+ .isEqualTo(Label.create("//path/to:target"));
assertThat(BlazeCommandLogParser.parseTestTarget("//path/to:target (cached) PASSED in 5.3s"))
- .isEqualTo(new Label("//path/to:target"));
+ .isEqualTo(Label.create("//path/to:target"));
+ }
+
+ @Test
+ public void testParseFailedTarget() {
+ assertThat(BlazeCommandLogParser.parseBuildFailure("Target //path/to:target failed to build"))
+ .isEqualTo(Label.create("//path/to:target"));
+ assertThat(BlazeCommandLogParser.parseTestTarget("Target //path/to:target failed to build"))
+ .isNull();
+ assertThat(BlazeCommandLogParser.parseBuildFailure("//path/to:target FAILED in 5.3s"))
+ .isNull();
}
@Test
@@ -62,8 +72,8 @@
"Executed 1 out of 3 test: 2 test passes.");
assertThat(BlazeCommandLogParser.parseTestTargets(lines.stream()))
.containsExactly(
- new Label("//base:integration_tests"),
- new Label("//base:unit_tests"),
- new Label("//golang:unit_tests"));
+ Label.create("//base:integration_tests"),
+ Label.create("//base:unit_tests"),
+ Label.create("//golang:unit_tests"));
}
}
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
index 8a855ae..a43534a 100644
--- 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
@@ -69,7 +69,7 @@
ImmutableMultimap<TargetKey, TargetKey> reverseDependencies =
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(testMap.targetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
- .containsExactly(new Label("//test:test"));
+ .containsExactly(Label.create("//test:test"));
}
@Test
@@ -95,7 +95,7 @@
ImmutableMultimap<TargetKey, TargetKey> reverseDependencies =
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(testMap.targetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
- .containsExactly(new Label("//test:test"));
+ .containsExactly(Label.create("//test:test"));
}
@Test
@@ -127,7 +127,7 @@
ImmutableMultimap<TargetKey, TargetKey> reverseDependencies =
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(testMap.targetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
- .containsExactly(new Label("//test:test"), new Label("//test:test2"));
+ .containsExactly(Label.create("//test:test"), Label.create("//test:test2"));
}
@Test
@@ -165,7 +165,7 @@
ImmutableMultimap<TargetKey, TargetKey> reverseDependencies =
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(testMap.targetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
- .containsExactly(new Label("//test:test"), new Label("//test:test2"))
+ .containsExactly(Label.create("//test:test"), Label.create("//test:test2"))
.inOrder();
}
@@ -204,7 +204,7 @@
ImmutableMultimap<TargetKey, TargetKey> reverseDependencies =
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(testMap.targetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
- .containsExactly(new Label("//test:test"), new Label("//test:test2"));
+ .containsExactly(Label.create("//test:test"), Label.create("//test:test2"));
}
@Test
@@ -237,7 +237,7 @@
ImmutableMultimap<TargetKey, TargetKey> reverseDependencies =
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(testMap.targetsForSourceFile(reverseDependencies, new File("/test/Test.java")))
- .containsExactly(new Label("//test:test"));
+ .containsExactly(Label.create("//test:test"));
}
private ArtifactLocation sourceRoot(String relativePath) {
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
index af61e7f..fdc880e 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/LanguageSupportTest.java
@@ -81,7 +81,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
errorCollector.assertNoIssues();
assertThat(workspaceLanguageSettings)
.isEqualTo(
@@ -98,7 +98,9 @@
.add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.C))
.build())
.build();
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ WorkspaceLanguageSettings settings =
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
+ LanguageSupport.validateLanguageSettings(context, settings);
errorCollector.assertIssues("Workspace type 'c' is not supported by this plugin");
}
@@ -127,7 +129,9 @@
.add(LanguageClass.PYTHON))
.build())
.build();
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ WorkspaceLanguageSettings settings =
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
+ LanguageSupport.validateLanguageSettings(context, settings);
errorCollector.assertIssues("Language 'python' is not supported by this plugin");
}
@@ -155,7 +159,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
assertThat(workspaceLanguageSettings)
.isEqualTo(
new WorkspaceLanguageSettings(
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
index b064721..249783c 100644
--- 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
@@ -16,16 +16,12 @@
package com.google.idea.blaze.base.sync.aspects;
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.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.io.FileAttributeProvider;
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.WorkspaceType;
-import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.common.experiments.ExperimentService;
import com.google.idea.common.experiments.MockExperimentService;
import com.google.repackaged.devtools.intellij.ideinfo.IntellijIdeInfo;
@@ -74,11 +70,7 @@
.setJavaPackage("package"))
.build();
- WorkspaceLanguageSettings workspaceLanguageSettings =
- new WorkspaceLanguageSettings(
- WorkspaceType.ANDROID, ImmutableSet.of(LanguageClass.ANDROID));
- TargetIdeInfo target =
- IdeInfoFromProtobuf.makeTargetIdeInfo(workspaceLanguageSettings, ideProto);
+ TargetIdeInfo target = IdeInfoFromProtobuf.makeTargetIdeInfo(ideProto);
TestUtils.assertIsSerializable(target);
}
@@ -88,7 +80,7 @@
state.fileToTargetMapKey =
ImmutableMap.of(
new File("fileName"),
- TargetIdeInfo.builder().setLabel(new Label("//test:test")).build().key);
+ TargetIdeInfo.builder().setLabel(Label.create("//test:test")).build().key);
state.fileState = ImmutableMap.of();
state.targetMap =
new TargetMap(ImmutableMap.of()); // Tested separately in testRuleIdeInfoIsSerializable
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
index fb09872..343f562 100644
--- 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
@@ -18,7 +18,6 @@
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;
@@ -41,13 +40,17 @@
"sys3/inc1",
"-isystm",
"sys4/inc1");
- List<String> sysIncludes = Lists.newArrayList();
- List<String> flags = Lists.newArrayList();
- UnfilteredCompilerOptions.splitUnfilteredCompilerOptions(unfilteredOptions, sysIncludes, flags);
+ UnfilteredCompilerOptions compilerOptions =
+ UnfilteredCompilerOptions.builder()
+ .registerSingleOrSplitOption("-isystem")
+ .build(unfilteredOptions);
- assertThat(sysIncludes).containsExactly("sys/inc1", "sys2/inc1", "sys3/inc1");
+ List<String> sysIncludes = compilerOptions.getExtractedOptionValues("-isystem");
+ List<String> flags = compilerOptions.getUninterpretedOptions();
- assertThat(flags).containsExactly("-VER2", "-isystm", "sys4/inc1");
+ assertThat(sysIncludes).containsExactly("sys/inc1", "sys2/inc1", "sys3/inc1").inOrder();
+
+ assertThat(flags).containsExactly("-VER2", "-isystm", "sys4/inc1").inOrder();
}
@Test
@@ -55,12 +58,47 @@
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);
+ UnfilteredCompilerOptions compilerOptions =
+ UnfilteredCompilerOptions.builder()
+ .registerSingleOrSplitOption("-isystem")
+ .build(unfilteredOptions);
- assertThat(sysIncludes).containsExactly("sys/inc1", "sys2/inc1", "sys3/inc1");
+ List<String> sysIncludes = compilerOptions.getExtractedOptionValues("-isystem");
+ List<String> flags = compilerOptions.getUninterpretedOptions();
+ assertThat(sysIncludes).containsExactly("sys/inc1", "sys2/inc1", "sys3/inc1").inOrder();
- assertThat(flags).containsExactly("-VER2");
+ assertThat(flags).containsExactly("-VER2").inOrder();
+ }
+
+ @Test
+ public void testMultipleFlagsToExtract() {
+ ImmutableList<String> unfilteredOptions =
+ ImmutableList.of(
+ "-I",
+ "foo/headers1",
+ "-fno-exceptions",
+ "-Werror",
+ "-DMACRO1=1",
+ "-D",
+ "MACRO2",
+ "-Ifoo/headers2",
+ "-I=sysroot_header",
+ "-Wall",
+ "-I",
+ "foo/headers3");
+ UnfilteredCompilerOptions compilerOptions =
+ UnfilteredCompilerOptions.builder()
+ .registerSingleOrSplitOption("-I")
+ .registerSingleOrSplitOption("-D")
+ .build(unfilteredOptions);
+
+ List<String> defines = compilerOptions.getExtractedOptionValues("-D");
+ List<String> includes = compilerOptions.getExtractedOptionValues("-I");
+ List<String> flags = compilerOptions.getUninterpretedOptions();
+ assertThat(includes)
+ .containsExactly("foo/headers1", "foo/headers2", "=sysroot_header", "foo/headers3")
+ .inOrder();
+ assertThat(defines).containsExactly("MACRO1=1", "MACRO2").inOrder();
+ assertThat(flags).containsExactly("-fno-exceptions", "-Werror", "-Wall").inOrder();
}
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/projectview/RelatedWorkspacePathFinderTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/projectview/RelatedWorkspacePathFinderTest.java
new file mode 100644
index 0000000..15a6d84
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/projectview/RelatedWorkspacePathFinderTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+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.WorkspacePathResolverImpl;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link RelatedWorkspacePathFinder} */
+@RunWith(JUnit4.class)
+public class RelatedWorkspacePathFinderTest {
+
+ private static final File WORKSPACE_ROOT = new File("/workspace");
+
+ private MockFileAttributeProvider files;
+ private RelatedWorkspacePathFinder relatedPathFinder;
+ private WorkspacePathResolver workspacePathResolver;
+
+ @Before
+ public void setUp() throws IOException {
+ files = new MockFileAttributeProvider();
+ relatedPathFinder = new RelatedWorkspacePathFinder(files);
+ workspacePathResolver = new WorkspacePathResolverImpl(new WorkspaceRoot(WORKSPACE_ROOT));
+ }
+
+ @Test
+ public void initialJavaDirectory() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/com/google"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "javatests/com/google"));
+
+ WorkspacePath initialPath = new WorkspacePath("java/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).hasSize(1);
+ assertThat(relatedPaths).containsExactly(new WorkspacePath("javatests/com/google"));
+ }
+
+ @Test
+ public void middleJavaDirectory() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/java/com/google"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/javatests/com/google"));
+
+ WorkspacePath initialPath = new WorkspacePath("srcs/java/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).hasSize(1);
+ assertThat(relatedPaths).containsExactly(new WorkspacePath("srcs/javatests/com/google"));
+ }
+
+ @Test
+ public void finalJavaDirectory() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/java"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/javatests"));
+
+ WorkspacePath initialPath = new WorkspacePath("srcs/java");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).hasSize(1);
+ assertThat(relatedPaths).containsExactly(new WorkspacePath("srcs/javatests"));
+ }
+
+ @Test
+ public void noJavaDirectory() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/com/google"));
+
+ WorkspacePath initialPath = new WorkspacePath("srcs/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).isEmpty();
+ }
+
+ @Test
+ public void javatestsDirectoryDoesNotExist() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/com/google"));
+
+ WorkspacePath initialPath = new WorkspacePath("java/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).isEmpty();
+ }
+
+ @Test
+ public void javaInMiddleOfWord() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/cooljavastuff/com/google"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "srcs/cooljavatestsstuff/com/google"));
+
+ WorkspacePath initialPath = new WorkspacePath("java/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).isEmpty();
+ }
+
+ @Test
+ public void javatestsExistsButSubdirectoryDoesNotExist() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/com/google"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "javatests/com"));
+
+ WorkspacePath initialPath = new WorkspacePath("java/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).isEmpty();
+ }
+
+ @Test
+ public void onlyReplacesFirstFoundJavaPath() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/src/java"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "javatests/src/java"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "javatests/src/javatests"));
+
+ WorkspacePath initialPath = new WorkspacePath("java/src/java");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).hasSize(1);
+ assertThat(relatedPaths).containsExactly(new WorkspacePath("javatests/src/java"));
+ }
+
+ @Test
+ public void skipsFirstJavaIfMatchingJavatestsIsNotFound() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/src/java"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/src/javatests"));
+
+ WorkspacePath initialPath = new WorkspacePath("java/src/java");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).hasSize(1);
+ assertThat(relatedPaths).containsExactly(new WorkspacePath("java/src/javatests"));
+ }
+
+ @Test
+ public void javatestsIsNotRelatedToJava() throws Exception {
+ files.mkdirs(new File(WORKSPACE_ROOT, "java/com/google"));
+ files.mkdirs(new File(WORKSPACE_ROOT, "javatests/com/google"));
+
+ WorkspacePath initialPath = new WorkspacePath("javatests/com/google");
+ ImmutableSet<WorkspacePath> relatedPaths =
+ relatedPathFinder.findRelatedWorkspaceDirectories(workspacePathResolver, initialPath);
+
+ assertThat(relatedPaths).isEmpty();
+ }
+
+ private static class MockFileAttributeProvider extends FileAttributeProvider {
+
+ private final Set<File> existingFiles = new HashSet<>();
+
+ @Override
+ public boolean exists(File file) {
+ return existingFiles.contains(file);
+ }
+
+ void mkdirs(File file) {
+ while (file != null && !existingFiles.contains(file)) {
+ existingFiles.add(file);
+ file = file.getParentFile();
+ }
+ }
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/PartitionTargetsTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/PartitionTargetsTest.java
new file mode 100644
index 0000000..7da1a7a
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/PartitionTargetsTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test that targets are correctly partitioned in {@link BlazeBuildTargetSharder#shardTargets}. */
+@RunWith(JUnit4.class)
+public class PartitionTargetsTest {
+
+ @Test
+ public void testShardSizeRespected() {
+ List<TargetExpression> targets =
+ ImmutableList.of(
+ TargetExpression.fromString("//java/com/google:one"),
+ TargetExpression.fromString("//java/com/google:two"),
+ TargetExpression.fromString("//java/com/google:three"),
+ TargetExpression.fromString("//java/com/google:four"),
+ TargetExpression.fromString("//java/com/google:five"));
+ ShardedTargetList shards = BlazeBuildTargetSharder.shardTargets(targets, 2);
+ assertThat(shards.shardedTargets).hasSize(3);
+ assertThat(shards.shardedTargets.get(0)).hasSize(2);
+ assertThat(shards.shardedTargets.get(1)).hasSize(2);
+ assertThat(shards.shardedTargets.get(2)).hasSize(1);
+
+ shards = BlazeBuildTargetSharder.shardTargets(targets, 4);
+ assertThat(shards.shardedTargets).hasSize(2);
+ assertThat(shards.shardedTargets.get(0)).hasSize(4);
+ assertThat(shards.shardedTargets.get(1)).hasSize(1);
+
+ shards = BlazeBuildTargetSharder.shardTargets(targets, 100);
+ assertThat(shards.shardedTargets).hasSize(1);
+ assertThat(shards.shardedTargets.get(0)).hasSize(5);
+ }
+
+ @Test
+ public void testAllSubsequentExcludedTargetsAppendedToShards() {
+ List<TargetExpression> targets =
+ ImmutableList.of(
+ TargetExpression.fromString("//java/com/google:one"),
+ TargetExpression.fromString("-//java/com/google:two"),
+ TargetExpression.fromString("//java/com/google:three"),
+ TargetExpression.fromString("-//java/com/google:four"),
+ TargetExpression.fromString("//java/com/google:five"),
+ TargetExpression.fromString("-//java/com/google:six"));
+ ShardedTargetList shards = BlazeBuildTargetSharder.shardTargets(targets, 3);
+ assertThat(shards.shardedTargets).hasSize(2);
+ assertThat(shards.shardedTargets.get(0)).hasSize(5);
+ assertThat(shards.shardedTargets.get(0))
+ .isEqualTo(
+ ImmutableList.of(
+ TargetExpression.fromString("//java/com/google:one"),
+ TargetExpression.fromString("-//java/com/google:two"),
+ TargetExpression.fromString("//java/com/google:three"),
+ TargetExpression.fromString("-//java/com/google:four"),
+ TargetExpression.fromString("-//java/com/google:six")));
+ assertThat(shards.shardedTargets.get(1)).hasSize(3);
+ assertThat(shards.shardedTargets.get(1))
+ .containsExactly(
+ TargetExpression.fromString("-//java/com/google:four"),
+ TargetExpression.fromString("//java/com/google:five"),
+ TargetExpression.fromString("-//java/com/google:six"))
+ .inOrder();
+
+ shards = BlazeBuildTargetSharder.shardTargets(targets, 1);
+ assertThat(shards.shardedTargets).hasSize(6);
+ assertThat(shards.shardedTargets.get(0))
+ .containsExactly(
+ TargetExpression.fromString("//java/com/google:one"),
+ TargetExpression.fromString("-//java/com/google:two"),
+ TargetExpression.fromString("-//java/com/google:four"),
+ TargetExpression.fromString("-//java/com/google:six"))
+ .inOrder();
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/QueryResultLineProcessorTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/QueryResultLineProcessorTest.java
new file mode 100644
index 0000000..a984e94
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/QueryResultLineProcessorTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link QueryResultLineProcessor}. */
+@RunWith(JUnit4.class)
+public class QueryResultLineProcessorTest extends BlazeTestCase {
+
+ @Test
+ public void testRecognizesStandardResultLines() {
+ ImmutableList.Builder<TargetExpression> output = ImmutableList.builder();
+ QueryResultLineProcessor processor = new QueryResultLineProcessor(output, x -> true);
+
+ processor.processLine("css_library rule //java/com/google/foo/styles:global");
+ processor.processLine("java_library rule //java/com/google/bar/console:runtime_deps");
+
+ ImmutableList<TargetExpression> parsedTargets = output.build();
+ assertThat(parsedTargets)
+ .containsExactly(
+ TargetExpression.fromString("//java/com/google/foo/styles:global"),
+ TargetExpression.fromString("//java/com/google/bar/console:runtime_deps"));
+ }
+
+ @Test
+ public void testIgnoresNonRules() {
+ ImmutableList.Builder<TargetExpression> output = ImmutableList.builder();
+ QueryResultLineProcessor processor = new QueryResultLineProcessor(output, x -> true);
+
+ processor.processLine("generated file //java/com/google/foo:libthrowable_utils.jar");
+ processor.processLine("source file //java/com/google/foo:BUILD");
+ processor.processLine("package group //java/com/google/foo:packages");
+
+ assertThat(output.build()).isEmpty();
+ }
+
+ @Test
+ public void testFilterRuleTypes() {
+ ImmutableSet<String> acceptedRuleTypes =
+ ImmutableSet.of("java_library", "custom_type", "sh_test");
+ ImmutableList.Builder<TargetExpression> output = ImmutableList.builder();
+ QueryResultLineProcessor processor =
+ new QueryResultLineProcessor(output, t -> acceptedRuleTypes.contains(t.ruleType));
+
+ processor.processLine("css_library rule //java/com/google/foo/styles:global");
+ processor.processLine("java_library rule //java/com/google/bar/console:runtime_deps");
+ processor.processLine("java_test rule //java/com/google/bar/console:test1");
+ processor.processLine("test_suite rule //java/com/google/bar/console:all_tests");
+ processor.processLine("custom_type rule //java/com/google/bar/console:custom");
+ processor.processLine("sh_test rule //java/com/google/bar/console:sh_test");
+
+ assertThat(output.build())
+ .containsExactly(
+ TargetExpression.fromString("//java/com/google/bar/console:runtime_deps"),
+ TargetExpression.fromString("//java/com/google/bar/console:custom"),
+ TargetExpression.fromString("//java/com/google/bar/console:sh_test"));
+ }
+
+ @Test
+ public void testFilterRuleTypesRetainingExplicitlySpecifiedTargets() {
+ ImmutableSet<String> acceptedRuleTypes =
+ ImmutableSet.of("java_library", "custom_type", "sh_test");
+ ImmutableSet<String> explicitTargets = ImmutableSet.of("//java/com/google/foo/styles:global");
+
+ ImmutableList.Builder<TargetExpression> output = ImmutableList.builder();
+ QueryResultLineProcessor processor =
+ new QueryResultLineProcessor(
+ output,
+ t -> explicitTargets.contains(t.label) || acceptedRuleTypes.contains(t.ruleType));
+
+ processor.processLine("css_library rule //java/com/google/foo/styles:global");
+ processor.processLine("java_library rule //java/com/google/bar/console:runtime_deps");
+ processor.processLine("java_test rule //java/com/google/bar/console:test1");
+ processor.processLine("test_suite rule //java/com/google/bar/console:all_tests");
+ processor.processLine("custom_type rule //java/com/google/bar/console:custom");
+ processor.processLine("sh_test rule //java/com/google/bar/console:sh_test");
+
+ assertThat(output.build())
+ .containsExactly(
+ TargetExpression.fromString("//java/com/google/foo/styles:global"),
+ TargetExpression.fromString("//java/com/google/bar/console:runtime_deps"),
+ TargetExpression.fromString("//java/com/google/bar/console:custom"),
+ TargetExpression.fromString("//java/com/google/bar/console:sh_test"));
+ }
+}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/WildcardTargetPatternTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/WildcardTargetPatternTest.java
new file mode 100644
index 0000000..e3d78b8
--- /dev/null
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/sharding/WildcardTargetPatternTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.sharding;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link WildcardTargetPattern}. */
+@RunWith(JUnit4.class)
+public class WildcardTargetPatternTest {
+
+ @Test
+ public void testRecursiveWildcardPattern() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google/...");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNotNull();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google"))).isTrue();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google/foo"))).isTrue();
+ assertThat(wildcardPattern.isRecursive()).isTrue();
+ assertThat(wildcardPattern.getBasePackage()).isEqualTo(new WorkspacePath("java/com/google"));
+ assertThat(wildcardPattern.rulesOnly()).isTrue();
+ }
+
+ @Test
+ public void testRecursiveWildcardPatternAlternativeFormat() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google/...:all");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNotNull();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google"))).isTrue();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google/foo"))).isTrue();
+ assertThat(wildcardPattern.isRecursive()).isTrue();
+ assertThat(wildcardPattern.getBasePackage()).isEqualTo(new WorkspacePath("java/com/google"));
+ assertThat(wildcardPattern.rulesOnly()).isTrue();
+ }
+
+ @Test
+ public void testRecursiveWildcardPatternAllTargets() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google/...:all-targets");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNotNull();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google"))).isTrue();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google/foo"))).isTrue();
+ assertThat(wildcardPattern.isRecursive()).isTrue();
+ assertThat(wildcardPattern.getBasePackage()).isEqualTo(new WorkspacePath("java/com/google"));
+ assertThat(wildcardPattern.rulesOnly()).isFalse();
+ }
+
+ @Test
+ public void testRecursiveWildcardPatternAllTargetsAlternativeFormat() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google/...:*");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNotNull();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google"))).isTrue();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google/foo"))).isTrue();
+ assertThat(wildcardPattern.isRecursive()).isTrue();
+ assertThat(wildcardPattern.getBasePackage()).isEqualTo(new WorkspacePath("java/com/google"));
+ assertThat(wildcardPattern.rulesOnly()).isFalse();
+ }
+
+ @Test
+ public void testNonRecursiveAllTargetsWildcardPattern() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google:*");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNotNull();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google"))).isTrue();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google/foo"))).isFalse();
+ assertThat(wildcardPattern.isRecursive()).isFalse();
+ assertThat(wildcardPattern.getBasePackage()).isEqualTo(new WorkspacePath("java/com/google"));
+ assertThat(wildcardPattern.rulesOnly()).isFalse();
+ }
+
+ @Test
+ public void testNonRecursiveWildcardPattern() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google:all");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNotNull();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google"))).isTrue();
+ assertThat(wildcardPattern.coversPackage(new WorkspacePath("java/com/google/foo"))).isFalse();
+ assertThat(wildcardPattern.isRecursive()).isFalse();
+ assertThat(wildcardPattern.getBasePackage()).isEqualTo(new WorkspacePath("java/com/google"));
+ assertThat(wildcardPattern.rulesOnly()).isTrue();
+ }
+
+ @Test
+ public void testNonWildcardPattern() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google:single_target");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNull();
+ }
+
+ @Test
+ public void testNonWildcardImplicitTargetName() {
+ TargetExpression target = TargetExpression.fromString("//java/com/google/foo");
+ WildcardTargetPattern wildcardPattern = WildcardTargetPattern.fromExpression(target);
+ assertThat(wildcardPattern).isNull();
+ }
+}
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
index a7c7816..495f9dc 100644
--- 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
@@ -17,18 +17,11 @@
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.command.info.BlazeInfo;
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 java.io.File;
-import java.util.List;
-import java.util.Set;
-import org.jetbrains.annotations.NotNull;
+import com.google.idea.blaze.base.sync.aspects.IdeInfoFromProtobuf;
+import com.google.repackaged.devtools.intellij.ideinfo.IntellijIdeInfo;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -37,79 +30,8 @@
@RunWith(JUnit4.class)
public class ArtifactLocationDecoderTest extends BlazeTestCase {
- private static final String EXECUTION_ROOT = "/path/to/_blaze_user/1234bf129e/root";
private static final String OUTPUT_BASE = "/path/to/_blaze_user/1234bf129e";
-
- 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(
- new File("/path/to"),
- new File("/path/to/READONLY/root"),
- new File("/path/to/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"),
- new File(OUTPUT_BASE));
-
- fileChecker.addFiles(
- new File("/path/to/com/google/Bla.java"),
- new File("/path/to/READONLY/root/com/google/Foo.java"),
- new File("/path/to/CUSTOM/root/com/other/Test.java"));
-
- ArtifactLocationDecoder decoder =
- new ArtifactLocationDecoderImpl(
- blazeRoots,
- new WorkspacePathResolverImpl(
- new WorkspaceRoot(new File("/path/to/root")), blazeRoots));
-
- ArtifactLocation blah =
- ArtifactLocation.builder().setRelativePath("com/google/Bla.java").setIsSource(true).build();
- assertThat(decoder.decode(blah).getPath()).isEqualTo("/path/to/com/google/Bla.java");
-
- ArtifactLocation foo =
- ArtifactLocation.builder().setRelativePath("com/google/Foo.java").setIsSource(true).build();
- assertThat(decoder.decode(foo).getPath())
- .isEqualTo("/path/to/READONLY/root/com/google/Foo.java");
-
- ArtifactLocation test =
- ArtifactLocation.builder().setRelativePath("com/other/Test.java").setIsSource(true).build();
- assertThat(decoder.decode(test).getPath())
- .isEqualTo("/path/to/CUSTOM/root/com/other/Test.java");
-
- ArtifactLocation.Builder temp =
- ArtifactLocation.builder().setRelativePath("third_party/other/Temp.java").setIsSource(true);
- assertThat(decoder.decode(temp.build()).getPath())
- .isEqualTo("/path/to/third_party/other/Temp.java");
- }
+ private static final String EXECUTION_ROOT = OUTPUT_BASE + "/execroot/my_proj";
@Test
public void testGeneratedArtifact() throws Exception {
@@ -122,12 +44,11 @@
ArtifactLocationDecoder decoder =
new ArtifactLocationDecoderImpl(
- new BlazeRoots(
- new File(EXECUTION_ROOT),
- ImmutableList.of(new File("/path/to/root")),
- new ExecutionRootPath("root/blaze-out/crosstool/bin"),
- new ExecutionRootPath("root/blaze-out/crosstool/genfiles"),
- new File(OUTPUT_BASE)),
+ BlazeInfo.createMockBlazeInfo(
+ OUTPUT_BASE,
+ EXECUTION_ROOT,
+ EXECUTION_ROOT + "/blaze-out/crosstool/bin",
+ EXECUTION_ROOT + "/blaze-out/crosstool/genfiles"),
null);
assertThat(decoder.decode(artifactLocation).getPath())
@@ -135,25 +56,115 @@
}
@Test
- public void testExternalArtifact() throws Exception {
+ public void testExternalSourceArtifactOldFormat() throws Exception {
ArtifactLocation artifactLocation =
- ArtifactLocation.builder()
- .setRelativePath("external/com/google/Bla.java")
- .setIsSource(true)
- .setIsExternal(true)
- .build();
+ IdeInfoFromProtobuf.makeArtifactLocation(
+ IntellijIdeInfo.ArtifactLocation.newBuilder()
+ .setRelativePath("external/repo_name/com/google/Bla.java")
+ .setIsSource(true)
+ .setIsExternal(true)
+ .build());
+
+ assertThat(artifactLocation.getRelativePath()).isEqualTo("com/google/Bla.java");
+ assertThat(artifactLocation.getExecutionRootRelativePath())
+ .isEqualTo("external/repo_name/com/google/Bla.java");
ArtifactLocationDecoder decoder =
new ArtifactLocationDecoderImpl(
- new BlazeRoots(
- new File(EXECUTION_ROOT),
- ImmutableList.of(new File("/path/to/root")),
- new ExecutionRootPath("root/blaze-out/crosstool/bin"),
- new ExecutionRootPath("root/blaze-out/crosstool/genfiles"),
- new File(OUTPUT_BASE)),
+ BlazeInfo.createMockBlazeInfo(
+ OUTPUT_BASE,
+ EXECUTION_ROOT,
+ EXECUTION_ROOT + "/blaze-out/crosstool/bin",
+ EXECUTION_ROOT + "/blaze-out/crosstool/genfiles"),
null);
assertThat(decoder.decode(artifactLocation).getPath())
- .isEqualTo(OUTPUT_BASE + "/external/com/google/Bla.java");
+ .isEqualTo(EXECUTION_ROOT + "/external/repo_name/com/google/Bla.java");
+ }
+
+ @Test
+ public void testExternalDerivedArtifactOldFormat() throws Exception {
+ ArtifactLocation artifactLocation =
+ IdeInfoFromProtobuf.makeArtifactLocation(
+ IntellijIdeInfo.ArtifactLocation.newBuilder()
+ .setRelativePath("external/repo_name/com/google/Bla.java")
+ .setRootExecutionPathFragment("blaze-out/crosstool/bin")
+ .setIsSource(false)
+ .setIsExternal(true)
+ .build());
+
+ assertThat(artifactLocation.getRelativePath()).isEqualTo("com/google/Bla.java");
+ assertThat(artifactLocation.getExecutionRootRelativePath())
+ .isEqualTo("blaze-out/crosstool/bin/external/repo_name/com/google/Bla.java");
+
+ ArtifactLocationDecoder decoder =
+ new ArtifactLocationDecoderImpl(
+ BlazeInfo.createMockBlazeInfo(
+ OUTPUT_BASE,
+ EXECUTION_ROOT,
+ EXECUTION_ROOT + "/blaze-out/crosstool/bin",
+ EXECUTION_ROOT + "/blaze-out/crosstool/genfiles"),
+ null);
+
+ assertThat(decoder.decode(artifactLocation).getPath())
+ .isEqualTo(
+ EXECUTION_ROOT + "/blaze-out/crosstool/bin/external/repo_name/com/google/Bla.java");
+ }
+
+ @Test
+ public void testExternalSourceArtifactNewFormat() throws Exception {
+ ArtifactLocation artifactLocation =
+ IdeInfoFromProtobuf.makeArtifactLocation(
+ IntellijIdeInfo.ArtifactLocation.newBuilder()
+ .setRelativePath("com/google/Bla.java")
+ .setRootExecutionPathFragment("../repo_name")
+ .setIsSource(true)
+ .setIsExternal(true)
+ .setIsNewExternalVersion(true)
+ .build());
+
+ assertThat(artifactLocation.getRelativePath()).isEqualTo("com/google/Bla.java");
+ assertThat(artifactLocation.getExecutionRootRelativePath())
+ .isEqualTo("../repo_name/com/google/Bla.java");
+
+ ArtifactLocationDecoder decoder =
+ new ArtifactLocationDecoderImpl(
+ BlazeInfo.createMockBlazeInfo(
+ OUTPUT_BASE,
+ EXECUTION_ROOT,
+ EXECUTION_ROOT + "/blaze-out/crosstool/bin",
+ EXECUTION_ROOT + "/blaze-out/crosstool/genfiles"),
+ null);
+
+ assertThat(decoder.decode(artifactLocation).getPath())
+ .isEqualTo(OUTPUT_BASE + "/execroot/repo_name/com/google/Bla.java");
+ }
+
+ @Test
+ public void testExternalDerivedArtifactNewFormat() throws Exception {
+ ArtifactLocation artifactLocation =
+ IdeInfoFromProtobuf.makeArtifactLocation(
+ IntellijIdeInfo.ArtifactLocation.newBuilder()
+ .setRelativePath("com/google/Bla.java")
+ .setRootExecutionPathFragment("../repo_name/blaze-out/crosstool/bin")
+ .setIsSource(false)
+ .setIsNewExternalVersion(true)
+ .build());
+
+ assertThat(artifactLocation.getRelativePath()).isEqualTo("com/google/Bla.java");
+ assertThat(artifactLocation.getExecutionRootRelativePath())
+ .isEqualTo("../repo_name/blaze-out/crosstool/bin/com/google/Bla.java");
+
+ ArtifactLocationDecoder decoder =
+ new ArtifactLocationDecoderImpl(
+ BlazeInfo.createMockBlazeInfo(
+ OUTPUT_BASE,
+ EXECUTION_ROOT,
+ EXECUTION_ROOT + "/blaze-out/crosstool/bin",
+ EXECUTION_ROOT + "/blaze-out/crosstool/genfiles"),
+ null);
+
+ assertThat(decoder.decode(artifactLocation).getPath())
+ .isEqualTo(OUTPUT_BASE + "/execroot/repo_name/blaze-out/crosstool/bin/com/google/Bla.java");
}
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolverTest.java b/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolverTest.java
index f880353..afba81b 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolverTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/sync/workspace/ExecutionRootPathResolverTest.java
@@ -19,9 +19,13 @@
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.bazel.BazelBuildSystemProvider;
+import com.google.idea.blaze.base.bazel.BuildSystemProvider;
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 com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.openapi.extensions.ExtensionPoint;
import java.io.File;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,19 +36,23 @@
public class ExecutionRootPathResolverTest 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 String EXECUTION_ROOT = "/path/to/_bazel_user/1234bf129e/root";
- private static final BlazeRoots BLAZE_ROOTS =
- new BlazeRoots(
- new File(EXECUTION_ROOT),
- ImmutableList.of(WORKSPACE_ROOT.directory()),
- new ExecutionRootPath("blaze-out/crosstool/bin"),
- new ExecutionRootPath("blaze-out/crosstool/genfiles"),
- null);
+ private ExecutionRootPathResolver pathResolver;
- private final ExecutionRootPathResolver pathResolver =
- new ExecutionRootPathResolver(
- BLAZE_ROOTS, new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_ROOTS));
+ @Override
+ protected void initTest(Container applicationServices, Container projectServices) {
+ ExtensionPoint<BuildSystemProvider> extensionPoint =
+ registerExtensionPoint(BuildSystemProvider.EP_NAME, BuildSystemProvider.class);
+ extensionPoint.registerExtension(new BazelBuildSystemProvider());
+
+ pathResolver =
+ new ExecutionRootPathResolver(
+ BuildSystem.Bazel,
+ WORKSPACE_ROOT,
+ new File(EXECUTION_ROOT),
+ new WorkspacePathResolverImpl(WORKSPACE_ROOT));
+ }
@Test
public void testExternalWorkspacePathRelativeToExecRoot() {
@@ -57,9 +65,9 @@
public void testGenfilesPathRelativeToExecRoot() {
ImmutableList<File> files =
pathResolver.resolveToIncludeDirectories(
- new ExecutionRootPath("blaze-out/crosstool/genfiles/res/normal"));
+ new ExecutionRootPath("bazel-out/crosstool/genfiles/res/normal"));
assertThat(files)
- .containsExactly(new File(EXECUTION_ROOT, "blaze-out/crosstool/genfiles/res/normal"));
+ .containsExactly(new File(EXECUTION_ROOT, "bazel-out/crosstool/genfiles/res/normal"));
}
@Test
@@ -68,4 +76,14 @@
pathResolver.resolveToIncludeDirectories(new ExecutionRootPath("tools/fast"));
assertThat(files).containsExactly(WORKSPACE_ROOT.fileForPath(new WorkspacePath("tools/fast")));
}
+
+ @Test
+ public void testGenfilesPathWithDifferentConfigSettingStillResolves() {
+ ImmutableList<File> files =
+ pathResolver.resolveToIncludeDirectories(
+ new ExecutionRootPath("bazel-out/arm-linux-fastbuild/genfiles/res/normal"));
+ assertThat(files)
+ .containsExactly(
+ new File(EXECUTION_ROOT, "bazel-out/arm-linux-fastbuild/genfiles/res/normal"));
+ }
}
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
index 282ea53..446d6ba 100644
--- 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
@@ -19,7 +19,6 @@
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.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import java.io.File;
@@ -31,20 +30,10 @@
@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"),
- null);
@Test
public void testResolveToIncludeDirectories() {
- WorkspacePathResolver workspacePathResolver =
- new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS);
+ WorkspacePathResolver workspacePathResolver = new WorkspacePathResolverImpl(WORKSPACE_ROOT);
ImmutableList<File> files =
workspacePathResolver.resolveToIncludeDirectories(new WorkspacePath("tools/fast"));
assertThat(files).containsExactly(new File("/path/to/root/tools/fast"));
@@ -52,11 +41,18 @@
@Test
public void testResolveToIncludeDirectoriesForExecRootPath() {
- WorkspacePathResolver workspacePathResolver =
- new WorkspacePathResolverImpl(WORKSPACE_ROOT, BLAZE_CITC_ROOTS);
+ WorkspacePathResolver workspacePathResolver = new WorkspacePathResolverImpl(WORKSPACE_ROOT);
ImmutableList<File> files =
workspacePathResolver.resolveToIncludeDirectories(
new WorkspacePath("blaze-out/crosstool/bin/tools/fast"));
assertThat(files).containsExactly(new File("/path/to/root/blaze-out/crosstool/bin/tools/fast"));
}
+
+ @Test
+ public void testResolveToFile() {
+ WorkspacePathResolver workspacePathResolver = new WorkspacePathResolverImpl(WORKSPACE_ROOT);
+ WorkspacePath relativePath = new WorkspacePath("third_party/tools");
+ assertThat(workspacePathResolver.resolveToFile(relativePath))
+ .isEqualTo(WORKSPACE_ROOT.fileForPath(relativePath));
+ }
}
diff --git a/base/tests/unittests/com/google/idea/blaze/base/targetmaps/ReverseDependencyMapTest.java b/base/tests/unittests/com/google/idea/blaze/base/targetmaps/ReverseDependencyMapTest.java
index 574194c..9f0b306 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/targetmaps/ReverseDependencyMapTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/targetmaps/ReverseDependencyMapTest.java
@@ -61,8 +61,8 @@
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l2")),
- TargetKey.forPlainTarget(new Label("//l:l1")));
+ TargetKey.forPlainTarget(Label.create("//l:l2")),
+ TargetKey.forPlainTarget(Label.create("//l:l1")));
}
@Test
@@ -93,12 +93,12 @@
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l2")),
- TargetKey.forPlainTarget(new Label("//l:l1")));
+ TargetKey.forPlainTarget(Label.create("//l:l2")),
+ TargetKey.forPlainTarget(Label.create("//l:l1")));
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l3")),
- TargetKey.forPlainTarget(new Label("//l:l1")));
+ TargetKey.forPlainTarget(Label.create("//l:l3")),
+ TargetKey.forPlainTarget(Label.create("//l:l1")));
}
@Test
@@ -129,12 +129,12 @@
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l3")),
- TargetKey.forPlainTarget(new Label("//l:l1")));
+ TargetKey.forPlainTarget(Label.create("//l:l3")),
+ TargetKey.forPlainTarget(Label.create("//l:l1")));
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l3")),
- TargetKey.forPlainTarget(new Label("//l:l2")));
+ TargetKey.forPlainTarget(Label.create("//l:l3")),
+ TargetKey.forPlainTarget(Label.create("//l:l2")));
}
@Test
@@ -177,20 +177,20 @@
ReverseDependencyMap.createRdepsMap(targetMap);
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l3")),
- TargetKey.forPlainTarget(new Label("//l:l1")));
+ TargetKey.forPlainTarget(Label.create("//l:l3")),
+ TargetKey.forPlainTarget(Label.create("//l:l1")));
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l3")),
- TargetKey.forPlainTarget(new Label("//l:l2")));
+ TargetKey.forPlainTarget(Label.create("//l:l3")),
+ TargetKey.forPlainTarget(Label.create("//l:l2")));
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l3")),
- TargetKey.forPlainTarget(new Label("//l:l4")));
+ TargetKey.forPlainTarget(Label.create("//l:l3")),
+ TargetKey.forPlainTarget(Label.create("//l:l4")));
assertThat(reverseDependencies)
.containsEntry(
- TargetKey.forPlainTarget(new Label("//l:l4")),
- TargetKey.forPlainTarget(new Label("//l:l5")));
+ TargetKey.forPlainTarget(Label.create("//l:l4")),
+ TargetKey.forPlainTarget(Label.create("//l:l5")));
}
private static ArtifactLocation sourceRoot(String relativePath) {
diff --git a/base/tests/unittests/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMapTest.java b/base/tests/unittests/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMapTest.java
index 922cbd1..6aa4f43 100644
--- a/base/tests/unittests/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMapTest.java
+++ b/base/tests/unittests/com/google/idea/blaze/base/targetmaps/TransitiveDependencyMapTest.java
@@ -53,8 +53,8 @@
@Test
public void testGetSimpleDependency() {
- TargetKey simpleA = TargetKey.forPlainTarget(new Label("//com/google/example/simple:a"));
- TargetKey simpleB = TargetKey.forPlainTarget(new Label("//com/google/example/simple:b"));
+ TargetKey simpleA = TargetKey.forPlainTarget(Label.create("//com/google/example/simple:a"));
+ TargetKey simpleB = TargetKey.forPlainTarget(Label.create("//com/google/example/simple:b"));
assertThat(transitiveDependencyMap.getTransitiveDependencies(simpleA)).containsExactly(simpleB);
assertThat(transitiveDependencyMap.getTransitiveDependencies(simpleB)).isEmpty();
@@ -62,10 +62,10 @@
@Test
public void testGetChainDependencies() {
- TargetKey chainA = TargetKey.forPlainTarget(new Label("//com/google/example/chain:a"));
- TargetKey chainB = TargetKey.forPlainTarget(new Label("//com/google/example/chain:b"));
- TargetKey chainC = TargetKey.forPlainTarget(new Label("//com/google/example/chain:c"));
- TargetKey chainD = TargetKey.forPlainTarget(new Label("//com/google/example/chain:d"));
+ TargetKey chainA = TargetKey.forPlainTarget(Label.create("//com/google/example/chain:a"));
+ TargetKey chainB = TargetKey.forPlainTarget(Label.create("//com/google/example/chain:b"));
+ TargetKey chainC = TargetKey.forPlainTarget(Label.create("//com/google/example/chain:c"));
+ TargetKey chainD = TargetKey.forPlainTarget(Label.create("//com/google/example/chain:d"));
assertThat(transitiveDependencyMap.getTransitiveDependencies(chainA))
.containsExactly(chainB, chainC, chainD);
@@ -77,13 +77,15 @@
@Test
public void testGetDiamondDependencies() {
- TargetKey diamondA = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:a"));
- TargetKey diamondB = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:b"));
- TargetKey diamondBB = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:bb"));
- TargetKey diamondBBB = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:bbb"));
- TargetKey diamondC = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:c"));
- TargetKey diamondCC = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:cc"));
- TargetKey diamondCCC = TargetKey.forPlainTarget(new Label("//com/google/example/diamond:ccc"));
+ TargetKey diamondA = TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:a"));
+ TargetKey diamondB = TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:b"));
+ TargetKey diamondBB = TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:bb"));
+ TargetKey diamondBBB =
+ TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:bbb"));
+ TargetKey diamondC = TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:c"));
+ TargetKey diamondCC = TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:cc"));
+ TargetKey diamondCCC =
+ TargetKey.forPlainTarget(Label.create("//com/google/example/diamond:ccc"));
assertThat(transitiveDependencyMap.getTransitiveDependencies(diamondA))
.containsExactly(diamondB, diamondBB, diamondBBB, diamondC, diamondCC, diamondCCC);
@@ -100,24 +102,24 @@
@Test
public void testGetDependencyForNonExistentTarget() {
- TargetKey bogus = TargetKey.forPlainTarget(new Label("//com/google/fake:target"));
+ TargetKey bogus = TargetKey.forPlainTarget(Label.create("//com/google/fake:target"));
assertThat(transitiveDependencyMap.getTransitiveDependencies(bogus)).isEmpty();
}
private static TargetMap buildTargetMap() {
- Label simpleA = new Label("//com/google/example/simple:a");
- Label simpleB = new Label("//com/google/example/simple:b");
- Label chainA = new Label("//com/google/example/chain:a");
- Label chainB = new Label("//com/google/example/chain:b");
- Label chainC = new Label("//com/google/example/chain:c");
- Label chainD = new Label("//com/google/example/chain:d");
- Label diamondA = new Label("//com/google/example/diamond:a");
- Label diamondB = new Label("//com/google/example/diamond:b");
- Label diamondBB = new Label("//com/google/example/diamond:bb");
- Label diamondBBB = new Label("//com/google/example/diamond:bbb");
- Label diamondC = new Label("//com/google/example/diamond:c");
- Label diamondCC = new Label("//com/google/example/diamond:cc");
- Label diamondCCC = new Label("//com/google/example/diamond:ccc");
+ Label simpleA = Label.create("//com/google/example/simple:a");
+ Label simpleB = Label.create("//com/google/example/simple:b");
+ Label chainA = Label.create("//com/google/example/chain:a");
+ Label chainB = Label.create("//com/google/example/chain:b");
+ Label chainC = Label.create("//com/google/example/chain:c");
+ Label chainD = Label.create("//com/google/example/chain:d");
+ Label diamondA = Label.create("//com/google/example/diamond:a");
+ Label diamondB = Label.create("//com/google/example/diamond:b");
+ Label diamondBB = Label.create("//com/google/example/diamond:bb");
+ Label diamondBBB = Label.create("//com/google/example/diamond:bbb");
+ Label diamondC = Label.create("//com/google/example/diamond:c");
+ Label diamondCC = Label.create("//com/google/example/diamond:cc");
+ Label diamondCCC = Label.create("//com/google/example/diamond:ccc");
return TargetMapBuilder.builder()
.addTarget(TargetIdeInfo.builder().setLabel(simpleA).addDependency(simpleB))
.addTarget(TargetIdeInfo.builder().setLabel(simpleB))
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
index 8027d58..9080df7 100644
--- a/base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java
+++ b/base/tests/utils/integration/com/google/idea/blaze/base/BlazeIntegrationTestCase.java
@@ -23,6 +23,7 @@
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.SyncCache;
import com.google.idea.testing.EdtRule;
import com.google.idea.testing.IntellijTestSetupRule;
import com.google.idea.testing.ServiceHelper;
@@ -115,7 +116,6 @@
workspaceRoot.toString(),
"test-project",
projectDataDirectory.getPath(),
- "location-hash",
workspaceRoot.fileForPath(new WorkspacePath("project-view-file")).getPath(),
buildSystem()));
@@ -136,6 +136,7 @@
@After
public final void tearDown() throws Exception {
+ SyncCache.getInstance(getProject()).clear();
testFixture.tearDown();
testFixture = null;
}
diff --git a/base/tests/utils/integration/com/google/idea/blaze/base/TestFileSystem.java b/base/tests/utils/integration/com/google/idea/blaze/base/TestFileSystem.java
index cf15e9f..f01b053 100644
--- a/base/tests/utils/integration/com/google/idea/blaze/base/TestFileSystem.java
+++ b/base/tests/utils/integration/com/google/idea/blaze/base/TestFileSystem.java
@@ -46,6 +46,11 @@
this.tempDirTestFixture = tempDirTestFixture;
}
+ /** Returns the root directory of the file system */
+ public String getRootDir() {
+ return LightPlatformTestCase.getSourceRoot().getPath();
+ }
+
/** Creates an empty file in the temp file system */
public VirtualFile createFile(String filePath) {
filePath = makePathRelativeToTestFixture(filePath);
@@ -140,7 +145,7 @@
if (!FileUtil.isAbsolute(filePath)) {
return filePath;
}
- String tempDirPath = LightPlatformTestCase.getSourceRoot().getPath();
+ String tempDirPath = getRootDir();
assertThat(FileUtil.isAncestor(tempDirPath, filePath, true)).isTrue();
return FileUtil.getRelativePath(tempDirPath, filePath, File.separatorChar);
}
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
index 44ce8c1..7810b88 100644
--- 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
@@ -36,7 +36,10 @@
@Before
public final void doSetup() {
BlazeProjectDataManager mockProjectDataManager =
- new MockBlazeProjectDataManager(MockBlazeProjectDataBuilder.builder(workspaceRoot).build());
+ new MockBlazeProjectDataManager(
+ MockBlazeProjectDataBuilder.builder(workspaceRoot)
+ .setOutputBase(fileSystem.getRootDir() + "/output_base")
+ .build());
registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
editorTest = new EditorTestHelper(getProject(), testFixture);
}
diff --git a/base/tests/utils/integration/com/google/idea/blaze/base/run/producer/BlazeRunConfigurationProducerTestCase.java b/base/tests/utils/integration/com/google/idea/blaze/base/run/producer/BlazeRunConfigurationProducerTestCase.java
new file mode 100644
index 0000000..434bd3a
--- /dev/null
+++ b/base/tests/utils/integration/com/google/idea/blaze/base/run/producer/BlazeRunConfigurationProducerTestCase.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 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.producer;
+
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.EditorTestHelper;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.Location;
+import com.intellij.execution.PsiLocation;
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.ide.DataManager;
+import com.intellij.idea.CommandLineApplication.MyDataManagerImpl;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.module.ModuleUtil;
+import com.intellij.openapi.util.Key;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.testFramework.MapDataContext;
+import javax.annotation.Nullable;
+import org.junit.Before;
+
+/** Run configuration producer integration test base */
+public class BlazeRunConfigurationProducerTestCase extends BlazeIntegrationTestCase {
+
+ protected EditorTestHelper editorTest;
+
+ @Before
+ public final void doSetup() {
+ BlazeProjectDataManager mockProjectDataManager =
+ new MockBlazeProjectDataManager(MockBlazeProjectDataBuilder.builder(workspaceRoot).build());
+ registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
+ editorTest = new EditorTestHelper(getProject(), testFixture);
+
+ // IntelliJ replaces the normal DataManager with a mock version in headless environments.
+ // We rely on a functional DataManager in run configuration tests to recognize when multiple
+ // psi elements are selected.
+ DataManager dataManager =
+ new MyDataManagerImpl() {
+ DataContext dataContext;
+
+ @Override
+ public <T> void saveInDataContext(
+ DataContext dataContext, Key<T> dataKey, @Nullable T data) {
+ this.dataContext = dataContext;
+ super.saveInDataContext(dataContext, dataKey, data);
+ }
+
+ @Override
+ public DataContext getDataContext() {
+ return dataContext != null ? dataContext : super.getDataContext();
+ }
+ };
+ registerApplicationComponent(DataManager.class, dataManager);
+ }
+
+ protected PsiFile createAndIndexFile(WorkspacePath path, String... contents) {
+ PsiFile file = workspace.createPsiFile(path, contents);
+ editorTest.openFileInEditor(file); // open file to trigger update of indices
+ return file;
+ }
+
+ @Nullable
+ protected static String getTestFilterContents(BlazeCommandRunConfiguration config) {
+ BlazeCommandRunConfigurationCommonState handlerState =
+ config.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ return handlerState != null ? handlerState.getTestFilterFlag() : null;
+ }
+
+ @Nullable
+ protected static BlazeCommandName getCommandType(BlazeCommandRunConfiguration config) {
+ BlazeCommandRunConfigurationCommonState handlerState =
+ config.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ return handlerState != null ? handlerState.getCommandState().getCommand() : null;
+ }
+
+ protected ConfigurationContext createContextFromPsi(PsiElement element) {
+ final MapDataContext dataContext = new MapDataContext();
+ dataContext.put(CommonDataKeys.PROJECT, getProject());
+ dataContext.put(LangDataKeys.MODULE, ModuleUtil.findModuleForPsiElement(element));
+ dataContext.put(Location.DATA_KEY, PsiLocation.fromPsiElement(element));
+ return ConfigurationContext.getFromContext(dataContext);
+ }
+
+ protected ConfigurationContext createContextFromMultipleElements(PsiElement[] elements) {
+ final MapDataContext dataContext = new MapDataContext();
+ dataContext.put(CommonDataKeys.PROJECT, getProject());
+ dataContext.put(LangDataKeys.MODULE, ModuleUtil.findModuleForPsiElement(elements[0]));
+ dataContext.put(Location.DATA_KEY, PsiLocation.fromPsiElement(elements[0]));
+ dataContext.put(LangDataKeys.PSI_ELEMENT_ARRAY, elements);
+ return ConfigurationContext.getFromContext(dataContext);
+ }
+
+ @Nullable
+ protected RunConfiguration createConfigurationFromLocation(PsiFile psiFile) {
+ MapDataContext dataContext = new MapDataContext();
+ dataContext.put(CommonDataKeys.PROJECT, getProject());
+ dataContext.put(LangDataKeys.MODULE, ModuleUtil.findModuleForPsiElement(psiFile));
+ dataContext.put(Location.DATA_KEY, PsiLocation.fromPsiElement(psiFile));
+ RunnerAndConfigurationSettings settings =
+ ConfigurationContext.getFromContext(dataContext).getConfiguration();
+ return settings != null ? settings.getConfiguration() : null;
+ }
+
+ protected static ArtifactLocation sourceRoot(String relativePath) {
+ return ArtifactLocation.builder().setRelativePath(relativePath).setIsSource(true).build();
+ }
+}
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
index 53c6b53..a227d50 100644
--- 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
@@ -27,11 +27,11 @@
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.command.info.BlazeInfoRunner;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.model.BlazeVersionData;
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;
@@ -45,16 +45,20 @@
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.aspects.BuildResult;
import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
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.projectstructure.ModuleFinder;
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.base.sync.sharding.ShardedTargetList;
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.ide.IdeEventQueue;
+import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
@@ -80,45 +84,61 @@
private MockProjectViewManager projectViewManager;
private MockBlazeVcsHandler vcsHandler;
- private MockBlazeInfo blazeInfoData;
+ private MockBlazeInfoRunner blazeInfoData;
private MockBlazeIdeInterface blazeIdeInterface;
protected ErrorCollector errorCollector;
protected BlazeContext context;
private ImmutableList<ContentEntry> workspaceContentEntries = ImmutableList.of();
+ private Map<String, ModifiableRootModel> modules = Maps.newHashMap();
+
+ private class MockModuleEditor extends ModuleEditorImpl {
+ public MockModuleEditor(Project project, BlazeImportSettings importSettings) {
+ super(project, importSettings);
+ }
+
+ @Override
+ public void commit() {
+ // don't commit module changes,
+ // and make sure they're properly disposed when the test is finished
+ for (ModifiableRootModel model : modules.values()) {
+ Disposer.register(getTestRootDisposable(), model::dispose);
+ if (model.getModule().getName().equals(BlazeDataStorage.WORKSPACE_MODULE_NAME)) {
+ workspaceContentEntries = ImmutableList.copyOf(model.getContentEntries());
+ }
+ }
+ BlazeSyncIntegrationTestCase.this.modules = modules;
+ }
+ }
+
+ // Since MockModuleEditor does not actually commit modules, the normal ModuleManager
+ // won't find modules we've created. This helps look up modules for later stages of Sync.
+ // We could override ModuleManager, but that has a wide interface and there are a lot of
+ // changes across API versions.
+ private class MockModuleFinder implements ModuleFinder {
+
+ MockModuleFinder() {}
+
+ @Nullable
+ @Override
+ public Module findModuleByName(String name) {
+ return getModuleCreatedDuringSync(name);
+ }
+ }
@Before
public void doSetup() throws Exception {
projectViewManager = new MockProjectViewManager();
vcsHandler = new MockBlazeVcsHandler();
- blazeInfoData = new MockBlazeInfo();
+ blazeInfoData = new MockBlazeInfoRunner();
blazeIdeInterface = new MockBlazeIdeInterface();
registerProjectService(ProjectViewManager.class, projectViewManager);
registerExtension(BlazeVcsHandler.EP_NAME, vcsHandler);
- registerApplicationService(BlazeInfo.class, blazeInfoData);
+ registerApplicationService(BlazeInfoRunner.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,
- // and make sure they're properly disposed when the test is finished
- for (ModifiableRootModel model : modules.values()) {
- Disposer.register(getTestRootDisposable(), model::dispose);
- if (model.getModule().getName().equals(BlazeDataStorage.WORKSPACE_MODULE_NAME)) {
- workspaceContentEntries = ImmutableList.copyOf(model.getContentEntries());
- }
- }
- }
- };
- }
- });
+ registerApplicationService(ModuleEditorProvider.class, MockModuleEditor::new);
+ registerProjectService(ModuleFinder.class, new MockModuleFinder());
errorCollector = new ErrorCollector();
context = new BlazeContext();
@@ -145,6 +165,12 @@
return workspaceContentEntries;
}
+ /** The modules created during sync */
+ private Module getModuleCreatedDuringSync(String module) {
+ ModifiableRootModel modifiableRootModel = modules.get(module);
+ return modifiableRootModel != null ? modifiableRootModel.getModule() : null;
+ }
+
/** Search the workspace module's {@link ContentEntry}s for one with the given file. */
@Nullable
protected ContentEntry findContentEntry(VirtualFile root) {
@@ -262,13 +288,13 @@
}
}
- private static class MockBlazeInfo extends BlazeInfo {
+ private static class MockBlazeInfoRunner extends BlazeInfoRunner {
private final Map<String, String> results = Maps.newHashMap();
@Override
public ListenableFuture<String> runBlazeInfo(
@Nullable BlazeContext context,
- BuildSystem buildSystem,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
List<String> blazeFlags,
String key) {
@@ -278,7 +304,7 @@
@Override
public ListenableFuture<byte[]> runBlazeInfoGetBytes(
@Nullable BlazeContext context,
- BuildSystem buildSystem,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
List<String> blazeFlags,
String key) {
@@ -286,12 +312,13 @@
}
@Override
- public ListenableFuture<ImmutableMap<String, String>> runBlazeInfo(
+ public ListenableFuture<BlazeInfo> runBlazeInfo(
@Nullable BlazeContext context,
BuildSystem buildSystem,
+ String binaryPath,
WorkspaceRoot workspaceRoot,
List<String> blazeFlags) {
- return Futures.immediateFuture(ImmutableMap.copyOf(results));
+ return Futures.immediateFuture(new BlazeInfo(buildSystem, ImmutableMap.copyOf(results)));
}
public void setResults(Map<String, String> results) {
@@ -310,7 +337,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets,
+ ShardedTargetList shardedTargets,
WorkspaceLanguageSettings workspaceLanguageSettings,
ArtifactLocationDecoder artifactLocationDecoder,
SyncState.Builder syncStateBuilder,
@@ -326,7 +353,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets) {
+ ShardedTargetList shardedTargets) {
return BuildResult.SUCCESS;
}
@@ -337,7 +364,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
BlazeVersionData blazeVersionData,
- List<TargetExpression> targets) {
+ ShardedTargetList shardedTargets) {
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
index 874fd28..020ee9f 100644
--- a/base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/BlazeTestCase.java
@@ -69,7 +69,7 @@
protected Project project;
private ExtensionsAreaImpl extensionsArea;
- private Disposable testDisposable;
+ protected Disposable testDisposable;
private static class RootDisposable implements Disposable {
@Override
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
index f040cf2..02aaf29 100644
--- a/base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/TestUtils.java
@@ -17,7 +17,6 @@
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;
@@ -29,6 +28,7 @@
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingManagerImpl;
+import com.intellij.util.PlatformUtils;
import com.intellij.util.pico.DefaultPicoContainer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -36,16 +36,17 @@
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import javax.annotation.Nullable;
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();
+ private final ExecutorService executor = MoreExecutors.newDirectExecutorService();
public BlazeMockApplication(@NotNull Disposable parentDisposable) {
super(parentDisposable);
@@ -119,4 +120,22 @@
}
}
}
+
+ /**
+ * Sets the platform prefix system property, reverting to the previous value when the supplied
+ * parent disposable is disposed.
+ */
+ public static void setPlatformPrefix(Disposable parentDisposable, String platformPrefix) {
+ String prevValue = System.getProperty(PlatformUtils.PLATFORM_PREFIX_KEY);
+ System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, platformPrefix);
+ Disposer.register(
+ parentDisposable,
+ () -> {
+ if (prevValue != null) {
+ System.setProperty(PlatformUtils.PLATFORM_PREFIX_KEY, prevValue);
+ } else {
+ System.clearProperty(PlatformUtils.PLATFORM_PREFIX_KEY);
+ }
+ });
+ }
}
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
index 3e970b4..34caa8b 100644
--- 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
@@ -23,7 +23,7 @@
/** Used in tests. */
public class MockBlazeExecutor extends BlazeExecutor {
- private final ListeningExecutorService executor = MoreExecutors.sameThreadExecutor();
+ private final ListeningExecutorService executor = MoreExecutors.newDirectExecutorService();
@Override
public <T> ListenableFuture<T> submit(final Callable<T> callable) {
diff --git a/base/tests/utils/unit/com/google/idea/blaze/base/model/MockBlazeProjectDataBuilder.java b/base/tests/utils/unit/com/google/idea/blaze/base/model/MockBlazeProjectDataBuilder.java
index 25bd08d..8e104a7 100644
--- a/base/tests/utils/unit/com/google/idea/blaze/base/model/MockBlazeProjectDataBuilder.java
+++ b/base/tests/utils/unit/com/google/idea/blaze/base/model/MockBlazeProjectDataBuilder.java
@@ -15,26 +15,24 @@
*/
package com.google.idea.blaze.base.model;
-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.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.ideinfo.TargetMap;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
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.ArtifactLocationDecoderImpl;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl;
/**
- * Use to build mock praject data for tests.
+ * Use to build mock project data for tests.
*
- * <p>For any data you don't supply, the builder make a best-effort attempt to create default
+ * <p>For any data you don't supply, the builder makes a best-effort attempt to create default
* objects using whatever data you have supplied if applicable.
*/
public class MockBlazeProjectDataBuilder {
@@ -42,8 +40,8 @@
private long syncTime = 0;
private TargetMap targetMap;
- private ImmutableMap<String, String> blazeInfo;
- private BlazeRoots blazeRoots;
+ private String outputBase;
+ private BlazeInfo blazeInfo;
private BlazeVersionData blazeVersionData;
private WorkspacePathResolver workspacePathResolver;
private ArtifactLocationDecoder artifactLocationDecoder;
@@ -51,7 +49,7 @@
private SyncState syncState;
private ImmutableMultimap<TargetKey, TargetKey> reverseDependencies;
- public MockBlazeProjectDataBuilder(WorkspaceRoot workspaceRoot) {
+ private MockBlazeProjectDataBuilder(WorkspaceRoot workspaceRoot) {
this.workspaceRoot = workspaceRoot;
}
@@ -69,13 +67,13 @@
return this;
}
- public MockBlazeProjectDataBuilder setBlazeInfo(ImmutableMap<String, String> blazeInfo) {
- this.blazeInfo = blazeInfo;
+ public MockBlazeProjectDataBuilder setOutputBase(String outputBase) {
+ this.outputBase = outputBase;
return this;
}
- public MockBlazeProjectDataBuilder setBlazeRoots(BlazeRoots blazeRoots) {
- this.blazeRoots = blazeRoots;
+ public MockBlazeProjectDataBuilder setBlazeInfo(BlazeInfo blazeInfo) {
+ this.blazeInfo = blazeInfo;
return this;
}
@@ -116,27 +114,26 @@
public BlazeProjectData build() {
TargetMap targetMap =
this.targetMap != null ? this.targetMap : new TargetMap(ImmutableMap.of());
- ImmutableMap<String, String> blazeInfo =
- this.blazeInfo != null ? this.blazeInfo : ImmutableMap.of();
- BlazeRoots blazeRoots =
- this.blazeRoots != null
- ? this.blazeRoots
- : new BlazeRoots(
- null,
- ImmutableList.of(workspaceRoot.directory()),
- new ExecutionRootPath("bin"),
- new ExecutionRootPath("gen"),
- null);
+ BlazeInfo blazeInfo = this.blazeInfo;
+ if (blazeInfo == null) {
+ String outputBase = this.outputBase != null ? this.outputBase : "/usr/workspace/1234";
+ blazeInfo =
+ BlazeInfo.createMockBlazeInfo(
+ outputBase,
+ outputBase + "/execroot",
+ outputBase + "/execroot/bin",
+ outputBase + "/execroot/gen");
+ }
BlazeVersionData blazeVersionData =
this.blazeVersionData != null ? this.blazeVersionData : new BlazeVersionData();
WorkspacePathResolver workspacePathResolver =
this.workspacePathResolver != null
? this.workspacePathResolver
- : new WorkspacePathResolverImpl(workspaceRoot, blazeRoots);
+ : new WorkspacePathResolverImpl(workspaceRoot);
ArtifactLocationDecoder artifactLocationDecoder =
this.artifactLocationDecoder != null
? this.artifactLocationDecoder
- : new ArtifactLocationDecoderImpl(blazeRoots, workspacePathResolver);
+ : new ArtifactLocationDecoderImpl(blazeInfo, workspacePathResolver);
WorkspaceLanguageSettings workspaceLanguageSettings =
this.workspaceLanguageSettings != null
? this.workspaceLanguageSettings
@@ -150,13 +147,11 @@
syncTime,
targetMap,
blazeInfo,
- blazeRoots,
blazeVersionData,
workspacePathResolver,
artifactLocationDecoder,
workspaceLanguageSettings,
syncState,
- reverseDependencies,
- null);
+ reverseDependencies);
}
}
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
index 8dbac18..bedd5d9 100644
--- 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
@@ -18,6 +18,7 @@
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.projectview.ProjectViewSet;
import com.intellij.openapi.project.Project;
import java.io.File;
import java.util.Collection;
@@ -32,7 +33,7 @@
@Override
public ListenableFuture<?> prefetchProjectFiles(
- Project project, BlazeProjectData blazeProjectData) {
+ Project project, ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
return Futures.immediateFuture(null);
}
}
diff --git a/build_defs/BUILD b/build_defs/BUILD
index 3c8b0b3..19ad33f 100644
--- a/build_defs/BUILD
+++ b/build_defs/BUILD
@@ -25,3 +25,13 @@
name = "api_version_txt",
srcs = ["api_version_txt.py"],
)
+
+py_binary(
+ name = "append_optional_xml_elements",
+ srcs = ["append_optional_xml_elements.py"],
+)
+
+py_binary(
+ name = "package_meta_inf_files",
+ srcs = ["package_meta_inf_files.py"],
+)
diff --git a/build_defs/append_optional_xml_elements.py b/build_defs/append_optional_xml_elements.py
new file mode 100755
index 0000000..c987fe1
--- /dev/null
+++ b/build_defs/append_optional_xml_elements.py
@@ -0,0 +1,46 @@
+"""Appends XML elements specifying optional dependencies to a plugin XML file.
+"""
+
+import argparse
+from itertools import izip
+from xml.dom.minidom import parse
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument(
+ "--plugin_xml", help="The main plugin xml file", required=True)
+parser.add_argument("--output", help="The output file.")
+parser.add_argument(
+ "optional_xml_files",
+ nargs="+",
+ help="Sequence of module, module xml... pairs")
+
+
+def pairwise(t):
+ it = iter(t)
+ return izip(it, it)
+
+
+def main():
+
+ args = parser.parse_args()
+ dom = parse(args.plugin_xml)
+
+ plugin_xml = dom.documentElement
+
+ for module, optional_xml in pairwise(args.optional_xml_files):
+ depends_element = dom.createElement("depends")
+ depends_element.setAttribute("optional", "true")
+ depends_element.setAttribute("config-file", optional_xml)
+ depends_element.appendChild(dom.createTextNode(module))
+ plugin_xml.appendChild(depends_element)
+
+ if args.output:
+ with file(args.output, "w") as f:
+ f.write(dom.toxml())
+ else:
+ print dom.toxml()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/build_defs/build_defs.bzl b/build_defs/build_defs.bzl
index b695241..5325028 100644
--- a/build_defs/build_defs.bzl
+++ b/build_defs/build_defs.bzl
@@ -2,6 +2,7 @@
"""
load(":intellij_plugin_debug_target.bzl", "intellij_plugin_debug_target")
+load(":intellij_plugin.bzl", "intellij_plugin", "optional_plugin_xml")
def merged_plugin_xml(name, srcs, **kwargs):
"""Merges N plugin.xml files together."""
@@ -178,72 +179,7 @@
tools = [api_version_txt_tool],
**kwargs)
-def intellij_plugin(name, deps, plugin_xml, meta_inf_files=[], jar_name=None, **kwargs):
- """Creates an intellij plugin from the given deps and plugin.xml.
-
- Args:
- name: The name of the target
- deps: Any java dependencies rolled up into the plugin jar.
- plugin_xml: An xml file to be placed in META-INF/plugin.jar
- meta_inf_files: Any further files to be placed in META-INF/plugin.jar
- jar_name: The name of the final plugin jar, or <name>.jar if None
- **kwargs: Any further arguments to be passed to the final target
- """
- zip_tool = "//third_party:zip"
- binary_name = name + "_binary"
- deploy_jar = binary_name + "_deploy.jar"
- native.java_binary(
- name = binary_name,
- 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),
- ]
- srcs = meta_inf_files + [
- plugin_xml,
- deploy_jar,
- ]
-
- for meta_inf_file in meta_inf_files:
- cmd.append("meta_inf_files='$(locations {meta_inf_file})'".format(meta_inf_file=meta_inf_file))
- cmd.append("for f in $$meta_inf_files; do cp $$f META-INF/; done")
- cmd.append("$(location {zip_tool}) -u $@ META-INF/* >/dev/null".format(zip_tool=zip_tool))
- cmd.append("rm -rf META-INF")
-
- jar_name = jar_name or (name + ".jar")
- native.genrule(
- name = name + "_genrule",
- srcs = srcs,
- tools = [zip_tool],
- outs = [jar_name],
- cmd = " ; ".join(cmd),
- )
-
- # included (with tag) as a hack so that IJwB can recognize this is an intellij plugin
- native.java_import(
- name = name,
- jars = [name + ".jar"],
- tags = ["intellij-plugin"],
- **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
- """
- native.java_library(
- name = name,
- exports = plugins,
- tags = ["intellij-plugin-bundle"],
- )
-
-def repackaged_jar(name, deps, rules, launcher=None, **kwargs):
+def repackaged_jar(name, deps, rules, **kwargs):
"""Repackages classes in a jar, to avoid collisions in the classpath.
Args:
@@ -255,25 +191,18 @@
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).
- launcher: The launcher arg to pass to java_binary
**kwargs: Any additional arguments to pass to the final target.
"""
- java_binary_name = name + "_deploy_jar"
+ java_binary_name = name + "_orig"
out = name + ".jar"
native.java_binary(
name = java_binary_name,
create_executable = 0,
stamp = 0,
- launcher = launcher,
- runtime_deps = deps,
- )
- _repackage_jar(name, java_binary_name, out, rules, **kwargs)
+ runtime_deps = deps)
+ _repackaged_jar(name, java_binary_name, out, rules, **kwargs)
-def repackage_jar(name, src_rule, out, rules, **kwargs):
- print("repackage_jar is deprecated. Please switch to repackaged_jar.")
- _repackage_jar(name, src_rule, out, rules, **kwargs)
-
-def _repackage_jar(name, src_rule, out, rules, **kwargs):
+def _repackaged_jar(name, src_rule, out, rules, **kwargs):
"""Repackages classes in a jar, to avoid collisions in the classpath."""
repackage_tool = "@jarjar//jar"
deploy_jar = "{src_rule}_deploy.jar".format(src_rule=src_rule)
@@ -290,7 +219,7 @@
repackage_tool = repackage_tool,
deploy_jar = deploy_jar,
))
- genrule_name = name + "_gen"
+ genrule_name = name + "_repackaged"
native.genrule(
name = genrule_name,
srcs = [deploy_jar],
@@ -302,3 +231,9 @@
name = name,
jars = [out],
**kwargs)
+
+def beta_gensignature(name, srcs, stable, stable_version, beta_version):
+ if stable_version == beta_version:
+ native.alias(name = name, actual = stable)
+ else:
+ native.gensignature(name = name, srcs = srcs)
diff --git a/build_defs/intellij_plugin.bzl b/build_defs/intellij_plugin.bzl
new file mode 100644
index 0000000..207435d
--- /dev/null
+++ b/build_defs/intellij_plugin.bzl
@@ -0,0 +1,220 @@
+"""IntelliJ plugin target rule.
+
+Creates a plugin jar with the given plugin xml and any
+optional plugin xmls.
+
+To provide optional plugin xmls, use the 'optional_plugin_xml'
+rule. These will be renamed, put in the META-INF directory,
+and the main plugin xml stamped with optional plugin dependencies
+that point to the correct META-INF optional plugin xmls.
+
+optional_plugin_xml(
+ name = "optional_python_xml",
+ plugin_xml = "my_optional_python_plugin.xml",
+ module = "com.idea.python.module.id",
+)
+
+intellij_plugin(
+ name = "my_plugin",
+ plugin_xml = ["my_plugin.xml"],
+ optional_plugin_xmls = [":optional_python_xml"],
+ deps = [
+ ":code_deps",
+ ],
+)
+
+"""
+
+optional_plugin_xml_provider = provider()
+
+def _optional_plugin_xml_impl(ctx):
+ attr = ctx.attr
+ optional_plugin_xmls = []
+ if ctx.file.plugin_xml:
+ optional_plugin_xmls.append(struct(
+ plugin_xml = ctx.file.plugin_xml,
+ module = attr.module,
+ ))
+ return struct(
+ optional_plugin_xml_data = optional_plugin_xml_provider(
+ optional_plugin_xmls = optional_plugin_xmls,
+ ),
+ )
+
+optional_plugin_xml = rule(
+ implementation = _optional_plugin_xml_impl,
+ attrs = {
+ "plugin_xml": attr.label(mandatory=True, allow_single_file=[".xml"]),
+ "module": attr.string(mandatory=True),
+ },
+)
+
+def _merge_optional_plugin_xmls(ctx):
+ # Collect optional plugin xmls
+ module_to_xmls = {}
+ for target in ctx.attr.optional_plugin_xmls:
+ if not hasattr(target, "optional_plugin_xml_data"):
+ fail("optional_plugin_xmls only accepts optional_plugin_xml targets")
+ for xml in target.optional_plugin_xml_data.optional_plugin_xmls:
+ module = xml.module
+ plugin_xmls = module_to_xmls.setdefault(module, [])
+ plugin_xmls.append(xml.plugin_xml)
+
+ # Merge xmls with the same module dependency
+ module_to_merged_xmls = {}
+ for module, plugin_xmls in module_to_xmls.items():
+ merged_name = "merged_xml_for_" + module + "_" + ctx.label.name + ".xml"
+ merged_file = ctx.new_file(merged_name)
+ ctx.action(
+ executable = ctx.executable._merge_xml_binary,
+ arguments = ["--output", merged_file.path] + [plugin_xml.path for plugin_xml in plugin_xmls],
+ inputs = list(plugin_xmls),
+ outputs = [merged_file],
+ progress_message = "Merging optional xmls",
+ mnemonic = "MergeOptionalXmls",
+ )
+ module_to_merged_xmls[module] = merged_file
+ return module_to_merged_xmls
+
+def _add_optional_dependencies_to_plugin_xml(ctx, modules):
+ input_plugin_xml_file = ctx.file.plugin_xml
+ if not modules:
+ return input_plugin_xml_file
+
+ # Add optional dependencies into the plugin xml
+ args = []
+ final_plugin_xml_file = ctx.new_file("final_plugin_xml_" + ctx.label.name + ".xml")
+ args.extend(["--plugin_xml", input_plugin_xml_file.path])
+ args.extend(["--output", final_plugin_xml_file.path])
+ for module in modules:
+ args.append(module)
+ args.append(_filename_for_module_dependency(module))
+ ctx.action(
+ executable = ctx.executable._append_optional_xml_elements,
+ arguments = args,
+ inputs = [input_plugin_xml_file],
+ outputs = [final_plugin_xml_file],
+ progress_message = "Adding optional dependencies to final plugin xml",
+ mnemonic = "AddModuleDependencies",
+ )
+ return final_plugin_xml_file
+
+def _only_file(target):
+ return list(target.files)[0]
+
+def _filename_for_module_dependency(module):
+ """A unique filename for the optional xml dependency for a given module."""
+ return "optional-" + module + ".xml"
+
+def _package_meta_inf_files(ctx, final_plugin_xml_file, module_to_merged_xmls):
+ jar_name = ctx.attr.jar_name
+ jar_file = ctx.new_file(jar_name)
+
+ args = []
+ args.extend(["--deploy_jar", ctx.file.deploy_jar.path])
+ args.extend(["--output", jar_file.path])
+ args.extend([final_plugin_xml_file.path, "plugin.xml"])
+ for module, merged_xml in module_to_merged_xmls.items():
+ args.append(merged_xml.path)
+ args.append(_filename_for_module_dependency(module))
+ ctx.action(
+ executable = ctx.executable._package_meta_inf_files,
+ arguments = args,
+ inputs = [ctx.file.deploy_jar, final_plugin_xml_file] + module_to_merged_xmls.values(),
+ outputs = [jar_file],
+ mnemonic = "PackagePluginJar",
+ progress_message = "Packaging plugin jar",
+ )
+ return jar_file
+
+def _intellij_plugin_jar_impl(ctx):
+ module_to_merged_xmls = _merge_optional_plugin_xmls(ctx)
+ final_plugin_xml_file = _add_optional_dependencies_to_plugin_xml(ctx, module_to_merged_xmls.keys())
+ jar_file = _package_meta_inf_files(ctx, final_plugin_xml_file, module_to_merged_xmls)
+ files = set([jar_file])
+ return struct(
+ files = files,
+ )
+
+_intellij_plugin_jar = rule(
+ implementation = _intellij_plugin_jar_impl,
+ attrs = {
+ "deploy_jar": attr.label(mandatory=True, allow_single_file=[".jar"]),
+ "plugin_xml": attr.label(mandatory=True, allow_single_file=[".xml"]),
+ "optional_plugin_xmls": attr.label_list(),
+ "jar_name": attr.string(mandatory=True),
+ "_merge_xml_binary": attr.label(
+ default = Label("//build_defs:merge_xml"),
+ executable = True,
+ cfg = "host",
+ ),
+ "_append_optional_xml_elements": attr.label(
+ default = Label("//build_defs:append_optional_xml_elements"),
+ executable = True,
+ cfg = "host",
+ ),
+ "_package_meta_inf_files": attr.label(
+ default = Label("//build_defs:package_meta_inf_files"),
+ executable = True,
+ cfg = "host",
+ ),
+ },
+)
+
+def intellij_plugin(name, deps, plugin_xml, optional_plugin_xmls=[], jar_name=None, **kwargs):
+ """Creates an intellij plugin from the given deps and plugin.xml.
+
+ Args:
+ name: The name of the target
+ deps: Any java dependencies rolled up into the plugin jar.
+ plugin_xml: An xml file to be placed in META-INF/plugin.jar
+ optional_plugin_xmls: A list of optional_plugin_xml targets.
+ jar_name: The name of the final plugin jar, or <name>.jar if None
+ **kwargs: Any further arguments to be passed to the final target
+ """
+ binary_name = name + "_binary"
+ deploy_jar = binary_name + "_deploy.jar"
+ native.java_binary(
+ name = binary_name,
+ runtime_deps = deps,
+ create_executable = 0,
+ )
+ jar_target_name = name + "_intellij_plugin_jar"
+ _intellij_plugin_jar(
+ name = jar_target_name,
+ deploy_jar = deploy_jar,
+ jar_name = jar_name or (name + ".jar"),
+ plugin_xml = plugin_xml,
+ optional_plugin_xmls = optional_plugin_xmls,
+ )
+ # included (with tag) as a hack so that IJwB can recognize this is an intellij plugin
+ native.java_import(
+ name = name,
+ jars = [jar_target_name],
+ tags = ["intellij-plugin"],
+ **kwargs)
+
+def _append_optional_dependencies(name, plugin_xml, module_to_merged_xml):
+ """Appends optional dependency xml elements to plugin xml."""
+ append_elements_tool = "//build_defs:append_optional_xml_elements"
+ args = [
+ "./$(location {append_elements_tool})",
+ "--plugin_xml=$(location {plugin_xml})",
+ "--optional_xml_files={merged_optional_xml_files}",
+ ]
+ dictionary = {k: _filename_for_module_dependency(k) for k in module_to_merged_xml.keys()}
+ cmd = " ".join(args).format(
+ append_elements_tool=append_elements_tool,
+ plugin_xml=plugin_xml,
+ merged_optional_xml_files='"%s"' % str(dictionary).replace('"', '\\"'),
+ ) + "> $@"
+
+ srcs = module_to_merged_xml.values() + [plugin_xml]
+
+ native.genrule(
+ name = name,
+ srcs = srcs,
+ outs = [name + ".xml"],
+ cmd = cmd,
+ tools = [append_elements_tool],
+ )
diff --git a/build_defs/intellij_plugin_debug_target.bzl b/build_defs/intellij_plugin_debug_target.bzl
index 484a6fe..37ec6f6 100644
--- a/build_defs/intellij_plugin_debug_target.bzl
+++ b/build_defs/intellij_plugin_debug_target.bzl
@@ -28,6 +28,8 @@
"""
+SUFFIX = ".intellij-plugin-debug-target-deploy-info"
+
def _trim_start(path, prefix):
return path[len(prefix):] if path.startswith(prefix) else path
@@ -86,12 +88,29 @@
implementation = _intellij_plugin_debug_target_aspect_impl,
)
+def _build_deploy_info_file(deploy_file):
+ return struct(
+ execution_path = deploy_file.src.path,
+ deploy_location = deploy_file.deploy_location,
+ )
+
def _intellij_plugin_debug_target_impl(ctx):
files = set()
deploy_files = []
for target in ctx.attr.deps:
files = files | target.files
deploy_files.extend(target.aspect_intellij_plugin_deploy_info.deploy_files)
+ deploy_info = struct(
+ deploy_files = [_build_deploy_info_file(f) for f in deploy_files]
+ )
+ output = ctx.new_file(ctx.label.name + SUFFIX)
+ ctx.file_action(output, deploy_info.to_proto())
+
+ # We've already consumed any dependent intellij_plugin_debug_targets into our own,
+ # do not build or report these
+ files = set([f for f in files if not f.path.endswith(SUFFIX)])
+ files = files | set([output])
+
return struct(
files = files,
intellij_plugin_deploy_info = struct(
diff --git a/build_defs/merge_xml.py b/build_defs/merge_xml.py
index b5840e6..2c58164 100755
--- a/build_defs/merge_xml.py
+++ b/build_defs/merge_xml.py
@@ -1,9 +1,22 @@
"""Merges multiple xml files with the same top element tags into a single file.
"""
+import argparse
import sys
from xml.dom.minidom import parse
+parser = argparse.ArgumentParser()
+
+parser.add_argument(
+ "--output",
+ help="The file to output to. If none, prints to stdout.",
+ required=False,)
+
+parser.add_argument(
+ "xmls",
+ nargs="+",
+ help="The xml files to merge",)
+
def AppendFileToTree(filepath, tree):
"""Reads XML from a file and appends XML content to the tree.
@@ -30,12 +43,16 @@
if __name__ == "__main__":
- if len(sys.argv) < 2:
- print "Need xml filename(s) to be checked as parameter"
+ args = parser.parse_args()
+ if not args.xmls:
sys.exit(2)
- dom = parse(sys.argv[1])
- for filename in sys.argv[2:]:
+ dom = parse(args.xmls[0])
+ for filename in args.xmls[1:]:
AppendFileToTree(filename, dom)
- print dom.toxml()
+ if args.output:
+ with file(args.output, "w") as f:
+ f.write(dom.toxml())
+ else:
+ print dom.toxml()
diff --git a/build_defs/package_meta_inf_files.py b/build_defs/package_meta_inf_files.py
new file mode 100644
index 0000000..c261974
--- /dev/null
+++ b/build_defs/package_meta_inf_files.py
@@ -0,0 +1,44 @@
+"""Adds a list of files into the META-INF directory of the passed deploy jar.
+"""
+
+import argparse
+from itertools import izip
+import shutil
+import zipfile
+
+# Set to Jan 1 1980, the earliest date supported by zipfile
+ZIP_DATE = (1980, 1, 1, 0, 0, 0)
+
+parser = argparse.ArgumentParser()
+
+parser.add_argument(
+ "--deploy_jar",
+ required=True,
+ help="The deploy jar to modify.",)
+parser.add_argument(
+ "--output",
+ required=True,
+ help="The output file.",)
+parser.add_argument(
+ "meta_inf_files",
+ nargs="+",
+ help="Sequence of input file, final file name pairs",)
+
+
+def pairwise(t):
+ it = iter(t)
+ return izip(it, it)
+
+
+def main():
+ args = parser.parse_args()
+
+ shutil.copyfile(args.deploy_jar, args.output)
+ output_jar = zipfile.ZipFile(args.output, "a")
+ for meta_inf_file, name in pairwise(args.meta_inf_files):
+ with file(meta_inf_file) as f:
+ zip_info = zipfile.ZipInfo("META-INF/" + name, ZIP_DATE)
+ output_jar.writestr(zip_info, f.read())
+
+if __name__ == "__main__":
+ main()
diff --git a/clwb/BUILD b/clwb/BUILD
index f1048b9..e420e93 100644
--- a/clwb/BUILD
+++ b/clwb/BUILD
@@ -10,6 +10,7 @@
"merged_plugin_xml",
"stamped_plugin_xml",
)
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_plugin_api")
load("//:version.bzl", "VERSION")
merged_plugin_xml(
@@ -18,8 +19,8 @@
"src/META-INF/clwb.xml",
"//base:plugin_xml",
"//cpp:plugin_xml",
+ "//python:plugin_xml",
],
- visibility = ["//visibility:public"],
)
merged_plugin_xml(
@@ -32,6 +33,7 @@
stamped_plugin_xml(
name = "stamped_plugin_xml",
+ changelog_file = "//:changelog",
include_product_code_in_stamp = True,
plugin_id = "com.google.idea.bazel.clwb",
plugin_name = "CLion with Bazel",
@@ -43,18 +45,30 @@
java_library(
name = "clwb_lib",
srcs = glob(["src/**/*.java"]),
- visibility = ["//visibility:public"],
+ runtime_deps = [
+ "//terminal",
+ ] + select_for_plugin_api({
+ "clion-2016.3.2": [],
+ "default": ["//python"],
+ }),
deps = [
"//base",
"//common/experiments",
"//cpp",
"//intellij_platform_sdk:plugin_api",
+ "//sdkcompat",
"@jsr305_annotations//jar",
],
)
+OPTIONAL_PLUGIN_XMLS = [
+ "//python:optional_xml",
+ "//terminal:optional_xml",
+]
+
intellij_plugin(
name = "clwb_bazel",
+ optional_plugin_xmls = OPTIONAL_PLUGIN_XMLS,
plugin_xml = ":stamped_plugin_xml",
deps = [
":clwb_lib",
diff --git a/clwb/clwb.bazelproject b/clwb/clwb.bazelproject
index 76911c2..b083707 100644
--- a/clwb/clwb.bazelproject
+++ b/clwb/clwb.bazelproject
@@ -3,7 +3,6 @@
-ijwb
-aswb
-plugin_dev
- -cpp/src/com/google/idea/blaze/cpp/versioned/v145
targets:
//clwb:clwb_bazel
diff --git a/clwb/src/META-INF/clwb.xml b/clwb/src/META-INF/clwb.xml
index 222ef38..1b79d3c 100644
--- a/clwb/src/META-INF/clwb.xml
+++ b/clwb/src/META-INF/clwb.xml
@@ -50,6 +50,7 @@
<SyncPlugin implementation="com.google.idea.blaze.clwb.sync.BlazeCLionSyncPlugin"/>
<BlazeCommandRunConfigurationHandlerProvider implementation="com.google.idea.blaze.clwb.run.BlazeCidrRunConfigurationHandlerProvider" order="first"/>
<RunConfigurationFactory implementation="com.google.idea.blaze.clwb.run.BlazeCidrDebuggableConfigurationFactory"/>
+ <BlazeTestEventsHandler implementation="com.google.idea.blaze.clwb.run.test.BlazeCidrTestEventsHandler"/>
</extensions>
<actions>
@@ -72,6 +73,11 @@
<component>
<implementation-class>com.google.idea.blaze.clwb.run.producers.NonBlazeProducerSuppressor</implementation-class>
</component>
+ <component>
+ <interface-class>com.jetbrains.cidr.cpp.cmake.workspace.CMakeWorkspace</interface-class>
+ <implementation-class>com.google.idea.blaze.plugin.CMakeWorkspaceOverride</implementation-class>
+ <option name="overrides" value="true"/>
+ </component>
</project-components>
</idea-plugin>
diff --git a/clwb/src/com/google/idea/blaze/clwb/problemsview/BlazeProblemsViewConsole.java b/clwb/src/com/google/idea/blaze/clwb/problemsview/BlazeProblemsViewConsole.java
index 543f346..725dde4 100644
--- a/clwb/src/com/google/idea/blaze/clwb/problemsview/BlazeProblemsViewConsole.java
+++ b/clwb/src/com/google/idea/blaze/clwb/problemsview/BlazeProblemsViewConsole.java
@@ -36,7 +36,7 @@
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.ArrayUtil;
-import com.intellij.util.concurrency.SequentialTaskExecutor;
+import com.intellij.util.concurrency.BoundedTaskExecutor;
import com.intellij.util.ui.MessageCategory;
import com.intellij.util.ui.UIUtil;
import java.util.ArrayList;
@@ -44,6 +44,7 @@
import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;
+import java.util.concurrent.ExecutorService;
import javax.swing.Icon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -58,8 +59,8 @@
EnumSet.allOf(ErrorTreeElementKind.class);
private final ProblemsViewPanel myPanel;
- private final SequentialTaskExecutor myViewUpdater =
- new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE);
+ private final ExecutorService myViewUpdater =
+ new BoundedTaskExecutor(PooledThreadExecutor.INSTANCE, 1);
private final Icon myActiveIcon = AllIcons.Toolwindows.Problems;
private final Icon myPassiveIcon = IconLoader.getDisabledIcon(myActiveIcon);
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrDebuggableConfigurationFactory.java b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrDebuggableConfigurationFactory.java
index 5363e69..55b0592 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrDebuggableConfigurationFactory.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrDebuggableConfigurationFactory.java
@@ -15,9 +15,7 @@
*/
package com.google.idea.blaze.clwb.run;
-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.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.model.BlazeProjectData;
@@ -57,10 +55,9 @@
Kind kind = blazeConfig.getKindForTarget();
if (state != null) {
if (kind != null && Kind.isTestRule(kind.toString())) {
- state.setCommand(BlazeCommandName.TEST);
- state.setBlazeFlags(ImmutableList.of(BlazeFlags.TEST_OUTPUT_STREAMED));
+ state.getCommandState().setCommand(BlazeCommandName.TEST);
} else {
- state.setCommand(BlazeCommandName.RUN);
+ state.getCommandState().setCommand(BlazeCommandName.RUN);
}
}
blazeConfig.setGeneratedName();
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrLauncher.java b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrLauncher.java
index 410cf57..473400b 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrLauncher.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrLauncher.java
@@ -26,14 +26,18 @@
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.DistributedExecutorSupport;
import com.google.idea.blaze.base.run.processhandler.LineProcessingProcessAdapter;
import com.google.idea.blaze.base.run.processhandler.ScopedBlazeProcessHandler;
+import com.google.idea.blaze.base.run.smrunner.BlazeTestEventsHandler;
+import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.scopes.IssuesScope;
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.sdkcompat.cidr.CidrConsoleBuilderAdapter;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.CommandLineState;
import com.intellij.execution.configurations.GeneralCommandLine;
@@ -50,10 +54,8 @@
import com.jetbrains.cidr.execution.debugger.CidrDebugProcess;
import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess;
import com.jetbrains.cidr.execution.testing.CidrLauncher;
-import com.jetbrains.cidr.execution.testing.OCGoogleTestConsoleProperties;
import java.io.File;
-import java.util.Objects;
-import org.jetbrains.annotations.NotNull;
+import javax.annotation.Nullable;
/**
* Handles running/debugging cc_test and cc_binary targets in CLion. Sets up gdb when debugging, and
@@ -68,7 +70,7 @@
private final BlazeCidrRunConfigurationRunner runner;
private final ExecutionEnvironment executionEnvironment;
- public BlazeCidrLauncher(
+ BlazeCidrLauncher(
BlazeCommandRunConfiguration configuration,
BlazeCidrRunConfigurationRunner runner,
ExecutionEnvironment environment) {
@@ -89,26 +91,40 @@
ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet();
LOG.assertTrue(projectViewSet != null);
- state.setConsoleBuilder(createConsoleBuilder());
+ ImmutableList<String> testHandlerFlags = ImmutableList.of();
+ BlazeTestEventsHandler testEventsHandler =
+ useTestUi()
+ ? BlazeTestEventsHandler.getHandlerForTarget(project, configuration.getTarget())
+ : null;
+ if (testEventsHandler != null) {
+ testHandlerFlags = BlazeTestEventsHandler.getBlazeFlags(project);
+ }
- BlazeCommand blazeCommand =
- BlazeCommand.builder(Blaze.getBuildSystem(project), handlerState.getCommand())
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(
+ Blaze.getBuildSystemProvider(project).getBinaryPath(),
+ handlerState.getCommandState().getCommand())
.addTargets(configuration.getTarget())
.addBlazeFlags(BlazeFlags.buildFlags(project, ProjectViewSet.builder().build()))
- .addBlazeFlags(handlerState.getBlazeFlags())
- .addExeFlags(handlerState.getExeFlags())
- .build();
+ .addBlazeFlags(testHandlerFlags)
+ .addBlazeFlags(handlerState.getBlazeFlagsState().getExpandedFlags())
+ .addExeFlags(handlerState.getExeFlagsState().getExpandedFlags());
+
+ command.addBlazeFlags(
+ DistributedExecutorSupport.getBlazeFlags(
+ project, handlerState.getRunOnDistributedExecutorState().runOnDistributedExecutor));
+
+ state.setConsoleBuilder(createConsoleBuilder(testEventsHandler));
WorkspaceRoot workspaceRoot = WorkspaceRoot.fromImportSettings(importSettings);
return new ScopedBlazeProcessHandler(
project,
- blazeCommand,
+ command.build(),
workspaceRoot,
new ScopedBlazeProcessHandler.ScopedProcessHandlerDelegate() {
@Override
public void onBlazeContextStart(BlazeContext context) {
- context
- .push(new IssuesScope(project));
+ context.push(new IssuesScope(project));
}
@Override
@@ -138,31 +154,28 @@
GeneralCommandLine commandLine = new GeneralCommandLine(runner.executableToDebug.getPath());
File workingDir = workspaceRoot.directory();
commandLine.setWorkDirectory(workingDir);
- commandLine.addParameters(handlerState.getExeFlags());
+ commandLine.addParameters(handlerState.getExeFlagsState().getExpandedFlags());
TrivialInstaller installer = new TrivialInstaller(commandLine);
ImmutableList<String> startupCommands = getGdbStartupCommands(workingDir);
CLionRunParameters parameters =
new CLionRunParameters(
new BlazeGDBDriverConfiguration(project, startupCommands, workspaceRoot), installer);
- CidrDebugProcess result =
- new CidrLocalDebugProcess(parameters, session, state.getConsoleBuilder());
- return result;
+ return new CidrLocalDebugProcess(parameters, session, state.getConsoleBuilder());
}
- @NotNull
@Override
protected Project getProject() {
return project;
}
- private CidrConsoleBuilder createConsoleBuilder() {
- if (Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)) {
- // Use the Google Test failure/success console instead of a standard console.
- return new GoogleTestConsoleBuilder(configuration.getProject());
+ private CidrConsoleBuilder createConsoleBuilder(
+ @Nullable BlazeTestEventsHandler testEventsHandler) {
+ if (testEventsHandler != null) {
+ return new GoogleTestConsoleBuilder(configuration.getProject(), testEventsHandler);
}
- return new CidrConsoleBuilder(configuration.getProject());
+ return new CidrConsoleBuilderAdapter(configuration.getProject());
}
private ImmutableList<String> getGdbStartupCommands(File workingDir) {
@@ -176,20 +189,27 @@
return ImmutableList.of(subPathCommand);
}
- private final class GoogleTestConsoleBuilder extends CidrConsoleBuilder {
- private GoogleTestConsoleBuilder(Project project) {
+ private boolean useTestUi() {
+ return BlazeCommandName.TEST.equals(handlerState.getCommandState().getCommand())
+ && !handlerState.getRunOnDistributedExecutorState().runOnDistributedExecutor;
+ }
+
+ private final class GoogleTestConsoleBuilder extends CidrConsoleBuilderAdapter {
+ private final BlazeTestEventsHandler testEventsHandler;
+
+ private GoogleTestConsoleBuilder(Project project, BlazeTestEventsHandler testEventsHandler) {
super(project);
+ this.testEventsHandler = testEventsHandler;
addFilter(new BlazeCidrTestOutputFilter(project));
}
@Override
protected ConsoleView createConsole() {
- OCGoogleTestConsoleProperties consoleProperties =
- new OCGoogleTestConsoleProperties(
- configuration,
- executionEnvironment.getExecutor(),
- executionEnvironment.getExecutionTarget());
- return createConsole(configuration.getType(), consoleProperties);
+ return SmRunnerUtils.getConsoleView(
+ configuration.getProject(),
+ configuration,
+ executionEnvironment.getExecutor(),
+ testEventsHandler);
}
}
}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationHandler.java b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationHandler.java
index c5ded30..6a6f411 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationHandler.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationHandler.java
@@ -78,7 +78,7 @@
@Override
@Nullable
public String getCommandName() {
- BlazeCommandName command = state.getCommand();
+ BlazeCommandName command = state.getCommandState().getCommand();
return command != null ? command.toString() : null;
}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationRunner.java b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationRunner.java
index 208cf11..42a78c7 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationRunner.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrRunConfigurationRunner.java
@@ -15,16 +15,15 @@
*/
package com.google.idea.blaze.clwb.run;
+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.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.command.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.projectview.ProjectViewManager;
@@ -50,7 +49,6 @@
import com.intellij.openapi.vfs.LocalFileSystem;
import com.jetbrains.cidr.execution.CidrCommandLineState;
import java.io.File;
-import java.util.List;
/** CLion-specific handler for {@link BlazeCommandRunConfiguration}s. */
public class BlazeCidrRunConfigurationRunner implements BlazeCommandRunConfigurationRunner {
@@ -109,7 +107,8 @@
final ProjectViewSet projectViewSet =
ProjectViewManager.getInstance(project).getProjectViewSet();
- final List<File> outputArtifacts = Lists.newArrayList();
+ BuildResultHelper buildResultHelper = BuildResultHelper.forFiles(file -> true);
+
final ListenableFuture<Void> buildOperation =
BlazeExecutor.submitTask(
project,
@@ -123,12 +122,13 @@
context.output(new StatusOutput("Building debug binary"));
BlazeCommand.Builder command =
- BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.BUILD)
+ BlazeCommand.builder(
+ Blaze.getBuildSystemProvider(project).getBinaryPath(),
+ BlazeCommandName.BUILD)
.addTargets(configuration.getTarget())
.addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
- .addBlazeFlags(handlerState.getBlazeFlags());
-
- command.addBlazeFlags("--experimental_show_artifacts");
+ .addBlazeFlags(handlerState.getBlazeFlagsState().getExpandedFlags())
+ .addBlazeFlags(buildResultHelper.getBuildFlags());
// If we are trying to debug, make sure we are building in debug mode.
// This can cause a rebuild, so it is a heavyweight setting.
@@ -140,8 +140,7 @@
.addBlazeCommand(command.build())
.context(context)
.stderr(
- LineProcessingOutputStream.of(
- new ExperimentalShowArtifactsLineProcessor(outputArtifacts),
+ buildResultHelper.stderr(
new IssueOutputLineProcessor(project, context, workspaceRoot)))
.build()
.run();
@@ -154,6 +153,7 @@
} catch (InterruptedException | java.util.concurrent.ExecutionException e) {
throw new ExecutionException(e);
}
+ ImmutableList<File> outputArtifacts = buildResultHelper.getBuildArtifacts();
if (outputArtifacts.isEmpty()) {
throw new ExecutionException(
String.format("No output artifacts found when building %s", configuration.getTarget()));
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrTestOutputFilter.java b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrTestOutputFilter.java
index b2498f1..cdd8900 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrTestOutputFilter.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCidrTestOutputFilter.java
@@ -22,7 +22,7 @@
import com.intellij.execution.filters.RegexpFilter;
import com.intellij.openapi.project.Project;
import java.io.File;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Identifies file paths in CLion test output which aren't found by CidrPathConsoleFilter. */
public class BlazeCidrTestOutputFilter extends RegexpFilter {
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCommandFlags.java b/clwb/src/com/google/idea/blaze/clwb/run/BlazeCommandFlags.java
deleted file mode 100644
index 12020f2..0000000
--- a/clwb/src/com/google/idea/blaze/clwb/run/BlazeCommandFlags.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.clwb.run;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.idea.blaze.base.ui.UiUtil;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMExternalizable;
-import com.intellij.openapi.util.WriteExternalException;
-import com.intellij.util.execution.ParametersListUtil;
-import java.util.List;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JTextArea;
-import org.jdom.Element;
-
-final class BlazeCommandFlags implements JDOMExternalizable {
- public static final class Editor {
- private final JTextArea blazeFlagsField = new JTextArea(5, 0);
- private final JTextArea exeFlagsField = new JTextArea(5, 0);
-
- public JComponent getEditorComponent() {
- return UiUtil.createBox(
- new JLabel("Blaze flags:"),
- blazeFlagsField,
- new JLabel("Executable flags:"),
- exeFlagsField);
- }
-
- public void setText(BlazeCommandFlags blazeCommandFlags) {
- blazeFlagsField.setText(ParametersListUtil.join(blazeCommandFlags.getBlazeFlags()));
- exeFlagsField.setText(ParametersListUtil.join(blazeCommandFlags.getExeFlags()));
- }
-
- public BlazeCommandFlags getBlazeCommandFlags() {
- ImmutableList<String> blazeFlags =
- ImmutableList.copyOf(
- ParametersListUtil.parse(Strings.nullToEmpty(blazeFlagsField.getText())));
- ImmutableList<String> exeFlags =
- ImmutableList.copyOf(
- ParametersListUtil.parse(Strings.nullToEmpty(exeFlagsField.getText())));
- return new BlazeCommandFlags(blazeFlags, exeFlags);
- }
- }
-
- private static final String USER_BLAZE_FLAG_TAG = "blaze-user-flag";
- private static final String USER_EXE_FLAG_TAG = "blaze-user-exe-flag";
-
- private ImmutableList<String> blazeFlags = ImmutableList.of();
- private ImmutableList<String> exeFlags = ImmutableList.of();
-
- public BlazeCommandFlags() {
- this.blazeFlags = ImmutableList.of();
- this.exeFlags = ImmutableList.of();
- }
-
- public BlazeCommandFlags(ImmutableList<String> blazeFlags, ImmutableList<String> exeFlags) {
- this.blazeFlags = blazeFlags;
- this.exeFlags = exeFlags;
- }
-
- public ImmutableList<String> getBlazeFlags() {
- return blazeFlags;
- }
-
- public ImmutableList<String> getExeFlags() {
- return exeFlags;
- }
-
- @Override
- public void readExternal(Element element) throws InvalidDataException {
- 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 {
- 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 boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- BlazeCommandFlags that = (BlazeCommandFlags) o;
- return Objects.equal(blazeFlags, that.blazeFlags) && Objects.equal(exeFlags, that.exeFlags);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(blazeFlags, exeFlags);
- }
-}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/RunConfigurationUtils.java b/clwb/src/com/google/idea/blaze/clwb/run/RunConfigurationUtils.java
index 10e7c7f..21845ca 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/RunConfigurationUtils.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/RunConfigurationUtils.java
@@ -34,7 +34,7 @@
if (handlerState == null) {
return false;
}
- BlazeCommandName command = handlerState.getCommand();
+ BlazeCommandName command = handlerState.getCommandState().getCommand();
return kind != null
&& command != null
&& ((kind == Kind.CC_TEST && command.equals(BlazeCommandName.TEST))
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/producers/BlazeCidrTestConfigurationProducer.java b/clwb/src/com/google/idea/blaze/clwb/run/producers/BlazeCidrTestConfigurationProducer.java
index 3589c9a..cf7f91f 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/producers/BlazeCidrTestConfigurationProducer.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/producers/BlazeCidrTestConfigurationProducer.java
@@ -17,7 +17,6 @@
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.model.primitives.Label;
import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
@@ -25,25 +24,13 @@
import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.clwb.run.test.GoogleTestLocation;
+import com.google.idea.blaze.clwb.run.test.GoogleTestSpecification;
import com.intellij.execution.Location;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.jetbrains.cidr.execution.testing.CidrTestUtil;
-import com.jetbrains.cidr.lang.psi.OCFile;
-import com.jetbrains.cidr.lang.psi.OCFunctionDefinition;
-import com.jetbrains.cidr.lang.psi.OCMacroCall;
-import com.jetbrains.cidr.lang.psi.OCMacroCallArgument;
-import com.jetbrains.cidr.lang.psi.OCStruct;
-import com.jetbrains.cidr.lang.symbols.OCSymbol;
-import com.jetbrains.cidr.lang.symbols.cpp.OCFunctionSymbol;
-import com.jetbrains.cidr.lang.symbols.cpp.OCStructSymbol;
-import com.jetbrains.cidr.lang.symbols.cpp.OCSymbolWithQualifiedName;
-import java.util.Collection;
-import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;
@@ -51,52 +38,6 @@
public class BlazeCidrTestConfigurationProducer
extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
- private static class TestTarget {
- @Nullable
- private static TestTarget createFromFile(@Nullable PsiElement element) {
- return createFromClassAndMethod(element, null, null);
- }
-
- @Nullable
- private static TestTarget createFromClass(@Nullable PsiElement element, String className) {
- return createFromClassAndMethod(element, className, null);
- }
-
- @Nullable
- private static TestTarget createFromClassAndMethod(
- @Nullable PsiElement element, String classOrSuiteName, @Nullable String testName) {
- Label label = TestTargetHeuristic.testTargetForPsiElement(element);
- if (label == null) {
- return null;
- }
- String filter = null;
- if (classOrSuiteName != null) {
- filter = classOrSuiteName;
- if (testName != null) {
- filter += "." + testName;
- }
- }
- return new TestTarget(element, label, filter);
- }
-
- private final PsiElement element;
- private final Label label;
- @Nullable private final String testFilterArg;
- private final String name;
-
- private TestTarget(PsiElement element, Label label, @Nullable String testFilter) {
- this.element = element;
- this.label = label;
- if (testFilter != null) {
- testFilterArg = BlazeFlags.TEST_FILTER + "=" + testFilter;
- name = String.format("%s (%s)", testFilter, label.toString());
- } else {
- testFilterArg = null;
- name = label.toString();
- }
- }
- }
-
public BlazeCidrTestConfigurationProducer() {
super(BlazeCommandRunConfigurationType.getInstance());
}
@@ -122,30 +63,35 @@
if (element == null) {
return false;
}
- TestTarget testObject = findTestObject(element);
- if (testObject == null) {
+ GoogleTestLocation test = GoogleTestLocation.findGoogleTest(element);
+ if (test == null) {
return false;
}
- sourceElement.set(testObject.element);
- configuration.setTarget(testObject.label);
+ Label label = getTestTarget(test.getPsiElement());
+ if (label == null) {
+ return false;
+ }
+ sourceElement.set(test.getPsiElement());
+ configuration.setTarget(label);
BlazeCommandRunConfigurationCommonState handlerState =
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
if (handlerState == null) {
return false;
}
- handlerState.setCommand(BlazeCommandName.TEST);
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
ImmutableList.Builder<String> flags = ImmutableList.builder();
- if (testObject.testFilterArg != null) {
- flags.add(testObject.testFilterArg);
+ String testFilter = test.getTestFilterFlag();
+ if (testFilter != null) {
+ flags.add(testFilter);
}
- flags.add(BlazeFlags.TEST_OUTPUT_STREAMED);
- flags.addAll(handlerState.getBlazeFlags());
+ flags.addAll(handlerState.getBlazeFlagsState().getRawFlags());
- handlerState.setBlazeFlags(flags.build());
+ handlerState.getBlazeFlagsState().setRawFlags(flags.build());
configuration.setName(
String.format(
- "%s test: %s", Blaze.buildSystemName(configuration.getProject()), testObject.name));
+ "%s test: %s",
+ Blaze.buildSystemName(configuration.getProject()), getTestName(label, test.gtest)));
return true;
}
@@ -157,107 +103,34 @@
if (handlerState == null) {
return false;
}
- if (!Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)) {
+ if (!Objects.equals(handlerState.getCommandState().getCommand(), BlazeCommandName.TEST)) {
return false;
}
PsiElement element = selectedPsiElement(context);
if (element == null) {
return false;
}
- TestTarget testObject = findTestObject(element);
- if (testObject == null) {
+ GoogleTestLocation test = GoogleTestLocation.findGoogleTest(element);
+ if (test == null) {
return false;
}
- List<String> flags = handlerState.getBlazeFlags();
- return testObject.label.equals(configuration.getTarget())
- && (testObject.testFilterArg == null || flags.contains(testObject.testFilterArg));
+ Label label = getTestTarget(test.getPsiElement());
+ if (label == null) {
+ return false;
+ }
+ return label.equals(configuration.getTarget())
+ && Objects.equals(handlerState.getTestFilterFlag(), test.getTestFilterFlag());
}
@Nullable
- private static TestTarget findTestObject(PsiElement element) {
- // Copied from on CidrGoogleTestRunConfigurationProducer::findTestObject.
- // Precedence order (decreasing): class/function, macro, file
- PsiElement parent =
- PsiTreeUtil.getNonStrictParentOfType(element, OCFunctionDefinition.class, OCStruct.class);
-
- OCStructSymbol parentSymbol;
- if (parent instanceof OCStruct
- && ((parentSymbol = ((OCStruct) parent).getSymbol()) != null)
- && CidrTestUtil.isGoogleTestClass(parentSymbol)) {
- Couple<String> name = CidrTestUtil.extractGoogleTestName(parentSymbol);
- if (name != null) {
- return TestTarget.createFromClassAndMethod(parent, name.first, name.second);
- }
- String className = parentSymbol.getQualifiedName().getName();
- return TestTarget.createFromClass(parent, className);
- } else if (parent instanceof OCFunctionDefinition) {
- OCFunctionSymbol symbol = ((OCFunctionDefinition) parent).getSymbol();
- if (symbol != null) {
- OCSymbolWithQualifiedName<?> resolvedOwner = symbol.getResolvedOwner();
- if (resolvedOwner != null) {
- OCSymbol<?> owner = resolvedOwner.getDefinitionSymbol();
- if (owner instanceof OCStructSymbol
- && CidrTestUtil.isGoogleTestClass((OCStructSymbol) owner)) {
- OCStruct struct = (OCStruct) owner.locateDefinition();
- Couple<String> name = CidrTestUtil.extractGoogleTestName((OCStructSymbol) owner);
- if (name != null) {
- return TestTarget.createFromClassAndMethod(struct, name.first, name.second);
- }
- return TestTarget.createFromClass(
- struct, ((OCStructSymbol) owner).getQualifiedName().getName());
- }
- }
- }
- }
-
- // if we're still here, let's test for a macro and, as a last resort, a file.
- parent = PsiTreeUtil.getNonStrictParentOfType(element, OCMacroCall.class, OCFile.class);
- if (parent instanceof OCMacroCall) {
- OCMacroCall gtestMacro = CidrTestUtil.findGoogleTestMacros(parent);
- if (gtestMacro != null) {
- List<OCMacroCallArgument> arguments = gtestMacro.getArguments();
- if (arguments.size() >= 2) {
- OCMacroCallArgument suiteArg = arguments.get(0);
- OCMacroCallArgument testArg = arguments.get(1);
-
- // if the element is the first argument of macro call,
- // then running entire suite, otherwise only a current test
- boolean isSuite =
- isFirstArgument(PsiTreeUtil.getParentOfType(element, OCMacroCallArgument.class))
- || isFirstArgument(element.getPrevSibling());
- String suiteName = CidrTestUtil.extractArgumentValue(suiteArg);
- String testName = CidrTestUtil.extractArgumentValue(testArg);
- OCStructSymbol symbol =
- CidrTestUtil.findGoogleTestSymbol(element.getProject(), suiteName, testName);
- if (symbol != null) {
- OCStruct targetElement = (OCStruct) symbol.locateDefinition();
- return TestTarget.createFromClassAndMethod(
- targetElement, suiteName, isSuite ? null : testName);
- }
- }
- }
- Couple<String> suite = CidrTestUtil.extractFullSuiteNameFromMacro(parent);
- if (suite != null) {
- Collection<OCStructSymbol> res =
- CidrTestUtil.findGoogleTestSymbolsForSuiteRandomly(
- element.getProject(), suite.first, true);
- if (res.size() != 0) {
- OCStruct struct = (OCStruct) res.iterator().next().locateDefinition();
- return TestTarget.createFromClassAndMethod(struct, suite.first, null);
- }
- }
- } else if (parent instanceof OCFile) {
- return TestTarget.createFromFile(parent);
- }
- return null;
+ private static Label getTestTarget(PsiElement element) {
+ return TestTargetHeuristic.testTargetForPsiElement(element);
}
- private static boolean isFirstArgument(@Nullable PsiElement element) {
- OCMacroCall macroCall = PsiTreeUtil.getParentOfType(element, OCMacroCall.class);
- if (macroCall != null) {
- List<OCMacroCallArgument> arguments = macroCall.getArguments();
- return arguments.size() > 0 && arguments.get(0).equals(element);
- }
- return false;
+ private static String getTestName(Label target, GoogleTestSpecification gtest) {
+ String filterDescription = gtest.description();
+ return filterDescription != null
+ ? String.format("%s (%s)", filterDescription, target.toString())
+ : target.toString();
}
}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/producers/NonBlazeProducerSuppressor.java b/clwb/src/com/google/idea/blaze/clwb/run/producers/NonBlazeProducerSuppressor.java
index 8f163a7..189ba34 100644
--- a/clwb/src/com/google/idea/blaze/clwb/run/producers/NonBlazeProducerSuppressor.java
+++ b/clwb/src/com/google/idea/blaze/clwb/run/producers/NonBlazeProducerSuppressor.java
@@ -15,20 +15,15 @@
*/
package com.google.idea.blaze.clwb.run.producers;
-import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.sdkcompat.clion.CMakeConfigurationProducersList;
import com.intellij.execution.RunConfigurationProducerService;
-import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.project.Project;
-import com.jetbrains.cidr.cpp.execution.testing.CMakeGoogleTestRunConfigurationProducer;
-import java.util.Collection;
/** Suppresses certain non-Blaze configuration producers in Blaze projects. */
public class NonBlazeProducerSuppressor extends AbstractProjectComponent {
- private static final Collection<Class<? extends RunConfigurationProducer<?>>>
- PRODUCERS_TO_SUPPRESS = ImmutableList.of(CMakeGoogleTestRunConfigurationProducer.class);
public NonBlazeProducerSuppressor(Project project) {
super(project);
@@ -44,6 +39,7 @@
private static void suppressProducers(Project project) {
RunConfigurationProducerService producerService =
RunConfigurationProducerService.getInstance(project);
- PRODUCERS_TO_SUPPRESS.forEach(producerService::addIgnoredProducer);
+ CMakeConfigurationProducersList.PRODUCERS_TO_SUPPRESS.forEach(
+ producerService::addIgnoredProducer);
}
}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/test/BlazeCidrTestEventsHandler.java b/clwb/src/com/google/idea/blaze/clwb/run/test/BlazeCidrTestEventsHandler.java
new file mode 100644
index 0000000..f117615
--- /dev/null
+++ b/clwb/src/com/google/idea/blaze/clwb/run/test/BlazeCidrTestEventsHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.clwb.run.test;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.smrunner.BlazeTestEventsHandler;
+import com.intellij.execution.Location;
+import com.intellij.execution.testframework.sm.runner.SMTestLocator;
+import com.intellij.openapi.project.Project;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Provides C/C++ specific methods needed by the SM-runner test UI. */
+public class BlazeCidrTestEventsHandler extends BlazeTestEventsHandler {
+
+ @Override
+ protected EnumSet<Kind> handledKinds() {
+ return EnumSet.of(Kind.CC_TEST);
+ }
+
+ @Override
+ public SMTestLocator getTestLocator() {
+ return BlazeCppTestLocator.INSTANCE;
+ }
+
+ @Nullable
+ @Override
+ public String getTestFilter(Project project, List<Location<?>> testLocations) {
+ List<String> filters = new ArrayList<>();
+ for (Location<?> location : testLocations) {
+ GoogleTestLocation test = GoogleTestLocation.findGoogleTest(location);
+ if (test != null && test.testFilter != null) {
+ filters.add(test.testFilter);
+ }
+ }
+ if (filters.isEmpty()) {
+ return null;
+ }
+ return String.format("%s=%s", BlazeFlags.TEST_FILTER, Joiner.on(':').join(filters));
+ }
+}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/test/BlazeCppTestLocator.java b/clwb/src/com/google/idea/blaze/clwb/run/test/BlazeCppTestLocator.java
new file mode 100644
index 0000000..cd02fc0
--- /dev/null
+++ b/clwb/src/com/google/idea/blaze/clwb/run/test/BlazeCppTestLocator.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.clwb.run.test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
+import com.google.idea.sdkcompat.cidr.CidrGoogleTestUtilAdapter;
+import com.intellij.execution.Location;
+import com.intellij.execution.testframework.sm.runner.SMTestLocator;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.CommonProcessors;
+import com.jetbrains.cidr.lang.psi.OCMacroCall;
+import com.jetbrains.cidr.lang.psi.OCStruct;
+import com.jetbrains.cidr.lang.symbols.OCSymbol;
+import com.jetbrains.cidr.lang.symbols.cpp.OCStructSymbol;
+import com.jetbrains.cidr.lang.symbols.symtable.OCGlobalProjectSymbolsCache;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** Locate cpp test classes / methods for test UI navigation. */
+public class BlazeCppTestLocator implements SMTestLocator {
+
+ public static final BlazeCppTestLocator INSTANCE = new BlazeCppTestLocator();
+
+ private static final Pattern SUITE_PATTERN = Pattern.compile("((\\w+)/)?(\\w+)(/(\\d+))?");
+ private static final Pattern METHOD_PATTERN = Pattern.compile("(\\w+)(/(\\d+))?");
+
+ private BlazeCppTestLocator() {}
+
+ @Override
+ public List<Location> getLocation(
+ String protocol, String path, Project project, GlobalSearchScope scope) {
+ GoogleTestLocation location = null;
+ if (SmRunnerUtils.GENERIC_SUITE_PROTOCOL.equals(protocol)) {
+ location = getLocation(project, path, null);
+ } else if (SmRunnerUtils.GENERIC_TEST_PROTOCOL.equals(protocol)) {
+ String[] components = path.split(SmRunnerUtils.TEST_NAME_PARTS_SPLITTER);
+ location = components.length != 2 ? null : getLocation(project, components[0], components[1]);
+ }
+ return location != null ? ImmutableList.of(location) : ImmutableList.of();
+ }
+
+ @Nullable
+ private static GoogleTestLocation getLocation(
+ Project project, String suiteComponent, @Nullable String methodComponent) {
+ Matcher matcher = SUITE_PATTERN.matcher(suiteComponent);
+ if (!matcher.matches()) {
+ return null;
+ }
+ String instantiation = matcher.group(2);
+ String suite = matcher.group(3);
+ String method = null;
+ if (methodComponent != null) {
+ matcher = METHOD_PATTERN.matcher(methodComponent);
+ if (!matcher.matches()) {
+ return null;
+ }
+ method = matcher.group(1);
+ }
+ PsiElement psi = findPsiElement(project, instantiation, suite, method);
+ if (psi == null) {
+ return null;
+ }
+ GoogleTestSpecification gtest =
+ new GoogleTestSpecification.FromGtestOutput(suiteComponent, methodComponent);
+ return new GoogleTestLocation(psi, gtest);
+ }
+
+ @Nullable
+ private static PsiElement findPsiElement(
+ Project project,
+ @Nullable String instantiation,
+ @Nullable String suite,
+ @Nullable String method) {
+ if (suite == null) {
+ return null;
+ }
+ OCSymbol<?> symbol;
+ if (method != null) {
+ symbol = CidrGoogleTestUtilAdapter.findGoogleTestSymbol(project, suite, method);
+ } else if (instantiation != null) {
+ symbol =
+ CidrGoogleTestUtilAdapter.findGoogleTestInstantiationSymbol(
+ project, suite, instantiation);
+ } else {
+ symbol = findSuiteSymbol(project, suite);
+ }
+ if (symbol == null) {
+ return null;
+ }
+ PsiElement psi = symbol.locateDefinition();
+ while (!(psi instanceof OCStruct || psi instanceof OCMacroCall) && psi != null) {
+ PsiElement prev = psi.getPrevSibling();
+ psi = prev == null ? psi.getParent() : prev;
+ }
+ return psi;
+ }
+
+ @Nullable
+ private static OCStructSymbol findSuiteSymbol(Project project, String suite) {
+ CommonProcessors.FindProcessor<OCSymbol> processor =
+ new CommonProcessors.FindProcessor<OCSymbol>() {
+ @Override
+ protected boolean accept(OCSymbol symbol) {
+ return symbol instanceof OCStructSymbol
+ && CidrGoogleTestUtilAdapter.isGoogleTestClass((OCStructSymbol) symbol);
+ }
+ };
+ OCGlobalProjectSymbolsCache.processTopLevelAndMemberSymbols(project, processor, suite);
+ if (processor.isFound()) {
+ return (OCStructSymbol) processor.getFoundValue();
+ }
+ Collection<OCStructSymbol> symbolsForSuite =
+ CidrGoogleTestUtilAdapter.findGoogleTestSymbolsForSuiteSorted(project, suite);
+ return Iterables.getFirst(symbolsForSuite, null);
+ }
+}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/test/GoogleTestLocation.java b/clwb/src/com/google/idea/blaze/clwb/run/test/GoogleTestLocation.java
new file mode 100644
index 0000000..84e036a
--- /dev/null
+++ b/clwb/src/com/google/idea/blaze/clwb/run/test/GoogleTestLocation.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.clwb.run.test;
+
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.sdkcompat.cidr.CidrGoogleTestUtilAdapter;
+import com.intellij.execution.Location;
+import com.intellij.execution.PsiLocation;
+import com.intellij.openapi.util.Couple;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.cidr.lang.psi.OCFile;
+import com.jetbrains.cidr.lang.psi.OCFunctionDefinition;
+import com.jetbrains.cidr.lang.psi.OCMacroCall;
+import com.jetbrains.cidr.lang.psi.OCMacroCallArgument;
+import com.jetbrains.cidr.lang.psi.OCStruct;
+import com.jetbrains.cidr.lang.symbols.OCSymbol;
+import com.jetbrains.cidr.lang.symbols.cpp.OCFunctionSymbol;
+import com.jetbrains.cidr.lang.symbols.cpp.OCStructSymbol;
+import com.jetbrains.cidr.lang.symbols.cpp.OCSymbolWithQualifiedName;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** A {@link PsiLocation} with corresponding gtest specification */
+public class GoogleTestLocation extends PsiLocation<PsiElement> {
+
+ public final GoogleTestSpecification gtest;
+ @Nullable public final String testFilter;
+
+ GoogleTestLocation(PsiElement psi, GoogleTestSpecification gtest) {
+ super(psi);
+ this.gtest = gtest;
+ this.testFilter = gtest.testFilter();
+ }
+
+ /** The raw test filter string with '--test_filter=' prepended, or null if there is no filter. */
+ @Nullable
+ public String getTestFilterFlag() {
+ return testFilter != null ? BlazeFlags.TEST_FILTER + "=" + testFilter : null;
+ }
+
+ @Nullable
+ public static GoogleTestLocation findGoogleTest(Location<?> location) {
+ if (location instanceof GoogleTestLocation) {
+ return (GoogleTestLocation) location;
+ }
+ return findGoogleTest(location.getPsiElement());
+ }
+
+ @Nullable
+ public static GoogleTestLocation findGoogleTest(PsiElement element) {
+ // Copied from on CidrGoogleTestRunConfigurationProducer::findTestObject.
+ // Precedence order (decreasing): class/function, macro, file
+ PsiElement parent =
+ PsiTreeUtil.getNonStrictParentOfType(element, OCFunctionDefinition.class, OCStruct.class);
+
+ OCStructSymbol parentSymbol;
+ if (parent instanceof OCStruct
+ && ((parentSymbol = ((OCStruct) parent).getSymbol()) != null)
+ && CidrGoogleTestUtilAdapter.isGoogleTestClass(parentSymbol)) {
+ Couple<String> name = CidrGoogleTestUtilAdapter.extractGoogleTestName(parentSymbol);
+ if (name != null) {
+ return createFromClassAndMethod(parent, name.first, name.second);
+ }
+ String className = parentSymbol.getQualifiedName().getName();
+ return createFromClass(parent, className);
+ } else if (parent instanceof OCFunctionDefinition) {
+ OCFunctionSymbol symbol = ((OCFunctionDefinition) parent).getSymbol();
+ if (symbol != null) {
+ OCSymbolWithQualifiedName<?> resolvedOwner = symbol.getResolvedOwner();
+ if (resolvedOwner != null) {
+ OCSymbol<?> owner = resolvedOwner.getDefinitionSymbol();
+ if (owner instanceof OCStructSymbol
+ && CidrGoogleTestUtilAdapter.isGoogleTestClass((OCStructSymbol) owner)) {
+ OCStruct struct = (OCStruct) owner.locateDefinition();
+ Couple<String> name =
+ CidrGoogleTestUtilAdapter.extractGoogleTestName((OCStructSymbol) owner);
+ if (name != null) {
+ return createFromClassAndMethod(struct, name.first, name.second);
+ }
+ return createFromClass(struct, ((OCStructSymbol) owner).getQualifiedName().getName());
+ }
+ }
+ }
+ }
+
+ // if we're still here, let's test for a macro and, as a last resort, a file.
+ parent = PsiTreeUtil.getNonStrictParentOfType(element, OCMacroCall.class, OCFile.class);
+ if (parent instanceof OCMacroCall) {
+ OCMacroCall gtestMacro = CidrGoogleTestUtilAdapter.findGoogleTestMacros(parent);
+ if (gtestMacro != null) {
+ List<OCMacroCallArgument> arguments = gtestMacro.getArguments();
+ if (arguments.size() >= 2) {
+ OCMacroCallArgument suiteArg = arguments.get(0);
+ OCMacroCallArgument testArg = arguments.get(1);
+
+ // if the element is the first argument of macro call,
+ // then running entire suite, otherwise only a current test
+ boolean isSuite =
+ isFirstArgument(PsiTreeUtil.getParentOfType(element, OCMacroCallArgument.class))
+ || isFirstArgument(element.getPrevSibling());
+ String suiteName = CidrGoogleTestUtilAdapter.extractArgumentValue(suiteArg);
+ String testName = CidrGoogleTestUtilAdapter.extractArgumentValue(testArg);
+ OCStructSymbol symbol =
+ CidrGoogleTestUtilAdapter.findGoogleTestSymbol(
+ element.getProject(), suiteName, testName);
+ if (symbol != null) {
+ OCStruct targetElement = (OCStruct) symbol.locateDefinition();
+ return createFromClassAndMethod(targetElement, suiteName, isSuite ? null : testName);
+ }
+ }
+ }
+ Couple<String> suite = CidrGoogleTestUtilAdapter.extractFullSuiteNameFromMacro(parent);
+ if (suite != null) {
+ Collection<OCStructSymbol> res =
+ CidrGoogleTestUtilAdapter.findGoogleTestSymbolsForSuiteRandomly(
+ element.getProject(), suite.first, true);
+ if (res.size() != 0) {
+ OCStruct struct = (OCStruct) res.iterator().next().locateDefinition();
+ GoogleTestSpecification gtest =
+ new GoogleTestSpecification.FromPsiElement(suite.first, null, suite.second, null);
+ return new GoogleTestLocation(struct, gtest);
+ }
+ }
+ } else if (parent instanceof OCFile) {
+ return createFromFile(parent);
+ }
+ return null;
+ }
+
+ private static boolean isFirstArgument(@Nullable PsiElement element) {
+ OCMacroCall macroCall = PsiTreeUtil.getParentOfType(element, OCMacroCall.class);
+ if (macroCall != null) {
+ List<OCMacroCallArgument> arguments = macroCall.getArguments();
+ return arguments.size() > 0 && arguments.get(0).equals(element);
+ }
+ return false;
+ }
+
+ @Nullable
+ private static GoogleTestLocation createFromFile(@Nullable PsiElement element) {
+ return createFromClassAndMethod(element, null, null);
+ }
+
+ @Nullable
+ private static GoogleTestLocation createFromClass(
+ @Nullable PsiElement element, @Nullable String className) {
+ return createFromClassAndMethod(element, className, null);
+ }
+
+ @Nullable
+ private static GoogleTestLocation createFromClassAndMethod(
+ @Nullable PsiElement element, @Nullable String classOrSuiteName, @Nullable String testName) {
+ if (element == null) {
+ return null;
+ }
+ GoogleTestSpecification gtest =
+ new GoogleTestSpecification.FromPsiElement(classOrSuiteName, testName, null, null);
+ return new GoogleTestLocation(element, gtest);
+ }
+}
diff --git a/clwb/src/com/google/idea/blaze/clwb/run/test/GoogleTestSpecification.java b/clwb/src/com/google/idea/blaze/clwb/run/test/GoogleTestSpecification.java
new file mode 100644
index 0000000..2111410
--- /dev/null
+++ b/clwb/src/com/google/idea/blaze/clwb/run/test/GoogleTestSpecification.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.clwb.run.test;
+
+import com.google.common.base.Joiner;
+import com.intellij.openapi.util.text.StringUtil;
+import javax.annotation.Nullable;
+
+/** A single gtest test case specification (https://github.com/google/googletest). */
+public interface GoogleTestSpecification {
+
+ /** The gtest filter string. Returns null if there is no filtering. */
+ @Nullable
+ String testFilter();
+
+ /** A human-readable description for this test. Returns null if there is no filtering. */
+ @Nullable
+ String description();
+
+ /**
+ * Built from the raw gtest output, without separating parameter components, etc.<br>
+ * This means there is no ambiguity -- guaranteed to be exactly what the gtest runner expects for
+ * this test case.
+ */
+ class FromGtestOutput implements GoogleTestSpecification {
+
+ private final String suiteComponent;
+ @Nullable private final String methodComponent;
+
+ public FromGtestOutput(String suiteComponent, @Nullable String methodComponent) {
+ this.suiteComponent = suiteComponent;
+ this.methodComponent = methodComponent;
+ }
+
+ @Override
+ public String testFilter() {
+ String method = methodComponent != null ? methodComponent : "*";
+ return String.format("%s.%s", suiteComponent, method);
+ }
+
+ @Override
+ public String description() {
+ return methodComponent == null
+ ? suiteComponent
+ : String.format("%s.%s", suiteComponent, methodComponent);
+ }
+ }
+
+ /**
+ * We don't know whether it's parameterized / typed in this context, so need to provide a more
+ * flexible filter.
+ */
+ class FromPsiElement implements GoogleTestSpecification {
+ @Nullable private final String suiteOrClass;
+ @Nullable private final String method;
+ @Nullable private final String instantiation;
+ @Nullable private final String param;
+
+ public FromPsiElement(
+ @Nullable String suiteOrClass,
+ @Nullable String method,
+ @Nullable String instantiation,
+ @Nullable String param) {
+ this.suiteOrClass = suiteOrClass;
+ this.method = method;
+ this.instantiation = instantiation;
+ this.param = param;
+ }
+
+ @Override
+ @Nullable
+ public String testFilter() {
+ if (suiteOrClass == null) {
+ return null;
+ }
+ String method = StringUtil.notNullize(this.method, "*");
+ String param = StringUtil.notNullize(this.param, "*");
+ if (instantiation != null) {
+ return Joiner.on(':')
+ .join(
+ String.format("%s/%s.%s/%s", instantiation, suiteOrClass, method, param),
+ String.format("%s/%s/%s.%s", instantiation, suiteOrClass, param, method));
+ }
+ // we don't know whether it's parameterized and/or typed, so need to handle all cases
+ return Joiner.on(':')
+ .join(
+ String.format("%s.%s", suiteOrClass, method),
+ String.format("%s/%s.%s", suiteOrClass, param, method),
+ String.format("*/%s.%s/*", suiteOrClass, method),
+ String.format("*/%s/*.%s", suiteOrClass, method));
+ }
+
+ @Override
+ @Nullable
+ public String description() {
+ if (suiteOrClass == null) {
+ return null;
+ }
+ if (method == null) {
+ return suiteOrClass;
+ }
+ if (instantiation == null) {
+ return suiteOrClass + "." + method;
+ }
+ String param = StringUtil.notNullize(this.param, "*");
+ return String.format("%s/%s.%s/%s", instantiation, suiteOrClass, method, param);
+ }
+ }
+}
diff --git a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeEditProjectViewImportWizardStep.java b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeEditProjectViewImportWizardStep.java
index 2998d4a..9c974de 100644
--- a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeEditProjectViewImportWizardStep.java
+++ b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeEditProjectViewImportWizardStep.java
@@ -82,6 +82,7 @@
public void onWizardFinished() throws CommitStepException {
try {
getProjectBuilder().commit();
+ control.commit();
} catch (BlazeProjectCommitException e) {
throw new CommitStepException(e.getMessage());
}
@@ -89,6 +90,6 @@
@Override
public String getHelpId() {
- return "docs/project-views.md";
+ return "docs/project-views";
}
}
diff --git a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectBuildSystemBinaryStep.java b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectBuildSystemBinaryStep.java
index 808fb63..6797e1e 100644
--- a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectBuildSystemBinaryStep.java
+++ b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectBuildSystemBinaryStep.java
@@ -28,8 +28,7 @@
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
-class BlazeSelectBuildSystemBinaryStep extends
- com.google.idea.blaze.clwb.wizard2.ProjectImportWizardStep {
+class BlazeSelectBuildSystemBinaryStep extends ProjectImportWizardStep {
private final JPanel component = new JPanel(new BorderLayout());
private SelectBazelBinaryControl control;
diff --git a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectProjectViewImportWizardStep.java b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectProjectViewImportWizardStep.java
index 9c99539..720091b 100644
--- a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectProjectViewImportWizardStep.java
+++ b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectProjectViewImportWizardStep.java
@@ -76,6 +76,6 @@
@Override
public String getHelpId() {
- return "docs/project-views.md";
+ return "docs/project-views";
}
}
diff --git a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectWorkspaceImportWizardStep.java b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectWorkspaceImportWizardStep.java
index 2b1666e..3d719bb 100644
--- a/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectWorkspaceImportWizardStep.java
+++ b/clwb/src/com/google/idea/blaze/clwb/wizard2/BlazeSelectWorkspaceImportWizardStep.java
@@ -25,8 +25,7 @@
import javax.swing.JPanel;
import org.jetbrains.annotations.NotNull;
-class BlazeSelectWorkspaceImportWizardStep extends
- com.google.idea.blaze.clwb.wizard2.ProjectImportWizardStep {
+class BlazeSelectWorkspaceImportWizardStep extends ProjectImportWizardStep {
private final JPanel component = new JPanel(new BorderLayout());
private BlazeSelectWorkspaceControl control;
@@ -75,6 +74,6 @@
@Override
public String getHelpId() {
- return "docs/import-project.md";
+ return "docs/import-project";
}
}
diff --git a/clwb/src/com/google/idea/blaze/plugin/CMakeOpenProjectActionOverride.java b/clwb/src/com/google/idea/blaze/plugin/CMakeOpenProjectActionOverride.java
new file mode 100644
index 0000000..8eb2d4e
--- /dev/null
+++ b/clwb/src/com/google/idea/blaze/plugin/CMakeOpenProjectActionOverride.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.intellij.ide.IdeBundle;
+import com.intellij.ide.actions.OpenProjectFileChooserDescriptor;
+import com.intellij.ide.impl.ProjectUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.application.ReadAction;
+import com.intellij.openapi.fileChooser.FileChooser;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.project.ProjectKt;
+import com.jetbrains.cidr.cpp.OpenCPPProjectAction;
+import com.jetbrains.cidr.cpp.cmake.CMakeProjectOpenProcessor;
+
+/** Replace {@link OpenCPPProjectAction} with a version that supports non-CMake projects. */
+public class CMakeOpenProjectActionOverride extends OpenCPPProjectAction {
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ FileChooserDescriptor descriptor = new OpenProjectFileChooserDescriptor(true, false);
+ Project project = e.getData(CommonDataKeys.PROJECT);
+ FileChooser.chooseFiles(
+ descriptor,
+ project,
+ VfsUtil.getUserHomeDir(),
+ files -> openProjectFile(project, files.get(0)));
+ }
+
+ private static VirtualFile getProjectFile(VirtualFile virtualFile) {
+ return ReadAction.compute(
+ () -> {
+ VirtualFile cmakeFile = CMakeProjectOpenProcessor.findSupportedSubFile(virtualFile);
+ if (cmakeFile != null) {
+ return cmakeFile;
+ }
+ return ProjectKt.getProjectStoreDirectory(virtualFile);
+ });
+ }
+
+ private static void openProjectFile(Project project, VirtualFile file) {
+ VirtualFile projectFile = getProjectFile(file);
+ if (projectFile != null) {
+ ProjectUtil.openOrImport(projectFile.getPath(), null, false);
+ return;
+ }
+ String message = IdeBundle.message("error.dir.contains.no.project", file.getPresentableUrl());
+ Messages.showInfoMessage(project, message, IdeBundle.message("title.cannot.open.project"));
+ }
+}
diff --git a/clwb/src/com/google/idea/blaze/plugin/CMakeWorkspaceOverride.java b/clwb/src/com/google/idea/blaze/plugin/CMakeWorkspaceOverride.java
new file mode 100644
index 0000000..7a2c2ca
--- /dev/null
+++ b/clwb/src/com/google/idea/blaze/plugin/CMakeWorkspaceOverride.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.settings.Blaze;
+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.ModuleRootManager;
+import com.intellij.openapi.roots.impl.storage.ClasspathStorage;
+import com.jetbrains.cidr.cpp.CPPModuleType;
+import com.jetbrains.cidr.cpp.cmake.workspace.CMakeWorkspace;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Suppress {@link CMakeWorkspace#projectOpened} for non-CMake projects. Remove this if the <a
+ * href="https://youtrack.jetbrains.com/issue/CPP-9632">upstream bug</a> is fixed.
+ */
+public class CMakeWorkspaceOverride extends CMakeWorkspace {
+
+ private final boolean isBlazeProject;
+
+ public CMakeWorkspaceOverride(Project project) {
+ super(project);
+ isBlazeProject = Blaze.isBlazeProject(project);
+ }
+
+ @Override
+ public void projectOpened() {
+ if (!isBlazeProject) {
+ super.projectOpened();
+ return;
+ }
+ removeClasspathStorageFromModules(myProject);
+ }
+
+ /**
+ * A hacky way of removing the classpath ID. {@link ClasspathStorage} doesn't have a method for
+ * removing the existing storage type, but #setStorageType will silently do this if it's passed an
+ * unrecognized type.
+ */
+ private static void removeClasspathStorageFromModules(Project project) {
+ String dummyClasspathId = "classpath.id.which.does.not.exist";
+ for (Module cppModule : getCppModules(project)) {
+ ClasspathStorage.setStorageType(ModuleRootManager.getInstance(cppModule), dummyClasspathId);
+ }
+ }
+
+ private static List<Module> getCppModules(Project project) {
+ ModuleType<?> type = CPPModuleType.getInstance();
+ return Arrays.stream(ModuleManager.getInstance(project).getModules())
+ .filter(module -> type.equals(ModuleType.get(module)))
+ .collect(Collectors.toList());
+ }
+}
diff --git a/clwb/src/com/google/idea/blaze/plugin/ClwbSpecificInitializer.java b/clwb/src/com/google/idea/blaze/plugin/ClwbSpecificInitializer.java
index 4a3445e..75b3b7b 100644
--- a/clwb/src/com/google/idea/blaze/plugin/ClwbSpecificInitializer.java
+++ b/clwb/src/com/google/idea/blaze/plugin/ClwbSpecificInitializer.java
@@ -16,12 +16,8 @@
package com.google.idea.blaze.plugin;
import com.google.idea.blaze.base.plugin.BlazeActionRemover;
+import com.google.idea.sdkcompat.clion.CMakeActionList;
import com.intellij.openapi.components.ApplicationComponent;
-import com.jetbrains.cidr.cpp.cmake.actions.ChangeCMakeProjectContentRootAction;
-import com.jetbrains.cidr.cpp.cmake.actions.DropCMakeCacheAction;
-import com.jetbrains.cidr.cpp.cmake.actions.OpenCMakeSettingsAction;
-import com.jetbrains.cidr.cpp.cmake.actions.ReloadCMakeProjectAction;
-import com.jetbrains.cidr.cpp.cmake.actions.ToggleCMakeAutoReloadAction;
/** Runs on startup. */
public class ClwbSpecificInitializer extends ApplicationComponent.Adapter {
@@ -33,12 +29,9 @@
// The original actions will be visible only on plain IDEA projects.
private static void hideCMakeActions() {
- BlazeActionRemover.hideAction(ChangeCMakeProjectContentRootAction.ID);
- BlazeActionRemover.hideAction(DropCMakeCacheAction.ID);
- BlazeActionRemover.hideAction(OpenCMakeSettingsAction.ID);
- BlazeActionRemover.hideAction(ReloadCMakeProjectAction.ID);
- BlazeActionRemover.hideAction(ToggleCMakeAutoReloadAction.ID);
- // 'CMake' > 'Show Generated CMake Files' action
- BlazeActionRemover.hideAction("CMake.ShowGeneratedDir");
+ for (String actionId : CMakeActionList.CMAKE_ACTION_IDS) {
+ BlazeActionRemover.hideAction(actionId);
+ }
+ BlazeActionRemover.replaceAction("OpenCPPProject", new CMakeOpenProjectActionOverride());
}
}
diff --git a/common/actionhelper/src/com/google/idea/common/actionhelper/ActionPresentationHelper.java b/common/actionhelper/src/com/google/idea/common/actionhelper/ActionPresentationHelper.java
index 69c5e1e..048b0f1 100644
--- a/common/actionhelper/src/com/google/idea/common/actionhelper/ActionPresentationHelper.java
+++ b/common/actionhelper/src/com/google/idea/common/actionhelper/ActionPresentationHelper.java
@@ -15,22 +15,30 @@
*/
package com.google.idea.common.actionhelper;
+import com.google.common.collect.Iterables;
+import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.vfs.VirtualFile;
-import java.util.List;
+import java.util.Collection;
import javax.annotation.Nullable;
/** Helps setting the presentation enabled/visible/text states. */
public class ActionPresentationHelper {
- private final Presentation presentation;
+ private final AnActionEvent event;
+
private boolean enabled = true;
private boolean visible = true;
private boolean disableWithoutSubject;
+ private boolean hideInContextMenuIfDisabled;
+
private boolean hasSubject;
private String text;
private String subjectText;
+ private boolean useTextMnemonic;
+
+ private String description;
/** Converts a subject to a string */
@FunctionalInterface
@@ -38,12 +46,12 @@
String subjectToString(T subject);
}
- private ActionPresentationHelper(Presentation presentation) {
- this.presentation = presentation;
+ private ActionPresentationHelper(AnActionEvent event) {
+ this.event = event;
}
- public static ActionPresentationHelper of(AnActionEvent e) {
- return new ActionPresentationHelper(e.getPresentation());
+ public static ActionPresentationHelper of(AnActionEvent event) {
+ return new ActionPresentationHelper(event);
}
/** Disables the action if the condition is true. */
@@ -52,12 +60,17 @@
return this;
}
- /** Hides the action if the condition is true. */
+ /** Hides the action if the condition is true. If the action is hidden, it is also disabled. */
public ActionPresentationHelper hideIf(boolean hideCondition) {
this.visible = this.visible && !hideCondition;
return this;
}
+ public ActionPresentationHelper hideInContextMenuIfDisabled() {
+ this.hideInContextMenuIfDisabled = true;
+ return this;
+ }
+
/** Disables the action if no subject has been provided. */
public ActionPresentationHelper disableWithoutSubject() {
this.disableWithoutSubject = true;
@@ -70,6 +83,18 @@
return this;
}
+ /** Use & or _ in the presentation text as a mnemonic shortcut. */
+ public ActionPresentationHelper useTextMnemonic() {
+ this.useTextMnemonic = true;
+ return this;
+ }
+
+ /** Sets the description of the presentation. */
+ public ActionPresentationHelper setDescription(String description) {
+ this.description = description;
+ return this;
+ }
+
/**
* Sets the text depending on the subject.
*
@@ -121,7 +146,7 @@
String noSubjectText,
String singleSubjectText,
String multipleSubjectText,
- List<VirtualFile> files) {
+ Collection<VirtualFile> files) {
return setTextWithSubjects(
noSubjectText,
singleSubjectText,
@@ -142,7 +167,7 @@
String noSubjectText,
String singleSubjectText,
String multipleSubjectText,
- List<T> subjects,
+ Collection<T> subjects,
SubjectToString<T> subjectToString) {
if (subjects.size() > 1) {
this.text = noSubjectText;
@@ -150,7 +175,7 @@
this.hasSubject = true;
return this;
} else {
- T subject = !subjects.isEmpty() ? subjects.get(0) : null;
+ T subject = !subjects.isEmpty() ? Iterables.getOnlyElement(subjects) : null;
return setTextWithSubject(noSubjectText, singleSubjectText, subject, subjectToString);
}
}
@@ -160,16 +185,26 @@
}
public void commit() {
- boolean enabled = this.enabled;
+ boolean enabled = this.enabled && this.visible;
if (disableWithoutSubject) {
enabled = enabled && hasSubject;
}
+ boolean visible = this.visible;
+ if (hideInContextMenuIfDisabled && !enabled && ActionPlaces.isPopupPlace(event.getPlace())) {
+ visible = false;
+ }
+
+ Presentation presentation = event.getPresentation();
presentation.setEnabled(enabled);
presentation.setVisible(visible);
String text = enabled && hasSubject ? subjectText : this.text;
if (text != null) {
- presentation.setText(text, false);
+ presentation.setText(text, useTextMnemonic);
+ }
+
+ if (description != null) {
+ presentation.setDescription(description);
}
}
}
diff --git a/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java b/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java
index 464a62d..1f1b6e0 100644
--- a/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java
+++ b/common/experiments/src/com/google/idea/common/experiments/WebExperimentSyncer.java
@@ -96,7 +96,7 @@
experimentValues = loadCache();
ListenableFuture<String> response = executor.submit(new WebExperimentsDownloader());
response.addListener(
- new WebExperimentsResultProcessor(response), MoreExecutors.sameThreadExecutor());
+ new WebExperimentsResultProcessor(response), MoreExecutors.directExecutor());
}
private void scheduleNextRefresh(boolean refreshWasSuccessful) {
@@ -105,7 +105,7 @@
ListenableScheduledFuture<String> refreshResults =
executor.schedule(new WebExperimentsDownloader(), delayInMinutes, TimeUnit.MINUTES);
refreshResults.addListener(
- new WebExperimentsResultProcessor(refreshResults), MoreExecutors.sameThreadExecutor());
+ new WebExperimentsResultProcessor(refreshResults), MoreExecutors.directExecutor());
}
private class WebExperimentsDownloader implements Callable<String> {
@@ -115,7 +115,7 @@
logger.debug("About to fetch experiments.");
return HttpRequests.request(
System.getProperty(EXPERIMENTS_URL_PROPERTY, DEFAULT_EXPERIMENT_URL) + pluginName)
- .readString(null /* progress indicator */);
+ .readString(/* progress indicator */ null);
}
}
@@ -144,10 +144,10 @@
setExperimentValues(mapBuilder);
logger.debug("Successfully fetched experiments: " + getExperimentValues());
- scheduleNextRefresh(true /* refreshWasSuccessful */);
+ scheduleNextRefresh(/* refreshWasSuccessful */ true);
} catch (InterruptedException | ExecutionException | RuntimeException e) {
logger.debug("Error fetching experiments", e);
- scheduleNextRefresh(false /* refreshWasSuccessful */);
+ scheduleNextRefresh(/* refreshWasSuccessful */ false);
}
}
}
diff --git a/common/formatter/src/com/google/idea/common/formatter/DelegatingCodeStyleManager.java b/common/formatter/src/com/google/idea/common/formatter/DelegatingCodeStyleManager.java
index 354fea4..b5ab232 100644
--- a/common/formatter/src/com/google/idea/common/formatter/DelegatingCodeStyleManager.java
+++ b/common/formatter/src/com/google/idea/common/formatter/DelegatingCodeStyleManager.java
@@ -15,7 +15,7 @@
*/
package com.google.idea.common.formatter;
-import com.google.idea.sdkcompat.codestyle.CodeStyleManagerSdkCompatAdapter;
+import com.google.idea.sdkcompat.codestyle.DelegatingCodeStyleManagerSdkCompatAdapter;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.FileType;
@@ -32,12 +32,11 @@
import javax.annotation.Nullable;
/** A delegating {@link CodeStyleManager}. */
-public abstract class DelegatingCodeStyleManager extends CodeStyleManagerSdkCompatAdapter {
-
- private final CodeStyleManager delegate;
+public abstract class DelegatingCodeStyleManager
+ extends DelegatingCodeStyleManagerSdkCompatAdapter {
public DelegatingCodeStyleManager(CodeStyleManager delegate) {
- this.delegate = delegate;
+ super(delegate);
}
@Override
diff --git a/cpp/BUILD b/cpp/BUILD
index c157efc..bbf1c7e 100644
--- a/cpp/BUILD
+++ b/cpp/BUILD
@@ -1,18 +1,10 @@
licenses(["notice"]) # Apache 2.0
-load("//intellij_platform_sdk:build_defs.bzl", "select_for_plugin_api")
-
java_library(
name = "cpp",
srcs = glob(
["src/**/*.java"],
- exclude = [
- "src/com/google/idea/blaze/cpp/versioned/**",
- ],
- ) + select_for_plugin_api({
- "android-studio-145.1617.8": [":api_v145_sources"],
- "default": [":api_v162_sources"],
- }),
+ ),
visibility = ["//visibility:public"],
deps = [
"//base",
@@ -29,18 +21,6 @@
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(
"//testing:test_defs.bzl",
"intellij_unit_test_suite",
@@ -54,6 +34,7 @@
":cpp",
"//base:unit_test_utils",
"//intellij_platform_sdk:plugin_api_for_tests",
+ "//sdkcompat",
"@jsr305_annotations//jar",
"@junit//jar",
],
diff --git a/cpp/src/META-INF/blaze-cpp.xml b/cpp/src/META-INF/blaze-cpp.xml
index aa0fb37..158f6d8 100644
--- a/cpp/src/META-INF/blaze-cpp.xml
+++ b/cpp/src/META-INF/blaze-cpp.xml
@@ -17,6 +17,14 @@
<depends>com.intellij.modules.cidr.lang</depends>
<depends>com.intellij.modules.cidr.debugger</depends>
+ <application-components>
+ <component>
+ <implementation-class>
+ com.google.idea.blaze.cpp.CidrSymbolBuilderSuppressor
+ </implementation-class>
+ </component>
+ </application-components>
+
<extensions defaultExtensionNs="com.google.idea.blaze">
<SyncPlugin implementation="com.google.idea.blaze.cpp.BlazeCSyncPlugin"/>
<PrefetchFileSource implementation="com.google.idea.blaze.cpp.CPrefetchFileSource"/>
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
index 4168385..aa1736e 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCSyncPlugin.java
@@ -89,7 +89,7 @@
VirtualFile execRoot =
VirtualFileSystemProvider.getInstance()
.getSystem()
- .refreshAndFindFileByIoFile(blazeProjectData.blazeRoots.executionRoot);
+ .refreshAndFindFileByIoFile(blazeProjectData.blazeInfo.getExecutionRoot());
if (execRoot != null) {
VfsUtil.markDirtyAndRefresh(false, true, true, execRoot);
}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
index abcb294..c0f5b94 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCWorkspace.java
@@ -19,37 +19,26 @@
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.google.idea.sdkcompat.cidr.OCWorkspaceAdapter;
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 {
+public final class BlazeCWorkspace extends OCWorkspaceAdapter {
private static final Logger logger = Logger.getInstance(BlazeCWorkspace.class);
- @Nullable private final Project project;
- @Nullable private final OCWorkspaceModificationTrackers modTrackers;
-
- @Nullable private BlazeConfigurationResolver configurationResolver;
+ private final 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;
- }
+ super(project);
+ this.configurationResolver = new BlazeConfigurationResolver(project);
}
public static BlazeCWorkspace getInstance(Project project) {
@@ -57,13 +46,8 @@
}
public void update(BlazeContext context, BlazeProjectData blazeProjectData) {
- logger.assertTrue(project != null);
- logger.assertTrue(modTrackers != null);
- logger.assertTrue(configurationResolver != null);
-
- long start = System.currentTimeMillis();
-
// Non-incremental update to our c configurations.
+ long start = System.currentTimeMillis();
configurationResolver.update(context, blazeProjectData);
long end = System.currentTimeMillis();
@@ -97,29 +81,15 @@
return false;
}
- @Nullable
- @Override
- public OCResolveConfiguration getSelectedResolveConfiguration() {
- return null;
- }
-
- @Override
- public OCWorkspaceModificationTrackers getModificationTrackers() {
- logger.assertTrue(modTrackers != null);
- return modTrackers;
- }
-
@Override
public List<? extends OCResolveConfiguration> getConfigurations() {
- return configurationResolver == null
- ? ImmutableList.of()
- : configurationResolver.getAllConfigurations();
+ return configurationResolver.getAllConfigurations();
}
@Override
public List<? extends OCResolveConfiguration> getConfigurationsForFile(
@Nullable VirtualFile sourceFile) {
- if (sourceFile == null || !sourceFile.isValid() || configurationResolver == null) {
+ if (sourceFile == null || !sourceFile.isValid()) {
return ImmutableList.of();
}
OCResolveConfiguration config = configurationResolver.getConfigurationForFile(sourceFile);
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
index 28eba21..654a8e2 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerMacros.java
@@ -15,7 +15,6 @@
*/
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;
@@ -62,17 +61,20 @@
// 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..."
+ // IntelliJ expects a string of "#define [VAR_NAME] [VALUE]\n#define [VAR_NAME2] [VALUE]\n...",
+ // where VALUE is optional.
for (String globalDefine : globalDefines) {
- allDefinesBuilder.add("#define " + globalDefine);
- }
- if (compilerInfo != null) {
- String[] split = compilerInfo.defines.split("\n");
- for (String s : split) {
- allDefinesBuilder.add(s);
+ String[] split = globalDefine.split("=", 2);
+ if (split.length == 1) {
+ allDefinesBuilder.add("#define " + split[0]);
+ } else {
+ allDefinesBuilder.add("#define " + split[0] + " " + split[1]);
}
}
- final String allDefines = Joiner.on("\n").join(allDefinesBuilder.build());
+ String allDefines = String.join("\n", allDefinesBuilder.build());
+ if (compilerInfo != null) {
+ allDefines += "\n" + compilerInfo.defines;
+ }
Map<String, String> allFeatures = Maps.newHashMap();
allFeatures.putAll(globalFeatures);
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
index 966b37c..ccc178d 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCompilerSettings.java
@@ -15,21 +15,19 @@
*/
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.google.idea.sdkcompat.cidr.CidrSwitchBuilderAdapter;
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 {
@@ -56,7 +54,10 @@
@Override
public OCCompilerKind getCompiler(OCLanguageKind languageKind) {
- return null;
+ if (languageKind == OCLanguageKind.C || languageKind == OCLanguageKind.CPP) {
+ return OCCompilerKind.CLANG;
+ }
+ return OCCompilerKind.UNKNOWN;
}
@Override
@@ -89,25 +90,10 @@
if (lang == OCLanguageKind.CPP) {
return cppCompilerSwitches;
}
- return new CidrSwitchBuilder().build();
+ return new CidrSwitchBuilderAdapter().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();
+ return new CidrSwitchBuilderAdapter().addAllRaw(allCompilerFlags).build();
}
}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java b/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
index 5e6e8b9..d01798e 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeConfigurationResolver.java
@@ -17,15 +17,16 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.common.collect.ImmutableCollection;
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.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.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
@@ -33,12 +34,15 @@
import com.google.idea.blaze.base.io.FileAttributeProvider;
import com.google.idea.blaze.base.model.BlazeProjectData;
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.LanguageClass;
+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.ScopedFunction;
import com.google.idea.blaze.base.scope.output.IssueOutput;
import com.google.idea.blaze.base.scope.scopes.TimingScope;
+import com.google.idea.blaze.base.settings.Blaze;
import com.google.idea.blaze.base.sync.workspace.ExecutionRootPathResolver;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.blaze.base.targetmaps.SourceToTargetMap;
@@ -49,15 +53,20 @@
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import com.jetbrains.cidr.toolchains.CompilerInfoCache;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
final class BlazeConfigurationResolver {
@@ -83,15 +92,24 @@
public void update(BlazeContext context, BlazeProjectData blazeProjectData) {
ImmutableMap<TargetKey, CToolchainIdeInfo> toolchainLookupMap =
- BlazeResolveConfiguration.buildToolchainLookupMap(
- context, blazeProjectData.targetMap, blazeProjectData.reverseDependencies);
+ BlazeResolveConfiguration.buildToolchainLookupMap(context, blazeProjectData.targetMap);
ImmutableMap<File, VirtualFile> headerRoots =
collectHeaderRoots(context, blazeProjectData, toolchainLookupMap);
+ ImmutableMap<CToolchainIdeInfo, BlazeCompilerSettings> compilerSettings =
+ buildCompilerSettingsMap(
+ context, project, toolchainLookupMap, blazeProjectData.workspacePathResolver);
+ CompilerInfoCache compilerInfoCache = new CompilerInfoCache();
resolveConfigurations =
- buildBlazeConfigurationMap(context, blazeProjectData, toolchainLookupMap, headerRoots);
+ buildBlazeConfigurationMap(
+ context,
+ blazeProjectData,
+ toolchainLookupMap,
+ headerRoots,
+ compilerSettings,
+ compilerInfoCache);
}
- private static ImmutableMap<File, VirtualFile> collectHeaderRoots(
+ private ImmutableMap<File, VirtualFile> collectHeaderRoots(
BlazeContext parentContext,
BlazeProjectData blazeProjectData,
ImmutableMap<TargetKey, CToolchainIdeInfo> toolchainLookupMap) {
@@ -107,10 +125,14 @@
});
}
- private static ImmutableMap<File, VirtualFile> doCollectHeaderRoots(
+ private ImmutableMap<File, VirtualFile> doCollectHeaderRoots(
BlazeContext context, BlazeProjectData projectData, Set<ExecutionRootPath> rootPaths) {
ExecutionRootPathResolver pathResolver =
- new ExecutionRootPathResolver(projectData.blazeRoots, projectData.workspacePathResolver);
+ new ExecutionRootPathResolver(
+ Blaze.getBuildSystem(project),
+ WorkspaceRoot.fromProject(project),
+ projectData.blazeInfo.getExecutionRoot(),
+ projectData.workspacePathResolver);
ConcurrentMap<File, VirtualFile> rootsMap = Maps.newConcurrentMap();
List<ListenableFuture<Void>> futures = Lists.newArrayListWithCapacity(rootPaths.size());
for (ExecutionRootPath path : rootPaths) {
@@ -123,7 +145,7 @@
VirtualFile vf = getVirtualFile(file);
if (vf != null) {
rootsMap.put(file, vf);
- } else if (!projectData.blazeRoots.isOutputArtifact(path)
+ } else if (!isOutputArtifact(projectData.blazeInfo, path)
&& FileAttributeProvider.getInstance().exists(file)) {
// If it's not a blaze output file, we expect it to always resolve.
LOG.info(String.format("Unresolved header root %s", file.getAbsolutePath()));
@@ -145,17 +167,24 @@
return ImmutableMap.of();
}
+ private static boolean isOutputArtifact(BlazeInfo blazeInfo, ExecutionRootPath path) {
+ return ExecutionRootPath.isAncestor(blazeInfo.getBlazeGenfilesExecutionRootPath(), path, false)
+ || ExecutionRootPath.isAncestor(blazeInfo.getBlazeBinExecutionRootPath(), path, false);
+ }
+
private static Set<ExecutionRootPath> collectExecutionRootPaths(
TargetMap targetMap, ImmutableMap<TargetKey, CToolchainIdeInfo> toolchainLookupMap) {
Set<ExecutionRootPath> paths = Sets.newHashSet();
for (TargetIdeInfo target : targetMap.targets()) {
if (target.cIdeInfo != null) {
+ paths.addAll(target.cIdeInfo.localIncludeDirectories);
paths.addAll(target.cIdeInfo.transitiveSystemIncludeDirectories);
paths.addAll(target.cIdeInfo.transitiveIncludeDirectories);
paths.addAll(target.cIdeInfo.transitiveQuoteIncludeDirectories);
}
}
- for (CToolchainIdeInfo toolchain : toolchainLookupMap.values()) {
+ Set<CToolchainIdeInfo> toolchains = new LinkedHashSet<>(toolchainLookupMap.values());
+ for (CToolchainIdeInfo toolchain : toolchains) {
paths.addAll(toolchain.builtInIncludeDirectories);
paths.addAll(toolchain.unfilteredToolchainSystemIncludes);
}
@@ -176,7 +205,9 @@
BlazeContext parentContext,
BlazeProjectData blazeProjectData,
ImmutableMap<TargetKey, CToolchainIdeInfo> toolchainLookupMap,
- ImmutableMap<File, VirtualFile> headerRoots) {
+ ImmutableMap<File, VirtualFile> headerRoots,
+ ImmutableMap<CToolchainIdeInfo, BlazeCompilerSettings> compilerSettings,
+ CompilerInfoCache compilerInfoCache) {
// Type specification needed to avoid incorrect type inference during command line build.
return Scope.push(
parentContext,
@@ -184,11 +215,11 @@
context -> {
context.push(new TimingScope("Build C configuration map"));
- ConcurrentMap<CToolchainIdeInfo, File> compilerWrapperCache = Maps.newConcurrentMap();
List<ListenableFuture<MapEntry>> mapEntryFutures = Lists.newArrayList();
for (TargetIdeInfo target : blazeProjectData.targetMap.targets()) {
- if (target.kind.getLanguageClass() == LanguageClass.C) {
+ if (target.kind.getLanguageClass() == LanguageClass.C
+ && target.kind != Kind.CC_TOOLCHAIN) {
ListenableFuture<MapEntry> future =
submit(
() ->
@@ -196,8 +227,9 @@
target,
toolchainLookupMap,
headerRoots,
- compilerWrapperCache,
- blazeProjectData));
+ compilerSettings,
+ blazeProjectData,
+ compilerInfoCache));
mapEntryFutures.add(future);
}
}
@@ -236,64 +268,116 @@
TargetIdeInfo target,
ImmutableMap<TargetKey, CToolchainIdeInfo> toolchainLookupMap,
ImmutableMap<File, VirtualFile> headerRoots,
- ConcurrentMap<CToolchainIdeInfo, File> compilerWrapperCache,
- BlazeProjectData blazeProjectData) {
+ ImmutableMap<CToolchainIdeInfo, BlazeCompilerSettings> compilerSettingsMap,
+ BlazeProjectData blazeProjectData,
+ CompilerInfoCache compilerInfoCache) {
TargetKey targetKey = target.key;
-
CToolchainIdeInfo toolchainIdeInfo = toolchainLookupMap.get(targetKey);
- if (toolchainIdeInfo != null) {
- File compilerWrapper =
- findOrCreateCompilerWrapperScript(
- compilerWrapperCache,
- toolchainIdeInfo,
- blazeProjectData.workspacePathResolver,
- targetKey);
- if (compilerWrapper != null) {
- BlazeResolveConfiguration config =
- BlazeResolveConfiguration.createConfigurationForTarget(
- project,
- new ExecutionRootPathResolver(
- blazeProjectData.blazeRoots, blazeProjectData.workspacePathResolver),
- blazeProjectData.workspacePathResolver,
- headerRoots,
- blazeProjectData.targetMap.get(targetKey),
- toolchainIdeInfo,
- compilerWrapper);
- if (config != null) {
- return new MapEntry(targetKey, config);
+ if (toolchainIdeInfo == null) {
+ return null;
+ }
+ BlazeCompilerSettings compilerSettings = compilerSettingsMap.get(toolchainIdeInfo);
+ if (compilerSettings == null) {
+ return null;
+ }
+ BlazeResolveConfiguration config =
+ BlazeResolveConfiguration.createConfigurationForTarget(
+ project,
+ new ExecutionRootPathResolver(
+ Blaze.getBuildSystem(project),
+ WorkspaceRoot.fromProject(project),
+ blazeProjectData.blazeInfo.getExecutionRoot(),
+ blazeProjectData.workspacePathResolver),
+ blazeProjectData.workspacePathResolver,
+ headerRoots,
+ blazeProjectData.targetMap.get(targetKey),
+ toolchainIdeInfo,
+ compilerSettings,
+ compilerInfoCache);
+ if (config == null) {
+ return null;
+ }
+ return new MapEntry(targetKey, config);
+ }
+
+ private static ImmutableMap<CToolchainIdeInfo, BlazeCompilerSettings> buildCompilerSettingsMap(
+ BlazeContext context,
+ Project project,
+ ImmutableMap<TargetKey, CToolchainIdeInfo> toolchainLookupMap,
+ WorkspacePathResolver workspacePathResolver) {
+ Set<CToolchainIdeInfo> toolchains =
+ toolchainLookupMap.values().stream().distinct().collect(Collectors.toSet());
+ List<ListenableFuture<Map.Entry<CToolchainIdeInfo, BlazeCompilerSettings>>>
+ compilerSettingsFutures = new ArrayList<>();
+ for (CToolchainIdeInfo toolchain : toolchains) {
+ compilerSettingsFutures.add(
+ submit(
+ () -> {
+ BlazeCompilerSettings settings =
+ createBlazeCompilerSettings(project, toolchain, workspacePathResolver);
+ if (settings == null) {
+ return null;
+ }
+ return new SimpleImmutableEntry<>(toolchain, settings);
+ }));
+ }
+ ImmutableMap.Builder<CToolchainIdeInfo, BlazeCompilerSettings> compilerSettingsMap =
+ ImmutableMap.builder();
+ try {
+ List<Map.Entry<CToolchainIdeInfo, BlazeCompilerSettings>> createdSettings =
+ Futures.allAsList(compilerSettingsFutures).get();
+ for (Map.Entry<CToolchainIdeInfo, BlazeCompilerSettings> createdSetting : createdSettings) {
+ if (createdSetting != null) {
+ compilerSettingsMap.put(createdSetting);
}
}
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ context.setCancelled();
+ } catch (ExecutionException e) {
+ IssueOutput.error("Could not build C compiler settings map: " + e).submit(context);
+ LOG.error("Could not build C compiler settings map", e);
}
- return null;
+ return compilerSettingsMap.build();
}
@Nullable
- private static File findOrCreateCompilerWrapperScript(
- Map<CToolchainIdeInfo, File> compilerWrapperCache,
+ private static BlazeCompilerSettings createBlazeCompilerSettings(
+ Project project,
CToolchainIdeInfo toolchainIdeInfo,
- WorkspacePathResolver workspacePathResolver,
- TargetKey targetKey) {
- File compilerWrapper = compilerWrapperCache.get(toolchainIdeInfo);
+ WorkspacePathResolver workspacePathResolver) {
+ File compilerWrapper = getCompilerWrapper(toolchainIdeInfo, workspacePathResolver);
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(), targetKey);
- LOG.warn(errorMessage);
- compilerWrapper = null;
- } else {
- compilerWrapper = createCompilerExecutableWrapper(cppExecutable);
- if (compilerWrapper != null) {
- compilerWrapperCache.put(toolchainIdeInfo, compilerWrapper);
- }
- }
+ return null;
}
- return compilerWrapper;
+ 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);
+ return new BlazeCompilerSettings(
+ project, compilerWrapper, compilerWrapper, cFlagsBuilder.build(), cppFlagsBuilder.build());
+ }
+
+ @Nullable
+ private static File getCompilerWrapper(
+ CToolchainIdeInfo toolchainIdeInfo, WorkspacePathResolver workspacePathResolver) {
+ File cppExecutable = toolchainIdeInfo.cppExecutable.getAbsoluteOrRelativeFile();
+ if (cppExecutable != null && !cppExecutable.isAbsolute()) {
+ cppExecutable = workspacePathResolver.resolveToFile(cppExecutable.getPath());
+ }
+ if (cppExecutable == null) {
+ LOG.warn(
+ String.format(
+ "Unable to find compiler executable: %s for toolchain %s",
+ toolchainIdeInfo.cppExecutable.toString(), toolchainIdeInfo));
+ return null;
+ }
+ return createCompilerExecutableWrapper(cppExecutable);
}
/**
@@ -352,24 +436,21 @@
@Nullable
public OCResolveConfiguration getConfigurationForFile(VirtualFile sourceFile) {
SourceToTargetMap sourceToTargetMap = SourceToTargetMap.getInstance(project);
- List<TargetKey> targetsForSourceFile =
- Lists.newArrayList(
- sourceToTargetMap.getRulesForSourceFile(VfsUtilCore.virtualToIoFile(sourceFile)));
+ ImmutableCollection<TargetKey> targetsForSourceFile =
+ sourceToTargetMap.getRulesForSourceFile(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()));
- TargetKey targetKey = Iterables.getFirst(targetsForSourceFile, 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.
+ TargetKey targetKey = targetsForSourceFile.stream().min(TargetKey::compareTo).orElse(null);
assert (targetKey != null);
return resolveConfigurations.get(targetKey);
}
- public List<? extends OCResolveConfiguration> getAllConfigurations() {
- return ImmutableList.copyOf(resolveConfigurations.values());
+ ImmutableList<? extends OCResolveConfiguration> getAllConfigurations() {
+ return resolveConfigurations.values().asList();
}
}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeCppSymbolRebuildSyncListener.java b/cpp/src/com/google/idea/blaze/cpp/BlazeCppSymbolRebuildSyncListener.java
index 07b1743..fb9e190 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeCppSymbolRebuildSyncListener.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeCppSymbolRebuildSyncListener.java
@@ -21,12 +21,12 @@
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
import com.google.idea.blaze.base.sync.SyncListener;
+import com.google.idea.sdkcompat.cidr.OCWorkspaceModificationTrackersCompatUtils;
import com.google.idea.sdkcompat.transactions.Transactions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.jetbrains.cidr.lang.workspace.OCWorkspace;
import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
-import com.jetbrains.cidr.lang.workspace.OCWorkspaceModificationTrackers;
/** Runs after sync, triggering a rebuild of the symbol tables. */
public class BlazeCppSymbolRebuildSyncListener extends SyncListener.Adapter {
@@ -45,20 +45,16 @@
if (!(workspace instanceof BlazeCWorkspace)) {
return;
}
- rebuildSymbolTables((BlazeCWorkspace) workspace);
+ rebuildSymbolTables(project);
}
- private static void rebuildSymbolTables(BlazeCWorkspace workspace) {
- OCWorkspaceModificationTrackers modTrackers = workspace.getModificationTrackers();
+ private static void rebuildSymbolTables(Project project) {
Transactions.submitTransactionAndWait(
() ->
ApplicationManager.getApplication()
.runWriteAction(
- () -> {
- modTrackers.getProjectFilesListTracker().incModificationCount();
- modTrackers.getSourceFilesListTracker().incModificationCount();
- modTrackers.getBuildConfigurationChangesTracker().incModificationCount();
- modTrackers.getBuildSettingsChangesTracker().incModificationCount();
- }));
+ () ->
+ OCWorkspaceModificationTrackersCompatUtils.incrementModificationCounts(
+ project)));
}
}
diff --git a/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfigurationTemporaryBase.java b/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfiguration.java
similarity index 66%
rename from cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfigurationTemporaryBase.java
rename to cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfiguration.java
index 2b04ff2..6581b12 100644
--- a/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfigurationTemporaryBase.java
+++ b/cpp/src/com/google/idea/blaze/cpp/BlazeResolveConfiguration.java
@@ -18,9 +18,8 @@
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.Iterables;
import com.google.common.collect.Maps;
import com.google.idea.blaze.base.ideinfo.CIdeInfo;
import com.google.idea.blaze.base.ideinfo.CToolchainIdeInfo;
@@ -28,13 +27,18 @@
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.ideinfo.TargetMap;
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.LanguageClass;
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.workspace.ExecutionRootPathResolver;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
+import com.google.idea.sdkcompat.cidr.OCResolveConfigurationAdapter;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.jetbrains.cidr.lang.OCFileTypeHelpers;
@@ -52,22 +56,20 @@
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.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
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 {
+final class BlazeResolveConfiguration extends UserDataHolderBase
+ implements OCResolveConfigurationAdapter {
- public static final Logger LOG = Logger.getInstance(BlazeResolveConfiguration.class);
-
+ private static final Logger logger = Logger.getInstance(BlazeResolveConfiguration.class);
private final ExecutionRootPathResolver executionRootPathResolver;
private final WorkspacePathResolver workspacePathResolver;
@@ -78,10 +80,13 @@
private final ImmutableList<HeadersSearchRoot> cLibraryIncludeRoots;
private final ImmutableList<HeadersSearchRoot> cppLibraryIncludeRoots;
private final HeaderRoots projectIncludeRoots;
+ private final ConcurrentMap<Pair<OCLanguageKind, VirtualFile>, HeaderRoots> libraryIncludeRoots =
+ new ConcurrentHashMap<>();
private final CompilerInfoCache compilerInfoCache;
private final BlazeCompilerMacros compilerMacros;
private final BlazeCompilerSettings compilerSettings;
+ private final CToolchainIdeInfo toolchainIdeInfo;
@Nullable
public static BlazeResolveConfiguration createConfigurationForTarget(
@@ -91,7 +96,8 @@
ImmutableMap<File, VirtualFile> headerRoots,
TargetIdeInfo target,
CToolchainIdeInfo toolchainIdeInfo,
- File compilerWrapper) {
+ BlazeCompilerSettings compilerSettings,
+ CompilerInfoCache compilerInfoCache) {
CIdeInfo cIdeInfo = target.cIdeInfo;
if (cIdeInfo == null) {
return null;
@@ -104,19 +110,14 @@
ImmutableSet.Builder<ExecutionRootPath> userIncludesBuilder = ImmutableSet.builder();
userIncludesBuilder.addAll(cIdeInfo.transitiveIncludeDirectories);
+ userIncludesBuilder.addAll(cIdeInfo.localIncludeDirectories);
ImmutableSet.Builder<ExecutionRootPath> userQuoteIncludesBuilder = ImmutableSet.builder();
userQuoteIncludesBuilder.addAll(cIdeInfo.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);
+ ImmutableList.Builder<String> defines = ImmutableList.builder();
+ defines.addAll(cIdeInfo.transitiveDefines);
+ defines.addAll(cIdeInfo.localDefines);
ImmutableMap<String, String> features = ImmutableMap.of();
@@ -131,53 +132,80 @@
userQuoteIncludesBuilder.build(),
userIncludesBuilder.build(),
userIncludesBuilder.build(),
- cIdeInfo.transitiveDefines,
+ defines.build(),
features,
- compilerWrapper,
- compilerWrapper,
- cFlagsBuilder.build(),
- cppFlagsBuilder.build());
+ compilerSettings,
+ compilerInfoCache,
+ toolchainIdeInfo);
}
- public static ImmutableMap<TargetKey, CToolchainIdeInfo> buildToolchainLookupMap(
- BlazeContext context,
- TargetMap targetMap,
- ImmutableMultimap<TargetKey, TargetKey> reverseDependencies) {
+ static ImmutableMap<TargetKey, CToolchainIdeInfo> buildToolchainLookupMap(
+ BlazeContext context, TargetMap targetMap) {
return Scope.push(
context,
childContext -> {
childContext.push(new TimingScope("Build toolchain lookup map"));
- List<TargetKey> seeds = Lists.newArrayList();
+ Map<TargetKey, CToolchainIdeInfo> toolchains = Maps.newLinkedHashMap();
for (TargetIdeInfo target : targetMap.targets()) {
CToolchainIdeInfo cToolchainIdeInfo = target.cToolchainIdeInfo;
if (cToolchainIdeInfo != null) {
- seeds.add(target.key);
+ toolchains.put(target.key, cToolchainIdeInfo);
}
}
- Map<TargetKey, CToolchainIdeInfo> lookupTable = Maps.newHashMap();
- for (TargetKey seed : seeds) {
- CToolchainIdeInfo toolchainInfo = targetMap.get(seed).cToolchainIdeInfo;
- LOG.assertTrue(toolchainInfo != null);
- List<TargetKey> worklist = Lists.newArrayList(reverseDependencies.get(seed));
- while (!worklist.isEmpty()) {
- // We should never see a label depend on two different toolchains.
- TargetKey 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));
+ ImmutableMap.Builder<TargetKey, CToolchainIdeInfo> lookupTable = ImmutableMap.builder();
+ for (TargetIdeInfo target : targetMap.targets()) {
+ if (target.kind.getLanguageClass() != LanguageClass.C
+ || target.kind == Kind.CC_TOOLCHAIN) {
+ continue;
+ }
+ List<TargetKey> toolchainDeps =
+ target
+ .dependencies
+ .stream()
+ .map(dep -> dep.targetKey)
+ .filter(toolchains::containsKey)
+ .collect(Collectors.toList());
+ if (toolchainDeps.size() != 1) {
+ issueToolchainWarning(context, target, toolchainDeps);
+ }
+ if (!toolchainDeps.isEmpty()) {
+ TargetKey toolchainKey = toolchainDeps.get(0);
+ CToolchainIdeInfo toolchainInfo = toolchains.get(toolchainKey);
+ lookupTable.put(target.key, toolchainInfo);
+ } else {
+ CToolchainIdeInfo arbitraryToolchain = Iterables.getFirst(toolchains.values(), null);
+ if (arbitraryToolchain != null) {
+ lookupTable.put(target.key, arbitraryToolchain);
}
}
}
- return ImmutableMap.copyOf(lookupTable);
+ return lookupTable.build();
});
}
- public BlazeResolveConfigurationTemporaryBase(
+ private static void issueToolchainWarning(
+ BlazeContext context, TargetIdeInfo target, List<TargetKey> toolchainDeps) {
+ String warningMessage =
+ String.format(
+ "cc target %s does not depend on exactly 1 cc toolchain. " + " Found %d toolchains.",
+ target.key, toolchainDeps.size());
+ if (usesAppleCcToolchain(target)) {
+ logger.warn(warningMessage + " (apple_cc_toolchain)");
+ } else {
+ IssueOutput.warn(warningMessage).submit(context);
+ }
+ }
+
+ private static boolean usesAppleCcToolchain(TargetIdeInfo target) {
+ return target
+ .dependencies
+ .stream()
+ .anyMatch(dep -> dep.targetKey.label.toString().startsWith("//tools/osx/crosstool"));
+ }
+
+ public BlazeResolveConfiguration(
Project project,
ExecutionRootPathResolver executionRootPathResolver,
WorkspacePathResolver workspacePathResolver,
@@ -190,14 +218,14 @@
ImmutableCollection<ExecutionRootPath> cppIncludeDirs,
ImmutableCollection<String> defines,
ImmutableMap<String, String> features,
- File cCompilerExecutable,
- File cppCompilerExecutable,
- ImmutableList<String> cCompilerFlags,
- ImmutableList<String> cppCompilerFlags) {
+ BlazeCompilerSettings compilerSettings,
+ CompilerInfoCache compilerInfoCache,
+ CToolchainIdeInfo toolchainIdeInfo) {
this.executionRootPathResolver = executionRootPathResolver;
this.workspacePathResolver = workspacePathResolver;
this.project = project;
this.targetKey = targetKey;
+ this.toolchainIdeInfo = toolchainIdeInfo;
ImmutableList.Builder<HeadersSearchRoot> cIncludeRootsBuilder = ImmutableList.builder();
collectHeaderRoots(headerRoots, cIncludeRootsBuilder, cIncludeDirs, true /* isUserHeader */);
@@ -217,11 +245,8 @@
headerRoots, quoteIncludeRootsBuilder, quoteIncludeDirs, true /* isUserHeader */);
this.projectIncludeRoots = new HeaderRoots(quoteIncludeRootsBuilder.build());
- this.compilerSettings =
- new BlazeCompilerSettings(
- project, cCompilerExecutable, cppCompilerExecutable, cCompilerFlags, cppCompilerFlags);
-
- this.compilerInfoCache = new CompilerInfoCache();
+ this.compilerSettings = compilerSettings;
+ this.compilerInfoCache = compilerInfoCache;
this.compilerMacros =
new BlazeCompilerMacros(project, compilerInfoCache, compilerSettings, defines, features);
}
@@ -242,12 +267,6 @@
@Nullable
@Override
- public VirtualFile getPrecompiledHeader() {
- return null;
- }
-
- @Nullable
- @Override
public OCLanguageKind getDeclaredLanguageKind(VirtualFile sourceOrHeaderFile) {
String fileName = sourceOrHeaderFile.getName();
if (OCFileTypeHelpers.isSourceFile(fileName)) {
@@ -268,8 +287,7 @@
@Nullable
private VirtualFile getSourceFileForHeaderFile(VirtualFile headerFile) {
- ArrayList<VirtualFile> roots =
- new ArrayList<>(OCImportGraph.getAllHeaderRoots(project, headerFile));
+ Collection<VirtualFile> roots = OCImportGraph.getAllHeaderRoots(project, headerFile);
final String headerNameWithoutExtension = headerFile.getNameWithoutExtension();
for (VirtualFile root : roots) {
@@ -281,11 +299,6 @@
}
@Override
- public OCLanguageKind getPrecompiledLanguageKind() {
- return getMaximumLanguageKind();
- }
-
- @Override
public OCLanguageKind getMaximumLanguageKind() {
return OCLanguageKind.CPP;
}
@@ -302,21 +315,27 @@
if (languageKind == null) {
languageKind = getLanguageKind(sourceFile);
}
+ Pair<OCLanguageKind, VirtualFile> cacheKey = Pair.create(languageKind, sourceFile);
+ return libraryIncludeRoots.computeIfAbsent(
+ cacheKey,
+ key -> {
+ OCLanguageKind lang = key.first;
+ VirtualFile source = key.second;
+ ImmutableSet.Builder<HeadersSearchRoot> roots = ImmutableSet.builder();
+ if (lang == OCLanguageKind.C) {
+ roots.addAll(cLibraryIncludeRoots);
+ } else {
+ roots.addAll(cppLibraryIncludeRoots);
+ }
- 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());
+ CidrCompilerResult<CompilerInfoCache.Entry> compilerInfoCacheHolder =
+ compilerInfoCache.getCompilerInfoCache(project, compilerSettings, lang, source);
+ CompilerInfoCache.Entry compilerInfo = compilerInfoCacheHolder.getResult();
+ if (compilerInfo != null) {
+ roots.addAll(compilerInfo.headerSearchPaths);
+ }
+ return new HeaderRoots(roots.build().asList());
+ });
}
private void collectHeaderRoots(
@@ -346,10 +365,9 @@
return compilerSettings;
}
- @Nullable
@Override
public Object getIndexingCluster() {
- return null;
+ return toolchainIdeInfo;
}
@Override
@@ -376,4 +394,35 @@
BlazeResolveConfiguration that = (BlazeResolveConfiguration) obj;
return compareTo(that) == 0;
}
+
+ /* This function is part of the v162/v163 plugin APIs. */
+ @Nullable
+ @Override
+ public VirtualFile getPrecompiledHeader() {
+ return null;
+ }
+
+ /* This function is part of the v162/v163 plugin APIs. */
+ @Override
+ public OCLanguageKind getPrecompiledLanguageKind() {
+ return getMaximumLanguageKind();
+ }
+
+ /* This function is part of the v171 plugin API. */
+ @Override
+ public Set<VirtualFile> getPrecompiledHeaders() {
+ return ImmutableSet.of();
+ }
+
+ /* This function is part of the v171 plugin API. */
+ @Override
+ public List<VirtualFile> getPrecompiledHeaders(OCLanguageKind kind, VirtualFile sourceFile) {
+ return ImmutableList.of();
+ }
+
+ /* This function is part of the v171 plugin API. */
+ @Override
+ public Collection<VirtualFile> getSources() {
+ return ImmutableList.of();
+ }
}
diff --git a/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java b/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java
index ff0b0ed..4e63e71 100644
--- a/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java
+++ b/cpp/src/com/google/idea/blaze/cpp/CPrefetchFileSource.java
@@ -18,6 +18,7 @@
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.base.projectview.ProjectViewSet;
import com.intellij.openapi.project.Project;
import java.io.File;
import java.util.Collection;
@@ -27,7 +28,10 @@
public class CPrefetchFileSource implements PrefetchFileSource {
@Override
public void addFilesToPrefetch(
- Project project, BlazeProjectData blazeProjectData, Collection<File> files) {}
+ Project project,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<File> files) {}
@Override
public Set<String> prefetchSrcFileExtensions() {
diff --git a/cpp/src/com/google/idea/blaze/cpp/CidrSymbolBuilderSuppressor.java b/cpp/src/com/google/idea/blaze/cpp/CidrSymbolBuilderSuppressor.java
new file mode 100644
index 0000000..1abc384
--- /dev/null
+++ b/cpp/src/com/google/idea/blaze/cpp/CidrSymbolBuilderSuppressor.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.extensions.ExtensionPoint;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.extensions.LoadingOrder;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.startup.StartupActivity;
+
+/**
+ * cidr-lang usually registers some StartupActivity instances that get run on project open to
+ * rebuild symbols. This causes problems with blaze projects because this happens before the project
+ * configuration has been set up. CLwB/ASwB trigger a symbol rebuild after the startup sync.
+ */
+public class CidrSymbolBuilderSuppressor implements ApplicationComponent {
+ private static final ImmutableList<Class<? extends StartupActivity>>
+ STARTUP_ACTIVITIES_TO_SUPPRESS =
+ ImmutableList.of(
+ com.jetbrains.cidr.lang.symbols.symtable.OCInitialTablesBuildingActivity.class,
+ com.jetbrains.cidr.modulemap.resolve.ModuleMapInitialBuildingActivity.class);
+
+ private void addFiltersToStartupActivities() {
+ ExtensionPoint<StartupActivity> ep =
+ Extensions.getRootArea().getExtensionPoint(StartupActivity.POST_STARTUP_ACTIVITY);
+ for (Class<? extends StartupActivity> startupActivity : STARTUP_ACTIVITIES_TO_SUPPRESS) {
+ StartupActivity startupActivityInstance =
+ StartupActivity.POST_STARTUP_ACTIVITY.findExtension(startupActivity);
+ Preconditions.checkNotNull(startupActivityInstance);
+ StartupActivity replacementStartupActivity =
+ new BlazeSuppressStartupActivity(startupActivityInstance);
+ ep.registerExtension(
+ replacementStartupActivity, LoadingOrder.before(startupActivity.getSimpleName()));
+ ep.unregisterExtension(startupActivityInstance);
+ }
+ }
+
+ @Override
+ public void initComponent() {
+ addFiltersToStartupActivities();
+ }
+
+ @Override
+ public void disposeComponent() {}
+
+ @Override
+ public String getComponentName() {
+ return "CidrSymbolBuilderSuppressor";
+ }
+
+ private static class BlazeSuppressStartupActivity implements StartupActivity {
+ final StartupActivity original;
+
+ private BlazeSuppressStartupActivity(StartupActivity original) {
+ this.original = original;
+ }
+
+ @Override
+ public void runActivity(Project project) {
+ if (!Blaze.isBlazeProject(project)) {
+ original.runActivity(project);
+ }
+ }
+ }
+}
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
deleted file mode 100644
index b2d63a0..0000000
--- a/cpp/src/com/google/idea/blaze/cpp/versioned/v145/BlazeResolveConfiguration.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.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.idea.blaze.base.ideinfo.TargetKey;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.sync.workspace.ExecutionRootPathResolver;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-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,
- ExecutionRootPathResolver executionRootPathResolver,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<File, VirtualFile> headerRoots,
- TargetKey targetKey,
- 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,
- executionRootPathResolver,
- workspacePathResolver,
- headerRoots,
- targetKey,
- 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 targetKey.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
deleted file mode 100644
index 959936b..0000000
--- a/cpp/src/com/google/idea/blaze/cpp/versioned/v162/BlazeResolveConfiguration.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.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.ideinfo.TargetKey;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
-import com.google.idea.blaze.base.sync.workspace.ExecutionRootPathResolver;
-import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vfs.VirtualFile;
-import java.io.File;
-
-final class BlazeResolveConfiguration extends BlazeResolveConfigurationTemporaryBase {
-
- public BlazeResolveConfiguration(
- Project project,
- ExecutionRootPathResolver executionRootPathResolver,
- WorkspacePathResolver workspacePathResolver,
- ImmutableMap<File, VirtualFile> headerRoots,
- TargetKey targetKey,
- 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,
- executionRootPathResolver,
- workspacePathResolver,
- headerRoots,
- targetKey,
- cSystemIncludeDirs,
- cppSystemIncludeDirs,
- quoteIncludeDirs,
- cIncludeDirs,
- cppIncludeDirs,
- defines,
- features,
- cCompilerExecutable,
- cppCompilerExecutable,
- cCompilerFlags,
- cppCompilerFlags);
- }
-}
diff --git a/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java b/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
index 317d838..a1e748c 100644
--- a/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
+++ b/cpp/tests/unittests/com/google/idea/blaze/cpp/BlazeCompilerSettingsTest.java
@@ -19,6 +19,7 @@
import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.sdkcompat.cidr.CidrCompilerSwitchesAdapter;
import com.jetbrains.cidr.lang.OCLanguageKind;
import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
import java.io.File;
@@ -39,43 +40,7 @@
new BlazeCompilerSettings(getProject(), cppExe, cppExe, cFlags, cFlags);
CidrCompilerSwitches compilerSwitches = settings.getCompilerSwitches(OCLanguageKind.C, null);
- List<String> commandLineArgs = compilerSwitches.getFileArgs();
+ List<String> commandLineArgs = CidrCompilerSwitchesAdapter.getFileArgs(compilerSwitches);
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/golang/src/com/google/idea/blaze/golang/sync/BlazeGoSyncPlugin.java b/golang/src/com/google/idea/blaze/golang/sync/BlazeGoSyncPlugin.java
index 7f2a5c7..d65c8e6 100644
--- a/golang/src/com/google/idea/blaze/golang/sync/BlazeGoSyncPlugin.java
+++ b/golang/src/com/google/idea/blaze/golang/sync/BlazeGoSyncPlugin.java
@@ -23,6 +23,7 @@
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.plugin.PluginUtils;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.IssueOutput;
@@ -34,10 +35,7 @@
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.golang.sdk.GoSdkUtil;
import com.google.idea.sdkcompat.transactions.Transactions;
-import com.intellij.ide.plugins.IdeaPluginDescriptor;
-import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.module.ModuleTypeManager;
@@ -51,10 +49,7 @@
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
-import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.PluginsAdvertiser;
-import com.intellij.openapi.util.EmptyRunnable;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.pom.NavigatableAdapter;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
@@ -155,7 +150,8 @@
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.GO)) {
return null;
}
@@ -164,41 +160,22 @@
@Override
public boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.GO)) {
return true;
}
- if (!isPluginEnabled()) {
+ if (!PluginUtils.isPluginEnabled(GO_PLUGIN_ID)) {
IssueOutput.error("Go plugin needed for Go language support.")
- .navigatable(
- new NavigatableAdapter() {
- @Override
- public void navigate(boolean requestFocus) {
- if (isPluginInstalled()) {
- PluginManager.enablePlugin(GO_PLUGIN_ID);
- } else {
- PluginsAdvertiser.installAndEnablePlugins(
- ImmutableSet.of(GO_PLUGIN_ID), EmptyRunnable.INSTANCE);
- }
- }
- })
+ .navigatable(PluginUtils.installOrEnablePluginNavigable(GO_PLUGIN_ID))
.submit(context);
return false;
}
return true;
}
- private static boolean isPluginInstalled() {
- return PluginManager.isPluginInstalled(PluginId.getId(GO_PLUGIN_ID));
- }
-
- private static boolean isPluginEnabled() {
- IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId(GO_PLUGIN_ID));
- return plugin != null && plugin.isEnabled();
- }
-
@Override
public void updateProjectSdk(
Project project,
diff --git a/golang/tests/unittests/com/google/idea/blaze/golang/sync/BlazeGoSyncPluginTest.java b/golang/tests/unittests/com/google/idea/blaze/golang/sync/BlazeGoSyncPluginTest.java
index e563a27..fe0cf37 100644
--- a/golang/tests/unittests/com/google/idea/blaze/golang/sync/BlazeGoSyncPluginTest.java
+++ b/golang/tests/unittests/com/google/idea/blaze/golang/sync/BlazeGoSyncPluginTest.java
@@ -71,7 +71,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
errorCollector.assertNoIssues();
assertThat(workspaceLanguageSettings)
.isEqualTo(
@@ -109,7 +109,9 @@
.add(ListSection.builder(AdditionalLanguagesSection.KEY).add(LanguageClass.GO))
.build())
.build();
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
+ LanguageSupport.validateLanguageSettings(context, workspaceLanguageSettings);
errorCollector.assertIssueContaining(
"Language 'go' is not supported for this plugin with workspace type: 'java'");
}
diff --git a/ijwb/BUILD b/ijwb/BUILD
index 55b2b72..ea9be4f 100644
--- a/ijwb/BUILD
+++ b/ijwb/BUILD
@@ -20,8 +20,9 @@
"//golang:plugin_xml",
"//java:plugin_xml",
"//plugin_dev:plugin_xml",
+ "//python:plugin_xml",
+ "//scala:plugin_xml",
],
- visibility = ["//visibility:public"],
)
merged_plugin_xml(
@@ -34,6 +35,7 @@
stamped_plugin_xml(
name = "stamped_plugin_xml",
+ changelog_file = "//:changelog",
include_product_code_in_stamp = True,
plugin_id = "com.google.idea.bazel.ijwb",
plugin_name = "IntelliJ with Bazel",
@@ -45,21 +47,33 @@
java_library(
name = "ijwb_lib",
srcs = glob(["src/**/*.java"]),
- visibility = ["//visibility:public"],
exports = [
"//plugin_dev",
],
+ runtime_deps = [
+ "//golang",
+ "//python",
+ "//terminal",
+ ],
deps = [
"//base",
- "//golang",
"//intellij_platform_sdk:plugin_api",
"//java",
+ "//scala",
+ "//sdkcompat",
"@jsr305_annotations//jar",
],
)
+OPTIONAL_PLUGIN_XMLS = [
+ "//scala:optional_xml",
+ "//python:optional_xml",
+ "//terminal:optional_xml",
+]
+
intellij_plugin(
name = "ijwb_bazel",
+ optional_plugin_xmls = OPTIONAL_PLUGIN_XMLS,
plugin_xml = ":stamped_plugin_xml",
deps = [
":ijwb_lib",
diff --git a/ijwb/src/META-INF/ijwb.xml b/ijwb/src/META-INF/ijwb.xml
index e4dc577..805e46e 100644
--- a/ijwb/src/META-INF/ijwb.xml
+++ b/ijwb/src/META-INF/ijwb.xml
@@ -26,7 +26,7 @@
<SyncPlugin implementation="com.google.idea.blaze.ijwb.javascript.BlazeJavascriptSyncPlugin"/>
<SyncPlugin implementation="com.google.idea.blaze.ijwb.typescript.BlazeTypescriptSyncPlugin"/>
<SyncPlugin implementation="com.google.idea.blaze.ijwb.dart.BlazeDartSyncPlugin"/>
- <java.JavaSyncAugmenter implementation="com.google.idea.blaze.ijwb.android.BlazeAndroidLiteJavaSyncAugmenter"/>
+ <JavaSyncAugmenter implementation="com.google.idea.blaze.ijwb.android.BlazeAndroidLiteJavaSyncAugmenter"/>
</extensions>
</idea-plugin>
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 69ec1d8..c7a5e99 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteJavaSyncAugmenter.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteJavaSyncAugmenter.java
@@ -47,12 +47,12 @@
// Add R.java jars
LibraryArtifact resourceJar = androidIdeInfo.resourceJar;
if (resourceJar != null) {
- jars.add(new BlazeJarLibrary(resourceJar, target.key));
+ jars.add(new BlazeJarLibrary(resourceJar));
}
LibraryArtifact idlJar = androidIdeInfo.idlJar;
if (idlJar != null) {
- genJars.add(new BlazeJarLibrary(idlJar, target.key));
+ genJars.add(new BlazeJarLibrary(idlJar));
}
}
}
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 4a9612d..5f3e545 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPlugin.java
@@ -15,11 +15,26 @@
*/
package com.google.idea.blaze.ijwb.android;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.ideinfo.AndroidSdkIdeInfo;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.TargetMap;
+import com.google.idea.blaze.base.model.BlazeLibrary;
+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.sync.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.libraries.LibrarySource;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
/** Rudimentary support for android in IntelliJ. */
public class BlazeAndroidLiteSyncPlugin extends BlazeSyncPlugin.Adapter {
@@ -33,4 +48,50 @@
return ImmutableSet.of();
}
}
+
+ @Nullable
+ @Override
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
+ if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.ANDROID)) {
+ return null;
+ }
+ BlazeLibrary sdkLibrary = getSdkLibrary(blazeProjectData);
+ if (sdkLibrary == null) {
+ return null;
+ }
+ return new LibrarySource.Adapter() {
+ @Override
+ public Collection<? extends BlazeLibrary> getLibraries() {
+ return ImmutableList.of(sdkLibrary);
+ }
+ };
+ }
+
+ @Nullable
+ private static BlazeLibrary getSdkLibrary(BlazeProjectData blazeProjectData) {
+ List<AndroidSdkIdeInfo> sdkTargets = androidSdkTargets(blazeProjectData.targetMap);
+ if (sdkTargets.isEmpty()) {
+ return null;
+ }
+ // for now, just add the first one found
+ // TODO: warn if there's more than one
+ ArtifactLocation sdk =
+ sdkTargets
+ .stream()
+ .map(info -> info.androidJar)
+ .filter(Objects::nonNull)
+ .findFirst()
+ .orElse(null);
+ return sdk != null ? new BlazeJarLibrary(new LibraryArtifact(null, sdk, null)) : null;
+ }
+
+ private static List<AndroidSdkIdeInfo> androidSdkTargets(TargetMap targetMap) {
+ return targetMap
+ .targets()
+ .stream()
+ .map(target -> target.androidSdkIdeInfo)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartLibrarySource.java b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartLibrarySource.java
index 8772ee3..0bfbbf0 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartLibrarySource.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartLibrarySource.java
@@ -16,6 +16,7 @@
package com.google.idea.blaze.ijwb.dart;
import com.google.idea.blaze.base.sync.libraries.LibrarySource;
+import com.google.idea.sdkcompat.dart.DartSdkCompatUtils;
import com.intellij.openapi.roots.libraries.Library;
import java.util.function.Predicate;
import javax.annotation.Nullable;
@@ -28,7 +29,7 @@
public Predicate<Library> getGcRetentionFilter() {
return library -> {
String libraryName = library.getName();
- return libraryName != null && libraryName.equals(BlazeDartSyncPlugin.DART_SDK_LIBRARY_NAME);
+ return libraryName != null && libraryName.equals(DartSdkCompatUtils.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 f0049d7..6bc8f5b 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPlugin.java
@@ -20,17 +20,17 @@
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.plugin.PluginUtils;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
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.libraries.LibrarySource;
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
-import com.google.idea.blaze.ijwb.ide.IdeCheck;
+import com.google.idea.sdkcompat.dart.DartSdkCompatUtils;
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.ApplicationLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import java.util.Set;
import javax.annotation.Nullable;
@@ -38,7 +38,6 @@
/** Supports dart. */
public class BlazeDartSyncPlugin extends BlazeSyncPlugin.Adapter {
- static final String DART_SDK_LIBRARY_NAME = "Dart SDK";
private static final String DART_PLUGIN_ID = "Dart";
@Override
@@ -61,8 +60,7 @@
return;
}
- Library dartSdkLibrary =
- ApplicationLibraryTable.getApplicationTable().getLibraryByName(DART_SDK_LIBRARY_NAME);
+ Library dartSdkLibrary = DartSdkCompatUtils.findDartLibrary(project);
if (dartSdkLibrary != null) {
if (workspaceModifiableModel.findLibraryOrderEntry(dartSdkLibrary) == null) {
workspaceModifiableModel.addLibraryEntry(dartSdkLibrary);
@@ -78,14 +76,17 @@
@Override
public boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.DART)) {
return true;
}
- if (!IdeCheck.isPluginEnabled(DART_PLUGIN_ID)) {
- IssueOutput.error("Dart plugin needed for Dart language support.").submit(context);
+ if (!PluginUtils.isPluginEnabled(DART_PLUGIN_ID)) {
+ IssueOutput.error("Dart plugin needed for Dart language support.")
+ .navigatable(PluginUtils.installOrEnablePluginNavigable(DART_PLUGIN_ID))
+ .submit(context);
return false;
}
return true;
@@ -93,7 +94,8 @@
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.DART)) {
return null;
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.java b/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.java
deleted file mode 100644
index 617b9a7..0000000
--- a/ijwb/src/com/google/idea/blaze/ijwb/ide/IdeCheck.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.ijwb.ide;
-
-import com.intellij.ide.plugins.IdeaPluginDescriptor;
-import com.intellij.ide.plugins.PluginManager;
-import com.intellij.openapi.extensions.PluginId;
-
-/** IDE and plugin checks. */
-public class IdeCheck {
- public static boolean isPluginEnabled(String pluginIdString) {
- PluginId pluginId = PluginId.getId(pluginIdString);
- if (!PluginManager.isPluginInstalled(pluginId)) {
- return false;
- }
- IdeaPluginDescriptor plugin = PluginManager.getPlugin(pluginId);
- if (plugin == null) {
- return false;
- }
- return plugin.isEnabled();
- }
-}
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 c684726..a7c376a 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPlugin.java
@@ -22,6 +22,7 @@
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.plugin.PluginUtils;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.IssueOutput;
@@ -46,6 +47,8 @@
/** Allows people to use a javascript-only workspace. */
public class BlazeJavascriptSyncPlugin extends BlazeSyncPlugin.Adapter {
+ private static final String JAVASCRIPT_PLUGIN_ID = "JavaScript";
+
@Nullable
@Override
public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
@@ -57,12 +60,16 @@
@Override
public ImmutableList<WorkspaceType> getSupportedWorkspaceTypes() {
- return ImmutableList.of(WorkspaceType.JAVASCRIPT);
+ return PlatformUtils.isIdeaUltimate()
+ ? ImmutableList.of(WorkspaceType.JAVASCRIPT)
+ : ImmutableList.of();
}
@Override
public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- return ImmutableSet.of(LanguageClass.JAVASCRIPT);
+ return PlatformUtils.isIdeaUltimate()
+ ? ImmutableSet.of(LanguageClass.JAVASCRIPT)
+ : ImmutableSet.of();
}
@Nullable
@@ -114,7 +121,8 @@
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.JAVASCRIPT)) {
return null;
}
@@ -123,16 +131,25 @@
@Override
public boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.JAVASCRIPT)) {
return true;
}
- if (!ApplicationManager.getApplication().isUnitTestMode() && !PlatformUtils.isIdeaUltimate()) {
+ if (!PlatformUtils.isIdeaUltimate()) {
IssueOutput.error("IntelliJ Ultimate needed for Javascript support.").submit(context);
return false;
}
+ if (!ApplicationManager.getApplication().isUnitTestMode()
+ && !PluginUtils.isPluginEnabled(JAVASCRIPT_PLUGIN_ID)) {
+ IssueOutput.error(
+ "Javascript support is disabled: please install/enable the JetBrains Javascript "
+ + "plugin, then restart the IDE")
+ .submit(context);
+ return false;
+ }
return true;
}
}
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 e013c14..8d8ab1a 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPlugin.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPlugin.java
@@ -22,6 +22,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.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
import com.google.idea.blaze.base.model.BlazeProjectData;
@@ -42,7 +43,6 @@
import com.google.idea.blaze.base.sync.libraries.LibrarySource;
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.intellij.openapi.module.Module;
@@ -51,7 +51,9 @@
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.util.PlatformUtils;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.Nullable;
@@ -62,7 +64,9 @@
@Override
public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
- return ImmutableSet.of(LanguageClass.TYPESCRIPT);
+ return PlatformUtils.isIdeaUltimate()
+ ? ImmutableSet.of(LanguageClass.TYPESCRIPT)
+ : ImmutableSet.of();
}
@Override
@@ -72,7 +76,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
@Nullable WorkingSet workingSet,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
@@ -83,8 +87,8 @@
return;
}
- Label tsConfig = projectViewSet.getScalarValue(TsConfigRuleSection.KEY);
- if (tsConfig == null) {
+ Set<Label> tsConfigTargets = getTsConfigTargets(projectViewSet);
+ if (tsConfigTargets.isEmpty()) {
invalidProjectViewError(context);
return;
}
@@ -96,8 +100,10 @@
childContext.output(new StatusOutput("Updating tsconfig..."));
BlazeCommand command =
- BlazeCommand.builder(Blaze.getBuildSystem(project), BlazeCommandName.RUN)
- .addTargets(tsConfig)
+ BlazeCommand.builder(
+ Blaze.getBuildSystemProvider(project).getSyncBinaryPath(),
+ BlazeCommandName.RUN)
+ .addTargets(new ArrayList<>(tsConfigTargets))
.addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
.build();
@@ -143,6 +149,7 @@
@Override
public boolean validateProjectView(
+ @Nullable Project project,
BlazeContext context,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
@@ -153,9 +160,8 @@
return false;
}
- // Must have either both typescript and ts_config_rule or neither
- Label tsConfig = projectViewSet.getScalarValue(TsConfigRuleSection.KEY);
- if (typescriptActive ^ (tsConfig != null)) {
+ // Must have either both typescript and ts_config_rules or neither
+ if (typescriptActive ^ !getTsConfigTargets(projectViewSet).isEmpty()) {
invalidProjectViewError(context);
return false;
}
@@ -165,19 +171,29 @@
private void invalidProjectViewError(BlazeContext context) {
IssueOutput.error(
- "For Typescript support you must add both additional_languages: "
- + "typescript and the ts_config_rule attribute.")
+ "For Typescript support you must add both `additional_languages`: "
+ + "typescript and the `ts_config_rules` attribute.")
.submit(context);
}
+ private static Set<Label> getTsConfigTargets(ProjectViewSet projectViewSet) {
+ Label oldSectionType = projectViewSet.getScalarValue(TsConfigRuleSection.KEY);
+ Set<Label> labels = new LinkedHashSet<>(projectViewSet.listItems(TsConfigRulesSection.KEY));
+ if (oldSectionType != null) {
+ labels.add(oldSectionType);
+ }
+ return labels;
+ }
+
@Override
public Collection<SectionParser> getSections() {
- return ImmutableList.of(TsConfigRuleSection.PARSER);
+ return ImmutableList.of(TsConfigRuleSection.PARSER, TsConfigRulesSection.PARSER);
}
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.TYPESCRIPT)) {
return null;
}
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 aa3caff..e0f0d5b 100644
--- a/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRuleSection.java
+++ b/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRuleSection.java
@@ -28,6 +28,7 @@
import javax.annotation.Nullable;
/** Points to the ts_config rule. */
+@Deprecated
public class TsConfigRuleSection {
public static final SectionKey<Label, ScalarSection<Label>> KEY = SectionKey.of("ts_config_rule");
public static final SectionParser PARSER = new TsConfigRuleSectionParser();
@@ -45,7 +46,7 @@
parseContext.addErrors(errors);
return null;
}
- return new Label(rest);
+ return Label.create(rest);
}
@Override
@@ -57,5 +58,16 @@
public ItemType getItemType() {
return ItemType.Label;
}
+
+ @Override
+ public boolean isDeprecated() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public String getDeprecationMessage() {
+ return "Use `ts_config_rules` instead, which allows specifying multiple `ts_config` targets.";
+ }
}
}
diff --git a/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRulesSection.java b/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRulesSection.java
new file mode 100644
index 0000000..8de392a
--- /dev/null
+++ b/ijwb/src/com/google/idea/blaze/ijwb/typescript/TsConfigRulesSection.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.typescript;
+
+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;
+
+/** Points to 'ts_config' rules. */
+public class TsConfigRulesSection {
+ public static final SectionKey<Label, ListSection<Label>> KEY = SectionKey.of("ts_config_rules");
+ public static final SectionParser PARSER = new LabelSectionParser(KEY);
+}
diff --git a/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/javascript/JavascriptSyncTest.java b/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/javascript/JavascriptSyncTest.java
index 5174f96..def1b77 100644
--- a/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/javascript/JavascriptSyncTest.java
+++ b/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/javascript/JavascriptSyncTest.java
@@ -18,12 +18,14 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.TestUtils;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.sync.BlazeSyncIntegrationTestCase;
import com.google.idea.blaze.base.sync.BlazeSyncParams;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.SourceFolder;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.PlatformUtils;
import javax.annotation.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,6 +37,7 @@
@Test
public void testSimpleTestSourcesIdentified() {
+ TestUtils.setPlatformPrefix(getTestRootDisposable(), PlatformUtils.IDEA_PREFIX);
setProjectView(
"directories:",
" common/jslayout/calendar",
@@ -75,6 +78,7 @@
@Test
public void testTestSourcesMissingFromDirectoriesSectionAreAdded() {
+ TestUtils.setPlatformPrefix(getTestRootDisposable(), PlatformUtils.IDEA_PREFIX);
setProjectView(
"directories:",
" common/jslayout",
@@ -107,6 +111,7 @@
@Test
public void testTestSourceChildrenAreNotAddedAsSourceFolders() {
+ TestUtils.setPlatformPrefix(getTestRootDisposable(), PlatformUtils.IDEA_PREFIX);
// child directories of test sources are always test sources, so they should never
// appear as separate SourceFolders.
setProjectView(
@@ -144,6 +149,26 @@
assertThat(testRoot.isTestSource()).isTrue();
}
+ @Test
+ public void testUsefulErrorMessageInCommunityEdition() {
+ TestUtils.setPlatformPrefix(getTestRootDisposable(), PlatformUtils.IDEA_CE_PREFIX);
+ setProjectView(
+ "directories:",
+ " common/jslayout",
+ "targets:",
+ " //common/jslayout/...:all",
+ "workspace_type: javascript");
+
+ workspace.createDirectory(new WorkspacePath("common/jslayout"));
+
+ BlazeSyncParams syncParams =
+ new BlazeSyncParams.Builder("Full Sync", BlazeSyncParams.SyncMode.FULL)
+ .addProjectViewTargets(true)
+ .build();
+ runBlazeSync(syncParams);
+ errorCollector.assertIssues("IntelliJ Ultimate needed for Javascript support.");
+ }
+
@Nullable
private static SourceFolder findSourceFolder(ContentEntry entry, VirtualFile file) {
for (SourceFolder sourceFolder : entry.getSourceFolders()) {
diff --git a/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/lang/projectview/ProjectViewCompletionTest.java b/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/lang/projectview/ProjectViewCompletionTest.java
new file mode 100644
index 0000000..401f132
--- /dev/null
+++ b/ijwb/tests/integrationtests/com/google/idea/blaze/ijwb/lang/projectview/ProjectViewCompletionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.lang.projectview;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.EditorTestHelper;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
+import com.intellij.psi.PsiFile;
+import java.util.stream.Collectors;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Project view completion tests requiring IJwB's sync plugins to be present. */
+@RunWith(JUnit4.class)
+public class ProjectViewCompletionTest extends BlazeIntegrationTestCase {
+
+ protected EditorTestHelper editorTest;
+
+ @Before
+ public final void doSetup() {
+ BlazeProjectDataManager mockProjectDataManager =
+ new MockBlazeProjectDataManager(MockBlazeProjectDataBuilder.builder(workspaceRoot).build());
+ registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
+ editorTest = new EditorTestHelper(getProject(), testFixture);
+ }
+
+ private PsiFile setInput(String... fileContents) {
+ return testFixture.configureByText(".blazeproject", Joiner.on("\n").join(fileContents));
+ }
+
+ @Test
+ public void testAdditionalLanguagesCompletion() {
+ setInput("additional_languages:", " <caret>");
+
+ String[] types = editorTest.getCompletionItemsAsStrings();
+
+ assertThat(types)
+ .asList()
+ .containsAllIn(
+ LanguageSupport.availableAdditionalLanguages(WorkspaceType.JAVA)
+ .stream()
+ .map(LanguageClass::getName)
+ .collect(Collectors.toList()));
+ }
+}
diff --git a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPluginTest.java b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPluginTest.java
index 9f3dfd9..aa90aa5 100644
--- a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPluginTest.java
+++ b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/android/BlazeAndroidLiteSyncPluginTest.java
@@ -87,7 +87,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
errorCollector.assertNoIssues();
assertThat(workspaceLanguageSettings)
.isEqualTo(
diff --git a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPluginTest.java b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPluginTest.java
index 2c00838..d8a27e3 100644
--- a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPluginTest.java
+++ b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/dart/BlazeDartSyncPluginTest.java
@@ -86,7 +86,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
errorCollector.assertNoIssues();
assertThat(workspaceLanguageSettings)
.isEqualTo(
diff --git a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPluginTest.java b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPluginTest.java
index b90851e..da42baf 100644
--- a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPluginTest.java
+++ b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/javascript/BlazeJavascriptSyncPluginTest.java
@@ -19,6 +19,7 @@
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.model.primitives.LanguageClass;
import com.google.idea.blaze.base.model.primitives.WorkspaceType;
import com.google.idea.blaze.base.projectview.ProjectView;
@@ -34,7 +35,7 @@
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 org.jetbrains.annotations.NotNull;
+import com.intellij.util.PlatformUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -47,8 +48,7 @@
private BlazeContext context;
@Override
- protected void initTest(
- @NotNull Container applicationServices, @NotNull Container projectServices) {
+ protected void initTest(Container applicationServices, Container projectServices) {
super.initTest(applicationServices, projectServices);
ExtensionPointImpl<BlazeSyncPlugin> ep =
@@ -60,7 +60,8 @@
}
@Test
- public void testJavascriptLanguageAvailable() {
+ public void testJavascriptLanguageAvailableForUltimateEdition() {
+ TestUtils.setPlatformPrefix(testDisposable, PlatformUtils.IDEA_PREFIX);
ProjectViewSet projectViewSet =
ProjectViewSet.builder()
.add(
@@ -74,7 +75,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
errorCollector.assertNoIssues();
assertThat(workspaceLanguageSettings)
.isEqualTo(
@@ -82,4 +83,22 @@
WorkspaceType.JAVASCRIPT,
ImmutableSet.of(LanguageClass.JAVASCRIPT, LanguageClass.GENERIC)));
}
+
+ @Test
+ public void testJavascriptWorkspaceTypeUnavailableForCommunityEdition() {
+ TestUtils.setPlatformPrefix(testDisposable, PlatformUtils.IDEA_CE_PREFIX);
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(
+ ScalarSection.builder(WorkspaceTypeSection.KEY)
+ .set(WorkspaceType.JAVASCRIPT))
+ .build())
+ .build();
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
+ LanguageSupport.validateLanguageSettings(context, workspaceLanguageSettings);
+ errorCollector.assertIssues("Workspace type 'javascript' is not supported by this plugin");
+ }
}
diff --git a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPluginTest.java b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPluginTest.java
index e39fa49..1975ae8 100644
--- a/ijwb/tests/unittests/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPluginTest.java
+++ b/ijwb/tests/unittests/com/google/idea/blaze/ijwb/typescript/BlazeTypescriptSyncPluginTest.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableList;
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.model.primitives.LanguageClass;
import com.google.idea.blaze.base.model.primitives.WorkspaceType;
import com.google.idea.blaze.base.projectview.ProjectView;
@@ -35,6 +36,7 @@
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 com.intellij.util.PlatformUtils;
import java.util.Set;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
@@ -75,7 +77,8 @@
}
@Test
- public void testTypescriptLanguageAvailable() {
+ public void testTypescriptLanguageAvailableInUltimateEdition() {
+ TestUtils.setPlatformPrefix(testDisposable, PlatformUtils.IDEA_PREFIX);
ProjectViewSet projectViewSet =
ProjectViewSet.builder()
.add(
@@ -87,7 +90,7 @@
.build())
.build();
WorkspaceLanguageSettings workspaceLanguageSettings =
- LanguageSupport.createWorkspaceLanguageSettings(context, projectViewSet);
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
errorCollector.assertNoIssues();
assertThat(workspaceLanguageSettings)
.isEqualTo(
@@ -96,4 +99,23 @@
ImmutableSet.of(
LanguageClass.TYPESCRIPT, LanguageClass.GENERIC, LanguageClass.JAVA)));
}
+
+ @Test
+ public void testTypescriptNotLanguageAvailableInCommunityEdition() {
+ TestUtils.setPlatformPrefix(testDisposable, PlatformUtils.IDEA_CE_PREFIX);
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.JAVA))
+ .add(
+ ListSection.builder(AdditionalLanguagesSection.KEY)
+ .add(LanguageClass.TYPESCRIPT))
+ .build())
+ .build();
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
+ LanguageSupport.validateLanguageSettings(context, workspaceLanguageSettings);
+ errorCollector.assertIssues("Language 'typescript' is not supported by this plugin");
+ }
}
diff --git a/intellij_platform_sdk/BUILD b/intellij_platform_sdk/BUILD
index 9edcbbf..d20389e 100644
--- a/intellij_platform_sdk/BUILD
+++ b/intellij_platform_sdk/BUILD
@@ -16,6 +16,21 @@
},
)
+config_setting(
+ name = "intellij-beta",
+ values = {
+ "define": "ij_product=intellij-beta",
+ },
+)
+
+# IntelliJ CE 2017.1.1
+config_setting(
+ name = "intellij-2017.1.1",
+ values = {
+ "define": "ij_product=intellij-2017.1.1",
+ },
+)
+
# IntelliJ CE 2016.3.1
config_setting(
name = "intellij-2016.3.1",
@@ -24,14 +39,6 @@
},
)
-# IntelliJ CE 2016.2.4
-config_setting(
- name = "intellij-162.2032.8",
- values = {
- "define": "ij_product=intellij-162.2032.8",
- },
-)
-
config_setting(
name = "android-studio-latest",
values = {
@@ -39,14 +46,6 @@
},
)
-# Android Studio 2.2.0.7
-config_setting(
- name = "android-studio-145.1617.8",
- values = {
- "define": "ij_product=android-studio-145.1617.8",
- },
-)
-
config_setting(
name = "android-studio-beta",
values = {
@@ -54,19 +53,19 @@
},
)
-# Android Studio 2.3.0.3
+# Android Studio 2.3.0.8
config_setting(
- name = "android-studio-2.3.0.3",
+ name = "android-studio-2.3.0.8",
values = {
- "define": "ij_product=android-studio-2.3.0.3",
+ "define": "ij_product=android-studio-2.3.0.8",
},
)
-# Android Studio 2.3.0.4
+# Android Studio 2.3.1.0
config_setting(
- name = "android-studio-2.3.0.4",
+ name = "android-studio-2.3.1.0",
values = {
- "define": "ij_product=android-studio-2.3.0.4",
+ "define": "ij_product=android-studio-2.3.1.0",
},
)
@@ -77,6 +76,21 @@
},
)
+config_setting(
+ name = "clion-beta",
+ values = {
+ "define": "ij_product=clion-beta",
+ },
+)
+
+# CLion 2017.1.1
+config_setting(
+ name = "clion-2017.1.1",
+ values = {
+ "define": "ij_product=clion-2017.1.1",
+ },
+)
+
# CLion 2016.3.2
config_setting(
name = "clion-2016.3.2",
@@ -178,6 +192,28 @@
),
)
+# IntelliJ tasks plugin
+java_library(
+ name = "tasks",
+ neverlink = 1,
+ exports = select_from_plugin_api_directory(
+ android_studio = [":tasks"],
+ clion = [":tasks"],
+ intellij = [":tasks"],
+ ),
+)
+
+# terminal plugin
+java_library(
+ name = "terminal",
+ neverlink = 1,
+ exports = select_from_plugin_api_directory(
+ android_studio = [],
+ clion = [":terminal"],
+ intellij = [":terminal"],
+ ),
+)
+
# Bundled plugins required by integration tests
java_library(
name = "bundled_plugins",
@@ -195,10 +231,10 @@
java_library(
name = "missing_test_classes",
srcs = select_for_plugin_api({
- "android-studio-2.3.0.3": [
+ "android-studio-2.3.0.8": [
"missing/tests/com/jetbrains/cidr/modulemap/resolve/MockModuleMapManagerImpl.java",
],
- "android-studio-2.3.0.4": [
+ "android-studio-2.3.1.0": [
"missing/tests/com/jetbrains/cidr/modulemap/resolve/MockModuleMapManagerImpl.java",
],
"default": [],
diff --git a/intellij_platform_sdk/BUILD.clion b/intellij_platform_sdk/BUILD.clion
index c83e150..d43b8a1 100644
--- a/intellij_platform_sdk/BUILD.clion
+++ b/intellij_platform_sdk/BUILD.clion
@@ -15,6 +15,16 @@
jars = glob(["clion-*/plugins/hg4idea/lib/hg4idea.jar"]),
)
+java_import(
+ name = "terminal",
+ jars = glob(["clion-*/plugins/terminal/lib/terminal.jar"]),
+)
+
+java_import(
+ name = "python",
+ jars = glob(["clion-*/plugins/python/lib/python.jar"]),
+)
+
# The plugins required by CLwB. Presumably there will be some, when we write
# some integration tests.
java_import(
diff --git a/intellij_platform_sdk/BUILD.idea b/intellij_platform_sdk/BUILD.idea
index 32a92ad..4133e09 100644
--- a/intellij_platform_sdk/BUILD.idea
+++ b/intellij_platform_sdk/BUILD.idea
@@ -25,6 +25,11 @@
jars = glob(["plugins/junit/lib/*.jar"]),
)
+java_import(
+ name = "terminal",
+ jars = ["plugins/terminal/lib/terminal.jar"],
+)
+
# The plugins required by IJwB. We need to include them
# when running integration tests.
java_import(
diff --git a/intellij_platform_sdk/build_defs.bzl b/intellij_platform_sdk/build_defs.bzl
index 6fa3efb..5c1bbda 100644
--- a/intellij_platform_sdk/build_defs.bzl
+++ b/intellij_platform_sdk/build_defs.bzl
@@ -2,32 +2,30 @@
# The current indirect ij_product mapping (eg. "intellij-latest")
INDIRECT_IJ_PRODUCTS = {
- "intellij-latest": "intellij-2016.3.1",
- "android-studio-latest": "android-studio-145.1617.8",
- "android-studio-beta": "android-studio-2.3.0.4",
- "clion-latest": "clion-162.1967.7",
+ "intellij-latest": "intellij-2017.1.1",
+ "intellij-beta": "intellij-2017.1.1",
+ "android-studio-latest": "android-studio-2.3.1.0",
+ "android-studio-beta": "android-studio-2.3.1.0",
+ "clion-latest": "clion-2017.1.1",
+ "clion-beta": "clion-2017.1.1",
}
DIRECT_IJ_PRODUCTS = {
+ "intellij-2017.1.1": struct(
+ ide="intellij",
+ directory="intellij_ce_2017_1_1",
+ ),
"intellij-2016.3.1": struct(
ide="intellij",
directory="intellij_ce_2016_3_1",
),
- "intellij-162.2032.8": struct(
- ide="intellij",
- directory="IC_162_2032_8",
- ),
- "android-studio-145.1617.8": struct(
+ "android-studio-2.3.0.8": struct(
ide="android-studio",
- directory="AI_145_1617_8",
+ directory="android_studio_2_3_0_8",
),
- "android-studio-2.3.0.3": struct(
+ "android-studio-2.3.1.0": struct(
ide="android-studio",
- directory="android_studio_2_3_0_3",
- ),
- "android-studio-2.3.0.4": struct(
- ide="android-studio",
- directory="android_studio_2_3_0_4",
+ directory="android_studio_2_3_1_0",
),
"clion-162.1967.7": struct(
ide="clion",
@@ -37,15 +35,12 @@
ide="clion",
directory="clion_2016_3_2",
),
+ "clion-2017.1.1": struct(
+ ide="clion",
+ directory="clion_2017_1_1",
+ ),
}
-# BUILD_VARS for each IDE corresponding to indirect ij_products, eg. "intellij-latest"
-
-
-
-
-
-
def select_for_plugin_api(params):
"""Selects for a plugin_api.
@@ -99,7 +94,7 @@
return select(select_params)
-def select_for_ide(intellij=None, android_studio=None, clion=None, default=None):
+def select_for_ide(intellij=None, android_studio=None, clion=None, default=[]):
"""Selects for the supported IDEs.
Args:
@@ -108,7 +103,7 @@
clion: Files to use for CLion. If None will use default.
default: Files to use for any IDEs not passed.
Returns:
- A select statement on all plugin_apis, sorted into IDEs.
+ A select statement on all plugin_apis to lists of files, sorted into IDEs.
Example:
java_library(
@@ -119,9 +114,9 @@
),
)
"""
- intellij = intellij or default
- android_studio = android_studio or default
- clion = clion or default
+ intellij = intellij if intellij != None else default
+ android_studio = android_studio if android_studio != None else default
+ clion = clion if clion != None else default
ide_to_value = {
"intellij" : intellij,
diff --git a/java/BUILD b/java/BUILD
index ac9f772..fb36558 100644
--- a/java/BUILD
+++ b/java/BUILD
@@ -1,16 +1,30 @@
licenses(["notice"]) # Apache 2.0
+load(
+ "//build_defs:build_defs.bzl",
+ "merged_plugin_xml",
+ "stamped_plugin_xml",
+ "intellij_plugin",
+)
+load(
+ "//testing:test_defs.bzl",
+ "intellij_integration_test_suite",
+ "intellij_unit_test_suite",
+)
+
java_library(
name = "java",
srcs = glob(["src/**/*.java"]),
visibility = ["//visibility:public"],
- deps = [
- "//base",
+ runtime_deps = [
"//common/actionhelper",
"//common/experiments",
+ ],
+ deps = [
+ "//base",
"//intellij_platform_sdk:junit",
"//intellij_platform_sdk:plugin_api",
- "//proto_deps",
+ "//proto:proto_deps",
"//sdkcompat",
"@jsr305_annotations//jar",
],
@@ -22,13 +36,6 @@
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 = [
@@ -54,12 +61,6 @@
],
)
-load(
- "//testing:test_defs.bzl",
- "intellij_integration_test_suite",
- "intellij_unit_test_suite",
-)
-
intellij_unit_test_suite(
name = "unit_tests",
srcs = glob(["tests/unittests/**/*.java"]),
@@ -71,7 +72,7 @@
"//common/experiments",
"//common/experiments:unit_test_utils",
"//intellij_platform_sdk:plugin_api_for_tests",
- "//proto_deps",
+ "//proto:proto_deps",
"@jsr305_annotations//jar",
"@junit//jar",
],
diff --git a/java/src/META-INF/blaze-java.xml b/java/src/META-INF/blaze-java.xml
index e46fa6c..e22c895 100644
--- a/java/src/META-INF/blaze-java.xml
+++ b/java/src/META-INF/blaze-java.xml
@@ -69,9 +69,10 @@
<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"/>
- <SyncListener implementation="com.google.idea.blaze.java.syncstatus.SyncStatusHelper$UpdateSyncStatusMap"/>
<BlazeTestEventsHandler implementation="com.google.idea.blaze.java.run.BlazeJavaTestEventsHandler"/>
<AttributeSpecificStringLiteralReferenceProvider implementation="com.google.idea.blaze.java.lang.build.references.JavaClassQualifiedNameReference"/>
+ <JavaLikeLanguage implementation="com.google.idea.blaze.java.sync.source.JavaLikeLanguage$Java"/>
+ <TestTargetHeuristic implementation="com.google.idea.blaze.java.run.JUnitTestHeuristic" order="before TestSizeHeuristic"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
@@ -84,6 +85,12 @@
<runConfigurationProducer
implementation="com.google.idea.blaze.java.run.producers.BlazeJavaTestMethodConfigurationProducer"
order="first"/>
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.java.run.producers.BlazeJavaAbstractTestCaseConfigurationProducer"
+ order="first"/>
+ <runConfigurationProducer
+ implementation="com.google.idea.blaze.java.run.producers.MultipleJavaClassesTestConfigurationProducer"
+ 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"/>
@@ -105,7 +112,6 @@
<attachSourcesProvider implementation="com.google.idea.blaze.java.libraries.AddLibraryTargetDirectoryToProjectViewAttachSourcesProvider"/>
<attachSourcesProvider implementation="com.google.idea.blaze.java.libraries.BlazeAttachSourceProvider"/>
<applicationService serviceImplementation="com.google.idea.blaze.java.settings.BlazeJavaUserSettings"/>
- <projectService serviceImplementation="com.google.idea.blaze.java.syncstatus.SyncStatusHelper"/>
<psi.referenceContributor language="BUILD" implementation="com.google.idea.blaze.java.lang.build.references.JavaClassReferenceContributor"/>
</extensions>
@@ -116,7 +122,11 @@
</project-components>
<extensionPoints>
- <extensionPoint qualifiedName="com.google.idea.blaze.java.JavaSyncAugmenter"
+ <extensionPoint qualifiedName="com.google.idea.blaze.JavaSyncAugmenter"
interface="com.google.idea.blaze.java.sync.BlazeJavaSyncAugmenter"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.JavaLikeLanguage"
+ interface="com.google.idea.blaze.java.sync.source.JavaLikeLanguage"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.JUnitParameterizedClassHeuristic"
+ interface="com.google.idea.blaze.java.run.producers.JUnitParameterizedClassHeuristic"/>
</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
index 390ce7b..be94716 100644
--- a/java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java
+++ b/java/src/com/google/idea/blaze/java/lang/build/BuildFileSafeDeleteProcessor.java
@@ -28,10 +28,9 @@
import com.intellij.usageView.UsageInfo;
import com.intellij.util.IncorrectOperationException;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
+import javax.annotation.Nullable;
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)
@@ -55,12 +54,7 @@
@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();
- }
- }
+ result.removeIf(BuildFileSafeDeleteProcessor::ignoreUsage);
return superResult;
}
diff --git a/java/src/com/google/idea/blaze/java/libraries/AddLibraryTargetDirectoryToProjectViewAction.java b/java/src/com/google/idea/blaze/java/libraries/AddLibraryTargetDirectoryToProjectViewAction.java
index ec05bb7..c5e45c6 100644
--- a/java/src/com/google/idea/blaze/java/libraries/AddLibraryTargetDirectoryToProjectViewAction.java
+++ b/java/src/com/google/idea/blaze/java/libraries/AddLibraryTargetDirectoryToProjectViewAction.java
@@ -21,6 +21,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.idea.blaze.base.actions.BlazeProjectAction;
+import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.model.BlazeProjectData;
@@ -86,7 +87,7 @@
if (blazeLibrary == null) {
return null;
}
- TargetKey originatingTarget = blazeLibrary.originatingTarget;
+ TargetKey originatingTarget = findOriginatingTargetForLibrary(blazeProjectData, blazeLibrary);
if (originatingTarget == null) {
return null;
}
@@ -123,6 +124,21 @@
return workspacePath;
}
+ @Nullable
+ private static TargetKey findOriginatingTargetForLibrary(
+ BlazeProjectData blazeProjectData, BlazeJarLibrary library) {
+ for (TargetIdeInfo target : blazeProjectData.targetMap.targets()) {
+ JavaIdeInfo javaIdeInfo = target.javaIdeInfo;
+ if (javaIdeInfo == null) {
+ continue;
+ }
+ if (javaIdeInfo.jars.contains(library.libraryArtifact)) {
+ return target.key;
+ }
+ }
+ return null;
+ }
+
static void addDirectoriesToProjectView(Project project, List<Library> libraries) {
Set<WorkspacePath> workspacePaths = Sets.newHashSet();
for (Library library : libraries) {
diff --git a/java/src/com/google/idea/blaze/java/libraries/JarCache.java b/java/src/com/google/idea/blaze/java/libraries/JarCache.java
index 8617b8c..66eafaa 100644
--- a/java/src/com/google/idea/blaze/java/libraries/JarCache.java
+++ b/java/src/com/google/idea/blaze/java/libraries/JarCache.java
@@ -78,8 +78,12 @@
}
public void onSync(
- BlazeContext context, BlazeProjectData projectData, BlazeSyncParams.SyncMode syncMode) {
- Collection<BlazeLibrary> libraries = BlazeLibraryCollector.getLibraries(projectData);
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData projectData,
+ BlazeSyncParams.SyncMode syncMode) {
+ Collection<BlazeLibrary> libraries =
+ BlazeLibraryCollector.getLibraries(projectViewSet, projectData);
boolean fullRefresh = syncMode == SyncMode.FULL;
boolean removeMissingFiles = syncMode == SyncMode.INCREMENTAL;
boolean enabled = updateEnabled();
@@ -326,7 +330,7 @@
ProjectViewSet projectViewSet,
BlazeProjectData projectData,
BlazeSyncParams.SyncMode syncMode) {
- getInstance(project).onSync(context, projectData, syncMode);
+ getInstance(project).onSync(context, projectViewSet, projectData, syncMode);
}
@Override
diff --git a/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java b/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
index 35a00ca..cc50651 100644
--- a/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
+++ b/java/src/com/google/idea/blaze/java/libraries/LibraryActionHelper.java
@@ -31,8 +31,8 @@
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.Navigatable;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
class LibraryActionHelper {
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java
index 33a6540..140b08d 100644
--- a/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaDebuggerRunner.java
@@ -17,7 +17,7 @@
import com.google.idea.blaze.base.model.primitives.Kind;
import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
-import com.google.idea.sdkcompat.debugger.GenericDebuggerRunnerSdkCompatAdapter;
+import com.intellij.debugger.impl.GenericDebuggerRunner;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.configurations.RemoteConnection;
@@ -30,7 +30,7 @@
import javax.annotation.Nullable;
/** A runner that adapts the GenericDebuggerRunner to work with Blaze run configurations. */
-public class BlazeJavaDebuggerRunner extends GenericDebuggerRunnerSdkCompatAdapter {
+public class BlazeJavaDebuggerRunner extends GenericDebuggerRunner {
// wait 10 minutes for the blaze build to complete before connecting
private static final long POLL_TIMEOUT_MILLIS = 10 * 60 * 1000;
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationFactory.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationFactory.java
index 3b7c1b5..3daee7a 100644
--- a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationFactory.java
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationFactory.java
@@ -50,7 +50,7 @@
BlazeCommandRunConfigurationCommonState state =
blazeConfig.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
if (state != null) {
- state.setCommand(BlazeCommandName.RUN);
+ state.getCommandState().setCommand(BlazeCommandName.RUN);
}
blazeConfig.setGeneratedName();
}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandler.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandler.java
index 479b964..109d56e 100644
--- a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandler.java
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunConfigurationHandler.java
@@ -72,7 +72,7 @@
@Override
@Nullable
public String getCommandName() {
- BlazeCommandName command = state.getCommand();
+ BlazeCommandName command = state.getCommandState().getCommand();
return command != null ? command.toString() : null;
}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java
index 6175856..e7c4773 100644
--- a/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaRunProfileState.java
@@ -40,7 +40,6 @@
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.BoolExperiment;
import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
@@ -65,9 +64,6 @@
*/
final class BlazeJavaRunProfileState extends CommandLineState implements RemoteState {
- private static final BoolExperiment smRunnerUiEnabled =
- new BoolExperiment("use.smrunner.ui.java", true);
-
// 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;
@@ -155,14 +151,11 @@
}
private boolean useTestUi() {
- if (!smRunnerUiEnabled.getValue()) {
- return false;
- }
BlazeCommandRunConfigurationCommonState state =
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
return state != null
- && BlazeCommandName.TEST.equals(state.getCommand())
- && !state.getRunOnDistributedExecutor();
+ && BlazeCommandName.TEST.equals(state.getCommandState().getCommand())
+ && !state.getRunOnDistributedExecutorState().runOnDistributedExecutor;
}
@Override
@@ -171,10 +164,10 @@
return null;
}
return new RemoteConnection(
- true /* useSockets */,
+ /* useSockets */ true,
DEBUG_HOST_NAME,
Integer.toString(DEBUG_PORT),
- false /* serverMode */);
+ /* serverMode */ false);
}
@VisibleForTesting
@@ -189,15 +182,19 @@
configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
assert handlerState != null;
- BlazeCommandName blazeCommand = handlerState.getCommand();
+ String binaryPath =
+ handlerState.getBlazeBinaryState().getBlazeBinary() != null
+ ? handlerState.getBlazeBinaryState().getBlazeBinary()
+ : Blaze.getBuildSystemProvider(project).getBinaryPath();
+
+ BlazeCommandName blazeCommand = handlerState.getCommandState().getCommand();
assert blazeCommand != null;
BlazeCommand.Builder command =
- BlazeCommand.builder(Blaze.getBuildSystem(project), blazeCommand)
- .setBlazeBinary(handlerState.getBlazeBinary())
+ BlazeCommand.builder(binaryPath, blazeCommand)
.addTargets(configuration.getTarget())
.addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
.addBlazeFlags(extraBlazeFlags)
- .addBlazeFlags(handlerState.getBlazeFlags());
+ .addBlazeFlags(handlerState.getBlazeFlagsState().getExpandedFlags());
if (debug) {
Kind kind = configuration.getKindForTarget();
@@ -208,14 +205,12 @@
command.addBlazeFlags(BlazeFlags.JAVA_TEST_DEBUG);
}
} else {
- boolean runDistributed = handlerState.getRunOnDistributedExecutor();
+ boolean runDistributed =
+ handlerState.getRunOnDistributedExecutorState().runOnDistributedExecutor;
command.addBlazeFlags(DistributedExecutorSupport.getBlazeFlags(project, runDistributed));
- if (!runDistributed) {
- command.addBlazeFlags(BlazeFlags.TEST_OUTPUT_STREAMED);
- }
}
- command.addExeFlags(handlerState.getExeFlags());
+ command.addExeFlags(handlerState.getExeFlagsState().getExpandedFlags());
return command.build();
}
}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaTestEventsHandler.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaTestEventsHandler.java
index 4a1024f..8091b51 100644
--- a/java/src/com/google/idea/blaze/java/run/BlazeJavaTestEventsHandler.java
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaTestEventsHandler.java
@@ -47,13 +47,13 @@
/** Overridden to support parameterized tests, which use nested test_suite XML elements. */
@Override
- public boolean ignoreSuite(TestSuite suite) {
+ public boolean ignoreSuite(@Nullable Kind kind, TestSuite suite) {
if (suite.testSuites.isEmpty()) {
return false;
}
for (TestSuite child : suite.testSuites) {
// target/class names are fully-qualified; unqualified names denote parameterized methods
- if (!child.name.contains(".")) {
+ if (child.name != null && !child.name.contains(".")) {
return false;
}
}
diff --git a/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRunConfigurationFactory.java b/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRunConfigurationFactory.java
index 007aba3..9b9aad8 100644
--- a/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRunConfigurationFactory.java
+++ b/java/src/com/google/idea/blaze/java/run/BlazeJavaTestRunConfigurationFactory.java
@@ -50,7 +50,7 @@
BlazeCommandRunConfigurationCommonState state =
blazeConfig.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
if (state != null) {
- state.setCommand(BlazeCommandName.TEST);
+ state.getCommandState().setCommand(BlazeCommandName.TEST);
}
blazeConfig.setGeneratedName();
}
diff --git a/java/src/com/google/idea/blaze/java/run/JUnitTestHeuristic.java b/java/src/com/google/idea/blaze/java/run/JUnitTestHeuristic.java
new file mode 100644
index 0000000..dae9416
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/JUnitTestHeuristic.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo.TestSize;
+import com.google.idea.blaze.base.run.TestTargetHeuristic;
+import com.google.idea.blaze.java.run.producers.BlazeJUnitTestFilterFlags.JUnitVersion;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.PsiFile;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Matches junit test sources to test targets with junit3/junit4 in their name. */
+public class JUnitTestHeuristic implements TestTargetHeuristic {
+
+ @Override
+ public boolean matchesSource(
+ Project project,
+ TargetIdeInfo target,
+ @Nullable PsiFile sourcePsiFile,
+ File sourceFile,
+ @Nullable TestSize testSize) {
+ JUnitVersion sourceVersion = junitVersion(sourcePsiFile);
+ if (sourceVersion == null) {
+ return false;
+ }
+ String targetName = target.key.label.targetName().toString().toLowerCase();
+ switch (sourceVersion) {
+ case JUNIT_4:
+ return targetName.contains("junit4");
+ case JUNIT_3:
+ return targetName.contains("junit3");
+ }
+ return false;
+ }
+
+ @Nullable
+ private JUnitVersion junitVersion(@Nullable PsiFile psiFile) {
+ if (!(psiFile instanceof PsiClassOwner)) {
+ return null;
+ }
+ for (PsiClass psiClass : ((PsiClassOwner) psiFile).getClasses()) {
+ if (JUnitUtil.isJUnit4TestClass(psiClass)) {
+ return JUnitVersion.JUNIT_4;
+ }
+ }
+ for (PsiClass psiClass : ((PsiClassOwner) psiFile).getClasses()) {
+ if (JUnitUtil.isJUnit3TestClass(psiClass)) {
+ return JUnitVersion.JUNIT_3;
+ }
+ }
+ return null;
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/RunUtil.java b/java/src/com/google/idea/blaze/java/run/RunUtil.java
index 724d72f..3985700 100644
--- a/java/src/com/google/idea/blaze/java/run/RunUtil.java
+++ b/java/src/com/google/idea/blaze/java/run/RunUtil.java
@@ -16,7 +16,7 @@
package com.google.idea.blaze.java.run;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
-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.google.idea.blaze.base.run.TestTargetFinder;
import com.google.idea.blaze.base.run.TestTargetHeuristic;
@@ -27,8 +27,7 @@
import com.intellij.psi.PsiFile;
import java.io.File;
import java.util.Collection;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Utility methods for finding rules and Android facets. */
public final class RunUtil {
@@ -40,18 +39,17 @@
* containing rules, the first rule sorted alphabetically by label.
*/
@Nullable
- public static TargetIdeInfo targetForTestClass(
- @NotNull Project project,
- @NotNull PsiClass testClass,
- @Nullable TestIdeInfo.TestSize testSize) {
+ public static TargetIdeInfo targetForTestClass(PsiClass testClass, @Nullable TestSize testSize) {
File testFile = getFileForClass(testClass);
if (testFile == null) {
return null;
}
+ Project project = testClass.getProject();
Collection<TargetIdeInfo> targets =
TestTargetFinder.getInstance(project).testTargetsForSourceFile(testFile);
Label testLabel =
- TestTargetHeuristic.chooseTestTargetForSourceFile(testFile, targets, testSize);
+ TestTargetHeuristic.chooseTestTargetForSourceFile(
+ project, testClass.getContainingFile(), testFile, targets, testSize);
if (testLabel == null) {
return null;
}
@@ -64,7 +62,7 @@
* memory.
*/
@Nullable
- public static File getFileForClass(@NotNull PsiClass aClass) {
+ public static File getFileForClass(PsiClass aClass) {
PsiFile containingFile = aClass.getContainingFile();
if (containingFile == null) {
return null;
diff --git a/java/src/com/google/idea/blaze/java/run/producers/BlazeJUnitTestFilterFlags.java b/java/src/com/google/idea/blaze/java/run/producers/BlazeJUnitTestFilterFlags.java
index 4ee0508..79090d1 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/BlazeJUnitTestFilterFlags.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJUnitTestFilterFlags.java
@@ -78,7 +78,8 @@
}
private static boolean isParameterized(PsiClass testClass) {
- return PsiMemberParameterizedLocation.getParameterizedLocation(testClass, null) != null;
+ return PsiMemberParameterizedLocation.getParameterizedLocation(testClass, null) != null
+ || JUnitParameterizedClassHeuristic.isParameterizedTest(testClass);
}
private static String methodFilter(PsiMethod method, boolean parameterizedClass) {
@@ -105,10 +106,12 @@
String filter =
testFilterForClassAndMethods(
entry.getKey(), version, extractMethodFilters(entry.getValue()));
- if (filter != null) {
- classFilters.add(filter);
+ if (filter == null) {
+ return null;
}
+ classFilters.add(filter);
}
+ classFilters.sort(String::compareTo);
return version == JUnitVersion.JUNIT_4
? String.join("|", classFilters)
: String.join(",", classFilters);
diff --git a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaAbstractTestCaseConfigurationProducer.java b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaAbstractTestCaseConfigurationProducer.java
new file mode 100644
index 0000000..d9fb30b
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaAbstractTestCaseConfigurationProducer.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.annotations.VisibleForTesting;
+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.TargetIdeInfo;
+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.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.java.run.RunUtil;
+import com.intellij.codeInsight.AnnotationUtil;
+import com.intellij.execution.JavaExecutionUtil;
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.execution.configurations.RunConfiguration;
+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 com.intellij.psi.PsiModifier;
+import com.intellij.psi.util.PsiTreeUtil;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Producer for abstract test classes/methods. */
+public class BlazeJavaAbstractTestCaseConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ private static class AbstractTestLocation {
+ private final PsiClass abstractClass;
+ @Nullable private final PsiMethod method;
+
+ private AbstractTestLocation(PsiClass abstractClass, @Nullable PsiMethod method) {
+ this.abstractClass = abstractClass;
+ this.method = method;
+ }
+ }
+
+ public BlazeJavaAbstractTestCaseConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+ AbstractTestLocation location = getAbstractLocation(context);
+ if (location == null) {
+ return false;
+ }
+ sourceElement.set(location.method != null ? location.method : location.abstractClass);
+ configuration.setName(configName(location.abstractClass, location.method));
+ configuration.setNameChangedByUser(true);
+ return true;
+ }
+
+ @Nullable
+ private static AbstractTestLocation getAbstractLocation(ConfigurationContext context) {
+ if (!SmRunnerUtils.getSelectedSmRunnerTreeElements(context).isEmpty()) {
+ // handled by a different producer
+ return null;
+ }
+ PsiMethod method = getTestMethod(context);
+ if (method != null) {
+ PsiClass psiClass = method.getContainingClass();
+ return isAbstractClass(psiClass) ? new AbstractTestLocation(psiClass, method) : null;
+ }
+ Location location = context.getLocation();
+ if (location == null) {
+ return null;
+ }
+ location = JavaExecutionUtil.stepIntoSingleClass(location);
+ if (location == null) {
+ return null;
+ }
+ PsiClass psiClass =
+ PsiTreeUtil.getParentOfType(location.getPsiElement(), PsiClass.class, false);
+ if (!isAbstractClass(psiClass)) {
+ return null;
+ }
+ for (PsiClass subclass : SubclassTestChooser.findTestSubclasses(psiClass)) {
+ if (JUnitUtil.isTestClass(subclass)) {
+ return new AbstractTestLocation(psiClass, null);
+ }
+ }
+ return null;
+ }
+
+ private static PsiMethod getTestMethod(ConfigurationContext context) {
+ PsiElement psi = context.getPsiLocation();
+ if (psi instanceof PsiMethod
+ && AnnotationUtil.isAnnotated((PsiMethod) psi, JUnitUtil.TEST_ANNOTATION, false)) {
+ return (PsiMethod) psi;
+ }
+ List<PsiMethod> selectedMethods = TestMethodSelectionUtil.getSelectedMethods(context);
+ return selectedMethods != null && selectedMethods.size() == 1 ? selectedMethods.get(0) : null;
+ }
+
+ private static boolean isAbstractClass(@Nullable PsiClass psiClass) {
+ return psiClass != null && psiClass.hasModifierProperty(PsiModifier.ABSTRACT);
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+ // this is an intermediate type -- when it's fully instantiated (via 'onFirstRun') it will be
+ // recognized by a different producer.
+ return false;
+ }
+
+ @Override
+ public void onFirstRun(
+ ConfigurationFromContext configuration,
+ ConfigurationContext context,
+ Runnable startRunnable) {
+ chooseSubclass(configuration, context, startRunnable);
+ }
+
+ @VisibleForTesting
+ static void chooseSubclass(
+ ConfigurationFromContext configuration,
+ ConfigurationContext context,
+ Runnable startRunnable) {
+ RunConfiguration config = configuration.getConfiguration();
+ if (!(config instanceof BlazeCommandRunConfiguration)) {
+ return;
+ }
+ AbstractTestLocation location = locationFromConfiguration(configuration);
+ if (location == null) {
+ return;
+ }
+ SubclassTestChooser.chooseSubclass(
+ context,
+ location.abstractClass,
+ (psiClass) -> {
+ if (psiClass != null) {
+ setupContext((BlazeCommandRunConfiguration) config, psiClass, location.method);
+ }
+ startRunnable.run();
+ });
+ }
+
+ @Nullable
+ private static AbstractTestLocation locationFromConfiguration(
+ ConfigurationFromContext configuration) {
+ PsiElement element = configuration.getSourceElement();
+ PsiMethod method = null;
+ PsiClass psiClass = null;
+ if (element instanceof PsiMethod) {
+ method = (PsiMethod) element;
+ psiClass = method.getContainingClass();
+ } else if (element instanceof PsiClass) {
+ psiClass = (PsiClass) element;
+ }
+
+ return isAbstractClass(psiClass) ? new AbstractTestLocation(psiClass, method) : null;
+ }
+
+ private static void setupContext(
+ BlazeCommandRunConfiguration configuration, PsiClass subClass, @Nullable PsiMethod method) {
+ TestIdeInfo.TestSize testSize =
+ method != null
+ ? TestSizeAnnotationMap.getTestSize(method)
+ : TestSizeAnnotationMap.getTestSize(subClass);
+ TargetIdeInfo target = RunUtil.targetForTestClass(subClass, testSize);
+ if (target == null) {
+ return;
+ }
+ configuration.setTarget(target.key.label);
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null) {
+ return;
+ }
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
+
+ // remove old test filter flag if present
+ List<String> flags = new ArrayList<>(handlerState.getBlazeFlagsState().getRawFlags());
+ flags.removeIf((flag) -> flag.startsWith(BlazeFlags.TEST_FILTER));
+
+ String testFilter =
+ BlazeJUnitTestFilterFlags.testFilterForClassAndMethods(
+ subClass, method == null ? ImmutableList.of() : ImmutableList.of(method));
+ if (testFilter == null) {
+ return;
+ }
+ flags.add(BlazeFlags.TEST_FILTER + "=" + testFilter);
+ handlerState.getBlazeFlagsState().setRawFlags(flags);
+
+ BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
+ nameBuilder.setTargetString(configName(subClass, method));
+ configuration.setName(nameBuilder.build());
+ configuration.setNameChangedByUser(true); // don't revert to generated name
+ }
+
+ private static String configName(PsiClass psiClass, @Nullable PsiMethod method) {
+ return method == null
+ ? psiClass.getName()
+ : String.format("%s.%s", psiClass.getName(), method.getName());
+ }
+}
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
index b90826a..0399176 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassRunConfigurationProducer.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassRunConfigurationProducer.java
@@ -41,7 +41,7 @@
import java.io.File;
import java.util.Collection;
import java.util.Objects;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Creates run configurations for Java main classes sourced by java_binary targets. */
public class BlazeJavaMainClassRunConfigurationProducer
@@ -81,7 +81,7 @@
if (handlerState == null) {
return false;
}
- handlerState.setCommand(BlazeCommandName.RUN);
+ handlerState.getCommandState().setCommand(BlazeCommandName.RUN);
configuration.setGeneratedName();
return true;
}
@@ -94,7 +94,7 @@
if (handlerState == null) {
return false;
}
- if (!Objects.equals(handlerState.getCommand(), BlazeCommandName.RUN)) {
+ if (!Objects.equals(handlerState.getCommandState().getCommand(), BlazeCommandName.RUN)) {
return false;
}
PsiClass mainClass = getMainClass(context);
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
index 7d9a20f..1609e30 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducer.java
@@ -15,6 +15,7 @@
*/
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.TargetIdeInfo;
@@ -36,8 +37,13 @@
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
/** Producer for run configurations related to Java test classes in Blaze. */
@@ -79,7 +85,7 @@
sourceElement.set(testClass);
TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(testClass);
- TargetIdeInfo target = RunUtil.targetForTestClass(context.getProject(), testClass, testSize);
+ TargetIdeInfo target = RunUtil.targetForTestClass(testClass, testSize);
if (target == null) {
return false;
}
@@ -90,17 +96,17 @@
if (handlerState == null) {
return false;
}
- String testFilter = BlazeJUnitTestFilterFlags.testFilterForClass(testClass);
+ String testFilter = getTestFilter(testClass);
if (testFilter == null) {
return false;
}
- handlerState.setCommand(BlazeCommandName.TEST);
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
// remove old test filter flag if present
- List<String> flags = new ArrayList<>(handlerState.getBlazeFlags());
+ List<String> flags = new ArrayList<>(handlerState.getBlazeFlagsState().getRawFlags());
flags.removeIf((flag) -> flag.startsWith(BlazeFlags.TEST_FILTER));
flags.add(BlazeFlags.TEST_FILTER + "=" + testFilter);
- handlerState.setBlazeFlags(flags);
+ handlerState.getBlazeFlagsState().setRawFlags(flags);
BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
nameBuilder.setTargetString(testClass.getName());
@@ -148,13 +154,25 @@
if (handlerState == null) {
return false;
}
- if (!Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)) {
+ if (!Objects.equals(handlerState.getCommandState().getCommand(), BlazeCommandName.TEST)) {
return false;
}
- String filter = BlazeJUnitTestFilterFlags.testFilterForClass(testClass);
+ String filter = getTestFilter(testClass);
if (filter == null) {
return false;
}
return Objects.equals(BlazeFlags.TEST_FILTER + "=" + filter, handlerState.getTestFilterFlag());
}
+
+ @Nullable
+ private static String getTestFilter(PsiClass testClass) {
+ Set<PsiClass> innerTestClasses = ProducerUtils.getInnerTestClasses(testClass);
+ if (innerTestClasses.isEmpty()) {
+ return BlazeJUnitTestFilterFlags.testFilterForClass(testClass);
+ }
+ innerTestClasses.add(testClass);
+ Map<PsiClass, Collection<Location<?>>> methodsPerClass =
+ innerTestClasses.stream().collect(Collectors.toMap(c -> c, c -> ImmutableList.of()));
+ return BlazeJUnitTestFilterFlags.testFilterForClassesAndMethods(methodsPerClass);
+ }
}
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
index e0453d1..b1cabb3 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducer.java
@@ -80,8 +80,7 @@
sourceElement.set(methodInfo.firstMethod);
TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(methodInfo.firstMethod);
- TargetIdeInfo target =
- RunUtil.targetForTestClass(context.getProject(), methodInfo.containingClass, testSize);
+ TargetIdeInfo target = RunUtil.targetForTestClass(methodInfo.containingClass, testSize);
if (target == null) {
return false;
}
@@ -92,13 +91,16 @@
if (handlerState == null) {
return false;
}
- handlerState.setCommand(BlazeCommandName.TEST);
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
// remove old test filter flag if present
- List<String> flags = new ArrayList<>(handlerState.getBlazeFlags());
+ List<String> flags = new ArrayList<>(handlerState.getBlazeFlagsState().getRawFlags());
flags.removeIf((flag) -> flag.startsWith(BlazeFlags.TEST_FILTER));
flags.add(methodInfo.testFilterFlag);
- handlerState.setBlazeFlags(flags);
+ if (!flags.contains(BlazeFlags.DISABLE_TEST_SHARDING)) {
+ flags.add(BlazeFlags.DISABLE_TEST_SHARDING);
+ }
+ handlerState.getBlazeFlagsState().setRawFlags(flags);
BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
nameBuilder.setTargetString(
@@ -118,7 +120,7 @@
if (handlerState == null) {
return false;
}
- if (!Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)) {
+ if (!Objects.equals(handlerState.getCommandState().getCommand(), BlazeCommandName.TEST)) {
return false;
}
@@ -127,7 +129,7 @@
return false;
}
- List<String> flags = handlerState.getBlazeFlags();
+ List<String> flags = handlerState.getBlazeFlagsState().getRawFlags();
return flags.contains(methodInfo.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
index b994e36..f316d6e 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/JUnitConfigurationUtil.java
@@ -18,8 +18,6 @@
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;
@@ -33,14 +31,11 @@
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;
/**
@@ -48,10 +43,6 @@
* 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;
}
@@ -61,14 +52,13 @@
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);
+ final PsiElement[] locationElements = collectLocationElements(dataContext);
if (locationElements != null) {
collectTestMembers(locationElements, false, false, processor);
} else {
- collectContextElements(dataContext, false, false, classes, processor);
+ collectContextElements(dataContext, false, false, processor);
}
return processor.getCollection().size() > 1;
}
@@ -83,14 +73,14 @@
final PsiClass[] classes = ((PsiClassOwner) psiElement).getClasses();
for (PsiClass aClass : classes) {
if ((!checkIsTest && aClass.hasModifierProperty(PsiModifier.PUBLIC)
- || checkIsTest && isTestClass(aClass))
+ || checkIsTest && JUnitUtil.isTestClass(aClass))
&& !collectingProcessor.execute(aClass)) {
return;
}
}
} else if (psiElement instanceof PsiClass) {
if ((!checkIsTest && ((PsiClass) psiElement).hasModifierProperty(PsiModifier.PUBLIC)
- || checkIsTest && isTestClass((PsiClass) psiElement))
+ || checkIsTest && JUnitUtil.isTestClass((PsiClass) psiElement))
&& !collectingProcessor.execute(psiElement)) {
return;
}
@@ -122,14 +112,10 @@
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);
@@ -142,9 +128,6 @@
if (psiFile instanceof PsiClassOwner) {
collectTestMembers(
((PsiClassOwner) psiFile).getClasses(), checkAbstract, checkIsTest, processor);
- for (PsiElement psiMember : processor.getCollection()) {
- classes.add(((PsiClass) psiMember).getQualifiedName());
- }
}
}
return true;
@@ -154,41 +137,16 @@
return false;
}
- private static PsiElement[] collectLocationElements(
- LinkedHashSet<String> classes, DataContext dataContext) {
+ private static PsiElement[] collectLocationElements(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/JUnitParameterizedClassHeuristic.java b/java/src/com/google/idea/blaze/java/run/producers/JUnitParameterizedClassHeuristic.java
new file mode 100644
index 0000000..cc995c5
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/JUnitParameterizedClassHeuristic.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiClass;
+
+/** A heuristic to recognize JUnit test runner classes which have parameterized test cases. */
+public interface JUnitParameterizedClassHeuristic {
+
+ ExtensionPointName<JUnitParameterizedClassHeuristic> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.JUnitParameterizedClassHeuristic");
+
+ static boolean isParameterizedTest(PsiClass psiClass) {
+ for (JUnitParameterizedClassHeuristic heuristic : EP_NAME.getExtensions()) {
+ if (heuristic.isParameterized(psiClass)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean isParameterized(PsiClass psiClass);
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/MultipleJavaClassesTestConfigurationProducer.java b/java/src/com/google/idea/blaze/java/run/producers/MultipleJavaClassesTestConfigurationProducer.java
new file mode 100644
index 0000000..b2f5e83
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/MultipleJavaClassesTestConfigurationProducer.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TestIdeInfo;
+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.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.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.java.run.RunUtil;
+import com.intellij.execution.Location;
+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.openapi.roots.ProjectFileIndex;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.JavaDirectoryService;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiModifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/**
+ * Runs tests in all selected java classes (or all classes below selected directory). Ignores
+ * classes spread across multiple test targets.
+ */
+public class MultipleJavaClassesTestConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ public MultipleJavaClassesTestConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+ TestLocation location = getTestLocation(context);
+ if (location == null) {
+ return false;
+ }
+ sourceElement.set(location.psiLocation);
+ configuration.setTarget(location.label);
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null) {
+ return false;
+ }
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
+
+ // remove old test filter flag if present
+ List<String> flags = new ArrayList<>(handlerState.getBlazeFlagsState().getRawFlags());
+ flags.removeIf((flag) -> flag.startsWith(BlazeFlags.TEST_FILTER));
+ if (location.testFilter != null) {
+ flags.add(location.testFilter);
+ }
+ handlerState.getBlazeFlagsState().setRawFlags(flags);
+
+ if (location.description != null) {
+ BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
+ nameBuilder.setTargetString(location.description);
+ configuration.setName(nameBuilder.build());
+ configuration.setNameChangedByUser(true); // don't revert to generated name
+ } else {
+ configuration.setGeneratedName();
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+
+ TestLocation location = getTestLocation(context);
+ if (location == null) {
+ return false;
+ }
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null) {
+ return false;
+ }
+ return BlazeCommandName.TEST.equals(handlerState.getCommandState().getCommand())
+ && location.label.equals(configuration.getTarget())
+ && Objects.equals(location.testFilter, handlerState.getTestFilterFlag());
+ }
+
+ @Nullable
+ private static TestLocation getTestLocation(ConfigurationContext context) {
+ if (!SmRunnerUtils.getSelectedSmRunnerTreeElements(context).isEmpty()) {
+ // handled by a different producer
+ return null;
+ }
+ PsiElement location = context.getPsiLocation();
+ if (location instanceof PsiDirectory) {
+ PsiDirectory dir = (PsiDirectory) location;
+ TargetIdeInfo target = getTestTargetIfUnique(dir);
+ return target != null ? TestLocation.fromDirectory(target.key.label, dir) : null;
+ }
+ Set<PsiClass> testClasses = selectedTestClasses(context);
+ if (testClasses.size() < 2) {
+ return null;
+ }
+ TargetIdeInfo target = getTestTargetIfUnique(testClasses);
+ if (target == null) {
+ return null;
+ }
+ testClasses = ProducerUtils.includeInnerTestClasses(testClasses);
+ return TestLocation.fromClasses(target.key.label, testClasses);
+ }
+
+ private static Set<PsiClass> selectedTestClasses(ConfigurationContext context) {
+ DataContext dataContext = context.getDataContext();
+ PsiElement[] elements = LangDataKeys.PSI_ELEMENT_ARRAY.getData(dataContext);
+ if (elements == null) {
+ return ImmutableSet.of();
+ }
+ return Arrays.stream(elements)
+ .map(JUnitUtil::getTestClass)
+ .filter(Objects::nonNull)
+ .filter(testClass -> !testClass.hasModifierProperty(PsiModifier.ABSTRACT))
+ .collect(Collectors.toSet());
+ }
+
+ @Nullable
+ private static TargetIdeInfo getTestTargetIfUnique(PsiDirectory directory) {
+ if (BlazePackage.hasBlazePackageChild(directory)) {
+ return null;
+ }
+ Set<PsiClass> classes = new HashSet<>();
+ addClassesInDirectory(directory, classes);
+ return getTestTargetIfUnique(classes);
+ }
+
+ private static void addClassesInDirectory(PsiDirectory directory, Set<PsiClass> list) {
+ Collections.addAll(list, JavaDirectoryService.getInstance().getClasses(directory));
+ for (PsiDirectory child : directory.getSubdirectories()) {
+ addClassesInDirectory(child, list);
+ }
+ }
+
+ @Nullable
+ private static TargetIdeInfo getTestTargetIfUnique(Set<PsiClass> classes) {
+ TargetIdeInfo testTarget = null;
+ for (PsiClass psiClass : classes) {
+ TargetIdeInfo target = testTargetForClass(psiClass);
+ if (target == null) {
+ continue;
+ }
+ if (testTarget != null && testTarget != target) {
+ return null;
+ }
+ testTarget = target;
+ }
+ return testTarget;
+ }
+
+ @Nullable
+ private static TargetIdeInfo testTargetForClass(PsiClass psiClass) {
+ PsiClass testClass = JUnitUtil.getTestClass(psiClass);
+ if (testClass == null || testClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
+ return null;
+ }
+ TestIdeInfo.TestSize testSize = TestSizeAnnotationMap.getTestSize(psiClass);
+ return RunUtil.targetForTestClass(psiClass, testSize);
+ }
+
+ private static class TestLocation {
+ @Nullable
+ static TestLocation fromClasses(Label label, Set<PsiClass> classes) {
+ Map<PsiClass, Collection<Location<?>>> methodsPerClass =
+ classes.stream().collect(Collectors.toMap(c -> c, c -> ImmutableList.of()));
+ String filter = BlazeJUnitTestFilterFlags.testFilterForClassesAndMethods(methodsPerClass);
+ if (filter == null) {
+ return null;
+ }
+ PsiClass sampleClass =
+ classes.stream().min(Comparator.comparing(PsiClass::getName)).orElse(null);
+ String name = sampleClass.getName();
+ if (classes.size() > 1) {
+ name += String.format(" and %s others", classes.size() - 1);
+ }
+ return new TestLocation(label, sampleClass, filter, name);
+ }
+
+ @Nullable
+ static TestLocation fromDirectory(Label label, PsiDirectory dir) {
+ String packagePrefix =
+ ProjectFileIndex.SERVICE
+ .getInstance(dir.getProject())
+ .getPackageNameByDirectory(dir.getVirtualFile());
+ if (packagePrefix == null) {
+ return null;
+ }
+ String description =
+ packagePrefix.isEmpty() ? null : String.format("all in directory '%s'", dir.getName());
+ return new TestLocation(label, dir, packagePrefix, description);
+ }
+
+ private final Label label;
+ private final PsiElement psiLocation;
+ @Nullable private final String testFilter;
+ @Nullable private final String description;
+
+ private TestLocation(
+ Label label, PsiElement psiLocation, String testFilter, @Nullable String description) {
+ this.label = label;
+ this.psiLocation = psiLocation;
+ this.testFilter = !testFilter.isEmpty() ? BlazeFlags.TEST_FILTER + "=" + testFilter : null;
+ this.description = description;
+ }
+ }
+}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/NonBlazeProducerSuppressor.java b/java/src/com/google/idea/blaze/java/run/producers/NonBlazeProducerSuppressor.java
index faf3545..4260daa 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/NonBlazeProducerSuppressor.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/NonBlazeProducerSuppressor.java
@@ -35,17 +35,18 @@
private static final Collection<Class<? extends RunConfigurationProducer<?>>>
PRODUCERS_TO_SUPPRESS =
ImmutableList.of(
- // JUnit test producers
com.intellij.execution.junit.AllInDirectoryConfigurationProducer.class,
com.intellij.execution.junit.AllInPackageConfigurationProducer.class,
com.intellij.execution.junit.TestClassConfigurationProducer.class,
com.intellij.execution.junit.TestMethodConfigurationProducer.class,
- com.intellij.execution.junit.PatternConfigurationProducer.class);
+ com.intellij.execution.junit.PatternConfigurationProducer.class,
+ com.intellij.execution.application.ApplicationConfigurationProducer.class);
- private static final ImmutableList<String> KOTLIN_JUNIT_PRODUCERS =
+ private static final ImmutableList<String> KOTLIN_PRODUCERS =
ImmutableList.of(
"org.jetbrains.kotlin.idea.run.KotlinJUnitRunConfigurationProducer",
- "org.jetbrains.kotlin.idea.run.KotlinPatternConfigurationProducer");
+ "org.jetbrains.kotlin.idea.run.KotlinPatternConfigurationProducer",
+ "org.jetbrains.kotlin.idea.run.KotlinRunConfigurationProducer");
private static Collection<Class<? extends RunConfigurationProducer<?>>> getKotlinProducers() {
// rather than compiling against the Kotlin plugin, and including a switch in the our
@@ -55,7 +56,7 @@
return ImmutableList.of();
}
ClassLoader loader = plugin.getPluginClassLoader();
- return KOTLIN_JUNIT_PRODUCERS
+ return KOTLIN_PRODUCERS
.stream()
.map((qualifiedName) -> loadClass(loader, qualifiedName))
.filter(Objects::nonNull)
@@ -71,7 +72,7 @@
return (Class<RunConfigurationProducer<?>>) clazz;
}
return null;
- } catch (ClassNotFoundException ignored) {
+ } catch (ClassNotFoundException | NoClassDefFoundError ignored) {
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
index b1b40ab..5690c02 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/ProducerUtils.java
@@ -21,17 +21,15 @@
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
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.
- */
+/** Utility methods for java test run configuration producers. */
public class ProducerUtils {
@Nullable
public static Location<PsiMethod> getMethodLocation(@NotNull Location contextLocation) {
@@ -63,4 +61,19 @@
}
return null;
}
+
+ /** For any test classes with nested inner test classes, also add the inner classes to the set. */
+ static Set<PsiClass> includeInnerTestClasses(Set<PsiClass> testClasses) {
+ Set<PsiClass> result = new HashSet<>(testClasses);
+ for (PsiClass psiClass : testClasses) {
+ result.addAll(getInnerTestClasses(psiClass));
+ }
+ return result;
+ }
+
+ static Set<PsiClass> getInnerTestClasses(PsiClass psiClass) {
+ return Arrays.stream(psiClass.getInnerClasses())
+ .filter(JUnitUtil::isTestClass)
+ .collect(Collectors.toSet());
+ }
}
diff --git a/java/src/com/google/idea/blaze/java/run/producers/SubclassTestChooser.java b/java/src/com/google/idea/blaze/java/run/producers/SubclassTestChooser.java
new file mode 100644
index 0000000..1bc5250
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/run/producers/SubclassTestChooser.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.actions.ConfigurationContext;
+import com.intellij.execution.junit.JUnitUtil;
+import com.intellij.ide.util.PsiClassListCellRenderer;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.search.searches.ClassInheritorsSearch;
+import com.intellij.ui.components.JBList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import javax.swing.ListSelectionModel;
+
+/**
+ * Pop up a dialog to choose a child test class. Called when creating a run configuration from an
+ * abstract test class/method.
+ */
+public class SubclassTestChooser {
+
+ static void chooseSubclass(
+ ConfigurationContext context,
+ PsiClass abstractClass,
+ Consumer<PsiClass> callbackOnClassSelection) {
+ List<PsiClass> classes = findTestSubclasses(abstractClass);
+ if (classes.isEmpty()) {
+ return;
+ }
+ if (classes.size() == 1) {
+ callbackOnClassSelection.accept(classes.get(0));
+ return;
+ }
+ PsiClassListCellRenderer renderer = new PsiClassListCellRenderer();
+ classes.sort(renderer.getComparator());
+ // JBList has no generics in AS 2.2. TODO: Add generics here when we migrate to AS 2.3.
+ JBList list = new JBList(classes);
+ list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ list.setCellRenderer(renderer);
+ JBPopupFactory.getInstance()
+ .createListPopupBuilder(list)
+ .setTitle("Choose test class to run")
+ .setMovable(false)
+ .setResizable(false)
+ .setRequestFocus(true)
+ .setItemChoosenCallback(
+ () -> callbackOnClassSelection.accept((PsiClass) list.getSelectedValue()))
+ .createPopup()
+ .showInBestPositionFor(context.getDataContext());
+ }
+
+ static List<PsiClass> findTestSubclasses(PsiClass abstractClass) {
+ return ClassInheritorsSearch.search(abstractClass)
+ .findAll()
+ .stream()
+ .filter(JUnitUtil::isTestClass)
+ .collect(Collectors.toList());
+ }
+}
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
index e19f9bf..3db22aa 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/TestMethodSelectionUtil.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/TestMethodSelectionUtil.java
@@ -27,8 +27,8 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Helper functions for getting selected test methods. */
public class TestMethodSelectionUtil {
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
index 13062b3..66cb44f 100644
--- a/java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java
+++ b/java/src/com/google/idea/blaze/java/run/producers/TestSizeAnnotationMap.java
@@ -25,7 +25,7 @@
/** Maps method and class annotations to our test size enumeration. */
public class TestSizeAnnotationMap {
- private static ImmutableMap<String, TestIdeInfo.TestSize> ANNOTATION_TO_TEST_SIZE =
+ private static final 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)
diff --git a/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
index 7c4aa21..0fbe869 100644
--- a/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
+++ b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncAugmenter.java
@@ -25,7 +25,7 @@
/** Augments the java importer */
public interface BlazeJavaSyncAugmenter {
ExtensionPointName<BlazeJavaSyncAugmenter> EP_NAME =
- ExtensionPointName.create("com.google.idea.blaze.java.JavaSyncAugmenter");
+ ExtensionPointName.create("com.google.idea.blaze.JavaSyncAugmenter");
/**
* Adds extra libraries for this source rule.
diff --git a/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
index b971b94..1d31d91 100644
--- a/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
+++ b/java/src/com/google/idea/blaze/java/sync/BlazeJavaSyncPlugin.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
import com.google.idea.blaze.base.ideinfo.TargetMap;
@@ -41,7 +42,6 @@
import com.google.idea.blaze.base.sync.libraries.LibrarySource;
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;
@@ -109,7 +109,7 @@
WorkspaceRoot workspaceRoot,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings,
- BlazeRoots blazeRoots,
+ BlazeInfo blazeInfo,
@Nullable WorkingSet workingSet,
WorkspacePathResolver workspacePathResolver,
ArtifactLocationDecoder artifactLocationDecoder,
@@ -249,7 +249,8 @@
@Nullable
@Override
- public LibrarySource getLibrarySource(BlazeProjectData blazeProjectData) {
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.JAVA)) {
return null;
}
diff --git a/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java b/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
index 10db930..d03fc00 100644
--- a/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
+++ b/java/src/com/google/idea/blaze/java/sync/DuplicateSourceDetector.java
@@ -24,7 +24,7 @@
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.Comparator;
import java.util.List;
import java.util.Set;
@@ -64,12 +64,7 @@
return;
}
- Collections.sort(
- duplicates,
- (lhs, rhs) ->
- lhs.artifactLocation
- .getRelativePath()
- .compareTo(rhs.artifactLocation.getRelativePath()));
+ duplicates.sort(Comparator.comparing(lhs -> lhs.artifactLocation.getRelativePath()));
context.output(new PerformanceWarning("Duplicate sources detected:"));
for (Duplicate duplicate : duplicates) {
diff --git a/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java b/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java
index 7e3255f..c39eb64 100644
--- a/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java
+++ b/java/src/com/google/idea/blaze/java/sync/JavaPrefetchFileSource.java
@@ -19,6 +19,7 @@
import com.google.idea.blaze.base.model.BlazeLibrary;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.prefetch.PrefetchFileSource;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.sync.libraries.BlazeLibraryCollector;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.java.libraries.JarCache;
@@ -35,7 +36,10 @@
public class JavaPrefetchFileSource implements PrefetchFileSource {
@Override
public void addFilesToPrefetch(
- Project project, BlazeProjectData blazeProjectData, Collection<File> files) {
+ Project project,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<File> files) {
BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
if (syncData == null) {
return;
@@ -47,7 +51,8 @@
boolean attachSourcesByDefault =
BlazeJavaUserSettings.getInstance().getAttachSourcesByDefault();
SourceJarManager sourceJarManager = SourceJarManager.getInstance(project);
- Collection<BlazeLibrary> libraries = BlazeLibraryCollector.getLibraries(blazeProjectData);
+ Collection<BlazeLibrary> libraries =
+ BlazeLibraryCollector.getLibraries(projectViewSet, blazeProjectData);
ArtifactLocationDecoder artifactLocationDecoder = blazeProjectData.artifactLocationDecoder;
for (BlazeLibrary library : libraries) {
if (!(library instanceof BlazeJarLibrary)) {
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
index 2e8df7f..c089e53 100644
--- a/java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java
+++ b/java/src/com/google/idea/blaze/java/sync/importer/BlazeJavaWorkspaceImporter.java
@@ -167,10 +167,7 @@
List<LibraryArtifact> allJars = Lists.newArrayList();
allJars.addAll(javaIdeInfo.jars);
Collection<BlazeJarLibrary> libraries =
- allJars
- .stream()
- .map(library -> new BlazeJarLibrary(library, target.key))
- .collect(Collectors.toList());
+ allJars.stream().map(BlazeJarLibrary::new).collect(Collectors.toList());
targetKeyToLibrary.putAll(target.key, libraries);
for (BlazeJarLibrary library : libraries) {
@@ -189,7 +186,7 @@
protoLibraryLegacyInfo.jarsV1,
protoLibraryLegacyInfo.jarsMutable,
protoLibraryLegacyInfo.jarsImmutable)) {
- addLibraryToJdeps(jdepsPathToLibrary, new BlazeJarLibrary(libraryArtifact, target.key));
+ addLibraryToJdeps(jdepsPathToLibrary, new BlazeJarLibrary(libraryArtifact));
}
}
@@ -303,7 +300,7 @@
if (libraries != null) {
for (LibraryArtifact libraryArtifact : libraries) {
- BlazeJarLibrary library = new BlazeJarLibrary(libraryArtifact, targetKey);
+ BlazeJarLibrary library = new BlazeJarLibrary(libraryArtifact);
result.put(library.key, library);
}
}
@@ -374,14 +371,10 @@
}
}
workspaceBuilder.generatedJarsFromSourceTargets.addAll(
- javaIdeInfo
- .generatedJars
- .stream()
- .map(libraryArtifact -> new BlazeJarLibrary(libraryArtifact, targetKey))
- .collect(Collectors.toList()));
+ javaIdeInfo.generatedJars.stream().map(BlazeJarLibrary::new).collect(Collectors.toList()));
if (javaIdeInfo.filteredGenJar != null) {
workspaceBuilder.generatedJarsFromSourceTargets.add(
- new BlazeJarLibrary(javaIdeInfo.filteredGenJar, targetKey));
+ new BlazeJarLibrary(javaIdeInfo.filteredGenJar));
}
for (BlazeJavaSyncAugmenter augmenter : augmenters) {
diff --git a/java/src/com/google/idea/blaze/java/sync/importer/JavaSourceFilter.java b/java/src/com/google/idea/blaze/java/sync/importer/JavaSourceFilter.java
index 579eede..474b729 100644
--- a/java/src/com/google/idea/blaze/java/sync/importer/JavaSourceFilter.java
+++ b/java/src/com/google/idea/blaze/java/sync/importer/JavaSourceFilter.java
@@ -25,10 +25,12 @@
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.sync.projectview.ProjectViewTargetImportFilter;
+import com.google.idea.blaze.java.sync.source.JavaLikeLanguage;
import com.intellij.openapi.project.Project;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/** Segments java rules into source/libraries */
@@ -59,14 +61,11 @@
.collect(Collectors.toList());
targetToJavaSources = Maps.newHashMap();
+ Predicate<ArtifactLocation> isSourceFile = JavaLikeLanguage.getSourceFileMatcher();
for (TargetIdeInfo target : javaTargets) {
- List<ArtifactLocation> javaSources =
- target
- .sources
- .stream()
- .filter(source -> source.getRelativePath().endsWith(".java"))
- .collect(Collectors.toList());
- targetToJavaSources.put(target.key, javaSources);
+ List<ArtifactLocation> javaLikeSources =
+ target.sources.stream().filter(isSourceFile).collect(Collectors.toList());
+ targetToJavaSources.put(target.key, javaLikeSources);
}
sourceTargets = Lists.newArrayList();
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
index ac53134..b58b8cc 100644
--- a/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java
+++ b/java/src/com/google/idea/blaze/java/sync/jdeps/JdepsMap.java
@@ -17,7 +17,7 @@
import com.google.idea.blaze.base.ideinfo.TargetKey;
import java.util.List;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Map of rule -> jdeps dependencies. */
public interface JdepsMap {
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
index 3d0b128..d5ff52c 100644
--- a/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java
+++ b/java/src/com/google/idea/blaze/java/sync/model/BlazeJarLibrary.java
@@ -17,7 +17,6 @@
import com.google.common.base.Objects;
import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
-import com.google.idea.blaze.base.ideinfo.TargetKey;
import com.google.idea.blaze.base.model.BlazeLibrary;
import com.google.idea.blaze.base.model.LibraryKey;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
@@ -33,16 +32,13 @@
/** An immutable reference to a .jar required by a rule. */
@Immutable
public final class BlazeJarLibrary extends BlazeLibrary {
- private static final long serialVersionUID = 2L;
+ private static final long serialVersionUID = 3L;
public final LibraryArtifact libraryArtifact;
- public final TargetKey originatingTarget;
-
- public BlazeJarLibrary(LibraryArtifact libraryArtifact, TargetKey originatingTarget) {
+ public BlazeJarLibrary(LibraryArtifact libraryArtifact) {
super(LibraryKey.fromJarFile(libraryArtifact.jarForIntellijLibrary()));
this.libraryArtifact = libraryArtifact;
- this.originatingTarget = originatingTarget;
}
@Override
@@ -68,7 +64,7 @@
@Override
public int hashCode() {
- return Objects.hashCode(super.hashCode(), libraryArtifact, originatingTarget);
+ return Objects.hashCode(super.hashCode(), libraryArtifact);
}
@Override
@@ -82,8 +78,6 @@
BlazeJarLibrary that = (BlazeJarLibrary) other;
- return super.equals(other)
- && Objects.equal(libraryArtifact, that.libraryArtifact)
- && Objects.equal(originatingTarget, that.originatingTarget);
+ return super.equals(other) && Objects.equal(libraryArtifact, that.libraryArtifact);
}
}
diff --git a/java/src/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProvider.java b/java/src/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProvider.java
index 3f7b512..acbf755 100644
--- a/java/src/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProvider.java
+++ b/java/src/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProvider.java
@@ -28,6 +28,8 @@
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFileManager;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
import javax.annotation.Nullable;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.java.JavaResourceRootType;
@@ -57,16 +59,20 @@
@Override
public ImmutableMap<File, SourceFolder> initializeSourceFolders(ContentEntry contentEntry) {
- ImmutableMap.Builder<File, SourceFolder> output = ImmutableMap.builder();
+ Map<File, SourceFolder> map = new HashMap<>();
BlazeContentEntry javaContentEntry =
blazeContentEntries.get(UrlUtil.urlToFile(contentEntry.getUrl()));
if (javaContentEntry != null) {
for (BlazeSourceDirectory sourceDirectory : javaContentEntry.sources) {
+ File file = sourceDirectory.getDirectory();
+ if (map.containsKey(file)) {
+ continue;
+ }
SourceFolder sourceFolder = addSourceFolderToContentEntry(contentEntry, sourceDirectory);
- output.put(UrlUtil.urlToFile(sourceFolder.getUrl()), sourceFolder);
+ map.put(file, sourceFolder);
}
}
- return output.build();
+ return ImmutableMap.copyOf(map);
}
@Override
@@ -99,8 +105,10 @@
if (Strings.isNullOrEmpty(relativePath)) {
return parentPackagePrefix;
}
-
- return parentPackagePrefix + "." + relativePath.replaceAll(File.separator, ".");
+ relativePath = relativePath.replaceAll(File.separator, ".");
+ return Strings.isNullOrEmpty(parentPackagePrefix)
+ ? relativePath
+ : parentPackagePrefix + "." + relativePath;
}
@VisibleForTesting
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
index e80c98b..704f4c4 100644
--- a/java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java
+++ b/java/src/com/google/idea/blaze/java/sync/projectstructure/Jdks.java
@@ -36,9 +36,9 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Utility methods related to IDEA JDKs. */
public class Jdks {
diff --git a/java/src/com/google/idea/blaze/java/sync/source/JavaLikeLanguage.java b/java/src/com/google/idea/blaze/java/sync/source/JavaLikeLanguage.java
new file mode 100644
index 0000000..f6c791a
--- /dev/null
+++ b/java/src/com/google/idea/blaze/java/sync/source/JavaLikeLanguage.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.ImmutableSet;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * For languages similar to Java to reuse certain parts of the Java plugin. E.g., package prefix
+ * calculation.
+ */
+public interface JavaLikeLanguage {
+ ExtensionPointName<JavaLikeLanguage> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.JavaLikeLanguage");
+
+ static Predicate<ArtifactLocation> getSourceFileMatcher() {
+ final Set<String> fileExtensions =
+ Arrays.stream(EP_NAME.getExtensions())
+ .map(JavaLikeLanguage::getFileExtensions)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toSet());
+ return artifactLocation ->
+ fileExtensions
+ .stream()
+ .anyMatch(extension -> artifactLocation.getRelativePath().endsWith(extension));
+ }
+
+ Set<String> getFileExtensions();
+
+ /** Java is itself a Java-like language. */
+ class Java implements JavaLikeLanguage {
+ @Override
+ public Set<String> getFileExtensions() {
+ return ImmutableSet.of(".java");
+ }
+ }
+}
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
index 64e1cb5..a29b5bc 100644
--- a/java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java
+++ b/java/src/com/google/idea/blaze/java/sync/source/JavaSourcePackageReader.java
@@ -42,8 +42,8 @@
private static final Logger logger = Logger.getInstance(SourceDirectoryCalculator.class);
- private static final Pattern JAVA_PACKAGE_PATTERN =
- Pattern.compile("^\\s*package\\s+([\\w\\.]+);");
+ // Package declaration of java-like languages.
+ private static final Pattern PACKAGE_PATTERN = Pattern.compile("^\\s*package\\s+([\\w\\.]+)");
@Override
@Nullable
@@ -61,7 +61,7 @@
String javaLine;
while ((javaLine = javaReader.readLine()) != null) {
- Matcher packageMatch = JAVA_PACKAGE_PATTERN.matcher(javaLine);
+ Matcher packageMatch = PACKAGE_PATTERN.matcher(javaLine);
if (packageMatch.find()) {
return packageMatch.group(1);
}
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
index 52fced0..cadef54 100644
--- a/java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java
+++ b/java/src/com/google/idea/blaze/java/sync/source/PackageManifestReader.java
@@ -15,6 +15,7 @@
*/
package com.google.idea.blaze.java.sync.source;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -29,11 +30,13 @@
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;
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 com.intellij.openapi.util.text.StringUtil;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
@@ -111,7 +114,7 @@
return manifestMap;
}
- protected Map<ArtifactLocation, String> parseManifestFile(File packageManifest) {
+ private static Map<ArtifactLocation, String> parseManifestFile(File packageManifest) {
Map<ArtifactLocation, String> outputMap = Maps.newHashMap();
InputStreamProvider inputStreamProvider = InputStreamProvider.getInstance();
@@ -119,14 +122,7 @@
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(input)) {
PackageManifest proto = PackageManifest.parseFrom(bufferedInputStream);
for (JavaSourcePackage source : proto.getSourcesList()) {
- ArtifactLocation artifactLocation =
- ArtifactLocation.builder()
- .setRootExecutionPathFragment(
- source.getArtifactLocation().getRootExecutionPathFragment())
- .setRelativePath(source.getArtifactLocation().getRelativePath())
- .setIsSource(source.getArtifactLocation().getIsSource())
- .build();
- outputMap.put(artifactLocation, source.getPackageString());
+ outputMap.put(fromProto(source.getArtifactLocation()), source.getPackageString());
}
}
return outputMap;
@@ -135,4 +131,26 @@
return outputMap;
}
}
+
+ private static ArtifactLocation fromProto(PackageManifestOuterClass.ArtifactLocation location) {
+ String relativePath = location.getRelativePath();
+ String rootExecutionPathFragment = location.getRootExecutionPathFragment();
+ if (!location.getIsNewExternalVersion() && location.getIsExternal()) {
+ // fix up incorrect paths created with older aspect version
+ // Note: bazel always uses the '/' separator here, even on windows.
+ List<String> components = StringUtil.split(relativePath, "/");
+ if (components.size() > 2) {
+ relativePath = Joiner.on('/').join(components.subList(2, components.size()));
+ String prefix = components.get(0) + "/" + components.get(1);
+ rootExecutionPathFragment =
+ rootExecutionPathFragment.isEmpty() ? prefix : rootExecutionPathFragment + "/" + prefix;
+ }
+ }
+ return ArtifactLocation.builder()
+ .setRootExecutionPathFragment(rootExecutionPathFragment)
+ .setRelativePath(relativePath)
+ .setIsSource(location.getIsSource())
+ .setIsExternal(location.getIsExternal())
+ .build();
+ }
}
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
index e1e4203..14afec5 100644
--- a/java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java
+++ b/java/src/com/google/idea/blaze/java/sync/source/SourceDirectoryCalculator.java
@@ -50,10 +50,12 @@
import java.io.File;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -72,7 +74,7 @@
private static final JavaPackageReader generatedFileJavaPackageReader =
new FilePathJavaPackageReader();
- private final ListeningExecutorService executorService = MoreExecutors.sameThreadExecutor();
+ private final ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService();
private final ListeningExecutorService packageReaderExecutorService =
MoreExecutors.listeningDecorator(new TransientExecutor(16));
@@ -132,7 +134,7 @@
result.add(new BlazeContentEntry(contentRoot, sourceDirectories));
}
}
- Collections.sort(result, (lhs, rhs) -> lhs.contentRoot.compareTo(rhs.contentRoot));
+ result.sort(Comparator.comparing(lhs -> lhs.contentRoot));
});
return ImmutableList.copyOf(result);
}
@@ -197,10 +199,11 @@
Collection<SourceArtifact> sourceArtifacts,
Collection<JavaPackageReader> javaPackageReaders) {
- // Split out java files
+ // Split out java-like files
+ Predicate<ArtifactLocation> isSourceFile = JavaLikeLanguage.getSourceFileMatcher();
List<SourceArtifact> javaArtifacts = Lists.newArrayList();
for (SourceArtifact sourceArtifact : sourceArtifacts) {
- if (isJavaFile(sourceArtifact.artifactLocation)) {
+ if (isSourceFile.test(sourceArtifact.artifactLocation)) {
javaArtifacts.add(sourceArtifact);
}
}
@@ -518,8 +521,4 @@
this.directoryName = directoryName;
}
}
-
- private static boolean isJavaFile(ArtifactLocation artifactLocation) {
- return artifactLocation.getRelativePath().endsWith(".java");
- }
}
diff --git a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
index 01d7f40..6ffabc2 100644
--- a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
+++ b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusClassNodeDecorator.java
@@ -48,7 +48,7 @@
}
Project project = node.getProject();
- if (SyncStatusHelper.getInstance(project).isUnsynced(virtualFile)) {
+ if (SyncStatusHelper.isUnsynced(project, virtualFile)) {
data.clearText();
data.addText(psiClass.getName(), SimpleTextAttributes.GRAY_ATTRIBUTES);
data.addText(" (unsynced)", SimpleTextAttributes.GRAY_ATTRIBUTES);
diff --git a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
index 91234b1..26b97fa 100644
--- a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
+++ b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabColorProvider.java
@@ -20,8 +20,8 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.JBColor;
import java.awt.Color;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/** Changes the color for unsynced files. */
public class BlazeJavaSyncStatusEditorTabColorProvider implements EditorTabColorProvider {
@@ -31,8 +31,7 @@
@Nullable
@Override
public Color getEditorTabColor(@NotNull Project project, @NotNull VirtualFile file) {
- if (file.getName().endsWith(".java")
- && SyncStatusHelper.getInstance(project).isUnsynced(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
index aa96de8..43af36c 100644
--- a/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java
+++ b/java/src/com/google/idea/blaze/java/syncstatus/BlazeJavaSyncStatusEditorTabTitleProvider.java
@@ -18,14 +18,14 @@
import com.intellij.openapi.fileEditor.impl.EditorTabTitleProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.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.getInstance(project).isUnsynced(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
index ff6365c..c79888d 100644
--- a/java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java
+++ b/java/src/com/google/idea/blaze/java/syncstatus/SyncStatusHelper.java
@@ -17,15 +17,9 @@
import com.google.common.collect.ImmutableSet;
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.settings.BlazeImportSettings;
-import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
-import com.google.idea.blaze.base.sync.SyncListener;
-import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.sync.SyncCache;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.java.sync.model.BlazeJavaSyncData;
-import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.vfs.VirtualFile;
@@ -34,27 +28,16 @@
class SyncStatusHelper {
- static SyncStatusHelper getInstance(Project project) {
- return ServiceManager.getService(project, SyncStatusHelper.class);
- }
-
- private final Project project;
- private Set<File> syncedJavaFiles = null;
-
- SyncStatusHelper(Project project) {
- this.project = project;
- }
-
- boolean isUnsynced(VirtualFile virtualFile) {
+ static boolean isUnsynced(Project project, VirtualFile virtualFile) {
if (!virtualFile.isInLocalFileSystem()) {
return false;
}
if (ProjectFileIndex.SERVICE.getInstance(project).getModuleForFile(virtualFile) == null) {
return false;
}
- if (syncedJavaFiles == null) {
- syncedJavaFiles = refresh();
- }
+ Set<File> syncedJavaFiles =
+ SyncCache.getInstance(project)
+ .get(SyncStatusHelper.class, SyncStatusHelper::getSyncedJavaFiles);
if (syncedJavaFiles == null) {
return false;
}
@@ -62,33 +45,14 @@
return !syncedJavaFiles.contains(file);
}
- Set<File> refresh() {
- BlazeProjectData blazeProjectData =
- BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
- if (blazeProjectData == null) {
- return null;
- }
- BlazeJavaSyncData syncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ @SuppressWarnings("unused")
+ private static Set<File> getSyncedJavaFiles(Project project, BlazeProjectData projectData) {
+ BlazeJavaSyncData syncData = projectData.syncState.get(BlazeJavaSyncData.class);
if (syncData == null) {
- return null;
+ return ImmutableSet.of();
}
- ArtifactLocationDecoder artifactLocationDecoder = blazeProjectData.artifactLocationDecoder;
- return ImmutableSet.<File>builder()
- .addAll(artifactLocationDecoder.decodeAll(syncData.importResult.javaSourceFiles))
- .build();
- }
-
- static class UpdateSyncStatusMap extends SyncListener.Adapter {
- @Override
- public void onSyncComplete(
- Project project,
- BlazeContext context,
- BlazeImportSettings importSettings,
- ProjectViewSet projectViewSet,
- BlazeProjectData blazeProjectData,
- SyncMode syncMode,
- SyncResult syncResult) {
- getInstance(project).syncedJavaFiles = null;
- }
+ ArtifactLocationDecoder artifactLocationDecoder = projectData.artifactLocationDecoder;
+ return ImmutableSet.copyOf(
+ artifactLocationDecoder.decodeAll(syncData.importResult.javaSourceFiles));
}
}
diff --git a/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java b/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
index a2f0582..2c58b33 100644
--- a/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
+++ b/java/src/com/google/idea/blaze/java/ui/BlazeIntelliJProblemsView.java
@@ -41,7 +41,7 @@
public void addMessage(IssueOutput issue, UUID sessionId) {
VirtualFile virtualFile =
issue.getFile() != null
- ? VfsUtil.findFileByIoFile(issue.getFile(), true /* refresh */)
+ ? VfsUtil.findFileByIoFile(issue.getFile(), /* refresh */ true)
: null;
CompilerMessageCategory category =
issue.getCategory() == IssueOutput.Category.ERROR
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
index 4a6bc6a..3d57300 100644
--- a/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeEditProjectViewImportWizardStep.java
@@ -83,6 +83,7 @@
public void onWizardFinished() throws CommitStepException {
try {
getProjectBuilder().commit();
+ control.commit();
} catch (BlazeProjectCommitException e) {
throw new CommitStepException(e.getMessage());
}
diff --git a/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java b/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
index 62be22e..b609203 100644
--- a/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
+++ b/java/src/com/google/idea/blaze/java/wizard2/BlazeNewProjectWizard.java
@@ -19,7 +19,7 @@
import com.intellij.ide.util.newProjectWizard.AddModuleWizard;
import com.intellij.projectImport.ProjectImportProvider;
import java.awt.event.ActionListener;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
final class BlazeNewProjectWizard extends AddModuleWizard {
public BlazeNewProjectWizard(ProjectImportProvider provider) {
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/run/JUnitTestHeuristicTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/run/JUnitTestHeuristicTest.java
new file mode 100644
index 0000000..5470d05
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/run/JUnitTestHeuristicTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.psi.PsiFile;
+import java.io.File;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link JUnitTestHeuristic}. */
+@RunWith(JUnit4.class)
+public class JUnitTestHeuristicTest extends BlazeIntegrationTestCase {
+
+ @Before
+ public final void doSetup() {
+ // required for IntelliJ to recognize annotations, JUnit version, etc.
+ workspace.createPsiFile(
+ new WorkspacePath("org/junit/runner/RunWith.java"),
+ "package org.junit.runner;"
+ + "public @interface RunWith {"
+ + " Class<? extends Runner> value();"
+ + "}");
+ workspace.createPsiFile(
+ new WorkspacePath("org/junit/Test"), "package org.junit;", "public @interface Test {}");
+ workspace.createPsiFile(
+ new WorkspacePath("org/junit/runners/JUnit4"),
+ "package org.junit.runners;",
+ "public class JUnit4 {}");
+ }
+
+ @Test
+ public void testMatchesJunit4Annotation() {
+ PsiFile psiFile =
+ workspace.createPsiFile(
+ new WorkspacePath("java/com/google/lib/JavaClass.java"),
+ "package com.google.lib;",
+ "import org.junit.Test;",
+ "import org.junit.runner.RunWith;",
+ "import org.junit.runners.JUnit4;",
+ "@RunWith(JUnit4.class)",
+ "public class JavaClass {",
+ " @Test",
+ " public void testMethod1() {}",
+ " @Test",
+ " public void testMethod2() {}",
+ "}");
+ File file = new File(psiFile.getVirtualFile().getPath());
+ TargetIdeInfo target =
+ TargetIdeInfo.builder().setLabel("//foo:AllJUnit4Tests").setKind("java_test").build();
+ assertThat(new JUnitTestHeuristic().matchesSource(getProject(), target, psiFile, file, null))
+ .isTrue();
+ }
+
+ @Test
+ public void testIgnoresJunit4AnnotationIfTargetNameDoesNotMatch() {
+ PsiFile psiFile =
+ workspace.createPsiFile(
+ new WorkspacePath("java/com/google/lib/JavaClass.java"),
+ "package com.google.lib;",
+ "import org.junit.Test;",
+ "import org.junit.runner.RunWith;",
+ "import org.junit.runners.JUnit4;",
+ "@RunWith(JUnit4.class)",
+ "public class JavaClass {",
+ " @Test",
+ " public void testMethod1() {}",
+ " @Test",
+ " public void testMethod2() {}",
+ "}");
+ File file = new File(psiFile.getVirtualFile().getPath());
+ TargetIdeInfo target =
+ TargetIdeInfo.builder().setLabel("//foo:unrelatedName").setKind("java_test").build();
+ assertThat(new JUnitTestHeuristic().matchesSource(getProject(), target, psiFile, file, null))
+ .isFalse();
+ }
+
+ @Test
+ public void testNonJavaFileDoesNotMatch() {
+ PsiFile psiFile = workspace.createPsiFile(new WorkspacePath("foo/script_test.py"));
+ File file = new File(psiFile.getVirtualFile().getPath());
+ TargetIdeInfo target =
+ TargetIdeInfo.builder().setLabel("//foo:unrelatedName").setKind("python_test").build();
+ assertThat(new JUnitTestHeuristic().matchesSource(getProject(), target, psiFile, file, null))
+ .isFalse();
+ }
+
+ @Test
+ public void testNullPsiFileDoesNotMatch() {
+ File file = new File("foo/script_test.py");
+ TargetIdeInfo target =
+ TargetIdeInfo.builder().setLabel("//foo:unrelatedName").setKind("python_test").build();
+ assertThat(new JUnitTestHeuristic().matchesSource(getProject(), target, null, file, null))
+ .isFalse();
+ }
+
+ @Test
+ public void testJunit4SourceDoesNotMatchJunit3TargetName() {
+ PsiFile psiFile =
+ workspace.createPsiFile(
+ new WorkspacePath("java/com/google/lib/JavaClass.java"),
+ "package com.google.lib;",
+ "import org.junit.Test;",
+ "import org.junit.runner.RunWith;",
+ "import org.junit.runners.JUnit4;",
+ "@RunWith(JUnit4.class)",
+ "public class JavaClass {",
+ " @Test",
+ " public void testMethod1() {}",
+ " @Test",
+ " public void testMethod2() {}",
+ "}");
+ File file = new File(psiFile.getVirtualFile().getPath());
+ TargetIdeInfo target =
+ TargetIdeInfo.builder().setLabel("//foo:AllJUnit3Tests").setKind("java_test").build();
+ assertThat(new JUnitTestHeuristic().matchesSource(getProject(), target, psiFile, file, null))
+ .isFalse();
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaAbstractTestCaseConfigurationProducerTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaAbstractTestCaseConfigurationProducerTest.java
new file mode 100644
index 0000000..b30fa3e
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaAbstractTestCaseConfigurationProducerTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.util.EmptyRunnable;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiMethod;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link BlazeJavaAbstractTestCaseConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class BlazeJavaAbstractTestCaseConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
+
+ @Test
+ public void testNonAbstractClassIgnored() {
+ PsiFile javaFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod1() {}",
+ " @org.junit.Test",
+ " public void testMethod2() {}",
+ "}");
+
+ PsiClass javaClass = ((PsiClassOwner) javaFile).getClasses()[0];
+ assertThat(javaClass).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(javaClass);
+ ConfigurationFromContext fromContext =
+ new BlazeJavaAbstractTestCaseConfigurationProducer()
+ .createConfigurationFromContext(context);
+ assertThat(fromContext).isNull();
+ }
+
+ @Test
+ public void testConfigurationCreatedFromAbstractClass() {
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ PsiFile abstractClassFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/AbstractTestCase.java"),
+ "package com.google.test;",
+ "public abstract class AbstractTestCase {}");
+
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "import com.google.test.AbstractTestCase;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass extends AbstractTestCase {",
+ " @org.junit.Test",
+ " public void testMethod1() {}",
+ " @org.junit.Test",
+ " public void testMethod2() {}",
+ "}");
+
+ PsiClass javaClass = ((PsiClassOwner) abstractClassFile).getClasses()[0];
+ assertThat(javaClass).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(abstractClassFile);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeJavaAbstractTestCaseConfigurationProducer.class))
+ .isTrue();
+ assertThat(fromContext.getSourceElement()).isEqualTo(javaClass);
+
+ RunConfiguration config = fromContext.getConfiguration();
+ assertThat(config).isInstanceOf(BlazeCommandRunConfiguration.class);
+ BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) config;
+ assertThat(blazeConfig.getTarget()).isNull();
+ assertThat(blazeConfig.getName()).isEqualTo("AbstractTestCase");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ BlazeJavaAbstractTestCaseConfigurationProducer.chooseSubclass(
+ fromContext, context, EmptyRunnable.INSTANCE);
+
+ assertThat(blazeConfig.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(blazeConfig))
+ .isEqualTo(BlazeFlags.TEST_FILTER + "=com.google.test.TestClass#");
+ }
+
+ @Test
+ public void testConfigurationCreatedFromMethodInAbstractClass() {
+ PsiFile abstractClassFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/AbstractTestCase.java"),
+ "package com.google.test;",
+ "public abstract class AbstractTestCase {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "import com.google.test.AbstractTestCase;",
+ "import org.junit.runner.RunWith;",
+ "import org.junit.runners.JUnit4;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass extends AbstractTestCase {}");
+
+ PsiClass javaClass = ((PsiClassOwner) abstractClassFile).getClasses()[0];
+ PsiMethod method = PsiUtils.findFirstChildOfClassRecursive(javaClass, PsiMethod.class);
+ assertThat(method).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(method);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeJavaAbstractTestCaseConfigurationProducer.class))
+ .isTrue();
+ assertThat(fromContext.getSourceElement()).isEqualTo(method);
+
+ RunConfiguration config = fromContext.getConfiguration();
+ assertThat(config).isInstanceOf(BlazeCommandRunConfiguration.class);
+ BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) config;
+ assertThat(blazeConfig.getTarget()).isNull();
+ assertThat(blazeConfig.getName()).isEqualTo("AbstractTestCase.testMethod");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ BlazeJavaAbstractTestCaseConfigurationProducer.chooseSubclass(
+ fromContext, context, EmptyRunnable.INSTANCE);
+
+ assertThat(blazeConfig.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(blazeConfig))
+ .isEqualTo(BlazeFlags.TEST_FILTER + "=com.google.test.TestClass#testMethod$");
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassConfigurationProducerTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassConfigurationProducerTest.java
index 6135b2f..87c8f28 100644
--- a/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassConfigurationProducerTest.java
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaMainClassConfigurationProducerTest.java
@@ -17,64 +17,31 @@
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.EditorTestHelper;
-import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
-import com.google.idea.blaze.base.ideinfo.TargetMap;
import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
-import com.google.idea.blaze.base.model.primitives.ExecutionRootPath;
import com.google.idea.blaze.base.model.primitives.TargetExpression;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.run.BlazeRunConfiguration;
-import com.google.idea.blaze.base.sync.SyncCache;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.base.sync.workspace.BlazeRoots;
-import com.intellij.execution.Location;
-import com.intellij.execution.PsiLocation;
-import com.intellij.execution.RunnerAndConfigurationSettings;
-import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.configurations.RunConfiguration;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.LangDataKeys;
-import com.intellij.openapi.module.ModuleUtil;
-import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
-import com.intellij.testFramework.MapDataContext;
-import java.io.File;
-import org.jetbrains.annotations.Nullable;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-/** Integration tests for {@link BlazeJavaMainClassConfigurationProducer}. */
+/** Integration tests for {@link BlazeJavaMainClassRunConfigurationProducer}. */
@RunWith(JUnit4.class)
-public class BlazeJavaMainClassConfigurationProducerTest extends BlazeIntegrationTestCase {
-
- private EditorTestHelper editorTest;
-
- @Before
- public final void doSetup() {
- BlazeProjectDataManager mockProjectDataManager =
- new MockBlazeProjectDataManager(getMockBlazeProjectDataBuilder().build());
- registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
- editorTest = new EditorTestHelper(getProject(), testFixture);
- }
-
- @After
- public final void doTearDown() {
- SyncCache.getInstance(getProject()).clear();
- }
+public class BlazeJavaMainClassConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
@Test
public void testUniqueJavaBinaryChosen() {
- setTargets(
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
@@ -83,14 +50,16 @@
.addSource(sourceRoot("com/google/binary/MainClass.java"))
.build())
.build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
PsiFile javaClass =
- workspace.createPsiFile(
+ createAndIndexFile(
WorkspacePath.createIfValid("com/google/binary/MainClass.java"),
"package com.google.binary;",
"import java.lang.String;",
"public class MainClass {",
- " public static void main(String[] args) {}",
+ " public static void main(java.lang.String[] args) {}",
"}");
RunConfiguration config = createConfigurationFromLocation(javaClass);
@@ -103,7 +72,8 @@
@Test
public void testNoJavaBinaryChosenIfNotInRDeps() {
- setTargets(
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
@@ -112,14 +82,16 @@
.addSource(sourceRoot("com/google/binary/OtherClass.java"))
.build())
.build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
PsiFile javaClass =
- workspace.createPsiFile(
+ createAndIndexFile(
WorkspacePath.createIfValid("com/google/binary/MainClass.java"),
"package com.google.binary;",
"import java.lang.String;",
"public class MainClass {",
- " public static void main(String[] args) {}",
+ " public static void main(java.lang.String[] args) {}",
"}");
assertThat(createConfigurationFromLocation(javaClass))
@@ -128,7 +100,8 @@
@Test
public void testNoResultForClassWithoutMainMethod() {
- setTargets(
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
@@ -138,9 +111,11 @@
.setJavaInfo(JavaIdeInfo.builder().setMainClass("com.google.binary.MainClass"))
.build())
.build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
PsiFile javaClass =
- workspace.createPsiFile(
+ createAndIndexFile(
WorkspacePath.createIfValid("com/google/binary/MainClass.java"),
"package com.google.binary;",
"public class MainClass {}");
@@ -150,7 +125,8 @@
@Test
public void testJavaBinaryWithMatchingNameChosen() {
- setTargets(
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
@@ -165,14 +141,16 @@
.addSource(sourceRoot("com/google/binary/MainClass.java"))
.build())
.build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
PsiFile javaClass =
- workspace.createPsiFile(
+ createAndIndexFile(
WorkspacePath.createIfValid("com/google/binary/MainClass.java"),
"package com.google.binary;",
"import java.lang.String;",
"public class MainClass {",
- " public static void main(String[] args) {}",
+ " public static void main(java.lang.String[] args) {}",
"}");
RunConfiguration config = createConfigurationFromLocation(javaClass);
@@ -184,7 +162,8 @@
@Test
public void testJavaBinaryWithMatchingMainClassChosen() {
- setTargets(
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
TargetMapBuilder.builder()
.addTarget(
TargetIdeInfo.builder()
@@ -200,14 +179,16 @@
.addSource(sourceRoot("com/google/binary/MainClass.java"))
.build())
.build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
PsiFile javaClass =
- workspace.createPsiFile(
+ createAndIndexFile(
WorkspacePath.createIfValid("com/google/binary/MainClass.java"),
"package com.google.binary;",
"import java.lang.String;",
"public class MainClass {",
- " public static void main(String[] args) {}",
+ " public static void main(java.lang.String[] args) {}",
"}");
RunConfiguration config = createConfigurationFromLocation(javaClass);
@@ -217,48 +198,4 @@
assertThat(blazeConfig.getTarget())
.isEqualTo(TargetExpression.fromString("//com/google/binary:OtherName"));
}
-
- @Nullable
- private RunConfiguration createConfigurationFromLocation(PsiFile psiFile) {
- // a nauseating hack to force IntelliJ to recognize 'main' methods...
- workspace.createPsiFile(
- WorkspacePath.createIfValid("java/lang/String.java"),
- "package java.lang;",
- "public class String {}");
- editorTest.openFileInEditor(psiFile);
-
- final MapDataContext dataContext = new MapDataContext();
-
- dataContext.put(CommonDataKeys.PROJECT, getProject());
- dataContext.put(LangDataKeys.MODULE, ModuleUtil.findModuleForPsiElement(psiFile));
- dataContext.put(Location.DATA_KEY, PsiLocation.fromPsiElement(psiFile));
- RunnerAndConfigurationSettings settings =
- ConfigurationContext.getFromContext(dataContext).getConfiguration();
- return settings != null ? settings.getConfiguration() : null;
- }
-
- private MockBlazeProjectDataBuilder getMockBlazeProjectDataBuilder() {
- String executionRootPath = "usr/local/_blaze_";
- VirtualFile vf = fileSystem.createDirectory(executionRootPath);
- BlazeRoots fakeRoots =
- new BlazeRoots(
- new File(vf.getPath()),
- ImmutableList.of(workspaceRoot.directory()),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen"),
- null);
- return MockBlazeProjectDataBuilder.builder(workspaceRoot).setBlazeRoots(fakeRoots);
- }
-
- private void setTargets(TargetMap targets) {
- BlazeProjectDataManager mockProjectDataManager =
- new MockBlazeProjectDataManager(
- getMockBlazeProjectDataBuilder().setTargetMap(targets).build());
- registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
- SyncCache.getInstance(getProject()).clear();
- }
-
- private static ArtifactLocation sourceRoot(String relativePath) {
- return ArtifactLocation.builder().setRelativePath(relativePath).setIsSource(true).build();
- }
}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducerTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducerTest.java
new file mode 100644
index 0000000..6c48f2f
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaTestClassConfigurationProducerTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiClassOwner;
+import com.intellij.psi.PsiFile;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link BlazeJavaTestClassConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class BlazeJavaTestClassConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
+
+ @Test
+ public void testProducedFromPsiFile() {
+ PsiFile javaFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod1() {}",
+ " @org.junit.Test",
+ " public void testMethod2() {}",
+ "}");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ ConfigurationContext context = createContextFromPsi(javaFile);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeJavaTestClassConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(config)).isEqualTo("--test_filter=com.google.test.TestClass#");
+ assertThat(config.getName()).isEqualTo("Blaze test TestClass");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testProducedFromPsiClass() {
+ PsiFile javaFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod1() {}",
+ " @org.junit.Test",
+ " public void testMethod2() {}",
+ "}");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiClass javaClass = ((PsiClassOwner) javaFile).getClasses()[0];
+ assertThat(javaClass).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(javaClass);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeJavaTestClassConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(config)).isEqualTo("--test_filter=com.google.test.TestClass#");
+ assertThat(config.getName()).isEqualTo("Blaze test TestClass");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testProducedFromPsiClassWithInnerTestClass() {
+ PsiFile javaFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/OuterClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.Suite.class)",
+ "@org.junit.runners.Suite.SuiteClasses({OuterClass.InnerClass.class})",
+ "public class OuterClass {",
+ " @org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ " public static class InnerClass {",
+ " @org.junit.Test",
+ " public void testMethod1() {}",
+ " @org.junit.Test",
+ " public void testMethod2() {}",
+ " }",
+ "}");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:OuterClass")
+ .addSource(sourceRoot("java/com/google/test/OuterClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiClass javaClass = ((PsiClassOwner) javaFile).getClasses()[0];
+ assertThat(javaClass).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(javaClass);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeJavaTestClassConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:OuterClass"));
+ assertThat(getTestFilterContents(config))
+ .isEqualTo(
+ "--test_filter=com.google.test.OuterClass#|com.google.test.OuterClass.InnerClass#");
+ assertThat(config.getName()).isEqualTo("Blaze test OuterClass");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducerTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducerTest.java
new file mode 100644
index 0000000..aa7d2a2
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/BlazeJavaTestMethodConfigurationProducerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiMethod;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link BlazeJavaTestMethodConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class BlazeJavaTestMethodConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
+
+ @Test
+ public void testProducedFromPsiMethod() {
+ PsiFile javaFile =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod1() {}",
+ "}");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiMethod method = PsiUtils.findFirstChildOfClassRecursive(javaFile, PsiMethod.class);
+ assertThat(method).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(method);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazeJavaTestMethodConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(config))
+ .isEqualTo("--test_filter=com.google.test.TestClass#testMethod1$");
+ assertThat(config.getName()).isEqualTo("Blaze test TestClass.testMethod1");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+
+ BlazeCommandRunConfigurationCommonState state =
+ config.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ assertThat(state.getBlazeFlagsState().getRawFlags()).contains(BlazeFlags.DISABLE_TEST_SHARDING);
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/MultipleJavaClassesTestConfigurationProducerTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/MultipleJavaClassesTestConfigurationProducerTest.java
new file mode 100644
index 0000000..731743a
--- /dev/null
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/run/producers/MultipleJavaClassesTestConfigurationProducerTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.SourceFolder;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link MultipleJavaClassesTestConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class MultipleJavaClassesTestConfigurationProducerTest
+ extends BlazeRunConfigurationProducerTestCase {
+
+ private SourceFolder javaSourceRoot;
+
+ @Before
+ public final void addSourceFolder() {
+ // create a source root so that the package prefixes are correct.
+ VirtualFile pkgRoot = workspace.createDirectory(new WorkspacePath("java"));
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ final ModifiableRootModel model =
+ ModuleRootManager.getInstance(testFixture.getModule()).getModifiableModel();
+ ContentEntry contentEntry = model.getContentEntries()[0];
+ javaSourceRoot = contentEntry.addSourceFolder(pkgRoot, false, "");
+ model.commit();
+ });
+
+ BlazeProjectDataManager mockProjectDataManager =
+ new MockBlazeProjectDataManager(MockBlazeProjectDataBuilder.builder(workspaceRoot).build());
+ registerProjectService(BlazeProjectDataManager.class, mockProjectDataManager);
+ }
+
+ @After
+ public final void removeSourceFolder() {
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ final ModifiableRootModel model =
+ ModuleRootManager.getInstance(testFixture.getModule()).getModifiableModel();
+ ContentEntry contentEntry = model.getContentEntries()[0];
+ contentEntry.removeSourceFolder(javaSourceRoot);
+ model.commit();
+ });
+ }
+
+ @Test
+ public void testProducedFromDirectory() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiDirectory directory =
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ ConfigurationContext context = createContextFromPsi(directory);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(MultipleJavaClassesTestConfigurationProducer.class))
+ .isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(config)).isEqualTo("--test_filter=com.google.test");
+ assertThat(config.getName()).isEqualTo("Blaze test all in directory 'test'");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testProducedFromDirectoryWithNestedTests() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiDirectory directory = workspace.createPsiDirectory(new WorkspacePath("java/com/google"));
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ ConfigurationContext context = createContextFromPsi(directory);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(MultipleJavaClassesTestConfigurationProducer.class))
+ .isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:TestClass"));
+ assertThat(getTestFilterContents(config)).isEqualTo("--test_filter=com.google");
+ assertThat(config.getName()).isEqualTo("Blaze test all in directory 'google'");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testNoFilterIfDirectoryAtPackageRoot() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiDirectory directory = workspace.createPsiDirectory(new WorkspacePath("java"));
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ ConfigurationContext context = createContextFromPsi(directory);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(MultipleJavaClassesTestConfigurationProducer.class))
+ .isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(getTestFilterContents(config)).isNull();
+ assertThat(config.getName()).isEqualTo("Blaze test test:TestClass");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testNotProducedFromDirectoryWithoutTests() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PsiDirectory directory =
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+
+ ConfigurationContext context = createContextFromPsi(directory);
+ assertThat(
+ new MultipleJavaClassesTestConfigurationProducer()
+ .createConfigurationFromContext(context))
+ .isNull();
+ }
+
+ @Test
+ public void testNotProducedFromSingleTestFile() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass")
+ .addSource(sourceRoot("java/com/google/test/TestClass.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ PsiFile file =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ ConfigurationContext context = createContextFromPsi(file);
+ assertThat(
+ new MultipleJavaClassesTestConfigurationProducer()
+ .createConfigurationFromContext(context))
+ .isNull();
+ }
+
+ @Test
+ public void testProducedFromTestFiles() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:allTests")
+ .addSource(sourceRoot("java/com/google/test/TestClass1.java"))
+ .addSource(sourceRoot("java/com/google/test/TestClass2.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ PsiFile testClass1 =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass1.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass1 {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+ PsiFile testClass2 =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass2.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass2 {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ ConfigurationContext context =
+ createContextFromMultipleElements(new PsiElement[] {testClass1, testClass2});
+ ConfigurationFromContext fromContext =
+ new MultipleJavaClassesTestConfigurationProducer().createConfigurationFromContext(context);
+ assertThat(fromContext).isNotNull();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget())
+ .isEqualTo(TargetExpression.fromString("//java/com/google/test:allTests"));
+ assertThat(getTestFilterContents(config))
+ .isEqualTo("--test_filter=com.google.test.TestClass1#|com.google.test.TestClass2#");
+ assertThat(config.getName()).isEqualTo("Blaze test TestClass1 and 1 others");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testNotProducedFromTestFilesInDifferentTestTargets() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass1")
+ .addSource(sourceRoot("java/com/google/test/TestClass1.java"))
+ .build())
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:TestClass2")
+ .addSource(sourceRoot("java/com/google/test/TestClass2.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ PsiFile testClass1 =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass1.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass1 {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+ PsiFile testClass2 =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/TestClass2.java"),
+ "package com.google.test;",
+ "@org.junit.runner.RunWith(org.junit.runners.JUnit4.class)",
+ "public class TestClass2 {",
+ " @org.junit.Test",
+ " public void testMethod() {}",
+ "}");
+
+ ConfigurationContext context =
+ createContextFromMultipleElements(new PsiElement[] {testClass1, testClass2});
+ assertThat(
+ new MultipleJavaClassesTestConfigurationProducer()
+ .createConfigurationFromContext(context))
+ .isNull();
+ }
+
+ @Test
+ public void testNotProducedFromNonTestFiles() {
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("java_test")
+ .setLabel("//java/com/google/test:allTests")
+ .addSource(sourceRoot("java/com/google/test/NonTestClass1.java"))
+ .addSource(sourceRoot("java/com/google/test/NonTestClass2.java"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ workspace.createPsiDirectory(new WorkspacePath("java/com/google/test"));
+ PsiFile testClass1 =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/NonTestClass1.java"),
+ "package com.google.test;",
+ "public class NonTestClass1 {");
+ PsiFile testClass2 =
+ createAndIndexFile(
+ new WorkspacePath("java/com/google/test/NonTestClass2.java"),
+ "package com.google.test;",
+ "public class NonTestClass2 {}");
+
+ ConfigurationContext context =
+ createContextFromMultipleElements(new PsiElement[] {testClass1, testClass2});
+ ConfigurationFromContext fromContext =
+ new MultipleJavaClassesTestConfigurationProducer().createConfigurationFromContext(context);
+ assertThat(fromContext).isNull();
+ }
+}
diff --git a/java/tests/integrationtests/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProviderTest.java b/java/tests/integrationtests/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProviderTest.java
index bd15bde..2412829 100644
--- a/java/tests/integrationtests/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProviderTest.java
+++ b/java/tests/integrationtests/com/google/idea/blaze/java/sync/projectstructure/JavaSourceFolderProviderTest.java
@@ -140,6 +140,42 @@
assertThat(testSourceChild.getPackagePrefix()).isEqualTo("apps.tests.model");
}
+ @Test
+ public void testRelativePackagePrefixWithoutParentPrefix() {
+ ImmutableList<BlazeContentEntry> contentEntries =
+ ImmutableList.of(
+ BlazeContentEntry.builder("/src/workspace/java")
+ .addSource(
+ BlazeSourceDirectory.builder("/src/workspace/java")
+ .setPackagePrefix("")
+ .build())
+ .build());
+
+ JavaSourceFolderProvider provider =
+ new JavaSourceFolderProvider(
+ new BlazeJavaSyncData(
+ new BlazeJavaImportResult(
+ contentEntries, ImmutableMap.of(), ImmutableList.of(), ImmutableSet.of(), null),
+ new GlobSet(ImmutableList.of())));
+
+ VirtualFile root = workspace.createDirectory(new WorkspacePath("java"));
+ ContentEntry contentEntry = getContentEntry(root);
+
+ ImmutableMap<File, SourceFolder> sourceFolders = provider.initializeSourceFolders(contentEntry);
+ assertThat(sourceFolders).hasSize(1);
+
+ VirtualFile testRoot = workspace.createDirectory(new WorkspacePath("java/apps/tests"));
+
+ SourceFolder testSourceChild =
+ provider.setSourceFolderForLocation(
+ contentEntry,
+ sourceFolders.get(new File(root.getPath())),
+ new File(testRoot.getPath()),
+ true);
+ assertThat(testSourceChild.isTestSource()).isTrue();
+ assertThat(testSourceChild.getPackagePrefix()).isEqualTo("apps.tests");
+ }
+
private ContentEntry getContentEntry(VirtualFile root) {
return ModuleRootManager.getInstance(testFixture.getModule())
.getModifiableModel()
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
index 622105e..612b946 100644
--- a/java/tests/unittests/com/google/idea/blaze/java/run/BlazeJavaRunProfileStateTest.java
+++ b/java/tests/unittests/com/google/idea/blaze/java/run/BlazeJavaRunProfileStateTest.java
@@ -16,10 +16,13 @@
package com.google.idea.blaze.java.run;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
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.bazel.BuildSystemProvider;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
import com.google.idea.blaze.base.command.BuildFlagsProvider;
@@ -53,15 +56,14 @@
public class BlazeJavaRunProfileStateTest extends BlazeTestCase {
private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
- new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+ new BlazeImportSettings("", "", "", "", BuildSystem.Blaze);
private BlazeCommandRunConfiguration configuration;
@Override
protected void initTest(
@NotNull Container applicationServices, @NotNull Container projectServices) {
- projectServices.register(
- BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager());
BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
ExperimentService experimentService = new MockExperimentService();
@@ -75,6 +77,11 @@
BlazeCommandRunConfigurationHandlerProvider.EP_NAME,
BlazeCommandRunConfigurationHandlerProvider.class);
handlerProviderEp.registerExtension(new BlazeCommandGenericRunConfigurationHandlerProvider());
+ ExtensionPointImpl<BuildSystemProvider> buildSystemProviderExtensionPoint =
+ registerExtensionPoint(BuildSystemProvider.EP_NAME, BuildSystemProvider.class);
+ BuildSystemProvider buildSystemProvider = mock(BuildSystemProvider.class);
+ when(buildSystemProvider.getBinaryPath()).thenReturn("/usr/bin/blaze");
+ buildSystemProviderExtensionPoint.registerExtension(buildSystemProvider);
configuration =
new BlazeCommandRunConfigurationType().getFactory().createTemplateConfiguration(project);
@@ -82,18 +89,18 @@
@Test
public void flagsShouldBeAppendedIfPresent() {
- configuration.setTarget(new Label("//label:rule"));
+ configuration.setTarget(Label.create("//label:rule"));
BlazeCommandRunConfigurationCommonState handlerState =
(BlazeCommandRunConfigurationCommonState) configuration.getHandler().getState();
- handlerState.setCommand(BlazeCommandName.fromString("command"));
- handlerState.setBlazeFlags(ImmutableList.of("--flag1", "--flag2"));
+ handlerState.getCommandState().setCommand(BlazeCommandName.fromString("command"));
+ handlerState.getBlazeFlagsState().setRawFlags(ImmutableList.of("--flag1", "--flag2"));
assertThat(
BlazeJavaRunProfileState.getBlazeCommand(
project,
configuration,
ProjectViewSet.builder().build(),
ImmutableList.of(),
- false /* debug */)
+ /* debug */ false)
.toList())
.isEqualTo(
ImmutableList.of(
@@ -102,24 +109,23 @@
BlazeFlags.getToolTagFlag(),
"--flag1",
"--flag2",
- "--test_output=streamed",
"--",
"//label:rule"));
}
@Test
public void debugFlagShouldBeIncludedForJavaTest() {
- configuration.setTarget(new Label("//label:rule"));
+ configuration.setTarget(Label.create("//label:rule"));
BlazeCommandRunConfigurationCommonState handlerState =
(BlazeCommandRunConfigurationCommonState) configuration.getHandler().getState();
- handlerState.setCommand(BlazeCommandName.fromString("command"));
+ handlerState.getCommandState().setCommand(BlazeCommandName.fromString("command"));
assertThat(
BlazeJavaRunProfileState.getBlazeCommand(
project,
configuration,
ProjectViewSet.builder().build(),
ImmutableList.of(),
- true /* debug */)
+ /* debug */ true)
.toList())
.isEqualTo(
ImmutableList.of(
@@ -133,17 +139,17 @@
@Test
public void debugFlagShouldBeIncludedForJavaBinary() {
- configuration.setTarget(new Label("//label:java_binary_rule"));
+ configuration.setTarget(Label.create("//label:java_binary_rule"));
BlazeCommandRunConfigurationCommonState handlerState =
(BlazeCommandRunConfigurationCommonState) configuration.getHandler().getState();
- handlerState.setCommand(BlazeCommandName.fromString("command"));
+ handlerState.getCommandState().setCommand(BlazeCommandName.fromString("command"));
assertThat(
BlazeJavaRunProfileState.getBlazeCommand(
project,
configuration,
ProjectViewSet.builder().build(),
ImmutableList.of(),
- true /* debug */)
+ /* debug */ true)
.toList())
.isEqualTo(
ImmutableList.of(
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
index ad731d7..c69b66b 100644
--- 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
@@ -16,9 +16,7 @@
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;
@@ -70,6 +68,7 @@
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.source.JavaLikeLanguage;
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;
@@ -83,8 +82,8 @@
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -94,18 +93,17 @@
public class BlazeJavaWorkspaceImporterTest extends BlazeTestCase {
private static final String FAKE_WORKSPACE_ROOT = "/root";
- private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File(FAKE_WORKSPACE_ROOT));
+ private final 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 ArtifactLocationDecoder FAKE_ARTIFACT_DECODER =
(ArtifactLocationDecoder)
artifactLocation -> new File("/", artifactLocation.getRelativePath());
private static final BlazeImportSettings DUMMY_IMPORT_SETTINGS =
- new BlazeImportSettings("", "", "", "", "", BuildSystem.Blaze);
+ new BlazeImportSettings("", "", "", "", BuildSystem.Blaze);
private ExtensionPointImpl<BlazeJavaSyncAugmenter> augmenters;
private static class JdepsMock implements JdepsMap {
@@ -124,7 +122,7 @@
}
private BlazeContext context;
- private ErrorCollector errorCollector = new ErrorCollector();
+ private final ErrorCollector errorCollector = new ErrorCollector();
private final JdepsMock jdepsMap = new JdepsMock();
private JavaWorkingSet workingSet = null;
private final WorkspaceLanguageSettings workspaceLanguageSettings =
@@ -132,6 +130,7 @@
private MockExperimentService experimentService;
@Override
+ @SuppressWarnings("FunctionalInterfaceClash") // False positive on getDeclaredPackageOfJavaFile.
protected void initTest(
@NotNull Container applicationServices, @NotNull Container projectServices) {
experimentService = new MockExperimentService();
@@ -139,8 +138,7 @@
BlazeExecutor blazeExecutor = new MockBlazeExecutor();
applicationServices.register(BlazeExecutor.class, blazeExecutor);
- projectServices.register(
- BlazeImportSettingsManager.class, new BlazeImportSettingsManager(project));
+ projectServices.register(BlazeImportSettingsManager.class, new BlazeImportSettingsManager());
BlazeImportSettingsManager.getInstance(getProject()).setImportSettings(DUMMY_IMPORT_SETTINGS);
// will silently fall back to FilePathJavaPackageReader
@@ -164,6 +162,9 @@
augmenters =
registerExtensionPoint(BlazeJavaSyncAugmenter.EP_NAME, BlazeJavaSyncAugmenter.class);
+
+ registerExtensionPoint(JavaLikeLanguage.EP_NAME, JavaLikeLanguage.class)
+ .registerExtension(new JavaLikeLanguage.Java());
}
BlazeJavaImportResult importWorkspace(
@@ -195,7 +196,7 @@
BlazeJavaImportResult result =
importWorkspace(workspaceRoot, TargetMapBuilder.builder(), ProjectView.builder().build());
errorCollector.assertNoIssues();
- assertTrue(result.contentEntries.isEmpty());
+ assertThat(result.contentEntries).isEmpty();
}
@Test
@@ -233,10 +234,10 @@
BlazeJavaImportResult result = importWorkspace(workspaceRoot, targetMapBuilder, projectView);
errorCollector.assertNoIssues();
- assertEquals(1, result.buildOutputJars.size());
+ assertThat(result.buildOutputJars).hasSize(1);
ArtifactLocation compilerOutputLib = result.buildOutputJars.iterator().next();
assertNotNull(compilerOutputLib);
- assertTrue(compilerOutputLib.relativePath.endsWith("example_debug.jar"));
+ assertThat(compilerOutputLib.relativePath).endsWith("example_debug.jar");
assertThat(result.contentEntries)
.containsExactly(
@@ -668,7 +669,7 @@
BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
errorCollector.assertNoIssues();
- assertEquals(1, result.libraries.size());
+ assertThat(result.libraries).hasSize(1);
}
@Test
@@ -713,7 +714,7 @@
BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
errorCollector.assertNoIssues();
- assertEquals(1, result.libraries.size());
+ assertThat(result.libraries).hasSize(1);
}
@Test
@@ -761,7 +762,7 @@
BlazeJavaImportResult result = importWorkspace(workspaceRoot, response, projectView);
errorCollector.assertNoIssues();
- assertEquals(1, result.libraries.size()); // The libraries were merged
+ assertThat(result.libraries).hasSize(1); // The libraries were merged
}
@Test
@@ -893,7 +894,7 @@
.add(DirectoryEntry.include(new WorkspacePath("import"))))
.add(
ListSection.builder(ImportTargetOutputSection.KEY)
- .add(new Label("//import:import")))
+ .add(Label.create("//import:import")))
.build();
TargetMapBuilder response =
@@ -989,7 +990,7 @@
.build();
TargetMapBuilder targetMapBuilder = targetMapForJdepsSuite();
jdepsMap.put(
- TargetKey.forPlainTarget(new Label("//java/apps/example:example_debug")),
+ TargetKey.forPlainTarget(Label.create("//java/apps/example:example_debug")),
Lists.newArrayList(jdepsPath("thirdparty/a.jar"), jdepsPath("thirdparty/c.jar")));
BlazeJavaImportResult result = importWorkspace(workspaceRoot, targetMapBuilder, projectView);
@@ -1073,7 +1074,7 @@
.add(DirectoryEntry.include(new WorkspacePath("java/apps/example"))))
.add(
ListSection.builder(ExcludeTargetSection.KEY)
- .add(new Label("//java/apps/example:example")))
+ .add(Label.create("//java/apps/example:example")))
.build();
TargetMapBuilder targetMapBuilder =
@@ -1220,7 +1221,7 @@
// First test - make sure that jdeps is working
jdepsMap.put(
- TargetKey.forPlainTarget(new Label("//java/example:liba")),
+ TargetKey.forPlainTarget(Label.create("//java/example:liba")),
Lists.newArrayList(jdepsPath("thirdparty/proto/a/liba-ijar.jar")));
BlazeJavaImportResult result = importWorkspace(workspaceRoot, targetMapBuilder, projectView);
errorCollector.assertNoIssues();
@@ -1332,11 +1333,10 @@
TargetIdeInfo target,
Collection<BlazeJarLibrary> jars,
Collection<BlazeJarLibrary> genJars) {
- if (target.key.label.equals(new Label("//java/example:source"))) {
+ if (target.key.label.equals(Label.create("//java/example:source"))) {
jars.add(
new BlazeJarLibrary(
- LibraryArtifact.builder().setInterfaceJar(gen("source.jar")).build(),
- target.key));
+ LibraryArtifact.builder().setInterfaceJar(gen("source.jar")).build()));
}
}
});
@@ -1394,11 +1394,8 @@
return null;
}
- private ArtifactLocation source(String relativePath) {
- return ArtifactLocation.builder()
- .setRelativePath(relativePath)
- .setIsSource(true)
- .build();
+ private static ArtifactLocation source(String relativePath) {
+ return ArtifactLocation.builder().setRelativePath(relativePath).setIsSource(true).build();
}
private static ArtifactLocation gen(String 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
index 25fac98..0538155 100644
--- 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
@@ -24,11 +24,11 @@
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.command.info.BlazeInfo;
import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
import com.google.idea.blaze.base.ideinfo.TargetKey;
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;
@@ -39,7 +39,6 @@
import com.google.idea.blaze.base.scope.output.IssueOutput;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoderImpl;
-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;
@@ -66,17 +65,17 @@
public class SourceDirectoryCalculatorTest extends BlazeTestCase {
private static final ImmutableMap<TargetKey, ArtifactLocation> NO_MANIFESTS = ImmutableMap.of();
- private static final Label LABEL = new Label("//fake:label");
+ private static final Label LABEL = Label.create("//fake:label");
private MockInputStreamProvider mockInputStreamProvider;
private SourceDirectoryCalculator sourceDirectoryCalculator;
- private BlazeContext context = new BlazeContext();
- private ErrorCollector issues = new ErrorCollector();
+ private final BlazeContext context = new BlazeContext();
+ private final ErrorCollector issues = new ErrorCollector();
private MockExperimentService experimentService;
- private WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/root"));
- private ArtifactLocationDecoder decoder =
+ private final WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/root"));
+ private final ArtifactLocationDecoder decoder =
(ArtifactLocationDecoder)
artifactLocation -> new File("/root", artifactLocation.getRelativePath());
@@ -101,6 +100,9 @@
applicationServices.register(ExperimentService.class, experimentService);
applicationServices.register(PrefetchService.class, new MockPrefetchService());
+
+ registerExtensionPoint(JavaLikeLanguage.EP_NAME, JavaLikeLanguage.class)
+ .registerExtension(new JavaLikeLanguage.Java());
}
@Test
@@ -894,16 +896,14 @@
.build()),
ImmutableList.of("com.google"));
ImmutableMap<TargetKey, ArtifactLocation> manifests =
- ImmutableMap.<TargetKey, ArtifactLocation>builder()
- .put(
- TargetKey.forPlainTarget(LABEL),
- ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setIsSource(true)
- .build())
- .build();
+ ImmutableMap.of(
+ TargetKey.forPlainTarget(LABEL),
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setIsSource(true)
+ .build());
Map<TargetKey, Map<ArtifactLocation, String>> manifestMap =
- readPackageManifestFiles(manifests, getDecoder("/root"));
+ readPackageManifestFiles(manifests, getDecoder());
assertThat(manifestMap.get(TargetKey.forPlainTarget(LABEL)))
.containsEntry(
@@ -921,16 +921,14 @@
ImmutableList.of("java/com/google/Bla.java"),
ImmutableList.of("com.google"));
ImmutableMap<TargetKey, ArtifactLocation> manifests =
- ImmutableMap.<TargetKey, ArtifactLocation>builder()
- .put(
- TargetKey.forPlainTarget(LABEL),
- ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setIsSource(true)
- .build())
- .build();
+ ImmutableMap.of(
+ TargetKey.forPlainTarget(LABEL),
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setIsSource(true)
+ .build());
Map<TargetKey, Map<ArtifactLocation, String>> manifestMap =
- readPackageManifestFiles(manifests, getDecoder("/root"));
+ readPackageManifestFiles(manifests, getDecoder());
assertThat(manifestMap.get(TargetKey.forPlainTarget(LABEL)))
.containsEntry(
@@ -954,38 +952,38 @@
ImmutableMap<TargetKey, ArtifactLocation> manifests =
ImmutableMap.<TargetKey, ArtifactLocation>builder()
.put(
- TargetKey.forPlainTarget(new Label("//a:a")),
+ TargetKey.forPlainTarget(Label.create("//a:a")),
ArtifactLocation.builder()
.setRelativePath("java/com/test.manifest")
.setIsSource(true)
.build())
.put(
- TargetKey.forPlainTarget(new Label("//b:b")),
+ TargetKey.forPlainTarget(Label.create("//b:b")),
ArtifactLocation.builder()
.setRelativePath("java/com/test2.manifest")
.setIsSource(true)
.build())
.build();
Map<TargetKey, Map<ArtifactLocation, String>> manifestMap =
- readPackageManifestFiles(manifests, getDecoder("/root"));
+ readPackageManifestFiles(manifests, getDecoder());
assertThat(manifestMap).hasSize(2);
- assertThat(manifestMap.get(TargetKey.forPlainTarget(new Label("//a:a"))))
+ assertThat(manifestMap.get(TargetKey.forPlainTarget(Label.create("//a:a"))))
.containsEntry(
ArtifactLocation.builder()
.setRelativePath("java/com/google/Bla.java")
.setIsSource(true)
.build(),
"com.google");
- assertThat(manifestMap.get(TargetKey.forPlainTarget(new Label("//a:a"))))
+ assertThat(manifestMap.get(TargetKey.forPlainTarget(Label.create("//a:a"))))
.containsEntry(
ArtifactLocation.builder()
.setRelativePath("java/com/google/Foo.java")
.setIsSource(true)
.build(),
"com.google.subpackage");
- assertThat(manifestMap.get(TargetKey.forPlainTarget(new Label("//b:b"))))
+ assertThat(manifestMap.get(TargetKey.forPlainTarget(Label.create("//b:b"))))
.containsEntry(
ArtifactLocation.builder()
.setRelativePath("java/com/google/other/Temp.java")
@@ -1006,14 +1004,12 @@
"package com.google.different;\n public class Bla {}");
ImmutableMap<TargetKey, ArtifactLocation> manifests =
- ImmutableMap.<TargetKey, ArtifactLocation>builder()
- .put(
- TargetKey.forPlainTarget(LABEL),
- ArtifactLocation.builder()
- .setRelativePath("java/com/test.manifest")
- .setIsSource(true)
- .build())
- .build();
+ ImmutableMap.of(
+ TargetKey.forPlainTarget(LABEL),
+ ArtifactLocation.builder()
+ .setRelativePath("java/com/test.manifest")
+ .setIsSource(true)
+ .build());
List<SourceArtifact> sourceArtifacts =
ImmutableList.of(
@@ -1041,7 +1037,7 @@
project,
context,
workspaceRoot,
- getDecoder("/root"),
+ getDecoder(),
ImmutableList.of(new WorkspacePath("java/com/google")),
sourceArtifacts,
manifests);
@@ -1093,23 +1089,18 @@
mockInputStreamProvider.addFile(manifestPath, manifest.build().toByteArray());
}
- private static ArtifactLocationDecoder getDecoder(String rootPath) {
- File root = new File(rootPath);
+ private static ArtifactLocationDecoder getDecoder() {
+ File root = new File("/root");
WorkspaceRoot workspaceRoot = new WorkspaceRoot(root);
- BlazeRoots roots =
- new BlazeRoots(
- root,
- ImmutableList.of(root),
- new ExecutionRootPath("out/crosstool/bin"),
- new ExecutionRootPath("out/crosstool/gen"),
- null);
- return new ArtifactLocationDecoderImpl(
- roots, new WorkspacePathResolverImpl(workspaceRoot, roots));
+ BlazeInfo roots =
+ BlazeInfo.createMockBlazeInfo(
+ "/", "/root", "/root/out/crosstool/bin", "/root/out/crosstool/gen");
+ return new ArtifactLocationDecoderImpl(roots, new WorkspacePathResolverImpl(workspaceRoot));
}
private static class MockInputStreamProvider implements InputStreamProvider {
- private final Map<String, InputStream> javaFiles = new HashMap<String, InputStream>();
+ private final Map<String, InputStream> javaFiles = new HashMap<>();
public MockInputStreamProvider addFile(String filePath, String javaSrc) {
try {
@@ -1140,7 +1131,7 @@
Map<TargetKey, ArtifactLocation> manifests, ArtifactLocationDecoder decoder) {
return PackageManifestReader.getInstance()
.readPackageManifestFiles(
- project, context, decoder, manifests, MoreExecutors.sameThreadExecutor());
+ project, context, decoder, manifests, MoreExecutors.newDirectExecutorService());
}
static class MockFileAttributeProvider extends FileAttributeProvider {
diff --git a/plugin_dev/BUILD b/plugin_dev/BUILD
index 1c56953..1586378 100644
--- a/plugin_dev/BUILD
+++ b/plugin_dev/BUILD
@@ -9,6 +9,7 @@
"//intellij_platform_sdk:devkit",
"//intellij_platform_sdk:plugin_api",
"//java",
+ "//proto:proto_deps",
"//sdkcompat",
"@jsr305_annotations//jar",
],
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java b/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
index 3947b69..608c452 100644
--- a/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/IntellijPluginRule.java
@@ -22,21 +22,14 @@
public class IntellijPluginRule {
public static final String TARGET_TAG_IJ_PLUGIN = "intellij-plugin";
- public static final String TARGET_TAG_IJ_PLUGIN_BUNDLE = "intellij-plugin-bundle";
public static boolean isPluginTarget(TargetIdeInfo target) {
return isIntellijPluginDebugTarget(target)
- || isPluginBundle(target)
|| isSinglePluginTarget(target);
}
public static boolean isIntellijPluginDebugTarget(TargetIdeInfo target) {
- return target.intellijPluginDeployInfo != null;
- }
-
- public static boolean isPluginBundle(TargetIdeInfo target) {
- return target.kindIsOneOf(Kind.JAVA_LIBRARY)
- && target.tags.contains(TARGET_TAG_IJ_PLUGIN_BUNDLE);
+ return target.kind == Kind.INTELLIJ_PLUGIN_DEBUG_TARGET;
}
public static boolean isSinglePluginTarget(TargetIdeInfo target) {
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
index 528cac4..3621e36 100644
--- a/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginConfiguration.java
@@ -20,13 +20,9 @@
import com.google.common.base.Strings;
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.TargetIdeInfo;
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.state.RunConfigurationFlagsState;
@@ -194,6 +190,7 @@
final BlazeIntellijPluginDeployer deployer =
new BlazeIntellijPluginDeployer(getProject(), sandboxHome, buildNumber);
deployer.addTarget(getTarget());
+ env.putUserData(BlazeIntellijPluginDeployer.USER_DATA_KEY, deployer);
// copy license from running instance of idea
IdeaJdkHelper.copyIDEALicense(sandboxHome);
@@ -332,8 +329,8 @@
final BlazeIntellijPluginConfiguration configuration =
(BlazeIntellijPluginConfiguration) super.clone();
configuration.target = target;
- configuration.blazeFlags.setFlags(blazeFlags.getFlags());
- configuration.exeFlags.setFlags(exeFlags.getFlags());
+ configuration.blazeFlags.setRawFlags(blazeFlags.getRawFlags());
+ configuration.exeFlags.setRawFlags(exeFlags.getRawFlags());
configuration.pluginSdk = pluginSdk;
configuration.vmParameters = vmParameters;
configuration.programParameters = programParameters;
@@ -341,14 +338,12 @@
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.getFlags())
- .addExeFlags(exeFlags.getFlags());
- return command.build();
+ RunConfigurationFlagsState getBlazeFlagsState() {
+ return blazeFlags;
+ }
+
+ RunConfigurationFlagsState getExeFlagsState() {
+ return exeFlags;
}
@Override
diff --git a/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginDeployer.java b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginDeployer.java
index c06caf2..2c366f9 100644
--- a/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginDeployer.java
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/BlazeIntellijPluginDeployer.java
@@ -15,14 +15,13 @@
*/
package com.google.idea.blaze.plugin.run;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
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.idea.blaze.base.ideinfo.Dependency;
-import com.google.idea.blaze.base.ideinfo.Dependency.DependencyType;
-import com.google.idea.blaze.base.ideinfo.IntellijPluginDeployInfo;
-import com.google.idea.blaze.base.ideinfo.IntellijPluginDeployInfo.IntellijPluginDeployFile;
+import com.google.idea.blaze.base.command.buildresult.BuildResultHelper;
import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
@@ -31,29 +30,43 @@
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
-import com.google.idea.blaze.base.sync.workspace.ArtifactLocationDecoder;
import com.google.idea.blaze.plugin.IntellijPluginRule;
+import com.google.repackaged.devtools.intellij.plugin.IntellijPluginTargetDeployInfo.IntellijPluginDeployFile;
+import com.google.repackaged.devtools.intellij.plugin.IntellijPluginTargetDeployInfo.IntellijPluginDeployInfo;
+import com.google.repackaged.protobuf.TextFormat;
import com.intellij.execution.ExecutionException;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.BuildNumber;
+import com.intellij.openapi.util.Key;
+import java.io.BufferedInputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-import org.jetbrains.annotations.Nullable;
+import javax.annotation.Nullable;
/** Handles finding files to deploy and copying these into the sandbox. */
class BlazeIntellijPluginDeployer {
+
+ static final Key<BlazeIntellijPluginDeployer> USER_DATA_KEY =
+ Key.create(BlazeIntellijPluginDeployer.class.getName());
+
private final String sandboxHome;
private final String buildNumber;
private final TargetMap targetMap;
- private final ArtifactLocationDecoder artifactLocationDecoder;
- private Map<File, File> filesToDeploy = Maps.newHashMap();
+ private final List<Label> targetsToDeploy = new ArrayList<>();
+ private final List<File> deployInfoFiles = new ArrayList<>();
+ private final Map<File, File> filesToDeploy = Maps.newHashMap();
+ private File executionRoot;
BlazeIntellijPluginDeployer(Project project, String sandboxHome, String buildNumber)
throws ExecutionException {
@@ -65,17 +78,36 @@
this.sandboxHome = sandboxHome;
this.buildNumber = buildNumber;
this.targetMap = blazeProjectData.targetMap;
- this.artifactLocationDecoder = blazeProjectData.artifactLocationDecoder;
}
/** Adds an intellij plugin target to deploy */
void addTarget(Label label) throws ExecutionException {
- ImmutableList<IntellijPluginDeployInfo> deployInfos = findDeployInfo(label);
- ImmutableMap<File, File> filesToDeploy = getFilesToDeploy(deployInfos);
- this.filesToDeploy.putAll(filesToDeploy);
+ targetsToDeploy.add(label);
+ }
+
+ void reportBuildComplete(File executionRoot, BuildResultHelper buildResultHelper) {
+ this.executionRoot = executionRoot;
+ for (File file : buildResultHelper.getBuildArtifacts()) {
+ if (file.getName().endsWith(".intellij-plugin-debug-target-deploy-info")) {
+ deployInfoFiles.add(file);
+ }
+ }
}
List<String> deploy() throws ExecutionException {
+ List<IntellijPluginDeployInfo> deployInfoList = Lists.newArrayList();
+ if (!deployInfoFiles.isEmpty()) {
+ for (File deployInfoFile : deployInfoFiles) {
+ deployInfoList.addAll(readDeployInfoFromFile(deployInfoFile));
+ }
+ } else {
+ for (Label label : targetsToDeploy) {
+ deployInfoList.addAll(findDeployInfoFromBareIntelliJPluginTargets(label));
+ }
+ }
+ ImmutableMap<File, File> filesToDeploy = getFilesToDeploy(executionRoot, deployInfoList);
+ this.filesToDeploy.putAll(filesToDeploy);
+
for (File file : filesToDeploy.keySet()) {
if (!file.exists()) {
throw new ExecutionException(
@@ -97,37 +129,33 @@
}
}
- private ImmutableList<IntellijPluginDeployInfo> findDeployInfo(Label label)
+ private static ImmutableList<IntellijPluginDeployInfo> readDeployInfoFromFile(File deployInfoFile)
throws ExecutionException {
+ ImmutableList.Builder<IntellijPluginDeployInfo> result = ImmutableList.builder();
+ try (InputStream inputStream = new BufferedInputStream(new FileInputStream(deployInfoFile))) {
+ IntellijPluginDeployInfo.Builder builder = IntellijPluginDeployInfo.newBuilder();
+ TextFormat.Parser parser = TextFormat.Parser.newBuilder().setAllowUnknownFields(true).build();
+ parser.merge(new InputStreamReader(inputStream, UTF_8), builder);
+ IntellijPluginDeployInfo deployInfo = builder.build();
+ result.add(deployInfo);
+ } catch (IOException e) {
+ throw new ExecutionException(e);
+ }
+ return result.build();
+ }
+
+ private ImmutableList<IntellijPluginDeployInfo> findDeployInfoFromBareIntelliJPluginTargets(
+ Label label) throws ExecutionException {
TargetIdeInfo target = targetMap.get(TargetKey.forPlainTarget(label));
if (target == null) {
throw new ExecutionException("Target '" + label + "' not imported during sync");
}
- if (IntellijPluginRule.isIntellijPluginDebugTarget(target)) {
- assert target.intellijPluginDeployInfo != null;
- return ImmutableList.of(target.intellijPluginDeployInfo);
- } else if (IntellijPluginRule.isSinglePluginTarget(target)) {
+ if (IntellijPluginRule.isSinglePluginTarget(target)) {
return ImmutableList.of(deployInfoForIntellijPlugin(target));
- } else if (IntellijPluginRule.isPluginBundle(target)) {
- return deployInfoForLegacyBundle(target);
}
throw new ExecutionException("Target is not a supported intellij plugin type.");
}
- private ImmutableList<IntellijPluginDeployInfo> deployInfoForLegacyBundle(TargetIdeInfo target)
- throws ExecutionException {
- ImmutableList.Builder<IntellijPluginDeployInfo> deployInfoBuilder = ImmutableList.builder();
- for (Dependency dep : target.dependencies) {
- if (dep.dependencyType == DependencyType.COMPILE_TIME && dep.targetKey.isPlainTarget()) {
- TargetIdeInfo depTarget = targetMap.get(dep.targetKey);
- if (depTarget != null && IntellijPluginRule.isSinglePluginTarget(depTarget)) {
- deployInfoBuilder.add(deployInfoForIntellijPlugin(depTarget));
- }
- }
- }
- return deployInfoBuilder.build();
- }
-
private static IntellijPluginDeployInfo deployInfoForIntellijPlugin(TargetIdeInfo target)
throws ExecutionException {
JavaIdeInfo javaIdeInfo = target.javaIdeInfo;
@@ -142,19 +170,21 @@
if (artifact == null || artifact.classJar == null) {
throw new ExecutionException("No output plugin jar found for '" + target + "'");
}
- IntellijPluginDeployFile deployFile =
- new IntellijPluginDeployFile(
- artifact.classJar, new File(artifact.classJar.relativePath).getName());
- return new IntellijPluginDeployInfo(ImmutableList.of(deployFile));
+ return IntellijPluginDeployInfo.newBuilder()
+ .addDeployFiles(
+ IntellijPluginDeployFile.newBuilder()
+ .setExecutionPath(artifact.classJar.getExecutionRootRelativePath())
+ .setDeployLocation(new File(artifact.classJar.relativePath).getName()))
+ .build();
}
private ImmutableMap<File, File> getFilesToDeploy(
- Collection<IntellijPluginDeployInfo> deployInfos) {
+ File executionRoot, Collection<IntellijPluginDeployInfo> deployInfos) {
ImmutableMap.Builder<File, File> result = ImmutableMap.builder();
for (IntellijPluginDeployInfo deployInfo : deployInfos) {
- for (IntellijPluginDeployFile deployFile : deployInfo.deployFiles) {
- File src = artifactLocationDecoder.decode(deployFile.src);
- File dest = new File(sandboxPluginDirectory(sandboxHome), deployFile.deployLocation);
+ for (IntellijPluginDeployFile deployFile : deployInfo.getDeployFilesList()) {
+ File src = new File(executionRoot, deployFile.getExecutionPath());
+ File dest = new File(sandboxPluginDirectory(sandboxHome), deployFile.getDeployLocation());
result.put(src, dest);
}
}
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
index 2a9d071..3c778fe 100644
--- a/plugin_dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java
+++ b/plugin_dev/src/com/google/idea/blaze/plugin/run/BuildPluginBeforeRunTaskProvider.java
@@ -19,8 +19,12 @@
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.command.BlazeCommandName;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.command.buildresult.BuildResultHelper;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.command.info.BlazeInfoRunner;
import com.google.idea.blaze.base.experiments.ExperimentScope;
import com.google.idea.blaze.base.filecache.FileCaches;
import com.google.idea.blaze.base.issueparser.IssueOutputLineProcessor;
@@ -45,6 +49,7 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import icons.BlazeIcons;
+import java.io.File;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
@@ -159,20 +164,64 @@
new ScopedTask(context) {
@Override
protected void execute(BlazeContext context) {
+ BlazeIntellijPluginDeployer deployer =
+ env.getUserData(BlazeIntellijPluginDeployer.USER_DATA_KEY);
+ if (deployer == null) {
+ IssueOutput.error("Could not find BlazeIntellijPluginDeployer in env.")
+ .submit(context);
+ return;
+ }
+
+ String binaryPath = Blaze.getBuildSystemProvider(project).getBinaryPath();
+ WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
BlazeIntellijPluginConfiguration config =
(BlazeIntellijPluginConfiguration) configuration;
- BlazeCommand command = config.buildBlazeCommand(project, projectViewSet);
+
+ ListenableFuture<String> executionRootFuture =
+ BlazeInfoRunner.getInstance()
+ .runBlazeInfo(
+ context,
+ binaryPath,
+ workspaceRoot,
+ config.getBlazeFlagsState().getExpandedFlags(),
+ BlazeInfo.EXECUTION_ROOT_KEY);
+
+ String executionRoot;
+ try {
+ executionRoot = executionRootFuture.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ context.setCancelled();
+ return;
+ } catch (ExecutionException e) {
+ IssueOutput.error(e.getMessage()).submit(context);
+ context.setHasError();
+ return;
+ }
+ if (executionRoot == null) {
+ IssueOutput.error("Could not determine execution root").submit(context);
+ return;
+ }
+
+ BuildResultHelper buildResultHelper = BuildResultHelper.forFiles(f -> true);
+ BlazeCommand command =
+ BlazeCommand.builder(binaryPath, BlazeCommandName.BUILD)
+ .addTargets(config.getTarget())
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
+ .addBlazeFlags(config.getBlazeFlagsState().getExpandedFlags())
+ .addExeFlags(config.getExeFlagsState().getExpandedFlags())
+ .addBlazeFlags(buildResultHelper.getBuildFlags())
+ .build();
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(
+ buildResultHelper.stderr(
new IssueOutputLineProcessor(project, context, workspaceRoot)))
.build()
.run();
@@ -180,6 +229,7 @@
context.setHasError();
}
FileCaches.refresh(project);
+ deployer.reportBuildComplete(new File(executionRoot), buildResultHelper);
}
};
diff --git a/proto_deps/BUILD b/proto/BUILD
similarity index 100%
rename from proto_deps/BUILD
rename to proto/BUILD
diff --git a/proto/proto_deps.jar b/proto/proto_deps.jar
new file mode 100755
index 0000000..2637779
--- /dev/null
+++ b/proto/proto_deps.jar
Binary files differ
diff --git a/proto_deps/proto_deps.jar b/proto_deps/proto_deps.jar
deleted file mode 100755
index ac441be..0000000
--- a/proto_deps/proto_deps.jar
+++ /dev/null
Binary files differ
diff --git a/python/BUILD b/python/BUILD
new file mode 100644
index 0000000..51e2752
--- /dev/null
+++ b/python/BUILD
@@ -0,0 +1,99 @@
+licenses(["notice"]) # Apache 2.0
+
+load(
+ "//build_defs:build_defs.bzl",
+ "intellij_plugin",
+ "merged_plugin_xml",
+ "optional_plugin_xml",
+ "stamped_plugin_xml",
+)
+load(
+ "//testing:test_defs.bzl",
+ "intellij_integration_test_suite",
+ "intellij_unit_test_suite",
+)
+
+java_library(
+ name = "python",
+ srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//common/experiments",
+ "//intellij_platform_sdk:plugin_api",
+ "//sdkcompat",
+ "//third_party/python",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+filegroup(
+ name = "plugin_xml",
+ srcs = ["src/META-INF/blaze-python.xml"],
+ visibility = ["//visibility:public"],
+)
+
+optional_plugin_xml(
+ name = "optional_xml",
+ module = "com.intellij.modules.python",
+ plugin_xml = "src/META-INF/python-contents.xml",
+ visibility = ["//visibility:public"],
+)
+
+merged_plugin_xml(
+ name = "merged_plugin_xml",
+ srcs = [
+ "//base:plugin_xml",
+ "//python:plugin_xml",
+ ],
+)
+
+stamped_plugin_xml(
+ name = "python_plugin_xml",
+ plugin_id = "com.google.idea.blaze.python",
+ plugin_name = "com.google.idea.blaze.python",
+ plugin_xml = "merged_plugin_xml",
+)
+
+intellij_plugin(
+ name = "python_integration_test_plugin",
+ testonly = 1,
+ optional_plugin_xmls = [":optional_xml"],
+ plugin_xml = ":python_plugin_xml",
+ deps = [
+ "//python",
+ ],
+)
+
+intellij_integration_test_suite(
+ name = "integration_tests",
+ srcs = glob(["tests/integrationtests/**/*.java"]),
+ required_plugins = "com.google.idea.blaze.python",
+ test_package_root = "com.google.idea.blaze.python",
+ runtime_deps = [
+ ":python_integration_test_plugin",
+ ],
+ deps = [
+ ":python",
+ "//base",
+ "//base:integration_test_utils",
+ "//base:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//third_party/python:python_for_tests",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
+
+intellij_unit_test_suite(
+ name = "unit_tests",
+ srcs = glob(["tests/unittests/**/*.java"]),
+ test_package_root = "com.google.idea.blaze.python",
+ deps = [
+ ":python",
+ "//base",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "@jsr305_annotations//jar",
+ "@junit//jar",
+ ],
+)
diff --git a/python/src/META-INF/blaze-python.xml b/python/src/META-INF/blaze-python.xml
new file mode 100644
index 0000000..8ee292f
--- /dev/null
+++ b/python/src/META-INF/blaze-python.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright 2017 The Bazel Authors. All rights reserved.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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>
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncPlugin implementation="com.google.idea.blaze.python.sync.AlwaysPresentPythonSyncPlugin"/>
+ </extensions>
+</idea-plugin>
\ No newline at end of file
diff --git a/python/src/META-INF/python-contents.xml b/python/src/META-INF/python-contents.xml
new file mode 100644
index 0000000..b2e1ab4
--- /dev/null
+++ b/python/src/META-INF/python-contents.xml
@@ -0,0 +1,47 @@
+<!--
+ ~ Copyright 2017 The Bazel Authors. All rights reserved.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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>
+
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncPlugin implementation="com.google.idea.blaze.python.sync.BlazePythonSyncPlugin"/>
+ <PrefetchFileSource implementation="com.google.idea.blaze.python.sync.PythonPrefetchFileSource"/>
+ <BlazeCommandRunConfigurationHandlerProvider implementation="com.google.idea.blaze.python.run.BlazePyRunConfigurationHandlerProvider" order="first"/>
+ <RunConfigurationFactory implementation="com.google.idea.blaze.python.run.BlazePyDebuggableRunConfigurationFactory"/>
+ <BlazeTestEventsHandler implementation="com.google.idea.blaze.python.run.smrunner.BlazePythonTestEventsHandler"/>
+ </extensions>
+
+ <extensions defaultExtensionNs="com.intellij">
+ <useScopeEnlarger implementation="com.google.idea.blaze.python.search.BlazePyUseScopeEnlarger"/>
+ <runConfigurationProducer implementation="com.google.idea.blaze.python.run.producers.BlazePyBinaryConfigurationProducer" order="first"/>
+ <runConfigurationProducer implementation="com.google.idea.blaze.python.run.producers.BlazePyTestConfigurationProducer" order="first"/>
+ <programRunner implementation="com.google.idea.blaze.python.run.BlazePyDebugRunner"/>
+ <consoleFilterProvider implementation="com.google.idea.blaze.python.run.filter.BlazePyTracebackFilter$BlazePyTracebackFilterProvider"/>
+ </extensions>
+
+ <extensionPoints>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazePyFilterProvider"
+ interface="com.google.idea.blaze.python.run.filter.BlazePyFilterProvider"/>
+ <extensionPoint qualifiedName="com.google.idea.blaze.BlazePyDebugFlagsProvider"
+ interface="com.google.idea.blaze.python.run.BlazePyDebugHelper"/>
+ </extensionPoints>
+
+ <project-components>
+ <component>
+ <implementation-class>com.google.idea.blaze.python.run.producers.NonBlazeProducerSuppressor</implementation-class>
+ </component>
+ </project-components>
+
+</idea-plugin>
diff --git a/python/src/com/google/idea/blaze/python/PySdkUtils.java b/python/src/com/google/idea/blaze/python/PySdkUtils.java
new file mode 100644
index 0000000..0b56d45
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/PySdkUtils.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python;
+
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.jetbrains.python.sdk.PythonSdkType;
+import javax.annotation.Nullable;
+
+/** Helper methods related to the python SDK. */
+public class PySdkUtils {
+
+ /** Find a python SDK associated with a blaze project, or its workspace module. */
+ @Nullable
+ public static Sdk getPythonSdk(Project project) {
+ Sdk projectSdk = ProjectRootManager.getInstance(project).getProjectSdk();
+ if (projectSdk != null && projectSdk.getSdkType() instanceof PythonSdkType) {
+ return projectSdk;
+ }
+ // look for a SDK associated with a python facet instead.
+ return PythonSdkType.findPythonSdk(
+ ModuleManager.getInstance(project)
+ .findModuleByName(BlazeDataStorage.WORKSPACE_MODULE_NAME));
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/PythonPluginUtils.java b/python/src/com/google/idea/blaze/python/PythonPluginUtils.java
new file mode 100644
index 0000000..62fd0ab
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/PythonPluginUtils.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python;
+
+import com.google.common.collect.ImmutableMap;
+import com.intellij.util.PlatformUtils;
+
+/** Utilities class related to the JetBrains python plugin. */
+public final class PythonPluginUtils {
+
+ private PythonPluginUtils() {}
+
+ private static final ImmutableMap<String, String> PRODUCT_TO_PLUGIN_ID =
+ ImmutableMap.of(
+ PlatformUtils.IDEA_PREFIX, "Pythonid",
+ PlatformUtils.IDEA_CE_PREFIX, "PythonCore",
+ PlatformUtils.CLION_PREFIX, "com.intellij.clion-python");
+
+ public static String getPythonPluginId() {
+ String pluginId = PRODUCT_TO_PLUGIN_ID.get(PlatformUtils.getPlatformPrefix());
+ if (pluginId == null) {
+ throw new RuntimeException(
+ "No python plugin ID for unhandled platform: " + PlatformUtils.getPlatformPrefix());
+ }
+ return pluginId;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyDebugHelper.java b/python/src/com/google/idea/blaze/python/run/BlazePyDebugHelper.java
new file mode 100644
index 0000000..9418e2c
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyDebugHelper.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+
+/** Extension point for adding blaze flags when debugging python targets. */
+public interface BlazePyDebugHelper {
+
+ ExtensionPointName<BlazePyDebugHelper> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BlazePyDebugFlagsProvider");
+
+ static ImmutableList<String> getAllBlazeDebugFlags() {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ for (BlazePyDebugHelper provider : EP_NAME.getExtensions()) {
+ builder.addAll(provider.getBlazeDebugFlags());
+ }
+ return builder.build();
+ }
+
+ @Nullable
+ static String validateDebugTarget(Project project, @Nullable TargetExpression target) {
+ for (BlazePyDebugHelper provider : EP_NAME.getExtensions()) {
+ String error = provider.validatePyDebugTarget(project, target);
+ if (error != null) {
+ return error;
+ }
+ }
+ return null;
+ }
+
+ ImmutableList<String> getBlazeDebugFlags();
+
+ /**
+ * Attempts to check whether the given target can be debugged by the Blaze plugin. If there's a
+ * known problem, returns an error message with the details.
+ */
+ @Nullable
+ String validatePyDebugTarget(Project project, @Nullable TargetExpression target);
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyDebugRunner.java b/python/src/com/google/idea/blaze/python/run/BlazePyDebugRunner.java
new file mode 100644
index 0000000..8b24142
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyDebugRunner.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.python.run.BlazePyRunConfigurationRunner.BlazePyDummyRunProfileState;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.xdebugger.XDebugSession;
+import com.jetbrains.python.debugger.PyDebugProcess;
+import com.jetbrains.python.debugger.PyDebugRunner;
+import com.jetbrains.python.run.PythonCommandLineState;
+import java.net.ServerSocket;
+
+/** Blaze plugin specific {@link PyDebugRunner}. */
+public class BlazePyDebugRunner extends PyDebugRunner {
+
+ @Override
+ public String getRunnerId() {
+ return "BlazePyDebugRunner";
+ }
+
+ @Override
+ public boolean canRun(String executorId, RunProfile profile) {
+ if (!DefaultDebugExecutor.EXECUTOR_ID.equals(executorId)
+ || !(profile instanceof BlazeCommandRunConfiguration)) {
+ return false;
+ }
+ BlazeCommandRunConfiguration config = (BlazeCommandRunConfiguration) profile;
+ BlazeCommandRunConfigurationCommonState handlerState =
+ config.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ BlazeCommandName command =
+ handlerState != null ? handlerState.getCommandState().getCommand() : null;
+ return PyDebugUtils.canUsePyDebugger(config.getKindForTarget())
+ && (BlazeCommandName.TEST.equals(command) || BlazeCommandName.RUN.equals(command));
+ }
+
+ @Override
+ protected PyDebugProcess createDebugProcess(
+ XDebugSession xDebugSession,
+ ServerSocket serverSocket,
+ ExecutionResult executionResult,
+ PythonCommandLineState pythonCommandLineState) {
+ PyDebugProcess process =
+ super.createDebugProcess(
+ xDebugSession, serverSocket, executionResult, pythonCommandLineState);
+ process.setPositionConverter(new BlazePyPositionConverter());
+ return process;
+ }
+
+ @Override
+ protected RunContentDescriptor doExecute(RunProfileState state, ExecutionEnvironment environment)
+ throws ExecutionException {
+ if (!(state instanceof BlazePyDummyRunProfileState)) {
+ return null;
+ }
+ try {
+ state = ((BlazePyDummyRunProfileState) state).toNativeState(environment);
+ return super.doExecute(state, environment);
+ } catch (ExecutionException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ExecutionException(e);
+ }
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyDebuggableRunConfigurationFactory.java b/python/src/com/google/idea/blaze/python/run/BlazePyDebuggableRunConfigurationFactory.java
new file mode 100644
index 0000000..7536401
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyDebuggableRunConfigurationFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetKey;
+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.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.BlazeRunConfigurationFactory;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.openapi.project.Project;
+
+/** Creates run configurations for debuggable python targets. */
+public class BlazePyDebuggableRunConfigurationFactory extends BlazeRunConfigurationFactory {
+ @Override
+ public boolean handlesTarget(Project project, BlazeProjectData blazeProjectData, Label label) {
+ TargetIdeInfo target = blazeProjectData.targetMap.get(TargetKey.forPlainTarget(label));
+ return target != null && target.kind != null && PyDebugUtils.canUsePyDebugger(target.kind);
+ }
+
+ @Override
+ protected ConfigurationFactory getConfigurationFactory() {
+ return BlazeCommandRunConfigurationType.getInstance().getFactory();
+ }
+
+ @Override
+ public void setupConfiguration(RunConfiguration configuration, Label target) {
+ final BlazeCommandRunConfiguration blazeConfig = (BlazeCommandRunConfiguration) configuration;
+ blazeConfig.setTarget(target);
+
+ BlazeCommandRunConfigurationCommonState state =
+ blazeConfig.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ Kind kind = blazeConfig.getKindForTarget();
+ if (state != null) {
+ BlazeCommandName command =
+ kind != null && Kind.isTestRule(kind.toString())
+ ? BlazeCommandName.TEST
+ : BlazeCommandName.RUN;
+ state.getCommandState().setCommand(command);
+ }
+ blazeConfig.setGeneratedName();
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyPositionConverter.java b/python/src/com/google/idea/blaze/python/run/BlazePyPositionConverter.java
new file mode 100644
index 0000000..7dd68d1
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyPositionConverter.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.intellij.openapi.application.AccessToken;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.xdebugger.XDebuggerUtil;
+import com.intellij.xdebugger.XSourcePosition;
+import com.jetbrains.python.debugger.PyDebugSupportUtils;
+import com.jetbrains.python.debugger.PyLocalPositionConverter;
+import com.jetbrains.python.debugger.PyPositionConverter;
+import com.jetbrains.python.debugger.PySignature;
+import com.jetbrains.python.debugger.PySourcePosition;
+import java.io.File;
+import java.io.IOException;
+import javax.annotation.Nullable;
+
+/**
+ * Converts the blaze-out symlink file paths to the actual source file paths. Otherwise a copy of
+ * {@link PyLocalPositionConverter}
+ */
+public class BlazePyPositionConverter implements PyPositionConverter {
+
+ private static final Logger logger = Logger.getInstance(BlazePyPositionConverter.class);
+
+ @Override
+ public PySourcePosition create(String filePath, int line) {
+ return new PySourcePosition(convertFilePath(filePath), line) {};
+ }
+
+ @Override
+ public PySourcePosition convertToPython(XSourcePosition position) {
+ return new PySourcePosition(
+ convertFilePath(position.getFile().getPath()),
+ convertLocalLineToRemote(position.getFile(), position.getLine())) {};
+ }
+
+ @Nullable
+ @Override
+ public XSourcePosition convertFromPython(PySourcePosition position) {
+ return createXSourcePosition(getVirtualFile(position.getFile()), position.getLine());
+ }
+
+ @Override
+ public PySignature convertSignature(PySignature signature) {
+ return signature;
+ }
+
+ private static String convertFilePath(String filePath) {
+ File file = new File(filePath);
+ try {
+ return file.getCanonicalPath();
+ } catch (IOException e) {
+ logger.warn(e);
+ return filePath;
+ }
+ }
+
+ private static VirtualFile getVirtualFile(String filePath) {
+ return LocalFileSystem.getInstance().findFileByPath(filePath);
+ }
+
+ @Nullable
+ private static XSourcePosition createXSourcePosition(@Nullable VirtualFile vFile, int line) {
+ if (vFile != null) {
+ return XDebuggerUtil.getInstance()
+ .createPosition(vFile, convertRemoteLineToLocal(vFile, line));
+ } else {
+ return null;
+ }
+ }
+
+ /** Convert from 1- to 0-indexed line numbering, and account for continuation lines */
+ private static int convertLocalLineToRemote(VirtualFile file, int line) {
+ AccessToken lock = ApplicationManager.getApplication().acquireReadActionLock();
+ try {
+ final Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document != null) {
+ while (PyDebugSupportUtils.isContinuationLine(document, line)) {
+ line++;
+ }
+ }
+ return line + 1;
+ } finally {
+ lock.finish();
+ }
+ }
+
+ /** Convert from 0- to 1-indexed line numbering, and account for continuation lines */
+ private static int convertRemoteLineToLocal(final VirtualFile vFile, int line) {
+ final Document document =
+ ApplicationManager.getApplication()
+ .runReadAction(
+ new Computable<Document>() {
+ @Override
+ public Document compute() {
+ return FileDocumentManager.getInstance().getDocument(vFile);
+ }
+ });
+
+ line--;
+ if (document != null) {
+ while (PyDebugSupportUtils.isContinuationLine(document, line - 1)) {
+ line--;
+ }
+ }
+ return line;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationHandler.java b/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationHandler.java
new file mode 100644
index 0000000..e8a2d3f
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationHandler.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationHandler;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationRunner;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.Blaze.BuildSystem;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RuntimeConfigurationException;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import javax.annotation.Nullable;
+import javax.swing.Icon;
+
+/** Python-specific handler for {@link BlazeCommandRunConfiguration}s. */
+public final class BlazePyRunConfigurationHandler implements BlazeCommandRunConfigurationHandler {
+
+ private final String buildSystemName;
+ private final BlazeCommandRunConfigurationCommonState state;
+
+ public BlazePyRunConfigurationHandler(BlazeCommandRunConfiguration configuration) {
+ BuildSystem buildSystem = Blaze.getBuildSystem(configuration.getProject());
+ this.buildSystemName = buildSystem.getName();
+ this.state = new BlazeCommandRunConfigurationCommonState(buildSystem);
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationCommonState getState() {
+ return state;
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationRunner createRunner(
+ Executor executor, ExecutionEnvironment environment) {
+ return new BlazePyRunConfigurationRunner();
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ state.validate(buildSystemName);
+ }
+
+ @Override
+ @Nullable
+ public String suggestedName(BlazeCommandRunConfiguration configuration) {
+ if (configuration.getTarget() == null) {
+ return null;
+ }
+ return new BlazeConfigurationNameBuilder(configuration).build();
+ }
+
+ @Override
+ @Nullable
+ public String getCommandName() {
+ BlazeCommandName command = state.getCommandState().getCommand();
+ return command != null ? command.toString() : null;
+ }
+
+ @Override
+ public String getHandlerName() {
+ return "Python Handler";
+ }
+
+ @Override
+ @Nullable
+ public Icon getExecutorIcon(RunConfiguration configuration, Executor executor) {
+ return null;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationHandlerProvider.java b/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationHandlerProvider.java
new file mode 100644
index 0000000..0975c01
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationHandlerProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+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;
+
+/** Python-specific handler provider for {@link BlazeCommandRunConfiguration}s. */
+public class BlazePyRunConfigurationHandlerProvider
+ implements BlazeCommandRunConfigurationHandlerProvider {
+
+ @Override
+ public boolean canHandleKind(Kind kind) {
+ return PyDebugUtils.canUsePyDebugger(kind);
+ }
+
+ @Override
+ public BlazeCommandRunConfigurationHandler createHandler(BlazeCommandRunConfiguration config) {
+ return new BlazePyRunConfigurationHandler(config);
+ }
+
+ @Override
+ public String getId() {
+ return "BlazePyRunConfigurationHandlerProvider";
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationRunner.java b/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationRunner.java
new file mode 100644
index 0000000..08f2a22
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/BlazePyRunConfigurationRunner.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.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.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.command.BlazeFlags;
+import com.google.idea.blaze.base.command.buildresult.BuildResultHelper;
+import com.google.idea.blaze.base.io.FileAttributeProvider;
+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.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.WithBrowserHyperlinkExecutionException;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandGenericRunConfigurationRunner.BlazeCommandRunProfileState;
+import com.google.idea.blaze.base.run.confighandler.BlazeCommandRunConfigurationRunner;
+import com.google.idea.blaze.base.run.filter.BlazeTargetFilter;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.base.scope.BlazeContext;
+import com.google.idea.blaze.base.scope.ScopedTask;
+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.IssuesScope;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.blaze.base.settings.BlazeUserSettings;
+import com.google.idea.blaze.base.sync.data.BlazeDataStorage;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.util.SaveUtil;
+import com.google.idea.blaze.python.run.filter.BlazePyFilterProvider;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.WrappingRunConfiguration;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import com.intellij.execution.filters.Filter;
+import com.intellij.execution.filters.TextConsoleBuilder;
+import com.intellij.execution.process.KillableProcessHandler;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.ExecutionUtil;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.execution.ui.ConsoleView;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.util.PathUtil;
+import com.intellij.util.execution.ParametersListUtil;
+import com.jetbrains.python.console.PyDebugConsoleBuilder;
+import com.jetbrains.python.console.PythonDebugLanguageConsoleView;
+import com.jetbrains.python.run.PythonConfigurationType;
+import com.jetbrains.python.run.PythonRunConfiguration;
+import com.jetbrains.python.run.PythonScriptCommandLineState;
+import java.io.File;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** Python-specific run configuration runner. */
+public class BlazePyRunConfigurationRunner implements BlazeCommandRunConfigurationRunner {
+
+ /** Used to store a runner to an {@link ExecutionEnvironment}. */
+ private static final Key<AtomicReference<File>> EXECUTABLE_KEY =
+ Key.create("blaze.debug.py.executable");
+
+ private static final Logger logger = Logger.getInstance(BlazePyRunConfigurationRunner.class);
+
+ // Filter executables instead of files in the bin directory
+ // This bin directory isn't the right one, because we don't know the blaze binary
+ // or the config flags used to execute the build command
+ // Introduced March 2017
+ private static final BoolExperiment filterExecutableFiles =
+ new BoolExperiment("filter.executable.files", true);
+
+ /** Converts to the native python plugin debug configuration state */
+ static class BlazePyDummyRunProfileState implements RunProfileState {
+ final BlazeCommandRunConfiguration configuration;
+
+ BlazePyDummyRunProfileState(BlazeCommandRunConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ PythonScriptCommandLineState toNativeState(ExecutionEnvironment env) throws ExecutionException {
+ File executable = env.getCopyableUserData(EXECUTABLE_KEY).get();
+ if (executable == null || StringUtil.isEmptyOrSpaces(executable.getPath())) {
+ throw new ExecutionException("No blaze output script found");
+ }
+ PythonRunConfiguration nativeConfig =
+ (PythonRunConfiguration)
+ PythonConfigurationType.getInstance()
+ .getFactory()
+ .createTemplateConfiguration(env.getProject());
+ nativeConfig.setScriptName(executable.getPath());
+ nativeConfig.setAddContentRoots(false);
+ nativeConfig.setAddSourceRoots(false);
+ nativeConfig.setWorkingDirectory(
+ Strings.nullToEmpty(
+ getRunfilesPath(executable, WorkspaceRoot.fromProjectSafe(env.getProject()))));
+
+ Module workspaceModule =
+ nativeConfig.getConfigurationModule().findModule(BlazeDataStorage.WORKSPACE_MODULE_NAME);
+ if (workspaceModule != null) {
+ nativeConfig.setModule(workspaceModule);
+ nativeConfig.setUseModuleSdk(true);
+ } else {
+ throw new ExecutionException(
+ "Can't find the workspace module when debugging a python target");
+ }
+
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState != null) {
+ nativeConfig.setScriptParameters(Strings.emptyToNull(getScriptParams(handlerState)));
+ }
+ return new PythonScriptCommandLineState(nativeConfig, env) {
+ @Override
+ public boolean isDebug() {
+ return true;
+ }
+
+ @Override
+ protected ConsoleView createAndAttachConsole(
+ Project project, ProcessHandler processHandler, Executor executor)
+ throws ExecutionException {
+ ConsoleView consoleView = createConsoleBuilder(project, getSdk()).getConsole();
+ consoleView.addMessageFilter(createUrlFilter(processHandler));
+ addTracebackFilter(project, consoleView, processHandler);
+
+ consoleView.attachToProcess(processHandler);
+ return consoleView;
+ }
+
+ @Override
+ protected ProcessHandler doCreateProcess(GeneralCommandLine commandLine)
+ throws ExecutionException {
+ ProcessHandler handler = super.doCreateProcess(commandLine);
+ if (handler instanceof KillableProcessHandler) {
+ // SIGINT can cause the JVM to crash, when stopped at a breakpoint (IDEA-167432).
+ ((KillableProcessHandler) handler).setShouldKillProcessSoftly(false);
+ }
+ return handler;
+ }
+ };
+ }
+
+ @Nullable
+ @Override
+ public ExecutionResult execute(Executor executor, ProgramRunner runner)
+ throws ExecutionException {
+ return null;
+ }
+
+ private static TextConsoleBuilder createConsoleBuilder(Project project, Sdk sdk) {
+ return new PyDebugConsoleBuilder(project, sdk) {
+ @Override
+ protected ConsoleView createConsole() {
+ PythonDebugLanguageConsoleView consoleView =
+ new PythonDebugLanguageConsoleView(project, sdk);
+ for (Filter filter : getFilters(project)) {
+ consoleView.addMessageFilter(filter);
+ }
+ return consoleView;
+ }
+ };
+ }
+
+ private static String getScriptParams(BlazeCommandRunConfigurationCommonState state) {
+ List<String> params = Lists.newArrayList(state.getExeFlagsState().getExpandedFlags());
+ String filterFlag = state.getTestFilterFlag();
+ if (filterFlag != null) {
+ params.add(filterFlag.substring((BlazeFlags.TEST_FILTER + "=").length()));
+ }
+ return ParametersListUtil.join(params);
+ }
+ }
+
+ private static ImmutableList<Filter> getFilters(Project project) {
+ return ImmutableList.<Filter>builder()
+ .addAll(BlazePyFilterProvider.getPyFilters(project))
+ .add(new BlazeTargetFilter(project))
+ .build();
+ }
+
+ @Override
+ public RunProfileState getRunProfileState(Executor executor, ExecutionEnvironment environment)
+ throws ExecutionException {
+ BlazeCommandRunConfiguration configuration = getConfiguration(environment);
+ if (isDebugging(environment)) {
+ environment.putCopyableUserData(EXECUTABLE_KEY, new AtomicReference<>());
+ return new BlazePyDummyRunProfileState(configuration);
+ }
+ return new BlazeCommandRunProfileState(environment, getFilters(environment.getProject()));
+ }
+
+ @Override
+ public boolean executeBeforeRunTask(ExecutionEnvironment env) {
+ if (!isDebugging(env)) {
+ return true;
+ }
+ try {
+ File executable = getExecutableToDebug(env);
+ env.getCopyableUserData(EXECUTABLE_KEY).set(executable);
+ if (executable != null) {
+ return true;
+ }
+ } catch (ExecutionException e) {
+ ExecutionUtil.handleExecutionError(
+ env.getProject(), env.getExecutor().getToolWindowId(), env.getRunProfile(), e);
+ logger.info(e);
+ }
+ return false;
+ }
+
+ private static boolean isDebugging(ExecutionEnvironment environment) {
+ Executor executor = environment.getExecutor();
+ return executor instanceof DefaultDebugExecutor;
+ }
+
+ private static BlazeCommandRunConfiguration getConfiguration(ExecutionEnvironment environment) {
+ RunProfile runProfile = environment.getRunProfile();
+ if (runProfile instanceof WrappingRunConfiguration) {
+ runProfile = ((WrappingRunConfiguration) runProfile).getPeer();
+ }
+ return (BlazeCommandRunConfiguration) runProfile;
+ }
+
+ /** Make a best-effort attempt to get the runfiles path. Returns null if it can't be found. */
+ @Nullable
+ private static String getRunfilesPath(File executable, @Nullable WorkspaceRoot root) {
+ if (root == null) {
+ return null;
+ }
+ String workspaceName = root.directory().getName();
+ File expectedPath = new File(executable.getPath() + ".runfiles", workspaceName);
+ if (FileAttributeProvider.getInstance().exists(expectedPath)) {
+ return expectedPath.getPath();
+ }
+ return null;
+ }
+
+ /**
+ * Builds blaze python target and returns the output build artifact.
+ *
+ * @throws ExecutionException if the target cannot be debugged.
+ */
+ private static File getExecutableToDebug(ExecutionEnvironment env) throws ExecutionException {
+ BlazeCommandRunConfiguration configuration = getConfiguration(env);
+ final Project project = configuration.getProject();
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(project).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ throw new ExecutionException("Not synced yet, please sync project");
+ }
+
+ String validationError =
+ BlazePyDebugHelper.validateDebugTarget(env.getProject(), configuration.getTarget());
+ if (validationError != null) {
+ throw new WithBrowserHyperlinkExecutionException(validationError);
+ }
+
+ final BlazeCommandRunConfigurationCommonState handlerState =
+ (BlazeCommandRunConfigurationCommonState) configuration.getHandler().getState();
+ final WorkspaceRoot workspaceRoot = WorkspaceRoot.fromProject(project);
+ final ProjectViewSet projectViewSet =
+ ProjectViewManager.getInstance(project).getProjectViewSet();
+
+ BuildResultHelper buildResultHelper = BuildResultHelper.forFiles(file -> true);
+ boolean suppressConsole = BlazeUserSettings.getInstance().getSuppressConsoleForRunAction();
+ final ListenableFuture<Void> buildOperation =
+ BlazeExecutor.submitTask(
+ project,
+ new ScopedTask() {
+ @Override
+ protected void execute(BlazeContext context) {
+ context
+ .push(new IssuesScope(project))
+ .push(
+ new BlazeConsoleScope.Builder(project)
+ .setSuppressConsole(suppressConsole)
+ .build());
+
+ context.output(new StatusOutput("Building debug binary"));
+
+ BlazeCommand.Builder command =
+ BlazeCommand.builder(
+ Blaze.getBuildSystemProvider(project).getBinaryPath(),
+ BlazeCommandName.BUILD)
+ .addTargets(configuration.getTarget())
+ .addBlazeFlags(BlazeFlags.buildFlags(project, projectViewSet))
+ .addBlazeFlags(handlerState.getBlazeFlagsState().getExpandedFlags())
+ .addBlazeFlags(BlazePyDebugHelper.getAllBlazeDebugFlags())
+ .addBlazeFlags(buildResultHelper.getBuildFlags());
+
+ ExternalTask.builder(workspaceRoot)
+ .addBlazeCommand(command.build())
+ .context(context)
+ .stderr(
+ buildResultHelper.stderr(
+ new IssueOutputLineProcessor(project, context, workspaceRoot)))
+ .build()
+ .run();
+ }
+ });
+
+ try {
+ SaveUtil.saveAllFiles();
+ buildOperation.get();
+ } catch (InterruptedException | java.util.concurrent.ExecutionException e) {
+ throw new ExecutionException(e);
+ }
+ List<File> candidateFiles =
+ buildResultHelper
+ .getBuildArtifacts()
+ .stream()
+ .filter(fileFilter(blazeProjectData))
+ .collect(Collectors.toList());
+ if (candidateFiles.isEmpty()) {
+ throw new ExecutionException(
+ String.format("No output artifacts found when building %s", configuration.getTarget()));
+ }
+ File file = findExecutable((Label) configuration.getTarget(), candidateFiles);
+ if (file == null) {
+ throw new ExecutionException(
+ String.format(
+ "More than 1 executable was produced when building %s; don't know which one to debug",
+ configuration.getTarget()));
+ }
+ LocalFileSystem.getInstance().refreshIoFiles(ImmutableList.of(file));
+ return file;
+ }
+
+ private static Predicate<File> fileFilter(BlazeProjectData blazeProjectData) {
+ return filterExecutableFiles.getValue()
+ ? File::canExecute
+ : f -> FileUtil.isAncestor(blazeProjectData.blazeInfo.getBlazeBinDirectory(), f, true);
+ }
+
+ /**
+ * Basic heuristic for choosing between multiple output files. Currently just looks for a filename
+ * matching the target name.
+ */
+ @VisibleForTesting
+ @Nullable
+ static File findExecutable(Label target, List<File> outputs) {
+ if (outputs.size() == 1) {
+ return outputs.get(0);
+ }
+ String name = PathUtil.getFileName(target.targetName().toString());
+ for (File file : outputs) {
+ if (file.getName().equals(name)) {
+ return file;
+ }
+ }
+ return null;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/PyDebugUtils.java b/python/src/com/google/idea/blaze/python/run/PyDebugUtils.java
new file mode 100644
index 0000000..ec41831
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/PyDebugUtils.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.google.idea.blaze.base.model.primitives.Kind;
+import javax.annotation.Nullable;
+
+/** Utilities class for debuggable python run configurations. */
+public class PyDebugUtils {
+
+ static boolean canUsePyDebugger(@Nullable Kind kind) {
+ return kind != null && kind.isOneOf(Kind.PY_BINARY, Kind.PY_APPENGINE_BINARY, Kind.PY_TEST);
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/PyTestUtils.java b/python/src/com/google/idea/blaze/python/run/PyTestUtils.java
new file mode 100644
index 0000000..4493706
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/PyTestUtils.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import com.google.common.collect.ImmutableSet;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import com.jetbrains.python.psi.types.PyClassLikeType;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+
+/** Utilities class for identifying python test psi elements. */
+public class PyTestUtils {
+
+ private static final ImmutableSet<String> PY_UNIT_TEST_CLASSES =
+ ImmutableSet.of("unittest.TestCase", "unittest.case.TestCase");
+
+ public static boolean isTestFile(PyFile file) {
+ for (PyClass cls : file.getTopLevelClasses()) {
+ if (isTestClass(cls)) {
+ return true;
+ }
+ }
+ for (PyFunction cls : file.getTopLevelFunctions()) {
+ if (isTestFunction(cls)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isTestClass(PyClass pyClass) {
+ final TypeEvalContext contextToUse =
+ TypeEvalContext.userInitiated(pyClass.getProject(), pyClass.getContainingFile());
+ for (PyClassLikeType type : pyClass.getAncestorTypes(contextToUse)) {
+ if (type != null && PY_UNIT_TEST_CLASSES.contains(type.getClassQName())) {
+ return true;
+ }
+ }
+ String name = pyClass.getName();
+ return name != null && name.endsWith("Test");
+ }
+
+ public static boolean isTestFunction(PyFunction fn) {
+ String name = fn.getName();
+ return name != null && name.startsWith("test");
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/filter/BlazePyFilterProvider.java b/python/src/com/google/idea/blaze/python/run/filter/BlazePyFilterProvider.java
new file mode 100644
index 0000000..2507b06
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/filter/BlazePyFilterProvider.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.filter;
+
+import com.intellij.execution.filters.Filter;
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.openapi.project.Project;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+/** Filters for python run configuration console output. */
+public interface BlazePyFilterProvider {
+
+ ExtensionPointName<BlazePyFilterProvider> EP_NAME =
+ ExtensionPointName.create("com.google.idea.blaze.BlazePyFilterProvider");
+
+ static Collection<Filter> getPyFilters(Project project) {
+ return Arrays.stream(EP_NAME.getExtensions())
+ .map(provider -> provider.getFilter(project))
+ .collect(Collectors.toList());
+ }
+
+ Filter getFilter(Project project);
+}
diff --git a/python/src/com/google/idea/blaze/python/run/filter/BlazePyTracebackFilter.java b/python/src/com/google/idea/blaze/python/run/filter/BlazePyTracebackFilter.java
new file mode 100644
index 0000000..a13892d
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/filter/BlazePyTracebackFilter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.filter;
+
+import com.google.idea.blaze.base.run.filter.FileResolver;
+import com.intellij.execution.filters.ConsoleFilterProvider;
+import com.intellij.execution.filters.Filter;
+import com.intellij.execution.filters.OpenFileHyperlinkInfo;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.annotation.Nullable;
+
+/** Parses traceback links in python test results */
+public class BlazePyTracebackFilter implements Filter {
+
+ /** Provider for traceback filter */
+ public static class BlazePyTracebackFilterProvider implements ConsoleFilterProvider {
+ @Override
+ public Filter[] getDefaultFilters(Project project) {
+ return new Filter[] {new BlazePyTracebackFilter(project)};
+ }
+ }
+
+ private static final Pattern TRACEBACK_FILE_LINE =
+ Pattern.compile("File \"(.*?)\", line ([0-9]+), in (.*?)");
+
+ private final Project project;
+
+ private BlazePyTracebackFilter(Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public Result applyFilter(String line, int entireLength) {
+ Matcher matcher = TRACEBACK_FILE_LINE.matcher(line);
+ if (!matcher.find()) {
+ return null;
+ }
+ String filePath = matcher.group(1);
+ if (filePath == null) {
+ return null;
+ }
+ VirtualFile file = FileResolver.resolve(project, filePath);
+ if (file == null) {
+ return null;
+ }
+ int lineNumber = parseLineNumber(matcher.group(2));
+ OpenFileHyperlinkInfo hyperlink = new OpenFileHyperlinkInfo(project, file, lineNumber - 1);
+
+ int startIx = matcher.start(2) - "line ".length();
+ int endIx = matcher.end(2);
+ if (startIx < 0) {
+ startIx = matcher.start(1);
+ endIx = matcher.end(1);
+ }
+ int offset = entireLength - line.length();
+ return new Result(startIx + offset, endIx + offset, hyperlink);
+ }
+
+ /** defaults to -1 if no line number can be parsed. */
+ private static int parseLineNumber(@Nullable String string) {
+ try {
+ return string != null ? Integer.parseInt(string) : -1;
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/producers/BlazePyBinaryConfigurationProducer.java b/python/src/com/google/idea/blaze/python/run/producers/BlazePyBinaryConfigurationProducer.java
new file mode 100644
index 0000000..1b61af0
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/producers/BlazePyBinaryConfigurationProducer.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.producers;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetKey;
+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.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.google.idea.blaze.base.targetmaps.SourceToTargetMap;
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.psi.PyFile;
+import java.io.File;
+import javax.annotation.Nullable;
+
+/** Producer for run configurations related to py_binary main classes in Blaze. */
+public class BlazePyBinaryConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ public BlazePyBinaryConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+
+ Location<?> location = context.getLocation();
+ if (location == null) {
+ return false;
+ }
+ PsiElement element = location.getPsiElement();
+ PsiFile file = element.getContainingFile();
+ if (!(file instanceof PyFile)) {
+ return false;
+ }
+ Label binaryTarget = getTargetLabel(file);
+ if (binaryTarget == null) {
+ return false;
+ }
+ configuration.setTarget(binaryTarget);
+ sourceElement.set(file);
+
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null) {
+ return false;
+ }
+ handlerState.getCommandState().setCommand(BlazeCommandName.RUN);
+ configuration.setGeneratedName();
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null
+ || !BlazeCommandName.RUN.equals(handlerState.getCommandState().getCommand())) {
+ return false;
+ }
+
+ Location<?> location = context.getLocation();
+ if (location == null) {
+ return false;
+ }
+ PsiElement element = location.getPsiElement();
+ PsiFile file = element.getContainingFile();
+ if (!(file instanceof PyFile)) {
+ return false;
+ }
+ Label binaryTarget = getTargetLabel(file);
+ if (binaryTarget == null) {
+ return false;
+ }
+ return binaryTarget.equals(configuration.getTarget());
+ }
+
+ @Nullable
+ private static Label getTargetLabel(PsiFile psiFile) {
+ VirtualFile vf = psiFile.getVirtualFile();
+ if (vf == null) {
+ return null;
+ }
+ File file = new File(vf.getPath());
+ ImmutableCollection<TargetKey> targetKeys =
+ SourceToTargetMap.getInstance(psiFile.getProject()).getRulesForSourceFile(file);
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(psiFile.getProject()).getBlazeProjectData();
+ if (blazeProjectData == null) {
+ return null;
+ }
+
+ String fileName = FileUtil.getNameWithoutExtension(file);
+ for (TargetKey key : targetKeys) {
+ TargetIdeInfo target = blazeProjectData.targetMap.get(key);
+ if (target == null) {
+ continue;
+ }
+ if (target.kind == Kind.PY_BINARY || target.kind == Kind.PY_APPENGINE_BINARY) {
+ // The 'main' attribute isn't exposed, so only suggest a binary if the name matches
+ if (key.label.targetName().toString().equals(fileName)) {
+ return key.label;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/producers/BlazePyTestConfigurationProducer.java b/python/src/com/google/idea/blaze/python/run/producers/BlazePyTestConfigurationProducer.java
new file mode 100644
index 0000000..5d21fa8
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/producers/BlazePyTestConfigurationProducer.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.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.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.BlazeConfigurationNameBuilder;
+import com.google.idea.blaze.base.run.TestTargetHeuristic;
+import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
+import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
+import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
+import com.google.idea.blaze.python.run.PyTestUtils;
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/** Producer for run configurations related to python test classes in Blaze. */
+public class BlazePyTestConfigurationProducer
+ extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {
+
+ public BlazePyTestConfigurationProducer() {
+ super(BlazeCommandRunConfigurationType.getInstance());
+ }
+
+ private static class TestLocation {
+ @Nullable private final PyClass testClass;
+ @Nullable private final PyFunction testFunction;
+
+ private TestLocation(@Nullable PyClass testClass, @Nullable PyFunction testFunction) {
+ this.testClass = testClass;
+ this.testFunction = testFunction;
+ }
+
+ @Nullable
+ private String testFilter() {
+ if (testClass == null) {
+ return null;
+ }
+ return testFunction == null
+ ? testClass.getName()
+ : testClass.getName() + "." + testFunction.getName();
+ }
+
+ @Nullable
+ PsiElement sourceElement(PsiFile file) {
+ if (testFunction != null) {
+ return testFunction;
+ }
+ return testClass != null ? testClass : file;
+ }
+ }
+
+ /**
+ * The single selected {@link PsiElement}. Returns null if we're in a SM runner tree UI context
+ * (handled by a different producer).
+ */
+ @Nullable
+ private static PsiElement selectedPsiElement(ConfigurationContext context) {
+ List<Location<?>> selectedTestUiElements =
+ SmRunnerUtils.getSelectedSmRunnerTreeElements(context);
+ if (!selectedTestUiElements.isEmpty()) {
+ return null;
+ }
+ Location<?> location = context.getLocation();
+ return location != null ? location.getPsiElement() : null;
+ }
+
+ @Override
+ protected boolean doSetupConfigFromContext(
+ BlazeCommandRunConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+
+ PsiElement element = selectedPsiElement(context);
+ if (element == null) {
+ return false;
+ }
+ PsiFile file = element.getContainingFile();
+ if (!(file instanceof PyFile) || !PyTestUtils.isTestFile((PyFile) file)) {
+ return false;
+ }
+ Label testTarget = TestTargetHeuristic.testTargetForPsiElement(element);
+ if (testTarget == null) {
+ return false;
+ }
+ configuration.setTarget(testTarget);
+
+ TestLocation testLocation = testLocation(element);
+ sourceElement.set(testLocation.sourceElement(file));
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null) {
+ return false;
+ }
+ handlerState.getCommandState().setCommand(BlazeCommandName.TEST);
+
+ ImmutableList.Builder<String> flags = ImmutableList.builder();
+ String filter = testLocation.testFilter();
+ if (filter != null) {
+ flags.add(BlazeFlags.TEST_FILTER + "=" + filter);
+ }
+ // remove conflicting flags from initial configuration
+ List<String> oldFlags = new ArrayList<>(handlerState.getBlazeFlagsState().getRawFlags());
+ oldFlags.removeIf((flag) -> flag.startsWith(BlazeFlags.TEST_FILTER));
+ flags.addAll(oldFlags);
+ handlerState.getBlazeFlagsState().setRawFlags(flags.build());
+
+ BlazeConfigurationNameBuilder nameBuilder = new BlazeConfigurationNameBuilder(configuration);
+ nameBuilder.setTargetString(
+ filter != null
+ ? String.format("%s (%s)", filter, testTarget.toString())
+ : testTarget.toString());
+ configuration.setName(nameBuilder.build());
+ configuration.setNameChangedByUser(true); // don't revert to generated name
+ return true;
+ }
+
+ @Override
+ protected boolean doIsConfigFromContext(
+ BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
+
+ BlazeCommandRunConfigurationCommonState handlerState =
+ configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
+ if (handlerState == null
+ || !BlazeCommandName.TEST.equals(handlerState.getCommandState().getCommand())) {
+ return false;
+ }
+
+ PsiElement element = selectedPsiElement(context);
+ if (element == null) {
+ return false;
+ }
+ if (!(element.getContainingFile() instanceof PyFile)) {
+ return false;
+ }
+ Label testTarget = TestTargetHeuristic.testTargetForPsiElement(element);
+ if (testTarget == null || !testTarget.equals(configuration.getTarget())) {
+ return false;
+ }
+ String filter = testLocation(element).testFilter();
+
+ String filterFlag = handlerState.getTestFilterFlag();
+ return (filterFlag == null && filter == null)
+ || Objects.equals(filterFlag, BlazeFlags.TEST_FILTER + "=" + filter);
+ }
+
+ private static TestLocation testLocation(PsiElement element) {
+ PyClass pyClass = PsiTreeUtil.getParentOfType(element, PyClass.class, false);
+ if (pyClass == null || !PyTestUtils.isTestClass(pyClass)) {
+ return new TestLocation(null, null);
+ }
+ PyFunction pyFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class, false);
+ if (pyFunction != null && PyTestUtils.isTestFunction(pyFunction)) {
+ return new TestLocation(pyClass, pyFunction);
+ }
+ return new TestLocation(pyClass, null);
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/producers/NonBlazeProducerSuppressor.java b/python/src/com/google/idea/blaze/python/run/producers/NonBlazeProducerSuppressor.java
new file mode 100644
index 0000000..d4cabff
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/producers/NonBlazeProducerSuppressor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.producers;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.idea.blaze.base.settings.Blaze;
+import com.google.idea.sdkcompat.python.PyConfigurationProducersList;
+import com.intellij.execution.RunConfigurationProducerService;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.intellij.openapi.components.AbstractProjectComponent;
+import com.intellij.openapi.project.Project;
+
+/** Suppresses certain non-Blaze configuration producers in Blaze projects. */
+public class NonBlazeProducerSuppressor extends AbstractProjectComponent {
+
+ public NonBlazeProducerSuppressor(Project project) {
+ super(project);
+ }
+
+ @Override
+ public void projectOpened() {
+ if (Blaze.isBlazeProject(myProject)) {
+ suppressProducers(myProject);
+ }
+ }
+
+ @VisibleForTesting
+ @SuppressWarnings("unchecked")
+ static void suppressProducers(Project project) {
+ RunConfigurationProducerService producerService =
+ RunConfigurationProducerService.getInstance(project);
+ PyConfigurationProducersList.PRODUCERS_TO_SUPPRESS.forEach(
+ (klass) -> {
+ if (RunConfigurationProducer.class.isAssignableFrom(klass)) {
+ producerService.addIgnoredProducer((Class<RunConfigurationProducer<?>>) klass);
+ }
+ });
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/run/smrunner/BlazePythonTestEventsHandler.java b/python/src/com/google/idea/blaze/python/run/smrunner/BlazePythonTestEventsHandler.java
new file mode 100644
index 0000000..f39eb76
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/smrunner/BlazePythonTestEventsHandler.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.smrunner;
+
+import com.google.common.base.Joiner;
+import com.google.idea.blaze.base.command.BlazeFlags;
+import com.google.idea.blaze.base.model.primitives.Kind;
+import com.google.idea.blaze.base.run.smrunner.BlazeTestEventsHandler;
+import com.intellij.execution.Location;
+import com.intellij.execution.testframework.sm.runner.SMTestLocator;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFunction;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Provides python-specific methods needed by the SM-runner test UI. */
+public class BlazePythonTestEventsHandler extends BlazeTestEventsHandler {
+
+ @Override
+ protected EnumSet<Kind> handledKinds() {
+ return EnumSet.of(Kind.PY_TEST);
+ }
+
+ @Override
+ public SMTestLocator getTestLocator() {
+ return BlazePythonTestLocator.INSTANCE;
+ }
+
+ @Override
+ public String testDisplayName(@Nullable Kind kind, String rawName) {
+ int lastDotIndex = rawName.lastIndexOf('.');
+ return lastDotIndex != -1 ? rawName.substring(lastDotIndex + 1) : rawName;
+ }
+
+ @Nullable
+ @Override
+ public String getTestFilter(Project project, List<Location<?>> testLocations) {
+ // python test runner parses filters of the form "class1.method1 class2.method2 ..."
+ List<String> filters = new ArrayList<>();
+ for (Location<?> location : testLocations) {
+ String filter = getFilter(location.getPsiElement());
+ if (filter != null) {
+ filters.add(filter);
+ }
+ }
+ if (filters.isEmpty()) {
+ return null;
+ }
+ return String.format("%s=%s", BlazeFlags.TEST_FILTER, Joiner.on(' ').join(filters));
+ }
+
+ @Nullable
+ private static String getFilter(PsiElement psiElement) {
+ if (psiElement instanceof PyClass) {
+ return ((PyClass) psiElement).getName();
+ }
+ if (!(psiElement instanceof PyFunction)) {
+ return null;
+ }
+ PyClass pyClass = ((PyFunction) psiElement).getContainingClass();
+ if (pyClass == null) {
+ return null;
+ }
+ String methodName = ((PyFunction) psiElement).getName();
+ String className = pyClass.getName();
+ return methodName != null && className != null ? className + "." + methodName : null;
+ }
+
+}
diff --git a/python/src/com/google/idea/blaze/python/run/smrunner/BlazePythonTestLocator.java b/python/src/com/google/idea/blaze/python/run/smrunner/BlazePythonTestLocator.java
new file mode 100644
index 0000000..5bcfdc2
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/run/smrunner/BlazePythonTestLocator.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.smrunner;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.run.smrunner.SmRunnerUtils;
+import com.google.idea.blaze.python.run.PyTestUtils;
+import com.intellij.execution.Location;
+import com.intellij.execution.PsiLocation;
+import com.intellij.execution.testframework.sm.runner.SMTestLocator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFunction;
+import com.jetbrains.python.psi.stubs.PyClassNameIndex;
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.Nullable;
+
+/** Locate python test classes / methods for test UI navigation. */
+public final class BlazePythonTestLocator implements SMTestLocator {
+
+ public static final BlazePythonTestLocator INSTANCE = new BlazePythonTestLocator();
+
+ static final String PY_TESTCASE_PREFIX = "__main__.";
+
+ private BlazePythonTestLocator() {}
+
+ @Override
+ public List<Location> getLocation(
+ String protocol, String path, Project project, GlobalSearchScope scope) {
+ if (protocol.equals(SmRunnerUtils.GENERIC_SUITE_PROTOCOL)) {
+ return findTestClass(project, scope, path);
+ }
+ if (protocol.equals(SmRunnerUtils.GENERIC_TEST_PROTOCOL)) {
+ path = StringUtil.trimStart(path, PY_TESTCASE_PREFIX);
+ String[] components = path.split("\\.");
+ if (components.length < 2) {
+ return ImmutableList.of();
+ }
+ return findTestMethod(
+ project, scope, components[components.length - 2], components[components.length - 1]);
+ }
+ return ImmutableList.of();
+ }
+
+ private static List<Location> findTestMethod(
+ Project project, GlobalSearchScope scope, String className, @Nullable String methodName) {
+ List<Location> results = new ArrayList<>();
+ if (methodName == null) {
+ return findTestClass(project, scope, className);
+ }
+ for (PyClass pyClass : PyClassNameIndex.find(className, project, scope)) {
+ ProgressManager.checkCanceled();
+ if (PyTestUtils.isTestClass(pyClass)) {
+ PyFunction method = pyClass.findMethodByName(methodName, true, null);
+ if (method != null && PyTestUtils.isTestFunction(method)) {
+ results.add(new PsiLocation<>(project, method));
+ }
+ results.add(new PsiLocation<>(project, pyClass));
+ }
+ }
+ return results;
+ }
+
+ private static List<Location> findTestClass(
+ Project project, GlobalSearchScope scope, String className) {
+ List<Location> results = new ArrayList<>();
+ for (PyClass pyClass : PyClassNameIndex.find(className, project, scope)) {
+ ProgressManager.checkCanceled();
+ if (PyTestUtils.isTestClass(pyClass)) {
+ results.add(new PsiLocation<>(project, pyClass));
+ }
+ }
+ return results;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/search/BlazePyUseScopeEnlarger.java b/python/src/com/google/idea/blaze/python/search/BlazePyUseScopeEnlarger.java
new file mode 100644
index 0000000..908a527
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/search/BlazePyUseScopeEnlarger.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.search;
+
+import com.google.idea.blaze.base.settings.Blaze;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.UseScopeEnlarger;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.psi.PyFile;
+import javax.annotation.Nullable;
+
+/**
+ * Genfiles (and files in READONLY, etc.) are not included in the project scope. To resolve
+ * references to these files, we need to either add them to the project scope (which would destroy
+ * performance) or modify the default scope behavior, as done here.
+ */
+public class BlazePyUseScopeEnlarger extends UseScopeEnlarger {
+
+ @Nullable
+ @Override
+ public SearchScope getAdditionalUseScope(PsiElement element) {
+ if (!Blaze.isBlazeProject(element.getProject())) {
+ return null;
+ }
+ if (isPyPackageOutsideProject(element) || isPyFileOutsideProject(element)) {
+ return GlobalSearchScope.projectScope(element.getProject());
+ }
+ return null;
+ }
+
+ private static boolean isPyPackageOutsideProject(PsiElement element) {
+ if (!(element instanceof PsiDirectory)) {
+ return false;
+ }
+ PsiDirectory dir = (PsiDirectory) element;
+ return dir.findFile(PyNames.INIT_DOT_PY) != null
+ && !inProjectScope(dir.getProject(), dir.getVirtualFile());
+ }
+
+ private static boolean isPyFileOutsideProject(PsiElement element) {
+ PsiFile file = element.getContainingFile();
+ return file instanceof PyFile
+ && !inProjectScope(file.getProject(), file.getViewProvider().getVirtualFile());
+ }
+
+ private static boolean inProjectScope(Project project, VirtualFile virtualFile) {
+ return GlobalSearchScope.projectScope(project).contains(virtualFile);
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/sync/AlwaysPresentPythonSyncPlugin.java b/python/src/com/google/idea/blaze/python/sync/AlwaysPresentPythonSyncPlugin.java
new file mode 100644
index 0000000..7499620
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/sync/AlwaysPresentPythonSyncPlugin.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.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.primitives.Kind;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.plugin.PluginUtils;
+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.ImportRoots;
+import com.google.idea.blaze.python.PythonPluginUtils;
+import com.intellij.openapi.project.Project;
+import java.util.Set;
+
+/**
+ * Unlike most of the python-specific code, will be run even if the JetBrains python plugin isn't
+ * enabled.
+ */
+public class AlwaysPresentPythonSyncPlugin extends BlazeSyncPlugin.Adapter {
+
+ @Override
+ public ImmutableList<WorkspaceType> getSupportedWorkspaceTypes() {
+ // retained for backwards-compatibility
+ return ImmutableList.of(WorkspaceType.PYTHON);
+ }
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ // retained for backwards-compatibility
+ return ImmutableSet.of(LanguageClass.PYTHON);
+ }
+
+ @Override
+ public boolean validate(
+ Project project, BlazeContext context, BlazeProjectData blazeProjectData) {
+ ImportRoots importRoots = ImportRoots.forProjectSafe(project);
+ if (importRoots == null) {
+ return true;
+ }
+ boolean hasPythonTarget =
+ blazeProjectData
+ .targetMap
+ .targets()
+ .stream()
+ .filter(target -> importRoots.importAsSource(target.key.label))
+ .anyMatch(target -> target.kindIsOneOf(Kind.allKindsForLanguage(LanguageClass.PYTHON)));
+ if (!hasPythonTarget) {
+ return true;
+ }
+ String pluginId = PythonPluginUtils.getPythonPluginId();
+ if (!PluginUtils.isPluginEnabled(pluginId)) {
+ IssueOutput.warn(
+ "Your project appears to contain Python targets. To enable Python support, "
+ + "install/enable the JetBrains python plugin, then restart the IDE")
+ .navigatable(PluginUtils.installOrEnablePluginNavigable(pluginId))
+ .submit(context);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/sync/BlazePythonSyncPlugin.java b/python/src/com/google/idea/blaze/python/sync/BlazePythonSyncPlugin.java
new file mode 100644
index 0000000..2354f3c
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/sync/BlazePythonSyncPlugin.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.io.VirtualFileSystemProvider;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.BlazeVersionData;
+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.ProjectView;
+import com.google.idea.blaze.base.projectview.ProjectViewEdit;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+import com.google.idea.blaze.base.projectview.ProjectViewSet.ProjectViewFile;
+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.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.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.BlazeSyncPlugin;
+import com.google.idea.blaze.base.sync.GenericSourceFolderProvider;
+import com.google.idea.blaze.base.sync.SourceFolderProvider;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.common.experiments.BoolExperiment;
+import com.google.idea.sdkcompat.transactions.Transactions;
+import com.intellij.facet.Facet;
+import com.intellij.facet.FacetManager;
+import com.intellij.facet.ModifiableFacetModel;
+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.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.ProjectRootManager;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.pom.NavigatableAdapter;
+import com.intellij.util.PlatformUtils;
+import com.jetbrains.python.PythonModuleTypeBase;
+import com.jetbrains.python.facet.PythonFacet;
+import com.jetbrains.python.facet.PythonFacetType;
+import com.jetbrains.python.sdk.PythonSdkType;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/** Allows people to use a python workspace. */
+public class BlazePythonSyncPlugin extends BlazeSyncPlugin.Adapter {
+
+ private static final Logger logger = Logger.getInstance(BlazePythonSyncPlugin.class);
+
+ private static final BoolExperiment refreshExecRoot =
+ new BoolExperiment("refresh.exec.root.python", true);
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ // supported for legacy reasons, but otherwise ignored.
+ return ImmutableSet.of(LanguageClass.PYTHON);
+ }
+
+ @Override
+ public Set<LanguageClass> getAlwaysActiveLanguages() {
+ return ImmutableSet.of(LanguageClass.PYTHON);
+ }
+
+ @Nullable
+ @Override
+ public ModuleType getWorkspaceModuleType(WorkspaceType workspaceType) {
+ // left here for backwards compatibility -- python workspace types are deprecated.
+ if (workspaceType == WorkspaceType.PYTHON && supportsPythonWorkspaceType()) {
+ return PythonModuleTypeBase.getInstance();
+ }
+ return null;
+ }
+
+ private static boolean supportsPythonWorkspaceType() {
+ return !PlatformUtils.isCLion();
+ }
+
+ @Override
+ public ImmutableList<WorkspaceType> getSupportedWorkspaceTypes() {
+ // 'supports' python by giving a more detailed error message with quick-fix later in the sync
+ // process, in the case where a python workspace type is not supported.
+ return ImmutableList.of(WorkspaceType.PYTHON);
+ }
+
+ @Nullable
+ @Override
+ public SourceFolderProvider getSourceFolderProvider(BlazeProjectData projectData) {
+ if (!projectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.PYTHON)) {
+ return null;
+ }
+ return GenericSourceFolderProvider.INSTANCE;
+ }
+
+ @Override
+ public void updateProjectStructure(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ @Nullable BlazeProjectData oldBlazeProjectData,
+ ModuleEditor moduleEditor,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
+ updatePythonFacet(context, blazeProjectData, workspaceModule, workspaceModifiableModel);
+ }
+
+ @Override
+ public void refreshVirtualFileSystem(BlazeProjectData blazeProjectData) {
+ if (!refreshExecRoot.getValue()) {
+ return;
+ }
+ long start = System.currentTimeMillis();
+ refreshExecRoot(blazeProjectData);
+ long end = System.currentTimeMillis();
+ logger.info(String.format("Refreshing execution root took: %d ms", (end - start)));
+ }
+
+ private static void refreshExecRoot(BlazeProjectData blazeProjectData) {
+ // recursive refresh of the blaze execution root. This is required because our blaze aspect
+ // can't yet tell us exactly which genfiles are required to resolve the project.
+ VirtualFile execRoot =
+ VirtualFileSystemProvider.getInstance()
+ .getSystem()
+ .refreshAndFindFileByIoFile(blazeProjectData.blazeInfo.getExecutionRoot());
+ if (execRoot != null) {
+ VfsUtil.markDirtyAndRefresh(false, true, true, execRoot);
+ }
+ }
+
+ private static void updatePythonFacet(
+ BlazeContext context,
+ BlazeProjectData blazeProjectData,
+ Module workspaceModule,
+ ModifiableRootModel workspaceModifiableModel) {
+ if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.PYTHON)
+ || blazeProjectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.PYTHON)) {
+ removeFacet(workspaceModule);
+ return;
+ }
+ if (ModuleType.get(workspaceModule) instanceof PythonModuleTypeBase) {
+ return;
+ }
+ PythonFacet pythonFacet = getOrCreatePythonFacet(context, workspaceModule);
+ if (pythonFacet == null) {
+ return;
+ }
+ Library pythonLib = getFacetLibrary(pythonFacet);
+ if (pythonLib != null) {
+ workspaceModifiableModel.addLibraryEntry(pythonLib);
+ }
+ }
+
+ private static void removeFacet(Module workspaceModule) {
+ FacetManager manager = FacetManager.getInstance(workspaceModule);
+ ModifiableFacetModel facetModel = manager.createModifiableModel();
+ PythonFacet facet = manager.findFacet(PythonFacet.ID, "Python");
+ if (facet != null) {
+ facetModel.removeFacet(facet);
+ facetModel.commit();
+ }
+ }
+
+ @Nullable
+ private static PythonFacet getOrCreatePythonFacet(BlazeContext context, Module module) {
+ PythonFacet facet = findPythonFacet(module);
+ if (facet != null && facetHasSdk(facet)) {
+ return facet;
+ }
+ FacetManager manager = FacetManager.getInstance(module);
+ ModifiableFacetModel facetModel = manager.createModifiableModel();
+ if (facet != null) {
+ // we can't modify in place, IntelliJ has no hook to trigger change events. Instead we create
+ // a new facet.
+ facetModel.removeFacet(facet);
+ }
+ Sdk sdk = getOrCreatePythonSdk();
+ if (sdk == null) {
+ String msg =
+ "Unable to find a Python SDK installed.\n"
+ + "After configuring a suitable SDK in the \"Project Structure\" dialog, "
+ + "sync the project again.";
+ IssueOutput.error(msg).submit(context);
+ return null;
+ }
+ facet = manager.createFacet(PythonFacetType.getInstance(), "Python", null);
+ facetModel.addFacet(facet);
+ facetModel.commit();
+ return facet;
+ }
+
+ private static boolean facetHasSdk(PythonFacet facet) {
+ // facets aren't properly updated when SDKs change (e.g. when they're deleted), so we need to
+ // manually check against the full list.
+ Sdk sdk = facet.getConfiguration().getSdk();
+ return sdk != null && PythonSdkType.getAllSdks().contains(sdk);
+ }
+
+ @Nullable
+ private static Library getFacetLibrary(PythonFacet pythonFacet) {
+ Sdk sdk = pythonFacet.getConfiguration().getSdk();
+ if (sdk == null) {
+ return null;
+ }
+ return LibraryTablesRegistrar.getInstance()
+ .getLibraryTable()
+ .getLibraryByName(sdk.getName() + PythonFacet.PYTHON_FACET_LIBRARY_NAME_SUFFIX);
+ }
+
+ private static PythonFacet findPythonFacet(Module module) {
+ final Facet<?>[] allFacets = FacetManager.getInstance(module).getAllFacets();
+ for (Facet<?> facet : allFacets) {
+ if (facet instanceof PythonFacet) {
+ return (PythonFacet) facet;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void updateProjectSdk(
+ Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ BlazeVersionData blazeVersionData,
+ BlazeProjectData blazeProjectData) {
+ if (!blazeProjectData.workspaceLanguageSettings.isWorkspaceType(WorkspaceType.PYTHON)) {
+ return;
+ }
+ Sdk currentSdk = ProjectRootManager.getInstance(project).getProjectSdk();
+ if (currentSdk != null && currentSdk.getSdkType() instanceof PythonSdkType) {
+ return;
+ }
+ Sdk sdk = getOrCreatePythonSdk();
+ if (sdk != null) {
+ setProjectSdk(project, sdk);
+ }
+ }
+
+ @Nullable
+ private static Sdk getOrCreatePythonSdk() {
+ List<Sdk> sdk = PythonSdkType.getAllSdks();
+ if (!sdk.isEmpty()) {
+ return sdk.get(0);
+ }
+ return SdkConfigurationUtil.createAndAddSDK("/usr/bin/python2.7", PythonSdkType.getInstance());
+ }
+
+ private static void setProjectSdk(Project project, Sdk sdk) {
+ Transactions.submitTransactionAndWait(
+ () ->
+ ApplicationManager.getApplication()
+ .runWriteAction(() -> ProjectRootManager.getInstance(project).setProjectSdk(sdk)));
+ }
+
+ @Override
+ public boolean validateProjectView(
+ @Nullable Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
+ ProjectViewFile topLevelProjectViewFile = projectViewSet.getTopLevelProjectViewFile();
+ if (!supportsPythonWorkspaceType()
+ && workspaceLanguageSettings.isWorkspaceType(WorkspaceType.PYTHON)) {
+ String msg = "Python workspace type is not supported (and is unnecessary) for this IDE. ";
+ boolean fixable =
+ topLevelProjectViewFile != null
+ && topLevelProjectViewFile.projectView.getScalarValue(WorkspaceTypeSection.KEY)
+ == WorkspaceType.PYTHON;
+ msg +=
+ fixable
+ ? "Click here to remove it, retaining python support"
+ : "Please remove it and resync.";
+ IssueOutput.error(msg)
+ .navigatable(
+ project == null || !fixable
+ ? null
+ : new NavigatableAdapter() {
+ @Override
+ public void navigate(boolean requestFocus) {
+ fixLanguageSupport(project, true);
+ }
+ })
+ .submit(context);
+ return false;
+ }
+ return true;
+ }
+
+ private static void fixLanguageSupport(Project project, boolean removeWorkspaceType) {
+ ProjectViewEdit edit =
+ ProjectViewEdit.editLocalProjectView(
+ project,
+ builder -> {
+ if (removeWorkspaceType) {
+ removePythonWorkspaceType(builder);
+ }
+ removeFromAdditionalLanguages(builder);
+ 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());
+ }
+
+ private static void removePythonWorkspaceType(ProjectView.Builder builder) {
+ ScalarSection<WorkspaceType> section = builder.getLast(WorkspaceTypeSection.KEY);
+ if (section != null && section.getValue() == WorkspaceType.PYTHON) {
+ builder.remove(section);
+ }
+ }
+
+ private static void removeFromAdditionalLanguages(ProjectView.Builder builder) {
+ ListSection<LanguageClass> existingSection = builder.getLast(AdditionalLanguagesSection.KEY);
+ builder.replace(
+ existingSection,
+ ListSection.update(AdditionalLanguagesSection.KEY, existingSection)
+ .remove(LanguageClass.PYTHON));
+ }
+}
diff --git a/python/src/com/google/idea/blaze/python/sync/PythonPrefetchFileSource.java b/python/src/com/google/idea/blaze/python/sync/PythonPrefetchFileSource.java
new file mode 100644
index 0000000..29bde5e
--- /dev/null
+++ b/python/src/com/google/idea/blaze/python/sync/PythonPrefetchFileSource.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.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.base.projectview.ProjectViewSet;
+import com.intellij.openapi.project.Project;
+import java.io.File;
+import java.util.Collection;
+import java.util.Set;
+
+/** Causes python files to become prefetched. */
+public class PythonPrefetchFileSource implements PrefetchFileSource {
+ @Override
+ public void addFilesToPrefetch(
+ Project project,
+ ProjectViewSet projectViewSet,
+ BlazeProjectData blazeProjectData,
+ Collection<File> files) {}
+
+ @Override
+ public Set<String> prefetchSrcFileExtensions() {
+ return ImmutableSet.of("py", "pyw", "pyi");
+ }
+}
diff --git a/python/tests/integrationtests/com/google/idea/blaze/python/run/producers/BlazePyBinaryConfigurationProducerTest.java b/python/tests/integrationtests/com/google/idea/blaze/python/run/producers/BlazePyBinaryConfigurationProducerTest.java
new file mode 100644
index 0000000..26e6177
--- /dev/null
+++ b/python/tests/integrationtests/com/google/idea/blaze/python/run/producers/BlazePyBinaryConfigurationProducerTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.producers;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.psi.PsiFile;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Integration tests for {@link BlazePyBinaryConfigurationProducer}. */
+@RunWith(JUnit4.class)
+public class BlazePyBinaryConfigurationProducerTest extends BlazeRunConfigurationProducerTestCase {
+
+ @Test
+ public void testProducedFromPyFile() {
+ PsiFile pyFile =
+ createAndIndexFile(
+ new WorkspacePath("py/bin/main.py"),
+ "def main():",
+ " return",
+ "if __name__ == '__main__':",
+ " main()");
+
+ workspace.createFile(new WorkspacePath("py/bin/BUILD"), "py_binary(name = 'main')");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("py_binary")
+ .setLabel("//py/bin:main")
+ .addSource(sourceRoot("py/bin/main.py"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ ConfigurationContext context = createContextFromPsi(pyFile);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazePyBinaryConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget()).isEqualTo(TargetExpression.fromString("//py/bin:main"));
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.RUN);
+ }
+}
diff --git a/python/tests/integrationtests/com/google/idea/blaze/python/run/producers/BlazePyTestConfigurationProducerTest.java b/python/tests/integrationtests/com/google/idea/blaze/python/run/producers/BlazePyTestConfigurationProducerTest.java
new file mode 100644
index 0000000..7f358ac
--- /dev/null
+++ b/python/tests/integrationtests/com/google/idea/blaze/python/run/producers/BlazePyTestConfigurationProducerTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.producers;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.idea.blaze.base.command.BlazeCommandName;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataBuilder;
+import com.google.idea.blaze.base.model.MockBlazeProjectDataManager;
+import com.google.idea.blaze.base.model.primitives.TargetExpression;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
+import com.google.idea.blaze.base.run.producer.BlazeRunConfigurationProducerTestCase;
+import com.google.idea.blaze.base.sync.data.BlazeProjectDataManager;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFunction;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Integration tests for {@link BlazePyTestConfigurationProducer}.
+ */
+@RunWith(JUnit4.class)
+public class BlazePyTestConfigurationProducerTest extends BlazeRunConfigurationProducerTestCase {
+
+ @Before
+ public final void suppressNativeProducers() {
+ // Project components triggered before we can set up BlazeImportSettings.
+ NonBlazeProducerSuppressor.suppressProducers(getProject());
+ }
+
+ @Test
+ public void testProducedFromPyFile() {
+ PsiFile pyFile =
+ createAndIndexFile(
+ new WorkspacePath("py/test/unittest.py"),
+ "class UnitTest(googletest.TestCase):",
+ " def testSomething():",
+ " return");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("py_test")
+ .setLabel("//py/test:unittests")
+ .addSource(sourceRoot("py/test/unittest.py"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ ConfigurationContext context = createContextFromPsi(pyFile);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazePyTestConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget()).isEqualTo(TargetExpression.fromString("//py/test:unittests"));
+ assertThat(getTestFilterContents(config)).isNull();
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testProducedFromPyClass() {
+ PsiFile pyFile =
+ createAndIndexFile(
+ new WorkspacePath("py/test/unittest.py"),
+ "class UnitTest(googletest.TestCase):",
+ " def testSomething():",
+ " return");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("py_test")
+ .setLabel("//py/test:unittests")
+ .addSource(sourceRoot("py/test/unittest.py"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PyClass pyClass = PsiUtils.findFirstChildOfClassRecursive(pyFile, PyClass.class);
+ assertThat(pyClass).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(pyClass);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazePyTestConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget()).isEqualTo(TargetExpression.fromString("//py/test:unittests"));
+ assertThat(getTestFilterContents(config)).isEqualTo("--test_filter=UnitTest");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+
+ @Test
+ public void testProducedFromTestCase() {
+ PsiFile pyFile =
+ createAndIndexFile(
+ new WorkspacePath("py/test/unittest.py"),
+ "class UnitTest(googletest.TestCase):",
+ " def testSomething():",
+ " return");
+
+ MockBlazeProjectDataBuilder builder = MockBlazeProjectDataBuilder.builder(workspaceRoot);
+ builder.setTargetMap(
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setKind("py_test")
+ .setLabel("//py/test:unittests")
+ .addSource(sourceRoot("py/test/unittest.py"))
+ .build())
+ .build());
+ registerProjectService(
+ BlazeProjectDataManager.class, new MockBlazeProjectDataManager(builder.build()));
+
+ PyFunction function = PsiUtils.findFirstChildOfClassRecursive(pyFile, PyFunction.class);
+ assertThat(function).isNotNull();
+
+ ConfigurationContext context = createContextFromPsi(function);
+ List<ConfigurationFromContext> configurations = context.getConfigurationsFromContext();
+ assertThat(configurations).hasSize(1);
+
+ ConfigurationFromContext fromContext = configurations.get(0);
+ assertThat(fromContext.isProducedBy(BlazePyTestConfigurationProducer.class)).isTrue();
+ assertThat(fromContext.getConfiguration()).isInstanceOf(BlazeCommandRunConfiguration.class);
+
+ BlazeCommandRunConfiguration config =
+ (BlazeCommandRunConfiguration) fromContext.getConfiguration();
+ assertThat(config.getTarget()).isEqualTo(TargetExpression.fromString("//py/test:unittests"));
+ assertThat(getTestFilterContents(config)).isEqualTo("--test_filter=UnitTest.testSomething");
+ assertThat(getCommandType(config)).isEqualTo(BlazeCommandName.TEST);
+ }
+}
diff --git a/python/tests/integrationtests/com/google/idea/blaze/python/run/smrunner/BlazePythonTestEventsHandlerTest.java b/python/tests/integrationtests/com/google/idea/blaze/python/run/smrunner/BlazePythonTestEventsHandlerTest.java
new file mode 100644
index 0000000..c87025c
--- /dev/null
+++ b/python/tests/integrationtests/com/google/idea/blaze/python/run/smrunner/BlazePythonTestEventsHandlerTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run.smrunner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.Iterables;
+import com.google.idea.blaze.base.BlazeIntegrationTestCase;
+import com.google.idea.blaze.base.lang.buildfile.psi.util.PsiUtils;
+import com.google.idea.blaze.base.model.primitives.WorkspacePath;
+import com.intellij.execution.Location;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFunction;
+import javax.annotation.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Integration tests for {@link BlazePythonTestEventsHandler}.
+ */
+@RunWith(JUnit4.class)
+public class BlazePythonTestEventsHandlerTest extends BlazeIntegrationTestCase {
+
+ private final BlazePythonTestEventsHandler handler = new BlazePythonTestEventsHandler();
+
+ @Test
+ public void testSuiteLocationResolves() {
+ PsiFile file =
+ workspace.createPsiFile(
+ new WorkspacePath("lib/app_unittest.py"),
+ "class AppUnitTest:",
+ " def function(self):",
+ " return");
+ PyClass pyClass = PsiUtils.findFirstChildOfClassRecursive(file, PyClass.class);
+ assertThat(pyClass).isNotNull();
+
+ String url = handler.suiteLocationUrl(null, "AppUnitTest");
+ Location<?> location = getLocation(url);
+ assertThat(location.getPsiElement()).isEqualTo(pyClass);
+ }
+
+ @Test
+ public void testFunctionLocationResolves() {
+ PsiFile file =
+ workspace.createPsiFile(
+ new WorkspacePath("lib/app_unittest.py"),
+ "class AppUnitTest:",
+ " def testApp(self):",
+ " return");
+ PyClass pyClass = PsiUtils.findFirstChildOfClassRecursive(file, PyClass.class);
+ PyFunction function = pyClass.findMethodByName("testApp", false, null);
+ assertThat(function).isNotNull();
+
+ String url = handler.testLocationUrl(null, null, "__main__.AppUnitTest.testApp", null);
+ Location<?> location = getLocation(url);
+ assertThat(location.getPsiElement()).isEqualTo(function);
+ }
+
+ @Test
+ public void testFunctionWithoutMainPrefixResolves() {
+ PsiFile file =
+ workspace.createPsiFile(
+ new WorkspacePath("lib/app/app_unittest.py"),
+ "class AppUnitTest:",
+ " def testApp(self):",
+ " return");
+ PyClass pyClass = PsiUtils.findFirstChildOfClassRecursive(file, PyClass.class);
+ PyFunction function = pyClass.findMethodByName("testApp", false, null);
+ assertThat(function).isNotNull();
+
+ String url = handler.testLocationUrl(null, null, "lib.app.AppUnitTest.testApp", null);
+ Location<?> location = getLocation(url);
+ assertThat(location.getPsiElement()).isEqualTo(function);
+ }
+
+ @Nullable
+ private Location<?> getLocation(String url) {
+ String protocol = VirtualFileManager.extractProtocol(url);
+ String path = VirtualFileManager.extractPath(url);
+ if (protocol == null) {
+ return null;
+ }
+ return Iterables.getFirst(
+ handler
+ .getTestLocator()
+ .getLocation(protocol, path, getProject(), GlobalSearchScope.allScope(getProject())),
+ null);
+ }
+}
diff --git a/python/tests/unittests/com/google/idea/blaze/python/run/BlazePyRunConfigurationRunnerTest.java b/python/tests/unittests/com/google/idea/blaze/python/run/BlazePyRunConfigurationRunnerTest.java
new file mode 100644
index 0000000..d29c2fb
--- /dev/null
+++ b/python/tests/unittests/com/google/idea/blaze/python/run/BlazePyRunConfigurationRunnerTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.python.run;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.primitives.Label;
+import java.io.File;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link BlazePyRunConfigurationRunner}. */
+@RunWith(JUnit4.class)
+public class BlazePyRunConfigurationRunnerTest {
+
+ @Test
+ public void testMultipleOutputFiles() {
+ Label target = Label.create("//path/to/package:SomeTest");
+ ImmutableList<File> outputFiles =
+ ImmutableList.of(
+ new File("blaze-bin/path/to/package/SomeTest.run.py"),
+ new File("blaze-bin/path/to/package/SomeTest"));
+ assertThat(BlazePyRunConfigurationRunner.findExecutable(target, outputFiles))
+ .isEqualTo(new File("blaze-bin/path/to/package/SomeTest"));
+ }
+}
diff --git a/scala/BUILD b/scala/BUILD
new file mode 100644
index 0000000..1343c03
--- /dev/null
+++ b/scala/BUILD
@@ -0,0 +1,97 @@
+licenses(["notice"]) # Apache 2.0
+
+load(
+ "//build_defs:build_defs.bzl",
+ "merged_plugin_xml",
+ "stamped_plugin_xml",
+ "intellij_plugin",
+ "optional_plugin_xml",
+)
+load(
+ "//testing:test_defs.bzl",
+ "intellij_unit_test_suite",
+ "intellij_integration_test_suite",
+)
+
+filegroup(
+ name = "plugin_xml",
+ srcs = ["src/META-INF/blaze-scala.xml"],
+ visibility = ["//visibility:public"],
+)
+
+optional_plugin_xml(
+ name = "optional_xml",
+ module = "org.intellij.scala",
+ plugin_xml = "src/META-INF/scala-contents.xml",
+ visibility = ["//visibility:public"],
+)
+
+merged_plugin_xml(
+ name = "merged_plugin_xml",
+ srcs = [
+ ":plugin_xml",
+ "//base:plugin_xml",
+ "//java:plugin_xml",
+ ],
+)
+
+stamped_plugin_xml(
+ name = "scala_plugin_xml",
+ plugin_id = "com.google.idea.blaze.scala",
+ plugin_name = "com.google.idea.blaze.scala",
+ plugin_xml = "merged_plugin_xml",
+)
+
+java_library(
+ name = "scala",
+ srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//intellij_platform_sdk:plugin_api",
+ "//java",
+ "//third_party/scala",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+intellij_plugin(
+ name = "scala_integration_test_plugin",
+ testonly = 1,
+ optional_plugin_xmls = [":optional_xml"],
+ plugin_xml = ":scala_plugin_xml",
+ deps = [":scala"],
+)
+
+intellij_unit_test_suite(
+ name = "unit_tests",
+ srcs = glob(["tests/unittests/**/*.java"]),
+ test_package_root = "com.google.idea.blaze",
+ deps = [
+ ":scala",
+ "//base",
+ "//base:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//java",
+ "//third_party/scala:scala_for_tests",
+ "@junit//jar",
+ ],
+)
+
+intellij_integration_test_suite(
+ name = "integration_tests",
+ srcs = glob(["tests/integrationtests/**/*.java"]),
+ required_plugins = "org.intellij.scala,com.google.idea.blaze.scala",
+ test_package_root = "com.google.idea.blaze.scala",
+ runtime_deps = [":scala_integration_test_plugin"],
+ deps = [
+ ":scala",
+ "//base",
+ "//base:integration_test_utils",
+ "//base:unit_test_utils",
+ "//intellij_platform_sdk:plugin_api_for_tests",
+ "//java",
+ "//third_party/scala:scala_for_tests",
+ "@junit//jar",
+ ],
+)
diff --git a/scala/src/META-INF/blaze-scala.xml b/scala/src/META-INF/blaze-scala.xml
new file mode 100644
index 0000000..375fdc7
--- /dev/null
+++ b/scala/src/META-INF/blaze-scala.xml
@@ -0,0 +1,5 @@
+<idea-plugin>
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncPlugin implementation="com.google.idea.blaze.scala.sync.AlwaysPresentScalaSyncPlugin"/>
+ </extensions>
+</idea-plugin>
diff --git a/scala/src/META-INF/scala-contents.xml b/scala/src/META-INF/scala-contents.xml
new file mode 100644
index 0000000..9c46cf1
--- /dev/null
+++ b/scala/src/META-INF/scala-contents.xml
@@ -0,0 +1,7 @@
+<idea-plugin>
+ <extensions defaultExtensionNs="com.google.idea.blaze">
+ <SyncPlugin implementation="com.google.idea.blaze.scala.sync.BlazeScalaSyncPlugin"/>
+ <JavaLikeLanguage
+ implementation="com.google.idea.blaze.scala.sync.source.ScalaJavaLikeLanguage"/>
+ </extensions>
+</idea-plugin>
diff --git a/scala/src/com/google/idea/blaze/scala/sync/AlwaysPresentScalaSyncPlugin.java b/scala/src/com/google/idea/blaze/scala/sync/AlwaysPresentScalaSyncPlugin.java
new file mode 100644
index 0000000..e331132
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/AlwaysPresentScalaSyncPlugin.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.model.primitives.LanguageClass;
+import com.google.idea.blaze.base.model.primitives.WorkspaceType;
+import com.google.idea.blaze.base.plugin.PluginUtils;
+import com.google.idea.blaze.base.projectview.ProjectViewSet;
+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.project.Project;
+import java.util.Set;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Unlike most of the scala-specific code, will be run even if the JetBrains scala plugin isn't
+ * enabled.
+ */
+public class AlwaysPresentScalaSyncPlugin extends BlazeSyncPlugin.Adapter {
+ private static final String SCALA_PLUGIN_ID = "org.intellij.scala";
+
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ if (workspaceType.equals(WorkspaceType.JAVA)) {
+ return ImmutableSet.of(LanguageClass.SCALA);
+ }
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public boolean validateProjectView(
+ @Nullable Project project,
+ BlazeContext context,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings) {
+ if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.SCALA)) {
+ return true;
+ }
+ if (!PluginUtils.isPluginEnabled(SCALA_PLUGIN_ID)) {
+ IssueOutput.error("Scala plugin needed for Scala language support.")
+ .navigatable(PluginUtils.installOrEnablePluginNavigable(SCALA_PLUGIN_ID))
+ .submit(context);
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/scala/src/com/google/idea/blaze/scala/sync/BlazeScalaLibrarySource.java b/scala/src/com/google/idea/blaze/scala/sync/BlazeScalaLibrarySource.java
new file mode 100644
index 0000000..86f276f
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/BlazeScalaLibrarySource.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.blaze.base.model.BlazeLibrary;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.sync.libraries.LibrarySource;
+import com.google.idea.blaze.scala.sync.model.BlazeScalaSyncData;
+import java.util.Collection;
+
+/** Provides libraries required by Scala rules. */
+public class BlazeScalaLibrarySource extends LibrarySource.Adapter {
+ private final BlazeProjectData blazeProjectData;
+
+ BlazeScalaLibrarySource(BlazeProjectData blazeProjectData) {
+ this.blazeProjectData = blazeProjectData;
+ }
+
+ @Override
+ public Collection<? extends BlazeLibrary> getLibraries() {
+ BlazeScalaSyncData syncData = blazeProjectData.syncState.get(BlazeScalaSyncData.class);
+ if (syncData == null) {
+ return ImmutableList.of();
+ }
+ return syncData.importResult.libraries.values();
+ }
+}
diff --git a/scala/src/com/google/idea/blaze/scala/sync/BlazeScalaSyncPlugin.java b/scala/src/com/google/idea/blaze/scala/sync/BlazeScalaSyncPlugin.java
new file mode 100644
index 0000000..20fa54c
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/BlazeScalaSyncPlugin.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.command.info.BlazeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMap;
+import com.google.idea.blaze.base.model.BlazeProjectData;
+import com.google.idea.blaze.base.model.SyncState;
+import com.google.idea.blaze.base.model.SyncState.Builder;
+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.libraries.LibrarySource;
+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.scala.sync.importer.BlazeScalaWorkspaceImporter;
+import com.google.idea.blaze.scala.sync.model.BlazeScalaImportResult;
+import com.google.idea.blaze.scala.sync.model.BlazeScalaSyncData;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.OrderEnumerator;
+import com.intellij.openapi.roots.ui.configuration.libraryEditor.ExistingLibraryEditor;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.jetbrains.plugins.scala.project.ScalaLibraryType;
+
+/** Supports scala. */
+public class BlazeScalaSyncPlugin extends BlazeSyncPlugin.Adapter {
+ @Override
+ public Set<LanguageClass> getSupportedLanguagesInWorkspace(WorkspaceType workspaceType) {
+ if (workspaceType.equals(WorkspaceType.JAVA)) {
+ return ImmutableSet.of(LanguageClass.SCALA);
+ }
+ 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.SCALA)) {
+ return;
+ }
+ OrderEnumerator.orderEntries(workspaceModule)
+ .forEachLibrary(
+ library -> {
+ // Convert the type of the SDK library to prevent the scala plugin from
+ // showing the missing SDK notification.
+ // TODO: use a canonical class in the SDK (e.g., scala.App) instead of the name?
+ if (library.getName() != null && library.getName().startsWith("scala-library")) {
+ ExistingLibraryEditor editor = new ExistingLibraryEditor(library, null);
+ editor.setType(ScalaLibraryType.instance());
+ editor.commit();
+ return false; // stop
+ }
+ return true; // continue
+ });
+ }
+
+ @Override
+ public void updateSyncState(
+ Project project,
+ BlazeContext context,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ WorkspaceLanguageSettings workspaceLanguageSettings,
+ BlazeInfo blazeInfo,
+ @Nullable WorkingSet workingSet,
+ WorkspacePathResolver workspacePathResolver,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ TargetMap targetMap,
+ Builder syncStateBuilder,
+ @Nullable SyncState previousSyncState) {
+ if (!workspaceLanguageSettings.isLanguageActive(LanguageClass.SCALA)) {
+ return;
+ }
+ BlazeScalaWorkspaceImporter blazeScalaWorkspaceImporter =
+ new BlazeScalaWorkspaceImporter(project, workspaceRoot, projectViewSet, targetMap);
+ BlazeScalaImportResult importResult =
+ Scope.push(
+ context,
+ (childContext) -> {
+ childContext.push(new TimingScope("ScalaWorkspaceImporter"));
+ return blazeScalaWorkspaceImporter.importWorkspace();
+ });
+ BlazeScalaSyncData syncData = new BlazeScalaSyncData(importResult);
+ syncStateBuilder.put(BlazeScalaSyncData.class, syncData);
+ }
+
+ @Nullable
+ @Override
+ public LibrarySource getLibrarySource(
+ ProjectViewSet projectViewSet, BlazeProjectData blazeProjectData) {
+ if (!blazeProjectData.workspaceLanguageSettings.isLanguageActive(LanguageClass.SCALA)) {
+ return null;
+ }
+ return new BlazeScalaLibrarySource(blazeProjectData);
+ }
+}
diff --git a/scala/src/com/google/idea/blaze/scala/sync/importer/BlazeScalaWorkspaceImporter.java b/scala/src/com/google/idea/blaze/scala/sync/importer/BlazeScalaWorkspaceImporter.java
new file mode 100644
index 0000000..5410f2c
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/importer/BlazeScalaWorkspaceImporter.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync.importer;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetKey;
+import com.google.idea.blaze.base.ideinfo.TargetMap;
+import com.google.idea.blaze.base.model.LibraryKey;
+import com.google.idea.blaze.base.model.primitives.Kind;
+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.sync.projectview.ProjectViewTargetImportFilter;
+import com.google.idea.blaze.base.targetmaps.TransitiveDependencyMap;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import com.google.idea.blaze.scala.sync.model.BlazeScalaImportResult;
+import com.intellij.openapi.project.Project;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Builds a BlazeWorkspace. */
+public final class BlazeScalaWorkspaceImporter {
+ private final Project project;
+ private final WorkspaceRoot workspaceRoot;
+ private final ProjectViewSet projectViewSet;
+ private final TargetMap targetMap;
+
+ public BlazeScalaWorkspaceImporter(
+ Project project,
+ WorkspaceRoot workspaceRoot,
+ ProjectViewSet projectViewSet,
+ TargetMap targetMap) {
+ this.project = project;
+ this.workspaceRoot = workspaceRoot;
+ this.projectViewSet = projectViewSet;
+ this.targetMap = targetMap;
+ }
+
+ public BlazeScalaImportResult importWorkspace() {
+ ProjectViewTargetImportFilter importFilter =
+ new ProjectViewTargetImportFilter(project, workspaceRoot, projectViewSet);
+
+ Collection<Kind> scalaKinds = Kind.allKindsForLanguage(LanguageClass.SCALA);
+ List<TargetKey> scalaSourceTargets =
+ targetMap
+ .targets()
+ .stream()
+ .filter(target -> target.javaIdeInfo != null)
+ .filter(target -> target.kindIsOneOf(scalaKinds))
+ .filter(importFilter::isSourceTarget)
+ .map(target -> target.key)
+ .collect(Collectors.toList());
+
+ ImmutableMap.Builder<LibraryKey, BlazeJarLibrary> libraries = ImmutableMap.builder();
+
+ // Add every jar in the transitive closure of dependencies.
+ // Direct dependencies of the working set will be double counted by BlazeJavaWorkspaceImporter,
+ // but since they'll all merged into one set, we will end up with exactly one of each.
+ for (TargetKey dependency :
+ TransitiveDependencyMap.getTransitiveDependencies(scalaSourceTargets, targetMap)) {
+ TargetIdeInfo target = targetMap.get(dependency);
+ if (target == null) {
+ continue;
+ }
+ // Except source targets.
+ if (importFilter.isSourceTarget(target)) {
+ continue;
+ }
+ if (target.javaIdeInfo != null) {
+ target
+ .javaIdeInfo
+ .jars
+ .stream()
+ .map(BlazeJarLibrary::new)
+ .forEach(library -> libraries.put(library.key, library));
+ }
+ }
+
+ return new BlazeScalaImportResult(libraries.build());
+ }
+}
diff --git a/scala/src/com/google/idea/blaze/scala/sync/model/BlazeScalaImportResult.java b/scala/src/com/google/idea/blaze/scala/sync/model/BlazeScalaImportResult.java
new file mode 100644
index 0000000..2140c19
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/model/BlazeScalaImportResult.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync.model;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.model.LibraryKey;
+import com.google.idea.blaze.java.sync.model.BlazeJarLibrary;
+import java.io.Serializable;
+import javax.annotation.concurrent.Immutable;
+
+/** The result of a blaze import operation. */
+@Immutable
+public class BlazeScalaImportResult implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final ImmutableMap<LibraryKey, BlazeJarLibrary> libraries;
+
+ public BlazeScalaImportResult(ImmutableMap<LibraryKey, BlazeJarLibrary> libraries) {
+ this.libraries = libraries;
+ }
+}
diff --git a/scala/src/com/google/idea/blaze/scala/sync/model/BlazeScalaSyncData.java b/scala/src/com/google/idea/blaze/scala/sync/model/BlazeScalaSyncData.java
new file mode 100644
index 0000000..56ce799
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/model/BlazeScalaSyncData.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync.model;
+
+import java.io.Serializable;
+
+/** Sync data for the scala plugin. */
+public class BlazeScalaSyncData implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ public final BlazeScalaImportResult importResult;
+
+ public BlazeScalaSyncData(BlazeScalaImportResult importResult) {
+ this.importResult = importResult;
+ }
+}
diff --git a/scala/src/com/google/idea/blaze/scala/sync/source/ScalaJavaLikeLanguage.java b/scala/src/com/google/idea/blaze/scala/sync/source/ScalaJavaLikeLanguage.java
new file mode 100644
index 0000000..df37840
--- /dev/null
+++ b/scala/src/com/google/idea/blaze/scala/sync/source/ScalaJavaLikeLanguage.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync.source;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.java.sync.source.JavaLikeLanguage;
+import java.util.Set;
+
+/** Provides Java-like parts of Scala to the Java plugin. */
+public class ScalaJavaLikeLanguage implements JavaLikeLanguage {
+ @Override
+ public Set<String> getFileExtensions() {
+ return ImmutableSet.of(".scala");
+ }
+}
diff --git a/scala/tests/integrationtests/com/google/idea/blaze/scala/sync/ScalaSyncTest.java b/scala/tests/integrationtests/com/google/idea/blaze/scala/sync/ScalaSyncTest.java
new file mode 100644
index 0000000..c55075f
--- /dev/null
+++ b/scala/tests/integrationtests/com/google/idea/blaze/scala/sync/ScalaSyncTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMap;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+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.WorkspacePath;
+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.base.sync.projectview.WorkspaceLanguageSettings;
+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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Scala-specific sync integration tests. */
+@RunWith(JUnit4.class)
+public class ScalaSyncTest extends BlazeSyncIntegrationTestCase {
+ @Test
+ public void testScalaClassesPresentInClassPath() throws Exception {
+ setProjectView(
+ "directories:",
+ " src/main/scala/com/google",
+ "targets:",
+ " //src/main/scala/com/google:lib",
+ "additional_languages:",
+ " scala");
+
+ workspace.createFile(
+ new WorkspacePath("src/main/scala/com/google/ClassWithUniqueName1.scala"),
+ "package com.google;",
+ "public class ClassWithUniqueName1 {}");
+
+ workspace.createFile(
+ new WorkspacePath("src/main/scala/com/google/ClassWithUniqueName2.scala"),
+ "package com.google;",
+ "public class ClassWithUniqueName2 {}");
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("src/main/scala/com/google/BUILD"))
+ .setLabel("//src/main/scala/com/google:lib")
+ .setKind("scala_library")
+ .addSource(sourceRoot("src/main/scala/com/google/ClassWithUniqueName1.scala"))
+ .addSource(sourceRoot("src/main/scala/com/google/ClassWithUniqueName2.scala"))
+ .setJavaInfo(JavaIdeInfo.builder()))
+ .build();
+
+ setTargetMap(targetMap);
+
+ BlazeSyncParams syncParams =
+ new BlazeSyncParams.Builder("Full Sync", BlazeSyncParams.SyncMode.FULL)
+ .addProjectViewTargets(true)
+ .build();
+ runBlazeSync(syncParams);
+
+ errorCollector.assertNoIssues();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.targetMap).isEqualTo(targetMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings)
+ .isEqualTo(
+ new WorkspaceLanguageSettings(
+ WorkspaceType.JAVA,
+ ImmutableSet.of(LanguageClass.GENERIC, LanguageClass.JAVA, LanguageClass.SCALA)));
+
+ BlazeJavaSyncData javaSyncData = blazeProjectData.syncState.get(BlazeJavaSyncData.class);
+ assertThat(javaSyncData).isNotNull();
+ List<BlazeContentEntry> contentEntries = javaSyncData.importResult.contentEntries;
+ assertThat(contentEntries).hasSize(1);
+
+ BlazeContentEntry contentEntry = contentEntries.get(0);
+ assertThat(contentEntry.contentRoot.getPath())
+ .isEqualTo(
+ workspaceRoot.fileForPath(new WorkspacePath("src/main/scala/com/google")).getPath());
+ assertThat(contentEntry.sources).hasSize(1);
+
+ BlazeSourceDirectory sourceDir = contentEntry.sources.get(0);
+ assertThat(sourceDir.getPackagePrefix()).isEqualTo("com.google");
+ assertThat(sourceDir.getDirectory().getPath())
+ .isEqualTo(
+ workspaceRoot.fileForPath(new WorkspacePath("src/main/scala/com/google")).getPath());
+ }
+
+ @Test
+ public void testSimpleSync() throws Exception {
+ setProjectView(
+ "directories:",
+ " src/main/scala/com/google",
+ "targets:",
+ " //src/main/scala/com/google:lib",
+ "additional_languages:",
+ " scala");
+
+ workspace.createFile(
+ new WorkspacePath("src/main/scala/com/google/Source.scala"),
+ "package com.google;",
+ "public class Source {}");
+
+ workspace.createFile(
+ new WorkspacePath("src/main/scala/com/google/Other.scala"),
+ "package com.google;",
+ "public class Other {}");
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setBuildFile(sourceRoot("src/main/scala/com/google/BUILD"))
+ .setLabel("//src/main/scala/com/google:lib")
+ .setKind("scala_library")
+ .addSource(sourceRoot("src/main/scala/com/google/Source.scala"))
+ .addSource(sourceRoot("src/main/scala/com/google/Other.scala")))
+ .build();
+
+ setTargetMap(targetMap);
+
+ runBlazeSync(
+ new BlazeSyncParams.Builder("Sync", SyncMode.INCREMENTAL)
+ .addProjectViewTargets(true)
+ .build());
+
+ errorCollector.assertNoIssues();
+
+ BlazeProjectData blazeProjectData =
+ BlazeProjectDataManager.getInstance(getProject()).getBlazeProjectData();
+ assertThat(blazeProjectData).isNotNull();
+ assertThat(blazeProjectData.targetMap).isEqualTo(targetMap);
+ assertThat(blazeProjectData.workspaceLanguageSettings)
+ .isEqualTo(
+ new WorkspaceLanguageSettings(
+ WorkspaceType.JAVA,
+ ImmutableSet.of(LanguageClass.GENERIC, LanguageClass.SCALA, LanguageClass.JAVA)));
+ }
+}
diff --git a/scala/tests/unittests/com/google/idea/blaze/java/sync/source/ScalaSourceDirectoryCalculatorTest.java b/scala/tests/unittests/com/google/idea/blaze/java/sync/source/ScalaSourceDirectoryCalculatorTest.java
new file mode 100644
index 0000000..c364c85
--- /dev/null
+++ b/scala/tests/unittests/com/google/idea/blaze/java/sync/source/ScalaSourceDirectoryCalculatorTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY 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 com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.TargetKey;
+import com.google.idea.blaze.base.io.InputStreamProvider;
+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.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.workspace.ArtifactLocationDecoder;
+import com.google.idea.blaze.java.sync.model.BlazeContentEntry;
+import com.google.idea.blaze.java.sync.model.BlazeSourceDirectory;
+import com.google.idea.blaze.scala.sync.source.ScalaJavaLikeLanguage;
+import com.intellij.openapi.extensions.ExtensionPoint;
+import com.intellij.util.containers.HashMap;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+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;
+
+/** Test cases for {@link SourceDirectoryCalculator} with Scala sources. */
+@RunWith(JUnit4.class)
+public class ScalaSourceDirectoryCalculatorTest extends BlazeTestCase {
+ private MockInputStreamProvider mockInputStreamProvider;
+ private SourceDirectoryCalculator sourceDirectoryCalculator;
+ private final BlazeContext context = new BlazeContext();
+ private final ErrorCollector issues = new ErrorCollector();
+ private final WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/root"));
+
+ private final ArtifactLocationDecoder decoder =
+ (ArtifactLocationDecoder)
+ artifactLocation -> new File("/root", artifactLocation.getRelativePath());
+
+ @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(PrefetchService.class, new MockPrefetchService());
+
+ ExtensionPoint<JavaLikeLanguage> javaLikeLanguages =
+ registerExtensionPoint(JavaLikeLanguage.EP_NAME, JavaLikeLanguage.class);
+ javaLikeLanguages.registerExtension(new JavaLikeLanguage.Java());
+ javaLikeLanguages.registerExtension(new ScalaJavaLikeLanguage());
+
+ context.addOutputSink(IssueOutput.class, issues);
+ sourceDirectoryCalculator = new SourceDirectoryCalculator();
+ }
+
+ @Test
+ public void testSingleScalaSource() {
+ mockInputStreamProvider.addFile(
+ "/root/src/main/scala/com/google/Foo.scala", "package com.google\n public class Foo {}");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/scala/com/google:foo")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/scala/com/google/Foo.scala")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ decoder,
+ ImmutableList.of(new WorkspacePath("src/main/scala/com/google")),
+ sourceArtifacts,
+ ImmutableMap.of());
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build());
+ issues.assertNoIssues();
+ }
+
+ @Test
+ public void testMultipleScalaSources() {
+ mockInputStreamProvider
+ .addFile(
+ "/root/src/main/scala/com/google/Foo.scala",
+ "package com.google;\n public class Foo {}")
+ .addFile(
+ "/root/src/main/scala/com/google/Bar.scala", "package com.google\n public class Bar {}")
+ .addFile(
+ "/root/src/main/scala/com/alphabet/Baz.scala",
+ "package com.alphabet {\n public class Baz {} }");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/scala/com/google:foo")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/scala/com/google/Foo.scala")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/scala/com/google:bar")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/scala/com/google/Bar.scala")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/scala/com/alphabet:baz")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/scala/com/alphabet/Baz.scala")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ decoder,
+ ImmutableList.of(
+ new WorkspacePath("src/main/scala/com/google"),
+ new WorkspacePath("src/main/scala/com/alphabet")),
+ sourceArtifacts,
+ ImmutableMap.of());
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/scala/com/alphabet")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/com/alphabet")
+ .setPackagePrefix("com.alphabet")
+ .build())
+ .build());
+ issues.assertNoIssues();
+ }
+
+ @Test
+ public void testMixedScalaAndJavaSources() {
+ mockInputStreamProvider
+ .addFile(
+ "/root/src/main/java/com/google/Foo.java", "package com.google;\n public class Foo {}")
+ .addFile(
+ "/root/src/main/scala/com/google/Bar.scala", "package com.google\n public class Bar {}")
+ .addFile(
+ "/root/src/main/scala/com/alphabet/Baz.scala",
+ "package com.alphabet {\n public class Baz {} }");
+ List<SourceArtifact> sourceArtifacts =
+ ImmutableList.of(
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/java/com/google:foo")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/java/com/google/Foo.java")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/scala/com/google:bar")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/scala/com/google/Bar.scala")
+ .setIsSource(true))
+ .build(),
+ SourceArtifact.builder(
+ TargetKey.forPlainTarget(Label.create("//src/main/scala/com/alphabet:baz")))
+ .setArtifactLocation(
+ ArtifactLocation.builder()
+ .setRelativePath("src/main/scala/com/alphabet/Baz.scala")
+ .setIsSource(true))
+ .build());
+ ImmutableList<BlazeContentEntry> result =
+ sourceDirectoryCalculator.calculateContentEntries(
+ project,
+ context,
+ workspaceRoot,
+ decoder,
+ ImmutableList.of(
+ new WorkspacePath("src/main/java/com/google"),
+ new WorkspacePath("src/main/scala/com/google"),
+ new WorkspacePath("src/main/scala/com/alphabet")),
+ sourceArtifacts,
+ ImmutableMap.of());
+ assertThat(result)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/java/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/java/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/scala/com/google")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/com/google")
+ .setPackagePrefix("com.google")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/scala/com/alphabet")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/com/alphabet")
+ .setPackagePrefix("com.alphabet")
+ .build())
+ .build());
+ issues.assertNoIssues();
+ }
+
+ private static class MockInputStreamProvider implements InputStreamProvider {
+
+ private final Map<String, InputStream> files = new HashMap<>();
+
+ MockInputStreamProvider addFile(String filePath, String src) {
+ try {
+ files.put(filePath, new ByteArrayInputStream(src.getBytes("UTF-8")));
+ } catch (UnsupportedEncodingException ignored) {
+ // ignored
+ }
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public InputStream getFile(@NotNull File path) {
+ return files.get(path.getPath());
+ }
+ }
+}
diff --git a/scala/tests/unittests/com/google/idea/blaze/scala/sync/BlazeScalaSyncPluginTest.java b/scala/tests/unittests/com/google/idea/blaze/scala/sync/BlazeScalaSyncPluginTest.java
new file mode 100644
index 0000000..6002f5d
--- /dev/null
+++ b/scala/tests/unittests/com/google/idea/blaze/scala/sync/BlazeScalaSyncPluginTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.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.ListSection;
+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.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.LanguageSupport;
+import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
+import com.google.idea.blaze.java.sync.BlazeJavaSyncPlugin;
+import com.intellij.openapi.extensions.impl.ExtensionPointImpl;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link BlazeScalaSyncPlugin} */
+@RunWith(JUnit4.class)
+public class BlazeScalaSyncPluginTest extends BlazeTestCase {
+ private final ErrorCollector errorCollector = new ErrorCollector();
+ private BlazeContext context;
+
+ @Override
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ ExtensionPointImpl<BlazeSyncPlugin> syncPlugins =
+ registerExtensionPoint(BlazeSyncPlugin.EP_NAME, BlazeSyncPlugin.class);
+ syncPlugins.registerExtension(new BlazeJavaSyncPlugin());
+ syncPlugins.registerExtension(new BlazeScalaSyncPlugin());
+ context = new BlazeContext();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+ }
+
+ @Test
+ public void testScalaValidAdditionalLanguage() {
+ ProjectViewSet projectViewSet =
+ ProjectViewSet.builder()
+ .add(
+ ProjectView.builder()
+ .add(ScalarSection.builder(WorkspaceTypeSection.KEY).set(WorkspaceType.JAVA))
+ .add(
+ ListSection.builder(AdditionalLanguagesSection.KEY)
+ .add(LanguageClass.SCALA))
+ .build())
+ .build();
+ WorkspaceLanguageSettings workspaceLanguageSettings =
+ LanguageSupport.createWorkspaceLanguageSettings(projectViewSet);
+ LanguageSupport.validateLanguageSettings(context, workspaceLanguageSettings);
+ errorCollector.assertNoIssues();
+ assertThat(workspaceLanguageSettings)
+ .isEqualTo(
+ new WorkspaceLanguageSettings(
+ WorkspaceType.JAVA,
+ ImmutableSet.of(LanguageClass.GENERIC, LanguageClass.JAVA, LanguageClass.SCALA)));
+ }
+}
diff --git a/scala/tests/unittests/com/google/idea/blaze/scala/sync/importer/BlazeScalaWorkspaceImporterTest.java b/scala/tests/unittests/com/google/idea/blaze/scala/sync/importer/BlazeScalaWorkspaceImporterTest.java
new file mode 100644
index 0000000..363bcfb
--- /dev/null
+++ b/scala/tests/unittests/com/google/idea/blaze/scala/sync/importer/BlazeScalaWorkspaceImporterTest.java
@@ -0,0 +1,573 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.scala.sync.importer;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.idea.blaze.base.BlazeTestCase;
+import com.google.idea.blaze.base.ideinfo.ArtifactLocation;
+import com.google.idea.blaze.base.ideinfo.JavaIdeInfo;
+import com.google.idea.blaze.base.ideinfo.LibraryArtifact;
+import com.google.idea.blaze.base.ideinfo.TargetIdeInfo;
+import com.google.idea.blaze.base.ideinfo.TargetMap;
+import com.google.idea.blaze.base.ideinfo.TargetMapBuilder;
+import com.google.idea.blaze.base.model.LibraryKey;
+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.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.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.java.sync.BlazeJavaSyncAugmenter;
+import com.google.idea.blaze.java.sync.importer.BlazeJavaWorkspaceImporter;
+import com.google.idea.blaze.java.sync.importer.JavaSourceFilter;
+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.source.JavaLikeLanguage;
+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.scala.sync.model.BlazeScalaImportResult;
+import com.google.idea.blaze.scala.sync.source.ScalaJavaLikeLanguage;
+import com.intellij.openapi.extensions.ExtensionPoint;
+import java.io.File;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for {@link BlazeScalaWorkspaceImporter} */
+@RunWith(JUnit4.class)
+public class BlazeScalaWorkspaceImporterTest extends BlazeTestCase {
+ private final WorkspaceRoot workspaceRoot = new WorkspaceRoot(new File("/root"));
+ private BlazeContext context;
+ private final ErrorCollector errorCollector = new ErrorCollector();
+
+ @Override
+ @SuppressWarnings("FunctionalInterfaceClash") // False positive on getDeclaredPackageOfJavaFile.
+ protected void initTest(
+ @NotNull Container applicationServices, @NotNull Container projectServices) {
+ super.initTest(applicationServices, projectServices);
+ context = new BlazeContext();
+ context.addOutputSink(IssueOutput.class, errorCollector);
+
+ registerExtensionPoint(BlazeJavaSyncAugmenter.EP_NAME, BlazeJavaSyncAugmenter.class);
+
+ BlazeImportSettingsManager importSettingsManager = new BlazeImportSettingsManager();
+ importSettingsManager.setImportSettings(
+ new BlazeImportSettings("", "", "", "", BuildSystem.Blaze));
+ projectServices.register(BlazeImportSettingsManager.class, importSettingsManager);
+
+ applicationServices.register(PrefetchService.class, new MockPrefetchService());
+ applicationServices.register(PackageManifestReader.class, new PackageManifestReader());
+
+ // will silently fall back to FilePathJavaPackageReader
+ applicationServices.register(
+ JavaSourcePackageReader.class,
+ new JavaSourcePackageReader() {
+ @Nullable
+ @Override
+ public String getDeclaredPackageOfJavaFile(
+ BlazeContext context,
+ ArtifactLocationDecoder artifactLocationDecoder,
+ SourceArtifact sourceArtifact) {
+ return null;
+ }
+ });
+
+ ExtensionPoint<JavaLikeLanguage> javaLikeLanguages =
+ registerExtensionPoint(JavaLikeLanguage.EP_NAME, JavaLikeLanguage.class);
+ javaLikeLanguages.registerExtension(new JavaLikeLanguage.Java());
+ javaLikeLanguages.registerExtension(new ScalaJavaLikeLanguage());
+ }
+
+ @Test
+ public void testEmptyProject() {
+ ProjectView projectView = ProjectView.builder().build();
+ TargetMap targetMap = TargetMapBuilder.builder().build();
+
+ BlazeJavaImportResult javaImportResult = importJava(projectView, targetMap);
+ BlazeScalaImportResult scalaImportResult = importScala(projectView, targetMap);
+ errorCollector.assertNoIssues();
+
+ assertThat(javaImportResult.libraries).isEmpty();
+ assertThat(javaImportResult.contentEntries).isEmpty();
+ assertThat(javaImportResult.javaSourceFiles).isEmpty();
+ assertThat(javaImportResult.libraries).isEmpty();
+ assertThat(scalaImportResult.libraries).isEmpty();
+ }
+
+ @Test
+ public void testSingleScalaBinary() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/apps/example"))))
+ .build();
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/apps/example:example")
+ .setBuildFile(source("src/main/scala/apps/example/BUILD"))
+ .setKind("scala_binary")
+ .addSource(source("src/main/scala/apps/example/Main.scala"))
+ .addSource(source("src/main/scala/apps/example/subdir/SubdirHelper.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/scala/apps/example/example.jar"))
+ .setClassJar(gen("src/main/scala/apps/example/example.jar")))))
+ .build();
+
+ BlazeJavaImportResult javaImportResult = importJava(projectView, targetMap);
+ BlazeScalaImportResult scalaImportResult = importScala(projectView, targetMap);
+ errorCollector.assertNoIssues();
+
+ assertThat(javaImportResult.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build());
+ assertThat(javaImportResult.libraries).isEmpty();
+ assertThat(javaImportResult.javaSourceFiles)
+ .containsExactly(
+ source("src/main/scala/apps/example/Main.scala"),
+ source("src/main/scala/apps/example/subdir/SubdirHelper.scala"));
+ assertThat(scalaImportResult.libraries).isEmpty();
+ }
+
+ @Test
+ public void testScalaBinaryWithMultipleLibraries() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/apps/example"))))
+ .build();
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/apps/example:example")
+ .setBuildFile(source("src/main/scala/apps/example/BUILD"))
+ .setKind("scala_binary")
+ .addSource(source("src/main/scala/apps/example/Main.scala"))
+ .addSource(source("src/main/scala/apps/example/subdir/SubdirHelper.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/scala/apps/example/example.jar"))
+ .setClassJar(gen("src/main/scala/apps/example/example.jar"))))
+ .addDependency("//src/main/scala/some/library1:library1")
+ .addDependency("//src/main/java/other/library2:library2"))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/some/library1:library1")
+ .setBuildFile(source("src/main/scala/some/library1/BUILD"))
+ .setKind("scala_library")
+ .addSource(source("src/main/scala/some/library1/Library.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("src/main/scala/some/library1/library1_ijar.jar"))
+ .setClassJar(gen("src/main/scala/some/library1/library1.jar"))))
+ .addDependency("//src/main/java/other/import:import"))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/java/other/library2:library2")
+ .setBuildFile(source("src/main/java/other/library2/BUILD"))
+ .setKind("java_library")
+ .addSource(source("src/main/java/other/library2/Library.java"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("src/main/java/other/library2/liblibrary2-ijar.jar"))
+ .setClassJar(
+ gen("src/main/java/other/library2/liblibrary2.jar")))))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/java/other/import:import")
+ .setBuildFile(source("src/main/java/other/import/BUILD"))
+ .setKind("java_import")
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("src/main/java/other/import/libimport-ijar.jar"))
+ .setClassJar(gen("src/main/java/other/import/libimport.jar")))))
+ .build();
+
+ BlazeJavaImportResult javaImportResult = importJava(projectView, targetMap);
+ BlazeScalaImportResult scalaImportResult = importScala(projectView, targetMap);
+ errorCollector.assertNoIssues();
+
+ assertThat(javaImportResult.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build());
+ // Direct library deps will be double counted.
+ assertThat(javaImportResult.libraries).hasSize(2);
+ assertThat(hasLibrary(javaImportResult.libraries, "library1_ijar")).isTrue();
+ assertThat(hasLibrary(javaImportResult.libraries, "library2-ijar")).isTrue();
+ assertThat(javaImportResult.javaSourceFiles)
+ .containsExactly(
+ source("src/main/scala/apps/example/Main.scala"),
+ source("src/main/scala/apps/example/subdir/SubdirHelper.scala"));
+ assertThat(scalaImportResult.libraries).hasSize(3);
+ assertThat(hasLibrary(scalaImportResult.libraries, "library1_ijar")).isTrue();
+ assertThat(hasLibrary(scalaImportResult.libraries, "library2-ijar")).isTrue();
+ assertThat(hasLibrary(scalaImportResult.libraries, "import-ijar")).isTrue();
+ }
+
+ @Test
+ public void testScalaAndJavaBinary() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/java/apps/example"))))
+ .build();
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/apps/example:example")
+ .setBuildFile(source("src/main/scala/apps/example/BUILD"))
+ .setKind("scala_binary")
+ .addSource(source("src/main/scala/apps/example/Main.scala"))
+ .addSource(source("src/main/scala/apps/example/subdir/SubdirHelper.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/scala/apps/example/example.jar"))
+ .setClassJar(gen("src/main/scala/apps/example/example.jar")))))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/java/apps/example:example")
+ .setBuildFile(source("src/main/java/apps/example/BUILD"))
+ .setKind("java_binary")
+ .addSource(source("src/main/java/apps/example/Main.java"))
+ .addSource(source("src/main/java/apps/example/subdir/SubdirHelper.java"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/java/apps/example/example.jar"))
+ .setClassJar(gen("src/main/java/apps/example/example.jar")))))
+ .build();
+
+ BlazeJavaImportResult javaImportResult = importJava(projectView, targetMap);
+ BlazeScalaImportResult scalaImportResult = importScala(projectView, targetMap);
+ errorCollector.assertNoIssues();
+
+ assertThat(javaImportResult.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/java/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/java/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build());
+ assertThat(javaImportResult.libraries).isEmpty();
+ assertThat(javaImportResult.javaSourceFiles)
+ .containsExactly(
+ source("src/main/scala/apps/example/Main.scala"),
+ source("src/main/scala/apps/example/subdir/SubdirHelper.scala"),
+ source("src/main/java/apps/example/Main.java"),
+ source("src/main/java/apps/example/subdir/SubdirHelper.java"));
+ assertThat(scalaImportResult.libraries).isEmpty();
+ }
+
+ @Test
+ public void testTwoScalaBinariesWithSharedLibrary() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/apps/other"))))
+ .build();
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/apps/example:example")
+ .setBuildFile(source("src/main/scala/apps/example/BUILD"))
+ .setKind("scala_binary")
+ .addSource(source("src/main/scala/apps/example/Main.scala"))
+ .addSource(source("src/main/scala/apps/example/subdir/SubdirHelper.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/scala/apps/example/example.jar"))
+ .setClassJar(gen("src/main/scala/apps/example/example.jar"))))
+ .addDependency("//src/main/scala/some/library:library"))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/apps/other:other")
+ .setBuildFile(source("src/main/scala/apps/other/BUILD"))
+ .setKind("scala_binary")
+ .addSource(source("src/main/scala/apps/other/Main.scala"))
+ .addSource(source("src/main/scala/apps/other/subdir/SubdirHelper.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/scala/apps/other/other.jar"))
+ .setClassJar(gen("src/main/scala/apps/other/other.jar"))))
+ .addDependency("//src/main/scala/some/library:library"))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/some/library:library")
+ .setBuildFile(source("src/main/scala/some/library/BUILD"))
+ .setKind("scala_library")
+ .addSource(source("src/main/scala/some/library/Library.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("src/main/scala/some/library/library_ijar.jar"))
+ .setClassJar(gen("src/main/scala/some/library/library.jar")))))
+ .build();
+
+ BlazeJavaImportResult javaImportResult = importJava(projectView, targetMap);
+ BlazeScalaImportResult scalaImportResult = importScala(projectView, targetMap);
+ errorCollector.assertNoIssues();
+
+ assertThat(javaImportResult.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/scala/apps/other")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/apps/other")
+ .setPackagePrefix("apps.other")
+ .build())
+ .build());
+ // Direct library deps will be double counted.
+ assertThat(javaImportResult.libraries).hasSize(1);
+ assertThat(hasLibrary(javaImportResult.libraries, "library_ijar")).isTrue();
+ assertThat(javaImportResult.javaSourceFiles)
+ .containsExactly(
+ source("src/main/scala/apps/example/Main.scala"),
+ source("src/main/scala/apps/example/subdir/SubdirHelper.scala"),
+ source("src/main/scala/apps/other/Main.scala"),
+ source("src/main/scala/apps/other/subdir/SubdirHelper.scala"));
+ assertThat(scalaImportResult.libraries).hasSize(1);
+ assertThat(hasLibrary(scalaImportResult.libraries, "library_ijar")).isTrue();
+ }
+
+ @Test
+ public void testSourceRulesNotInLibraries() {
+ ProjectView projectView =
+ ProjectView.builder()
+ .add(
+ ListSection.builder(DirectorySection.KEY)
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/apps/example")))
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/scala/some/library1")))
+ .add(DirectoryEntry.include(new WorkspacePath("src/main/java/other/library2"))))
+ .build();
+
+ TargetMap targetMap =
+ TargetMapBuilder.builder()
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/apps/example:example")
+ .setBuildFile(source("src/main/scala/apps/example/BUILD"))
+ .setKind("scala_binary")
+ .addSource(source("src/main/scala/apps/example/Main.scala"))
+ .addSource(source("src/main/scala/apps/example/subdir/SubdirHelper.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(gen("src/main/scala/apps/example/example.jar"))
+ .setClassJar(gen("src/main/scala/apps/example/example.jar"))))
+ .addDependency("//src/main/scala/some/library1:library1")
+ .addDependency("//src/main/java/other/library2:library2"))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/scala/some/library1:library1")
+ .setBuildFile(source("src/main/scala/some/library1/BUILD"))
+ .setKind("scala_library")
+ .addSource(source("src/main/scala/some/library1/Library.scala"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("src/main/scala/some/library1/library1_ijar.jar"))
+ .setClassJar(
+ gen("src/main/scala/some/library1/library1.jar")))))
+ .addTarget(
+ TargetIdeInfo.builder()
+ .setLabel("//src/main/java/other/library2:library2")
+ .setBuildFile(source("src/main/java/other/library2/BUILD"))
+ .setKind("java_library")
+ .addSource(source("src/main/java/other/library2/Library.java"))
+ .setJavaInfo(
+ JavaIdeInfo.builder()
+ .addJar(
+ LibraryArtifact.builder()
+ .setInterfaceJar(
+ gen("src/main/java/other/library2/libibrary2-ijar.jar"))
+ .setClassJar(
+ gen("src/main/java/other/library2/liblibrary2.jar")))))
+ .build();
+
+ BlazeJavaImportResult javaImportResult = importJava(projectView, targetMap);
+ BlazeScalaImportResult scalaImportResult = importScala(projectView, targetMap);
+ errorCollector.assertNoIssues();
+
+ assertThat(javaImportResult.contentEntries)
+ .containsExactly(
+ BlazeContentEntry.builder("/root/src/main/scala/apps/example")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/apps/example")
+ .setPackagePrefix("apps.example")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/scala/some/library1")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/scala/some/library1")
+ .setPackagePrefix("some.library1")
+ .build())
+ .build(),
+ BlazeContentEntry.builder("/root/src/main/java/other/library2")
+ .addSource(
+ BlazeSourceDirectory.builder("/root/src/main/java/other/library2")
+ .setPackagePrefix("other.library2")
+ .build())
+ .build());
+ assertThat(javaImportResult.libraries).isEmpty();
+ assertThat(javaImportResult.javaSourceFiles)
+ .containsExactly(
+ source("src/main/scala/apps/example/Main.scala"),
+ source("src/main/scala/apps/example/subdir/SubdirHelper.scala"),
+ source("src/main/scala/some/library1/Library.scala"),
+ source("src/main/java/other/library2/Library.java"));
+ assertThat(scalaImportResult.libraries).isEmpty();
+ }
+
+ private static boolean hasLibrary(
+ Map<LibraryKey, BlazeJarLibrary> libraries, String libraryName) {
+ return libraries
+ .values()
+ .stream()
+ .anyMatch(
+ library ->
+ library
+ .libraryArtifact
+ .jarForIntellijLibrary()
+ .relativePath
+ .endsWith(libraryName + ".jar"));
+ }
+
+ private BlazeJavaImportResult importJava(ProjectView projectView, TargetMap targetMap) {
+ ProjectViewSet projectViewSet = ProjectViewSet.builder().add(projectView).build();
+ WorkspaceLanguageSettings languageSettings =
+ new WorkspaceLanguageSettings(
+ WorkspaceType.JAVA,
+ ImmutableSet.of(LanguageClass.GENERIC, LanguageClass.SCALA, LanguageClass.JAVA));
+ JavaSourceFilter sourceFilter =
+ new JavaSourceFilter(project, workspaceRoot, projectViewSet, targetMap);
+ JdepsMap jdepsMap = key -> ImmutableList.of();
+ ArtifactLocationDecoder decoder = location -> new File(location.getRelativePath());
+ return new BlazeJavaWorkspaceImporter(
+ project,
+ workspaceRoot,
+ projectViewSet,
+ languageSettings,
+ targetMap,
+ sourceFilter,
+ jdepsMap,
+ null,
+ decoder)
+ .importWorkspace(context);
+ }
+
+ private BlazeScalaImportResult importScala(ProjectView projectView, TargetMap targetMap) {
+ ProjectViewSet projectViewSet = ProjectViewSet.builder().add(projectView).build();
+ return new BlazeScalaWorkspaceImporter(project, workspaceRoot, projectViewSet, targetMap)
+ .importWorkspace();
+ }
+
+ private static ArtifactLocation source(String relativePath) {
+ return ArtifactLocation.builder().setRelativePath(relativePath).setIsSource(true).build();
+ }
+
+ private static ArtifactLocation gen(String relativePath) {
+ return ArtifactLocation.builder()
+ .setRootExecutionPathFragment("blaze-out/bin")
+ .setRelativePath(relativePath)
+ .setIsSource(false)
+ .build();
+ }
+}
diff --git a/sdkcompat/BUILD b/sdkcompat/BUILD
index ce19ce5..a152a21 100644
--- a/sdkcompat/BUILD
+++ b/sdkcompat/BUILD
@@ -6,20 +6,14 @@
java_library(
name = "sdkcompat",
- srcs = select_for_plugin_api({
- "android-studio-145.1617.8": glob(["v145/**"]),
- "android-studio-2.3.0.3": glob(["v162/**"]),
- "android-studio-2.3.0.4": glob(["v162/**"]),
- "intellij-2016.3.1": glob(["v163/**"]),
- "intellij-162.2032.8": glob(["v162/**"]),
- "clion-162.1967.7": glob(
- ["v162/**"],
- exclude = ["v162/com/google/idea/sdkcompat/debugger/**"],
- ),
- }),
visibility = ["//visibility:public"],
- deps = [
- "//intellij_platform_sdk:plugin_api",
- "@jsr305_annotations//jar",
- ],
+ exports = select_for_plugin_api({
+ "android-studio-2.3.0.8": ["//sdkcompat/v162"],
+ "android-studio-2.3.1.0": ["//sdkcompat/v162"],
+ "intellij-2017.1.1": ["//sdkcompat/v171"],
+ "intellij-2016.3.1": ["//sdkcompat/v163"],
+ "clion-162.1967.7": ["//sdkcompat/v162"],
+ "clion-2016.3.2": ["//sdkcompat/v163"],
+ "clion-2017.1.1": ["//sdkcompat/v171"],
+ }),
)
diff --git a/sdkcompat/v145/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java b/sdkcompat/v145/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java
deleted file mode 100644
index 6051cc9..0000000
--- a/sdkcompat/v145/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.google.idea.sdkcompat.codestyle;
-
-import com.intellij.psi.codeStyle.CodeStyleManager;
-
-/** Adapter to extend two bridge different IntelliJ SDK versions. */
-public abstract class CodeStyleManagerSdkCompatAdapter extends CodeStyleManager {}
diff --git a/sdkcompat/v145/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java b/sdkcompat/v145/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java
deleted file mode 100644
index 6dfc995..0000000
--- a/sdkcompat/v145/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.google.idea.sdkcompat.debugger;
-
-import com.intellij.debugger.impl.GenericDebuggerRunner;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.configurations.RemoteConnection;
-import com.intellij.execution.configurations.RunProfileState;
-import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.execution.ui.RunContentDescriptor;
-import javax.annotation.Nullable;
-
-/** SDK compatibility for {@link GenericDebuggerRunner}. */
-public class GenericDebuggerRunnerSdkCompatAdapter extends GenericDebuggerRunner {
-
- @Nullable
- protected RunContentDescriptor attachVirtualMachine(
- RunProfileState state,
- ExecutionEnvironment env,
- RemoteConnection connection,
- long pollTimeout)
- throws ExecutionException {
- // no timeout available until 2016.2 onwards
- return super.attachVirtualMachine(
- state, env, connection, pollTimeout != 0 /* pollConnection */);
- }
-}
diff --git a/sdkcompat/v145/com/google/idea/sdkcompat/transactions/Transactions.java b/sdkcompat/v145/com/google/idea/sdkcompat/transactions/Transactions.java
deleted file mode 100644
index 94ab905..0000000
--- a/sdkcompat/v145/com/google/idea/sdkcompat/transactions/Transactions.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.google.idea.sdkcompat.transactions;
-
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.ModalityState;
-
-/** Created by tomlu on 12/22/16. */
-public class Transactions {
- public static void submitTransactionAndWait(Runnable runnable) {
- ApplicationManager.getApplication().invokeAndWait(runnable, ModalityState.any());
- }
-
- public static void submitTransaction(Disposable disposable, Runnable runnable) {
- ApplicationManager.getApplication().invokeLater(runnable);
- }
-}
diff --git a/sdkcompat/v145/com/google/idea/sdkcompat/vcs/ChangeListManagerSdkCompatAdapter.java b/sdkcompat/v145/com/google/idea/sdkcompat/vcs/ChangeListManagerSdkCompatAdapter.java
deleted file mode 100644
index df055ea..0000000
--- a/sdkcompat/v145/com/google/idea/sdkcompat/vcs/ChangeListManagerSdkCompatAdapter.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.google.idea.sdkcompat.vcs;
-
-import com.intellij.openapi.vcs.changes.ChangeListManager;
-import com.intellij.util.continuation.ContinuationPause;
-
-/** SDK adapter for change list interface. */
-public abstract class ChangeListManagerSdkCompatAdapter extends ChangeListManager {
- @Override
- public void freeze(ContinuationPause context, String reason) {
- throw new UnsupportedOperationException("ChangeListManager#freeze()");
- }
-}
diff --git a/sdkcompat/v162/BUILD b/sdkcompat/v162/BUILD
new file mode 100644
index 0000000..8eb53e7
--- /dev/null
+++ b/sdkcompat/v162/BUILD
@@ -0,0 +1,34 @@
+# Description: Indirections for SDK changes to the underlying platform library.
+
+licenses(["notice"]) # Apache 2.0
+
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_ide")
+
+java_library(
+ name = "v162",
+ srcs = glob([
+ "com/google/idea/sdkcompat/codestyle/**",
+ "com/google/idea/sdkcompat/smrunner/**",
+ "com/google/idea/sdkcompat/transactions/**",
+ "com/google/idea/sdkcompat/vcs/**",
+ ]) + select_for_ide(
+ android_studio = glob([
+ "com/google/idea/sdkcompat/cidr/**",
+ ]),
+ clion = glob([
+ "com/google/idea/sdkcompat/cidr/**",
+ "com/google/idea/sdkcompat/clion/**",
+ ]),
+ intellij = glob([
+ "com/google/idea/sdkcompat/python/**",
+ "com/google/idea/sdkcompat/dart/**",
+ ]),
+ ),
+ visibility = ["//sdkcompat:__pkg__"],
+ deps = [
+ "//intellij_platform_sdk:plugin_api",
+ "@jsr305_annotations//jar",
+ ] + select_for_ide(
+ intellij = ["//third_party/python"],
+ ),
+)
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java
new file mode 100644
index 0000000..d60a1a6
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java
@@ -0,0 +1,20 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
+import java.util.List;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrCompilerSwitchesAdapter {
+ /** Old interface does not know anything about CidrCompilerSwitches.Format */
+ public static List<String> getFileArgs(CidrCompilerSwitches switches) {
+ return switches.getFileArgs();
+ }
+
+ public static List<String> getCommandLineArgs(CidrCompilerSwitches switches) {
+ return switches.getCommandLineArgs();
+ }
+
+ public static String getCommandLineString(CidrCompilerSwitches switches) {
+ return switches.getCommandLineString();
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java
new file mode 100644
index 0000000..63eabeb
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java
@@ -0,0 +1,12 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.execution.CidrConsoleBuilder;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrConsoleBuilderAdapter extends CidrConsoleBuilder {
+
+ public CidrConsoleBuilderAdapter(Project project) {
+ super(project);
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java
new file mode 100644
index 0000000..c39c08b
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java
@@ -0,0 +1,24 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.google.common.base.Joiner;
+import com.jetbrains.cidr.lang.toolchains.CidrSwitchBuilder;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrSwitchBuilderAdapter extends CidrSwitchBuilder {
+ /**
+ * Old CidrSwitchBuilder is unable to deal with options with spaces embedded. This is a hack to
+ * preserve the old behaviour for 2016.2 Original hack explanation: - 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.
+ */
+ public CidrSwitchBuilderAdapter addAllRaw(List<String> switches) {
+ switches = switches.stream().map(flag -> flag.replace("\\ ", " ")).collect(Collectors.toList());
+ addAll(Joiner.on(" ").join(switches), CidrSwitchBuilder.Format.FILE_ARGS);
+ return this;
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java
new file mode 100644
index 0000000..912eb77
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java
@@ -0,0 +1,20 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/** Adapter to bridge different SDK versions. */
+public interface OCResolveConfigurationAdapter extends OCResolveConfiguration {
+ /* v171 */
+ public List<VirtualFile> getPrecompiledHeaders(OCLanguageKind kind, VirtualFile sourceFile);
+
+ /* v171 */
+ public Collection<VirtualFile> getSources();
+
+ /* v171 */
+ public Set<VirtualFile> getPrecompiledHeaders();
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java
new file mode 100644
index 0000000..99c1d36
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java
@@ -0,0 +1,28 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+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;
+
+/** Adapter to bridge different SDK versions. */
+public abstract class OCWorkspaceAdapter implements OCWorkspace {
+
+ private final Project project;
+
+ protected OCWorkspaceAdapter(Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public OCResolveConfiguration getSelectedResolveConfiguration() {
+ return null;
+ }
+
+ @Override
+ public OCWorkspaceModificationTrackers getModificationTrackers() {
+ return OCWorkspaceModificationTrackersCompatUtils.getTrackers(project);
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java
new file mode 100644
index 0000000..4b17895
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java
@@ -0,0 +1,25 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceModificationTrackers;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Handles changes to modification trackers between our supported versions. */
+public class OCWorkspaceModificationTrackersCompatUtils {
+
+ private static final Map<Project, OCWorkspaceModificationTrackers> trackers = new HashMap<>();
+
+ public static OCWorkspaceModificationTrackers getTrackers(Project project) {
+ return trackers.computeIfAbsent(project, OCWorkspaceModificationTrackers::new);
+ }
+
+ /** Must be called inside a write action, on the EDT. */
+ public static void incrementModificationCounts(Project project) {
+ OCWorkspaceModificationTrackers modTrackers = getTrackers(project);
+ modTrackers.getProjectFilesListTracker().incModificationCount();
+ modTrackers.getSourceFilesListTracker().incModificationCount();
+ modTrackers.getBuildConfigurationChangesTracker().incModificationCount();
+ modTrackers.getBuildSettingsChangesTracker().incModificationCount();
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/clion/CMakeActionList.java b/sdkcompat/v162/com/google/idea/sdkcompat/clion/CMakeActionList.java
new file mode 100644
index 0000000..9f58cf3
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/clion/CMakeActionList.java
@@ -0,0 +1,22 @@
+package com.google.idea.sdkcompat.clion;
+
+import com.google.common.collect.ImmutableSet;
+import com.jetbrains.cidr.cpp.cmake.actions.ChangeCMakeProjectContentRootAction;
+import com.jetbrains.cidr.cpp.cmake.actions.DropCMakeCacheAction;
+import com.jetbrains.cidr.cpp.cmake.actions.OpenCMakeSettingsAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ReloadCMakeProjectAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ToggleCMakeAutoReloadAction;
+
+/** Handles CMake actions which have changed between our supported versions. */
+public class CMakeActionList {
+
+ public static ImmutableSet<String> CMAKE_ACTION_IDS =
+ ImmutableSet.of(
+ ChangeCMakeProjectContentRootAction.ID,
+ DropCMakeCacheAction.ID,
+ OpenCMakeSettingsAction.ID,
+ ReloadCMakeProjectAction.ID,
+ ToggleCMakeAutoReloadAction.ID,
+ // 'CMake' > 'Show Generated CMake Files' action
+ "CMake.ShowGeneratedDir");
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java
deleted file mode 100644
index 6051cc9..0000000
--- a/sdkcompat/v162/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.google.idea.sdkcompat.codestyle;
-
-import com.intellij.psi.codeStyle.CodeStyleManager;
-
-/** Adapter to extend two bridge different IntelliJ SDK versions. */
-public abstract class CodeStyleManagerSdkCompatAdapter extends CodeStyleManager {}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
new file mode 100644
index 0000000..a16e94a
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
@@ -0,0 +1,13 @@
+package com.google.idea.sdkcompat.codestyle;
+
+import com.intellij.psi.codeStyle.CodeStyleManager;
+
+/** Adapter to bridge different SDK versions. */
+public abstract class DelegatingCodeStyleManagerSdkCompatAdapter extends CodeStyleManager {
+
+ protected CodeStyleManager delegate;
+
+ protected DelegatingCodeStyleManagerSdkCompatAdapter(CodeStyleManager delegate) {
+ this.delegate = delegate;
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java b/sdkcompat/v162/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java
new file mode 100644
index 0000000..58f48e4
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.sdkcompat.dart;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.libraries.ApplicationLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import javax.annotation.Nullable;
+
+/** Handles changes to the Dart plugin libraries between our supported versions. */
+public class DartSdkCompatUtils {
+
+ public static final String DART_SDK_LIBRARY_NAME = "Dart SDK";
+
+ @Nullable
+ public static Library findDartLibrary(Project project) {
+ return ApplicationLibraryTable.getApplicationTable().getLibraryByName(DART_SDK_LIBRARY_NAME);
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java
deleted file mode 100644
index ed822b3..0000000
--- a/sdkcompat/v162/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.google.idea.sdkcompat.debugger;
-
-import com.intellij.debugger.impl.GenericDebuggerRunner;
-
-/** SDK compatibility for {@link GenericDebuggerRunner}. */
-public class GenericDebuggerRunnerSdkCompatAdapter extends GenericDebuggerRunner {}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java
new file mode 100644
index 0000000..b3785da
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java
@@ -0,0 +1,17 @@
+package com.google.idea.sdkcompat.python;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+
+/** List of python configuration producers for a given plugin version. */
+public class PyConfigurationProducersList {
+
+ public static final Collection<Class<?>> PRODUCERS_TO_SUPPRESS =
+ ImmutableList.of(
+ com.jetbrains.python.run.PythonRunConfigurationProducer.class,
+ com.jetbrains.python.testing.attest.PythonAtTestConfigurationProducer.class,
+ com.jetbrains.python.testing.nosetest.PythonNoseTestConfigurationProducer.class,
+ com.jetbrains.python.testing.doctest.PythonDocTestConfigurationProducer.class,
+ com.jetbrains.python.testing.pytest.PyTestConfigurationProducer.class,
+ com.jetbrains.python.testing.unittest.PythonUnitTestConfigurationProducer.class);
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java
new file mode 100644
index 0000000..9ccba03
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java
@@ -0,0 +1,23 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.impl.PyImportResolver;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolveContext;
+import javax.annotation.Nullable;
+
+/** Adapter to bridge different SDK versions. */
+public interface PyImportResolverAdapter extends PyImportResolver {
+
+ @Nullable
+ PsiElement resolveImportReference(
+ QualifiedName name, PyQualifiedNameResolveContextAdapter context, boolean withRoots);
+
+ @Override
+ @Nullable
+ default PsiElement resolveImportReference(
+ QualifiedName name, QualifiedNameResolveContext context, boolean withRoots) {
+ return resolveImportReference(
+ name, new PyQualifiedNameResolveContextAdapter(context), withRoots);
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java
new file mode 100644
index 0000000..7330e11
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java
@@ -0,0 +1,77 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolveContext;
+import javax.annotation.Nullable;
+
+/** Adapter to bridge different SDK versions. */
+public class PyQualifiedNameResolveContextAdapter extends QualifiedNameResolveContext {
+
+ private final QualifiedNameResolveContext delegate;
+
+ PyQualifiedNameResolveContextAdapter(QualifiedNameResolveContext delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void copyFrom(QualifiedNameResolveContext context) {
+ delegate.copyFrom(context);
+ }
+
+ @Override
+ public void setFromElement(PsiElement element) {
+ delegate.setFromElement(element);
+ }
+
+ @Override
+ public void setFromModule(Module module) {
+ delegate.setFromModule(module);
+ }
+
+ @Override
+ public void setFromSdk(Project project, Sdk sdk) {
+ delegate.setFromSdk(project, sdk);
+ }
+
+ @Override
+ public void setSdk(Sdk sdk) {
+ delegate.setSdk(sdk);
+ }
+
+ @Override
+ @Nullable
+ public Module getModule() {
+ return delegate.getModule();
+ }
+
+ @Override
+ public boolean isValid() {
+ return delegate.isValid();
+ }
+
+ @Override
+ @Nullable
+ public PsiFile getFootholdFile() {
+ return delegate.getFootholdFile();
+ }
+
+ @Override
+ public PsiManager getPsiManager() {
+ return delegate.getPsiManager();
+ }
+
+ @Override
+ public Project getProject() {
+ return delegate.getProject();
+ }
+
+ @Override
+ public Sdk getSdk() {
+ return delegate.getSdk();
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java
new file mode 100644
index 0000000..36d4767
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java
@@ -0,0 +1,19 @@
+package com.google.idea.sdkcompat.python;
+
+import com.jetbrains.python.psi.PyQualifiedExpression;
+import com.jetbrains.python.psi.resolve.PyReferenceResolveProvider;
+import com.jetbrains.python.psi.resolve.RatedResolveResult;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+import java.util.List;
+
+/** Adapter to bridge different SDK versions. */
+public interface PyReferenceResolveProviderAdapter extends PyReferenceResolveProvider {
+
+ @Override
+ default List<RatedResolveResult> resolveName(PyQualifiedExpression element) {
+ TypeEvalContext context = TypeEvalContext.codeInsightFallback(element.getProject());
+ return resolveName(element, context);
+ }
+
+ List<RatedResolveResult> resolveName(PyQualifiedExpression element, TypeEvalContext context);
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java b/sdkcompat/v162/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java
new file mode 100644
index 0000000..5a6bef2
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java
@@ -0,0 +1,22 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.psi.resolve.ResolveImportUtil;
+import javax.annotation.Nullable;
+
+/** Handles changes to {@link ResolveImportUtil} between our supported versions. */
+public class ResolveImportCompatUtils {
+
+ @Nullable
+ public static PsiElement resolveChild(
+ @Nullable PsiElement parent,
+ String referencedName,
+ @Nullable PsiFile containingFile,
+ boolean fileOnly,
+ boolean checkForPackage,
+ boolean withoutStubs) {
+ return ResolveImportUtil.resolveChild(
+ parent, referencedName, containingFile, fileOnly, checkForPackage);
+ }
+}
diff --git a/sdkcompat/v162/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java b/sdkcompat/v162/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java
new file mode 100644
index 0000000..b0a7697
--- /dev/null
+++ b/sdkcompat/v162/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java
@@ -0,0 +1,54 @@
+package com.google.idea.sdkcompat.vcs;
+
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import com.intellij.openapi.vcs.merge.MergeData;
+import org.jetbrains.annotations.Nullable;
+
+/** SDK adapter for creating {@link MergeData}. */
+public final class MergeDataBuilder {
+ private byte[] baseContent;
+ private byte[] theirsContent;
+ private byte[] yoursContent;
+
+ @Nullable private VcsRevisionNumber theirsRevisionNumber;
+
+ public void setBaseContent(byte[] baseContent) {
+ this.baseContent = baseContent;
+ }
+
+ public void setTheirsContent(byte[] theirsContent) {
+ this.theirsContent = theirsContent;
+ }
+
+ public void setYoursContent(byte[] yoursContent) {
+ this.yoursContent = yoursContent;
+ }
+
+ public void setBaseRevisionNumber(@Nullable VcsRevisionNumber baseRevisionNumber) {}
+
+ public void setTheirsRevisionNumber(@Nullable VcsRevisionNumber theirsRevisionNumber) {
+ this.theirsRevisionNumber = theirsRevisionNumber;
+ }
+
+ public void setYoursRevisionNumber(@Nullable VcsRevisionNumber yoursRevisionNumber) {}
+
+ public void setBaseFilePath(@Nullable FilePath baseFilePath) {}
+
+ public void setTheirsFilePath(@Nullable FilePath theirsFilePath) {}
+
+ public void setYoursFilePath(@Nullable FilePath yoursFilePath) {}
+
+ public MergeData build() {
+ MergeData mergeData = new MergeData();
+
+ mergeData.ORIGINAL = baseContent;
+
+ mergeData.LAST = theirsContent;
+ mergeData.LAST_REVISION_NUMBER = theirsRevisionNumber;
+
+ mergeData.CURRENT = yoursContent;
+
+ return mergeData;
+ }
+}
diff --git a/sdkcompat/v163/BUILD b/sdkcompat/v163/BUILD
new file mode 100644
index 0000000..8e2c272
--- /dev/null
+++ b/sdkcompat/v163/BUILD
@@ -0,0 +1,34 @@
+# Description: Indirections for SDK changes to the underlying platform library.
+
+licenses(["notice"]) # Apache 2.0
+
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_ide")
+
+java_library(
+ name = "v163",
+ srcs = glob([
+ "com/google/idea/sdkcompat/codestyle/**",
+ "com/google/idea/sdkcompat/smrunner/**",
+ "com/google/idea/sdkcompat/transactions/**",
+ "com/google/idea/sdkcompat/vcs/**",
+ ]) + select_for_ide(
+ android_studio = glob([
+ "com/google/idea/sdkcompat/cidr/**",
+ ]),
+ clion = glob([
+ "com/google/idea/sdkcompat/cidr/**",
+ "com/google/idea/sdkcompat/clion/**",
+ ]),
+ intellij = glob([
+ "com/google/idea/sdkcompat/python/**",
+ "com/google/idea/sdkcompat/dart/**",
+ ]),
+ ),
+ visibility = ["//sdkcompat:__pkg__"],
+ deps = [
+ "//intellij_platform_sdk:plugin_api",
+ "@jsr305_annotations//jar",
+ ] + select_for_ide(
+ intellij = ["//third_party/python"],
+ ),
+)
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java
new file mode 100644
index 0000000..d60a1a6
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java
@@ -0,0 +1,20 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
+import java.util.List;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrCompilerSwitchesAdapter {
+ /** Old interface does not know anything about CidrCompilerSwitches.Format */
+ public static List<String> getFileArgs(CidrCompilerSwitches switches) {
+ return switches.getFileArgs();
+ }
+
+ public static List<String> getCommandLineArgs(CidrCompilerSwitches switches) {
+ return switches.getCommandLineArgs();
+ }
+
+ public static String getCommandLineString(CidrCompilerSwitches switches) {
+ return switches.getCommandLineString();
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java
new file mode 100644
index 0000000..70e753b
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java
@@ -0,0 +1,12 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.execution.CidrConsoleBuilder;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrConsoleBuilderAdapter extends CidrConsoleBuilder {
+
+ public CidrConsoleBuilderAdapter(Project project) {
+ super(project, null, null);
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrGoogleTestUtilAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrGoogleTestUtilAdapter.java
new file mode 100644
index 0000000..cf3a258
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrGoogleTestUtilAdapter.java
@@ -0,0 +1,6 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.jetbrains.cidr.execution.testing.CidrTestUtil;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrGoogleTestUtilAdapter extends CidrTestUtil {}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java
new file mode 100644
index 0000000..68772fa
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java
@@ -0,0 +1,24 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.google.common.base.Joiner;
+import com.jetbrains.cidr.lang.toolchains.CidrSwitchBuilder;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrSwitchBuilderAdapter extends CidrSwitchBuilder {
+ /**
+ * Old CidrSwitchBuilder is unable to deal with options with spaces embedded. This is a hack to
+ * preserve the old behaviour for 2016.3 Original hack explanation: - 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.
+ */
+ public CidrSwitchBuilderAdapter addAllRaw(List<String> switches) {
+ switches = switches.stream().map(flag -> flag.replace("\\ ", " ")).collect(Collectors.toList());
+ addAll(Joiner.on(" ").join(switches), CidrSwitchBuilder.Format.FILE_ARGS);
+ return this;
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java
new file mode 100644
index 0000000..912eb77
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java
@@ -0,0 +1,20 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/** Adapter to bridge different SDK versions. */
+public interface OCResolveConfigurationAdapter extends OCResolveConfiguration {
+ /* v171 */
+ public List<VirtualFile> getPrecompiledHeaders(OCLanguageKind kind, VirtualFile sourceFile);
+
+ /* v171 */
+ public Collection<VirtualFile> getSources();
+
+ /* v171 */
+ public Set<VirtualFile> getPrecompiledHeaders();
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java
new file mode 100644
index 0000000..4266e35
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java
@@ -0,0 +1,9 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.lang.workspace.OCWorkspace;
+
+/** Adapter to bridge different SDK versions. */
+public abstract class OCWorkspaceAdapter implements OCWorkspace {
+ protected OCWorkspaceAdapter(Project project) {}
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java
new file mode 100644
index 0000000..1f38a39
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java
@@ -0,0 +1,21 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceModificationTrackers;
+
+/** Handles changes to modification trackers between our supported versions. */
+public class OCWorkspaceModificationTrackersCompatUtils {
+
+ public static OCWorkspaceModificationTrackers getTrackers(Project project) {
+ return OCWorkspaceModificationTrackers.getInstance(project);
+ }
+
+ /** Must be called inside a write action, on the EDT. */
+ public static void incrementModificationCounts(Project project) {
+ OCWorkspaceModificationTrackers modTrackers = getTrackers(project);
+ modTrackers.getProjectFilesListTracker().incModificationCount();
+ modTrackers.getSourceFilesListTracker().incModificationCount();
+ modTrackers.getSelectedResolveConfigurationTracker().incModificationCount();
+ modTrackers.getBuildSettingsChangesTracker().incModificationCount();
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/clion/CMakeActionList.java b/sdkcompat/v163/com/google/idea/sdkcompat/clion/CMakeActionList.java
new file mode 100644
index 0000000..55f4936
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/clion/CMakeActionList.java
@@ -0,0 +1,22 @@
+package com.google.idea.sdkcompat.clion;
+
+import com.google.common.collect.ImmutableSet;
+import com.jetbrains.cidr.cpp.cmake.actions.ChangeCMakeProjectContentRootAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ClearCMakeCacheAndReloadAction;
+import com.jetbrains.cidr.cpp.cmake.actions.OpenCMakeSettingsAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ReloadCMakeProjectAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ToggleCMakeAutoReloadAction;
+
+/** Handles CMake actions which have changed between our supported versions. */
+public class CMakeActionList {
+
+ public static final ImmutableSet<String> CMAKE_ACTION_IDS =
+ ImmutableSet.of(
+ ChangeCMakeProjectContentRootAction.ID,
+ ClearCMakeCacheAndReloadAction.ID,
+ OpenCMakeSettingsAction.ID,
+ ReloadCMakeProjectAction.ID,
+ ToggleCMakeAutoReloadAction.ID,
+ // 'CMake' > 'Show Generated CMake Files' action
+ "CMake.ShowGeneratedDir");
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/clion/CMakeConfigurationProducersList.java b/sdkcompat/v163/com/google/idea/sdkcompat/clion/CMakeConfigurationProducersList.java
new file mode 100644
index 0000000..f402269
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/clion/CMakeConfigurationProducersList.java
@@ -0,0 +1,11 @@
+package com.google.idea.sdkcompat.clion;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.jetbrains.cidr.cpp.execution.testing.CMakeGoogleTestRunConfigurationProducer;
+
+/** List of C/C++ configuration producers for a given plugin version. */
+public class CMakeConfigurationProducersList {
+ public static final ImmutableList<Class<? extends RunConfigurationProducer<?>>>
+ PRODUCERS_TO_SUPPRESS = ImmutableList.of(CMakeGoogleTestRunConfigurationProducer.class);
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
similarity index 70%
rename from sdkcompat/v163/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java
rename to sdkcompat/v163/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
index 33d3ad4..8075c2e 100644
--- a/sdkcompat/v163/com/google/idea/sdkcompat/codestyle/CodeStyleManagerSdkCompatAdapter.java
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
@@ -9,8 +9,15 @@
import java.util.List;
import org.jetbrains.annotations.NotNull;
-/** Adapter to extend two bridge different IntelliJ SDK versions. */
-public abstract class CodeStyleManagerSdkCompatAdapter extends CodeStyleManager {
+/** Adapter to bridge different SDK versions. */
+public abstract class DelegatingCodeStyleManagerSdkCompatAdapter extends CodeStyleManager {
+
+ protected CodeStyleManager delegate;
+
+ protected DelegatingCodeStyleManagerSdkCompatAdapter(CodeStyleManager delegate) {
+ this.delegate = delegate;
+ }
+
@Override
public void reformatTextWithContext(@NotNull PsiFile file, @NotNull ChangedRangesInfo info)
throws IncorrectOperationException {
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java b/sdkcompat/v163/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java
new file mode 100644
index 0000000..58f48e4
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.sdkcompat.dart;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.libraries.ApplicationLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import javax.annotation.Nullable;
+
+/** Handles changes to the Dart plugin libraries between our supported versions. */
+public class DartSdkCompatUtils {
+
+ public static final String DART_SDK_LIBRARY_NAME = "Dart SDK";
+
+ @Nullable
+ public static Library findDartLibrary(Project project) {
+ return ApplicationLibraryTable.getApplicationTable().getLibraryByName(DART_SDK_LIBRARY_NAME);
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java
deleted file mode 100644
index ed822b3..0000000
--- a/sdkcompat/v163/com/google/idea/sdkcompat/debugger/GenericDebuggerRunnerSdkCompatAdapter.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.google.idea.sdkcompat.debugger;
-
-import com.intellij.debugger.impl.GenericDebuggerRunner;
-
-/** SDK compatibility for {@link GenericDebuggerRunner}. */
-public class GenericDebuggerRunnerSdkCompatAdapter extends GenericDebuggerRunner {}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java
new file mode 100644
index 0000000..b3785da
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java
@@ -0,0 +1,17 @@
+package com.google.idea.sdkcompat.python;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+
+/** List of python configuration producers for a given plugin version. */
+public class PyConfigurationProducersList {
+
+ public static final Collection<Class<?>> PRODUCERS_TO_SUPPRESS =
+ ImmutableList.of(
+ com.jetbrains.python.run.PythonRunConfigurationProducer.class,
+ com.jetbrains.python.testing.attest.PythonAtTestConfigurationProducer.class,
+ com.jetbrains.python.testing.nosetest.PythonNoseTestConfigurationProducer.class,
+ com.jetbrains.python.testing.doctest.PythonDocTestConfigurationProducer.class,
+ com.jetbrains.python.testing.pytest.PyTestConfigurationProducer.class,
+ com.jetbrains.python.testing.unittest.PythonUnitTestConfigurationProducer.class);
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java
new file mode 100644
index 0000000..9ccba03
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java
@@ -0,0 +1,23 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.impl.PyImportResolver;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolveContext;
+import javax.annotation.Nullable;
+
+/** Adapter to bridge different SDK versions. */
+public interface PyImportResolverAdapter extends PyImportResolver {
+
+ @Nullable
+ PsiElement resolveImportReference(
+ QualifiedName name, PyQualifiedNameResolveContextAdapter context, boolean withRoots);
+
+ @Override
+ @Nullable
+ default PsiElement resolveImportReference(
+ QualifiedName name, QualifiedNameResolveContext context, boolean withRoots) {
+ return resolveImportReference(
+ name, new PyQualifiedNameResolveContextAdapter(context), withRoots);
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java
new file mode 100644
index 0000000..7330e11
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java
@@ -0,0 +1,77 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.jetbrains.python.psi.resolve.QualifiedNameResolveContext;
+import javax.annotation.Nullable;
+
+/** Adapter to bridge different SDK versions. */
+public class PyQualifiedNameResolveContextAdapter extends QualifiedNameResolveContext {
+
+ private final QualifiedNameResolveContext delegate;
+
+ PyQualifiedNameResolveContextAdapter(QualifiedNameResolveContext delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void copyFrom(QualifiedNameResolveContext context) {
+ delegate.copyFrom(context);
+ }
+
+ @Override
+ public void setFromElement(PsiElement element) {
+ delegate.setFromElement(element);
+ }
+
+ @Override
+ public void setFromModule(Module module) {
+ delegate.setFromModule(module);
+ }
+
+ @Override
+ public void setFromSdk(Project project, Sdk sdk) {
+ delegate.setFromSdk(project, sdk);
+ }
+
+ @Override
+ public void setSdk(Sdk sdk) {
+ delegate.setSdk(sdk);
+ }
+
+ @Override
+ @Nullable
+ public Module getModule() {
+ return delegate.getModule();
+ }
+
+ @Override
+ public boolean isValid() {
+ return delegate.isValid();
+ }
+
+ @Override
+ @Nullable
+ public PsiFile getFootholdFile() {
+ return delegate.getFootholdFile();
+ }
+
+ @Override
+ public PsiManager getPsiManager() {
+ return delegate.getPsiManager();
+ }
+
+ @Override
+ public Project getProject() {
+ return delegate.getProject();
+ }
+
+ @Override
+ public Sdk getSdk() {
+ return delegate.getSdk();
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java
new file mode 100644
index 0000000..36d4767
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java
@@ -0,0 +1,19 @@
+package com.google.idea.sdkcompat.python;
+
+import com.jetbrains.python.psi.PyQualifiedExpression;
+import com.jetbrains.python.psi.resolve.PyReferenceResolveProvider;
+import com.jetbrains.python.psi.resolve.RatedResolveResult;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+import java.util.List;
+
+/** Adapter to bridge different SDK versions. */
+public interface PyReferenceResolveProviderAdapter extends PyReferenceResolveProvider {
+
+ @Override
+ default List<RatedResolveResult> resolveName(PyQualifiedExpression element) {
+ TypeEvalContext context = TypeEvalContext.codeInsightFallback(element.getProject());
+ return resolveName(element, context);
+ }
+
+ List<RatedResolveResult> resolveName(PyQualifiedExpression element, TypeEvalContext context);
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java b/sdkcompat/v163/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java
new file mode 100644
index 0000000..5a6bef2
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java
@@ -0,0 +1,22 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.psi.resolve.ResolveImportUtil;
+import javax.annotation.Nullable;
+
+/** Handles changes to {@link ResolveImportUtil} between our supported versions. */
+public class ResolveImportCompatUtils {
+
+ @Nullable
+ public static PsiElement resolveChild(
+ @Nullable PsiElement parent,
+ String referencedName,
+ @Nullable PsiFile containingFile,
+ boolean fileOnly,
+ boolean checkForPackage,
+ boolean withoutStubs) {
+ return ResolveImportUtil.resolveChild(
+ parent, referencedName, containingFile, fileOnly, checkForPackage);
+ }
+}
diff --git a/sdkcompat/v163/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java b/sdkcompat/v163/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java
new file mode 100644
index 0000000..b0a7697
--- /dev/null
+++ b/sdkcompat/v163/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java
@@ -0,0 +1,54 @@
+package com.google.idea.sdkcompat.vcs;
+
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import com.intellij.openapi.vcs.merge.MergeData;
+import org.jetbrains.annotations.Nullable;
+
+/** SDK adapter for creating {@link MergeData}. */
+public final class MergeDataBuilder {
+ private byte[] baseContent;
+ private byte[] theirsContent;
+ private byte[] yoursContent;
+
+ @Nullable private VcsRevisionNumber theirsRevisionNumber;
+
+ public void setBaseContent(byte[] baseContent) {
+ this.baseContent = baseContent;
+ }
+
+ public void setTheirsContent(byte[] theirsContent) {
+ this.theirsContent = theirsContent;
+ }
+
+ public void setYoursContent(byte[] yoursContent) {
+ this.yoursContent = yoursContent;
+ }
+
+ public void setBaseRevisionNumber(@Nullable VcsRevisionNumber baseRevisionNumber) {}
+
+ public void setTheirsRevisionNumber(@Nullable VcsRevisionNumber theirsRevisionNumber) {
+ this.theirsRevisionNumber = theirsRevisionNumber;
+ }
+
+ public void setYoursRevisionNumber(@Nullable VcsRevisionNumber yoursRevisionNumber) {}
+
+ public void setBaseFilePath(@Nullable FilePath baseFilePath) {}
+
+ public void setTheirsFilePath(@Nullable FilePath theirsFilePath) {}
+
+ public void setYoursFilePath(@Nullable FilePath yoursFilePath) {}
+
+ public MergeData build() {
+ MergeData mergeData = new MergeData();
+
+ mergeData.ORIGINAL = baseContent;
+
+ mergeData.LAST = theirsContent;
+ mergeData.LAST_REVISION_NUMBER = theirsRevisionNumber;
+
+ mergeData.CURRENT = yoursContent;
+
+ return mergeData;
+ }
+}
diff --git a/sdkcompat/v171/BUILD b/sdkcompat/v171/BUILD
new file mode 100644
index 0000000..d8392a9
--- /dev/null
+++ b/sdkcompat/v171/BUILD
@@ -0,0 +1,33 @@
+# Description: Indirections for SDK changes to the underlying platform library.
+
+licenses(["notice"]) # Apache 2.0
+
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_ide")
+
+java_library(
+ name = "v171",
+ srcs = glob([
+ "com/google/idea/sdkcompat/codestyle/**",
+ "com/google/idea/sdkcompat/python/**",
+ "com/google/idea/sdkcompat/smrunner/**",
+ "com/google/idea/sdkcompat/transactions/**",
+ "com/google/idea/sdkcompat/vcs/**",
+ ]) + select_for_ide(
+ android_studio = glob([
+ "com/google/idea/sdkcompat/cidr/**",
+ ]),
+ clion = glob([
+ "com/google/idea/sdkcompat/cidr/**",
+ "com/google/idea/sdkcompat/clion/**",
+ ]),
+ intellij = glob([
+ "com/google/idea/sdkcompat/dart/**",
+ ]),
+ ),
+ visibility = ["//sdkcompat:__pkg__"],
+ deps = [
+ "//intellij_platform_sdk:plugin_api",
+ "//third_party/python",
+ "@jsr305_annotations//jar",
+ ],
+)
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java
new file mode 100644
index 0000000..c20ad1f
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrCompilerSwitchesAdapter.java
@@ -0,0 +1,21 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.jetbrains.cidr.lang.toolchains.CidrCompilerSwitches;
+import java.util.List;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrCompilerSwitchesAdapter {
+ /** Old interface does not know anything about CidrCompilerSwitches.Format */
+ public static List<String> getFileArgs(CidrCompilerSwitches switches) {
+ return switches.getList(CidrCompilerSwitches.Format.RAW);
+ }
+
+ public static List<String> getCommandLineArgs(CidrCompilerSwitches switches) {
+ return switches.getList(CidrCompilerSwitches.Format.BASH_SHELL);
+ }
+
+ public static String getCommandLineString(CidrCompilerSwitches switches) {
+ return StringUtil.join(getCommandLineArgs(switches), " ");
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java
new file mode 100644
index 0000000..70e753b
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrConsoleBuilderAdapter.java
@@ -0,0 +1,12 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.execution.CidrConsoleBuilder;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrConsoleBuilderAdapter extends CidrConsoleBuilder {
+
+ public CidrConsoleBuilderAdapter(Project project) {
+ super(project, null, null);
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrGoogleTestUtilAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrGoogleTestUtilAdapter.java
new file mode 100644
index 0000000..efad3f4
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrGoogleTestUtilAdapter.java
@@ -0,0 +1,6 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.jetbrains.cidr.execution.testing.google.CidrGoogleTestUtil;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrGoogleTestUtilAdapter extends CidrGoogleTestUtil {}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java
new file mode 100644
index 0000000..40684be
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/CidrSwitchBuilderAdapter.java
@@ -0,0 +1,6 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.jetbrains.cidr.lang.toolchains.CidrSwitchBuilder;
+
+/** Adapter to bridge different SDK versions. */
+public class CidrSwitchBuilderAdapter extends CidrSwitchBuilder {}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java
new file mode 100644
index 0000000..a6bf252
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCResolveConfigurationAdapter.java
@@ -0,0 +1,14 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+
+/** Adapter to bridge different SDK versions. */
+public interface OCResolveConfigurationAdapter extends OCResolveConfiguration {
+ /* v162/v163 */
+ public VirtualFile getPrecompiledHeader();
+
+ /* v162/v163 */
+ public OCLanguageKind getPrecompiledLanguageKind();
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java
new file mode 100644
index 0000000..4266e35
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCWorkspaceAdapter.java
@@ -0,0 +1,9 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.lang.workspace.OCWorkspace;
+
+/** Adapter to bridge different SDK versions. */
+public abstract class OCWorkspaceAdapter implements OCWorkspace {
+ protected OCWorkspaceAdapter(Project project) {}
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java
new file mode 100644
index 0000000..1f38a39
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/cidr/OCWorkspaceModificationTrackersCompatUtils.java
@@ -0,0 +1,21 @@
+package com.google.idea.sdkcompat.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceModificationTrackers;
+
+/** Handles changes to modification trackers between our supported versions. */
+public class OCWorkspaceModificationTrackersCompatUtils {
+
+ public static OCWorkspaceModificationTrackers getTrackers(Project project) {
+ return OCWorkspaceModificationTrackers.getInstance(project);
+ }
+
+ /** Must be called inside a write action, on the EDT. */
+ public static void incrementModificationCounts(Project project) {
+ OCWorkspaceModificationTrackers modTrackers = getTrackers(project);
+ modTrackers.getProjectFilesListTracker().incModificationCount();
+ modTrackers.getSourceFilesListTracker().incModificationCount();
+ modTrackers.getSelectedResolveConfigurationTracker().incModificationCount();
+ modTrackers.getBuildSettingsChangesTracker().incModificationCount();
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/clion/CMakeActionList.java b/sdkcompat/v171/com/google/idea/sdkcompat/clion/CMakeActionList.java
new file mode 100644
index 0000000..1230fd0
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/clion/CMakeActionList.java
@@ -0,0 +1,23 @@
+package com.google.idea.sdkcompat.clion;
+
+import com.google.common.collect.ImmutableSet;
+import com.jetbrains.cidr.cpp.cmake.actions.ChangeCMakeProjectContentRootAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ClearCMakeCacheAndReloadAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ReloadCMakeProjectAction;
+import com.jetbrains.cidr.cpp.cmake.actions.ToggleCMakeAutoReloadAction;
+
+/** Handles CMake actions which have changed between our supported versions. */
+public class CMakeActionList {
+
+ public static final ImmutableSet<String> CMAKE_ACTION_IDS =
+ ImmutableSet.of(
+ ChangeCMakeProjectContentRootAction.ID,
+ ClearCMakeCacheAndReloadAction.ID,
+ // 'CMake' -> 'CMake Settings' action: com.cidr.cpp.cmake.actions.OpenCMakeSettingsAction
+ "CMake.OpenCMakeSettings",
+ ReloadCMakeProjectAction.ID,
+ ToggleCMakeAutoReloadAction.ID,
+ // 'CMake' > 'Show Generated CMake Files' action:
+ // com.cidr.cpp.cmake.actions.ShowCMakeGeneratedDirAction
+ "CMake.ShowCMakeGeneratedDir");
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/clion/CMakeConfigurationProducersList.java b/sdkcompat/v171/com/google/idea/sdkcompat/clion/CMakeConfigurationProducersList.java
new file mode 100644
index 0000000..abc58af
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/clion/CMakeConfigurationProducersList.java
@@ -0,0 +1,16 @@
+package com.google.idea.sdkcompat.clion;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.jetbrains.cidr.cpp.execution.testing.google.CMakeGoogleTestRunConfigurationProducer;
+import com.jetbrains.cidr.cpp.execution.testing.tcatch.CMakeCatchTestRunConfigurationProducer;
+
+/** List of C/C++ configuration producers for a given plugin version. */
+public class CMakeConfigurationProducersList {
+
+ public static final ImmutableList<Class<? extends RunConfigurationProducer<?>>>
+ PRODUCERS_TO_SUPPRESS =
+ ImmutableList.of(
+ CMakeGoogleTestRunConfigurationProducer.class,
+ CMakeCatchTestRunConfigurationProducer.class);
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
new file mode 100644
index 0000000..d6cbc72
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/codestyle/DelegatingCodeStyleManagerSdkCompatAdapter.java
@@ -0,0 +1,53 @@
+package com.google.idea.sdkcompat.codestyle;
+
+import com.intellij.formatting.FormattingMode;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.ChangedRangesInfo;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.psi.codeStyle.FormattingModeAwareIndentAdjuster;
+import com.intellij.util.IncorrectOperationException;
+import java.util.ArrayList;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+
+/** Adapter to bridge different SDK versions. */
+public abstract class DelegatingCodeStyleManagerSdkCompatAdapter extends CodeStyleManager
+ implements FormattingModeAwareIndentAdjuster {
+
+ protected CodeStyleManager delegate;
+
+ protected DelegatingCodeStyleManagerSdkCompatAdapter(CodeStyleManager delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void reformatTextWithContext(@NotNull PsiFile file, @NotNull ChangedRangesInfo info)
+ throws IncorrectOperationException {
+ List<TextRange> ranges = new ArrayList<>();
+ ranges.addAll(info.insertedRanges);
+ ranges.addAll(info.allChangedRanges);
+ this.reformatTextWithContext(file, ranges);
+ }
+
+ /** Uses same fallback as {@link CodeStyleManager#getCurrentFormattingMode}. */
+ @Override
+ public FormattingMode getCurrentFormattingMode() {
+ if (delegate instanceof FormattingModeAwareIndentAdjuster) {
+ return ((FormattingModeAwareIndentAdjuster) delegate).getCurrentFormattingMode();
+ }
+ return FormattingMode.REFORMAT;
+ }
+
+ @Override
+ public int adjustLineIndent(
+ @NotNull final Document document, final int offset, FormattingMode mode)
+ throws IncorrectOperationException {
+ if (delegate instanceof FormattingModeAwareIndentAdjuster) {
+ return ((FormattingModeAwareIndentAdjuster) delegate)
+ .adjustLineIndent(document, offset, mode);
+ }
+ return offset;
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java b/sdkcompat/v171/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java
new file mode 100644
index 0000000..c2d1a3e
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/dart/DartSdkCompatUtils.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.sdkcompat.dart;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
+import com.intellij.openapi.roots.libraries.Library;
+import javax.annotation.Nullable;
+
+/** Handles changes to the Dart plugin libraries between our supported versions. */
+public class DartSdkCompatUtils {
+
+ public static final String DART_SDK_LIBRARY_NAME = "Dart SDK";
+
+ @Nullable
+ public static Library findDartLibrary(Project project) {
+ return ProjectLibraryTable.getInstance(project).getLibraryByName(DART_SDK_LIBRARY_NAME);
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java
new file mode 100644
index 0000000..e65ad6e
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyConfigurationProducersList.java
@@ -0,0 +1,17 @@
+package com.google.idea.sdkcompat.python;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+
+/** List of python configuration producers for a given plugin version. */
+public class PyConfigurationProducersList {
+
+ public static final Collection<Class<?>> PRODUCERS_TO_SUPPRESS =
+ ImmutableList.of(
+ com.jetbrains.python.run.PythonRunConfigurationProducer.class,
+ com.jetbrains.python.testing.universalTests.PyUniversalTestsConfigurationProducer.class,
+ com.jetbrains.python.testing.nosetest.PythonNoseTestConfigurationProducer.class,
+ com.jetbrains.python.testing.doctest.PythonDocTestConfigurationProducer.class,
+ com.jetbrains.python.testing.pytest.PyTestConfigurationProducer.class,
+ com.jetbrains.python.testing.unittest.PythonUnitTestConfigurationProducer.class);
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java
new file mode 100644
index 0000000..7edba6c
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyImportResolverAdapter.java
@@ -0,0 +1,23 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.QualifiedName;
+import com.jetbrains.python.psi.impl.PyImportResolver;
+import com.jetbrains.python.psi.resolve.PyQualifiedNameResolveContext;
+import javax.annotation.Nullable;
+
+/** Adapter to bridge different SDK versions. */
+public interface PyImportResolverAdapter extends PyImportResolver {
+
+ @Nullable
+ PsiElement resolveImportReference(
+ QualifiedName name, PyQualifiedNameResolveContextAdapter context, boolean withRoots);
+
+ @Override
+ @Nullable
+ default PsiElement resolveImportReference(
+ QualifiedName name, PyQualifiedNameResolveContext context, boolean withRoots) {
+ return resolveImportReference(
+ name, new PyQualifiedNameResolveContextAdapter(context), withRoots);
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java
new file mode 100644
index 0000000..7311580
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyQualifiedNameResolveContextAdapter.java
@@ -0,0 +1,152 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.jetbrains.python.psi.resolve.PyQualifiedNameResolveContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/** Adapter to bridge different SDK versions. */
+public class PyQualifiedNameResolveContextAdapter implements PyQualifiedNameResolveContext {
+
+ private final PyQualifiedNameResolveContext delegate;
+
+ PyQualifiedNameResolveContextAdapter(PyQualifiedNameResolveContext delegate) {
+ this.delegate = delegate;
+ }
+
+ @Nullable
+ @Override
+ public PsiElement getFoothold() {
+ return delegate.getFoothold();
+ }
+
+ @Override
+ public int getRelativeLevel() {
+ return delegate.getRelativeLevel();
+ }
+
+ @Nullable
+ @Override
+ public Sdk getSdk() {
+ return delegate.getSdk();
+ }
+
+ @Nullable
+ @Override
+ public Module getModule() {
+ return delegate.getModule();
+ }
+
+ @NotNull
+ @Override
+ public Project getProject() {
+ return delegate.getProject();
+ }
+
+ @Override
+ public boolean getWithoutRoots() {
+ return delegate.getWithoutRoots();
+ }
+
+ @Override
+ public boolean getWithoutForeign() {
+ return delegate.getWithoutForeign();
+ }
+
+ @Override
+ public boolean getWithoutStubs() {
+ return delegate.getWithoutStubs();
+ }
+
+ @NotNull
+ @Override
+ public PsiManager getPsiManager() {
+ return delegate.getPsiManager();
+ }
+
+ @Override
+ public boolean getWithMembers() {
+ return delegate.getWithMembers();
+ }
+
+ @Override
+ public boolean getWithPlainDirectories() {
+ return delegate.getWithPlainDirectories();
+ }
+
+ @Override
+ public boolean getVisitAllModules() {
+ return delegate.getVisitAllModules();
+ }
+
+ @Nullable
+ @Override
+ public Sdk getEffectiveSdk() {
+ return delegate.getEffectiveSdk();
+ }
+
+ @Override
+ public boolean isValid() {
+ return delegate.isValid();
+ }
+
+ @Nullable
+ @Override
+ public PsiFile getFootholdFile() {
+ return delegate.getFootholdFile();
+ }
+
+ @Nullable
+ @Override
+ public PsiDirectory getContainingDirectory() {
+ return delegate.getContainingDirectory();
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithoutForeign() {
+ return delegate.copyWithoutForeign();
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithMembers() {
+ return delegate.copyWithMembers();
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithPlainDirectories() {
+ return delegate.copyWithPlainDirectories();
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithRelative(int i) {
+ return delegate.copyWithRelative(i);
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithoutRoots() {
+ return delegate.copyWithoutRoots();
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithRoots() {
+ return delegate.copyWithRoots();
+ }
+
+ @NotNull
+ @Override
+ public PyQualifiedNameResolveContext copyWithoutStubs() {
+ return delegate.copyWithoutStubs();
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java
new file mode 100644
index 0000000..9f8b5c3
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/python/PyReferenceResolveProviderAdapter.java
@@ -0,0 +1,6 @@
+package com.google.idea.sdkcompat.python;
+
+import com.jetbrains.python.psi.resolve.PyReferenceResolveProvider;
+
+/** Adapter to bridge different SDK versions. */
+public interface PyReferenceResolveProviderAdapter extends PyReferenceResolveProvider {}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java b/sdkcompat/v171/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java
new file mode 100644
index 0000000..0329801
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/python/ResolveImportCompatUtils.java
@@ -0,0 +1,22 @@
+package com.google.idea.sdkcompat.python;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.psi.resolve.ResolveImportUtil;
+import javax.annotation.Nullable;
+
+/** Handles changes to {@link ResolveImportUtil} between our supported versions. */
+public class ResolveImportCompatUtils {
+
+ @Nullable
+ public static PsiElement resolveChild(
+ @Nullable PsiElement parent,
+ String referencedName,
+ @Nullable PsiFile containingFile,
+ boolean fileOnly,
+ boolean checkForPackage,
+ boolean withoutStubs) {
+ return ResolveImportUtil.resolveChild(
+ parent, referencedName, containingFile, fileOnly, checkForPackage, withoutStubs);
+ }
+}
diff --git a/sdkcompat/v145/com/google/idea/sdkcompat/smrunner/SmRunnerCompatUtils.java b/sdkcompat/v171/com/google/idea/sdkcompat/smrunner/SmRunnerCompatUtils.java
similarity index 77%
rename from sdkcompat/v145/com/google/idea/sdkcompat/smrunner/SmRunnerCompatUtils.java
rename to sdkcompat/v171/com/google/idea/sdkcompat/smrunner/SmRunnerCompatUtils.java
index c4bd9a7..8555ad8 100644
--- a/sdkcompat/v145/com/google/idea/sdkcompat/smrunner/SmRunnerCompatUtils.java
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/smrunner/SmRunnerCompatUtils.java
@@ -8,6 +8,7 @@
public static TestFailedEvent getTestFailedEvent(
String name, @Nullable String message, @Nullable String content, long duration) {
- return new TestFailedEvent(name, -1, message, content, true, null, null, null, duration);
+ return new TestFailedEvent(
+ name, null, message, content, true, null, null, null, null, false, false, duration);
}
}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/transactions/Transactions.java b/sdkcompat/v171/com/google/idea/sdkcompat/transactions/Transactions.java
new file mode 100644
index 0000000..8862aa8
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/transactions/Transactions.java
@@ -0,0 +1,15 @@
+package com.google.idea.sdkcompat.transactions;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.TransactionGuard;
+
+/** SDK adapter to use transaction guards. */
+public class Transactions {
+ public static void submitTransactionAndWait(Runnable runnable) {
+ TransactionGuard.getInstance().submitTransactionAndWait(runnable);
+ }
+
+ public static void submitTransaction(Disposable disposable, Runnable runnable) {
+ TransactionGuard.submitTransaction(disposable, runnable);
+ }
+}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/vcs/ChangeListManagerSdkCompatAdapter.java b/sdkcompat/v171/com/google/idea/sdkcompat/vcs/ChangeListManagerSdkCompatAdapter.java
new file mode 100644
index 0000000..1e525c1
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/vcs/ChangeListManagerSdkCompatAdapter.java
@@ -0,0 +1,6 @@
+package com.google.idea.sdkcompat.vcs;
+
+import com.intellij.openapi.vcs.changes.ChangeListManager;
+
+/** SDK adapter to for changelist interface. */
+public abstract class ChangeListManagerSdkCompatAdapter extends ChangeListManager {}
diff --git a/sdkcompat/v171/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java b/sdkcompat/v171/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java
new file mode 100644
index 0000000..49b4665
--- /dev/null
+++ b/sdkcompat/v171/com/google/idea/sdkcompat/vcs/MergeDataBuilder.java
@@ -0,0 +1,78 @@
+package com.google.idea.sdkcompat.vcs;
+
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import com.intellij.openapi.vcs.merge.MergeData;
+import org.jetbrains.annotations.Nullable;
+
+/** SDK adapter for creating {@link MergeData}. */
+// TODO(grl): Move to com.google.devtools.intellij.piper.resolve and make package-private
+// once versions less than v171 have been deleted. We may as well keep the builder around,
+// since it uses piper-relevant terminology and complies with Java style conventions.
+public final class MergeDataBuilder {
+ private byte[] baseContent;
+ private byte[] theirsContent;
+ private byte[] yoursContent;
+
+ @Nullable private VcsRevisionNumber baseRevisionNumber;
+ @Nullable private VcsRevisionNumber theirsRevisionNumber;
+ @Nullable private VcsRevisionNumber yoursRevisionNumber;
+
+ @Nullable private FilePath baseFilePath;
+ @Nullable private FilePath theirsFilePath;
+ @Nullable private FilePath yoursFilePath;
+
+ public void setBaseContent(byte[] baseContent) {
+ this.baseContent = baseContent;
+ }
+
+ public void setTheirsContent(byte[] theirsContent) {
+ this.theirsContent = theirsContent;
+ }
+
+ public void setYoursContent(byte[] yoursContent) {
+ this.yoursContent = yoursContent;
+ }
+
+ public void setBaseRevisionNumber(@Nullable VcsRevisionNumber baseRevisionNumber) {
+ this.baseRevisionNumber = baseRevisionNumber;
+ }
+
+ public void setTheirsRevisionNumber(@Nullable VcsRevisionNumber theirsRevisionNumber) {
+ this.theirsRevisionNumber = theirsRevisionNumber;
+ }
+
+ public void setYoursRevisionNumber(@Nullable VcsRevisionNumber yoursRevisionNumber) {
+ this.yoursRevisionNumber = yoursRevisionNumber;
+ }
+
+ public void setBaseFilePath(@Nullable FilePath baseFilePath) {
+ this.baseFilePath = baseFilePath;
+ }
+
+ public void setTheirsFilePath(@Nullable FilePath theirsFilePath) {
+ this.theirsFilePath = theirsFilePath;
+ }
+
+ public void setYoursFilePath(@Nullable FilePath yoursFilePath) {
+ this.yoursFilePath = yoursFilePath;
+ }
+
+ public MergeData build() {
+ MergeData mergeData = new MergeData();
+
+ mergeData.ORIGINAL = baseContent;
+ mergeData.ORIGINAL_REVISION_NUMBER = baseRevisionNumber;
+ mergeData.ORIGINAL_FILE_PATH = baseFilePath;
+
+ mergeData.LAST = theirsContent;
+ mergeData.LAST_REVISION_NUMBER = theirsRevisionNumber;
+ mergeData.LAST_FILE_PATH = theirsFilePath;
+
+ mergeData.CURRENT = yoursContent;
+ mergeData.CURRENT_REVISION_NUMBER = yoursRevisionNumber;
+ mergeData.CURRENT_FILE_PATH = yoursFilePath;
+
+ return mergeData;
+ }
+}
diff --git a/terminal/BUILD b/terminal/BUILD
new file mode 100644
index 0000000..d3f2562
--- /dev/null
+++ b/terminal/BUILD
@@ -0,0 +1,22 @@
+licenses(["notice"]) # Apache 2.0
+
+load("//build_defs:build_defs.bzl", "optional_plugin_xml")
+
+java_library(
+ name = "terminal",
+ srcs = glob(["src/**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//base",
+ "//intellij_platform_sdk:plugin_api",
+ "//intellij_platform_sdk:terminal",
+ "@jsr305_annotations//jar",
+ ],
+)
+
+optional_plugin_xml(
+ name = "optional_xml",
+ module = "org.jetbrains.plugins.terminal",
+ plugin_xml = "src/META-INF/terminal-contents.xml",
+ visibility = ["//visibility:public"],
+)
diff --git a/terminal/src/META-INF/terminal-contents.xml b/terminal/src/META-INF/terminal-contents.xml
new file mode 100644
index 0000000..b5b3255
--- /dev/null
+++ b/terminal/src/META-INF/terminal-contents.xml
@@ -0,0 +1,5 @@
+<idea-plugin>
+ <extensions defaultExtensionNs="org.jetbrains.plugins.terminal">
+ <localTerminalCustomizer implementation="com.google.idea.blaze.terminal.DefaultTerminalLocationCustomizer"/>
+ </extensions>
+</idea-plugin>
diff --git a/terminal/src/com/google/idea/blaze/terminal/DefaultTerminalLocationCustomizer.java b/terminal/src/com/google/idea/blaze/terminal/DefaultTerminalLocationCustomizer.java
new file mode 100644
index 0000000..8023f0a
--- /dev/null
+++ b/terminal/src/com/google/idea/blaze/terminal/DefaultTerminalLocationCustomizer.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.idea.blaze.terminal;
+
+import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
+import com.intellij.openapi.project.Project;
+import javax.annotation.Nullable;
+import org.jetbrains.plugins.terminal.LocalTerminalCustomizer;
+
+/** Set the default terminal path to the workspace root. */
+public class DefaultTerminalLocationCustomizer extends LocalTerminalCustomizer {
+
+ // added in 2017.1, so foregoing the override annotation for backwards compatibility.
+ @SuppressWarnings("Overrides")
+ @Nullable
+ protected String getDefaultFolder(Project project) {
+ WorkspaceRoot root = WorkspaceRoot.fromProjectSafe(project);
+ return root != null ? root.toString() : null;
+ }
+}
diff --git a/testing/BUILD b/testing/BUILD
index 8b2600e..e9a3c7a 100644
--- a/testing/BUILD
+++ b/testing/BUILD
@@ -6,13 +6,24 @@
licenses(["notice"]) # Apache 2.0
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_ide")
+
java_library(
name = "lib",
testonly = 1,
- srcs = glob(["src/**/*.java"]),
+ srcs = glob(["src/**/*.java"]) +
+ select_for_ide(
+ android_studio = glob(["cidr/src/**/*.java"]),
+ clion = glob(["cidr/src/**/*.java"]),
+ default = [],
+ ),
deps = [
"//intellij_platform_sdk:plugin_api_for_tests",
"@jsr305_annotations//jar",
"@junit//jar",
- ],
+ ] + select_for_ide(
+ android_studio = ["//sdkcompat"],
+ clion = ["//sdkcompat"],
+ default = [],
+ ),
)
diff --git a/testing/cidr/src/com/google/idea/testing/cidr/StubOCCompilerMacros.java b/testing/cidr/src/com/google/idea/testing/cidr/StubOCCompilerMacros.java
new file mode 100644
index 0000000..6345104
--- /dev/null
+++ b/testing/cidr/src/com/google/idea/testing/cidr/StubOCCompilerMacros.java
@@ -0,0 +1,12 @@
+package com.google.idea.testing.cidr;
+
+import com.intellij.psi.PsiFile;
+import com.jetbrains.cidr.lang.preprocessor.OCInclusionContext;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerMacros;
+
+/** Stub {@link OCCompilerMacros} for testing. */
+class StubOCCompilerMacros extends OCCompilerMacros {
+
+ @Override
+ protected void fillFileMacros(OCInclusionContext context, PsiFile sourceFile) {}
+}
diff --git a/testing/cidr/src/com/google/idea/testing/cidr/StubOCCompilerSettings.java b/testing/cidr/src/com/google/idea/testing/cidr/StubOCCompilerSettings.java
new file mode 100644
index 0000000..41e0dee
--- /dev/null
+++ b/testing/cidr/src/com/google/idea/testing/cidr/StubOCCompilerSettings.java
@@ -0,0 +1,52 @@
+package com.google.idea.testing.cidr;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VfsUtilCore;
+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 javax.annotation.Nullable;
+
+/** Stub {@link OCCompilerSettings} for testing. */
+class StubOCCompilerSettings extends OCCompilerSettings {
+
+ private final Project project;
+
+ StubOCCompilerSettings(Project project) {
+ this.project = project;
+ }
+
+ @Nullable
+ @Override
+ public OCCompilerKind getCompiler(OCLanguageKind languageKind) {
+ return OCCompilerKind.CLANG;
+ }
+
+ @Nullable
+ @Override
+ public File getCompilerExecutable(OCLanguageKind languageKind) {
+ return null;
+ }
+
+ @Override
+ public File getCompilerWorkingDir() {
+ return VfsUtilCore.virtualToIoFile(project.getBaseDir());
+ }
+
+ @Override
+ public CidrToolEnvironment getEnvironment() {
+ return new DefaultCidrToolEnvironment();
+ }
+
+ @Override
+ public CidrCompilerSwitches getCompilerSwitches(
+ OCLanguageKind languageKind, @Nullable VirtualFile sourceFile) {
+ return new CidrSwitchBuilder().build();
+ }
+}
diff --git a/testing/cidr/src/com/google/idea/testing/cidr/StubOCResolveConfiguration.java b/testing/cidr/src/com/google/idea/testing/cidr/StubOCResolveConfiguration.java
new file mode 100644
index 0000000..6d6c083
--- /dev/null
+++ b/testing/cidr/src/com/google/idea/testing/cidr/StubOCResolveConfiguration.java
@@ -0,0 +1,104 @@
+package com.google.idea.testing.cidr;
+
+import com.google.common.collect.ImmutableList;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.UserDataHolderBase;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCFileTypeHelpers;
+import com.jetbrains.cidr.lang.OCLanguageKind;
+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.OCCompilerMacros;
+import com.jetbrains.cidr.lang.workspace.compiler.OCCompilerSettings;
+import com.jetbrains.cidr.lang.workspace.headerRoots.HeaderRoots;
+import javax.annotation.Nullable;
+
+/** Stub {@link OCResolveConfiguration} for testing. */
+class StubOCResolveConfiguration extends UserDataHolderBase implements OCResolveConfiguration {
+
+ private final Project project;
+ private final HeaderRoots projectIncludeRoots;
+ private final OCCompilerSettings compilerSettings;
+ private final OCCompilerMacros compilerMacros;
+
+ StubOCResolveConfiguration(Project project) {
+ this.project = project;
+ this.projectIncludeRoots = new HeaderRoots(ImmutableList.of());
+ this.compilerMacros = new StubOCCompilerMacros();
+ this.compilerSettings = new StubOCCompilerSettings(project);
+ }
+
+ @Override
+ public Project getProject() {
+ return project;
+ }
+
+ @Override
+ public String getDisplayName(boolean shorten) {
+ return "Stub resolve configuration";
+ }
+
+ @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);
+ }
+ return getMaximumLanguageKind();
+ }
+
+ private OCLanguageKind getLanguageKind(VirtualFile sourceFile) {
+ OCLanguageKind kind = OCLanguageKindCalculator.tryFileTypeAndExtension(project, sourceFile);
+ return kind != null ? kind : getMaximumLanguageKind();
+ }
+
+ @Override
+ public OCLanguageKind getMaximumLanguageKind() {
+ return OCLanguageKind.CPP;
+ }
+
+ @Override
+ public OCLanguageKind getPrecompiledLanguageKind() {
+ return getMaximumLanguageKind();
+ }
+
+ @Override
+ public HeaderRoots getProjectHeadersRoots() {
+ return projectIncludeRoots;
+ }
+
+ @Override
+ public HeaderRoots getLibraryHeadersRoots(OCResolveRootAndConfiguration headerContext) {
+ return projectIncludeRoots;
+ }
+
+ @Override
+ public OCCompilerMacros getCompilerMacros() {
+ return compilerMacros;
+ }
+
+ @Override
+ public OCCompilerSettings getCompilerSettings() {
+ return compilerSettings;
+ }
+
+ @Nullable
+ @Override
+ public Object getIndexingCluster() {
+ return null;
+ }
+
+ @Override
+ public int compareTo(OCResolveConfiguration o) {
+ return OCWorkspaceUtil.compareConfigurations(this, o);
+ }
+}
diff --git a/testing/cidr/src/com/google/idea/testing/cidr/StubOCWorkspace.java b/testing/cidr/src/com/google/idea/testing/cidr/StubOCWorkspace.java
new file mode 100644
index 0000000..1f58463
--- /dev/null
+++ b/testing/cidr/src/com/google/idea/testing/cidr/StubOCWorkspace.java
@@ -0,0 +1,68 @@
+package com.google.idea.testing.cidr;
+
+import com.google.common.collect.ImmutableList;
+import com.google.idea.sdkcompat.cidr.OCWorkspaceAdapter;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.cidr.lang.OCFileType;
+import com.jetbrains.cidr.lang.symbols.OCSymbol;
+import com.jetbrains.cidr.lang.workspace.OCResolveConfiguration;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.Nullable;
+
+/** A stub {@link com.jetbrains.cidr.lang.workspace.OCWorkspace} to use for testing. */
+class StubOCWorkspace extends OCWorkspaceAdapter {
+
+ private final List<OCResolveConfiguration> resolveConfigurations;
+
+ StubOCWorkspace(Project project) {
+ super(project);
+ resolveConfigurations = new ArrayList<>();
+ resolveConfigurations.add(new StubOCResolveConfiguration(project));
+ }
+
+ @Override
+ public Collection<VirtualFile> getLibraryFilesToBuildSymbols() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean areFromSameProject(@Nullable VirtualFile a, @Nullable VirtualFile b) {
+ return Objects.equals(a, b);
+ }
+
+ @Override
+ public boolean areFromSamePackage(@Nullable VirtualFile a, @Nullable VirtualFile b) {
+ return Objects.equals(a, b);
+ }
+
+ @Override
+ public boolean isInSDK(@Nullable VirtualFile file) {
+ return false;
+ }
+
+ @Override
+ public boolean isFromWrongSDK(OCSymbol symbol, @Nullable VirtualFile contextFile) {
+ return false;
+ }
+
+ @Override
+ public List<? extends OCResolveConfiguration> getConfigurations() {
+ return resolveConfigurations;
+ }
+
+ @Override
+ public List<? extends OCResolveConfiguration> getConfigurationsForFile(
+ @Nullable VirtualFile sourceFile) {
+ if (sourceFile == null) {
+ return Collections.emptyList();
+ }
+ return OCFileType.INSTANCE.equals(sourceFile.getFileType())
+ ? resolveConfigurations
+ : Collections.emptyList();
+ }
+}
diff --git a/testing/cidr/src/com/google/idea/testing/cidr/StubOCWorkspaceManager.java b/testing/cidr/src/com/google/idea/testing/cidr/StubOCWorkspaceManager.java
new file mode 100644
index 0000000..05921b7
--- /dev/null
+++ b/testing/cidr/src/com/google/idea/testing/cidr/StubOCWorkspaceManager.java
@@ -0,0 +1,90 @@
+package com.google.idea.testing.cidr;
+
+import com.intellij.lang.Language;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.impl.PsiManagerEx;
+import com.intellij.psi.impl.file.impl.FileManager;
+import com.intellij.util.ui.UIUtil;
+import com.jetbrains.cidr.lang.OCLanguage;
+import com.jetbrains.cidr.lang.preprocessor.OCInclusionContextUtil;
+import com.jetbrains.cidr.lang.workspace.OCWorkspace;
+import com.jetbrains.cidr.lang.workspace.OCWorkspaceManager;
+
+/**
+ * A stub {@link OCWorkspaceManager} to use for testing. Also allows toggling on C++ support (which
+ * may have been disabled by other OCWorkspaceManagers.
+ *
+ * <p>Once the plugin API ships with a more official OCWorkspaceManager-for-testing, we may be able
+ * to switch over to those classes. See: b/32420569
+ */
+public class StubOCWorkspaceManager extends OCWorkspaceManager {
+
+ private final Project project;
+ private final OCWorkspace workspace;
+
+ public StubOCWorkspaceManager(Project project) {
+ this.project = project;
+ this.workspace = new StubOCWorkspace(project);
+ }
+
+ @Override
+ public OCWorkspace getWorkspace() {
+ return workspace;
+ }
+
+ /**
+ * Enable C++ language support for testing (a previously registered OCWorkspace which may have
+ * disabled language support).
+ */
+ public void enableCSupportForTesting() throws Exception {
+ OCWorkspace workspace = OCWorkspaceManager.getWorkspace(project);
+ Boolean isCurrentlyEnabled = !OCLanguage.LANGUAGE_SUPPORT_DISABLED.get(project, false);
+ if (!isCurrentlyEnabled) {
+ enableLanguageSupport(project);
+ rebuildSymbols(project, workspace);
+ }
+ }
+
+ private static void enableLanguageSupport(Project project) {
+ OCLanguage.LANGUAGE_SUPPORT_DISABLED.set(project, false);
+ UIUtil.invokeLaterIfNeeded(
+ () ->
+ ApplicationManager.getApplication()
+ .runWriteAction(
+ () -> {
+ if (project.isDisposed()) {
+ return;
+ }
+ Language langToReset = PlainTextLanguage.INSTANCE;
+ FileManager fileManager =
+ ((PsiManagerEx) PsiManager.getInstance(project)).getFileManager();
+ for (PsiFile file : fileManager.getAllCachedFiles()) {
+ if (file.getLanguage() == langToReset) {
+ VirtualFile vf = OCInclusionContextUtil.getVirtualFile(file);
+ if (vf != null) {
+ fileManager.setViewProvider(vf, null);
+ }
+ }
+ }
+ }));
+ }
+
+ private static void rebuildSymbols(Project project, OCWorkspace workspace) {
+ ApplicationManager.getApplication()
+ .runReadAction(
+ () -> {
+ if (project.isDisposed()) {
+ return;
+ }
+ workspace
+ .getModificationTrackers()
+ .getBuildSettingsChangesTracker()
+ .incModificationCount();
+ });
+ }
+}
diff --git a/third_party/BUILD b/third_party/BUILD
index 283fe42..06e9b19 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -10,3 +10,13 @@
name = "zip",
srcs = ["zip-wrap/zip.sh"],
)
+
+sh_binary(
+ name = "unzip",
+ srcs = ["zip-wrap/unzip.sh"],
+)
+
+java_library(
+ name = "python",
+ exports = ["//third_party/python"],
+)
diff --git a/third_party/python/BUILD b/third_party/python/BUILD
new file mode 100644
index 0000000..2f69d16
--- /dev/null
+++ b/third_party/python/BUILD
@@ -0,0 +1,27 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_plugin_api")
+
+java_library(
+ name = "python_internal",
+ visibility = ["//visibility:private"],
+ exports = select_for_plugin_api({
+ "intellij-2016.3.1": ["@python_2016_3//:python"],
+ "intellij-2017.1.1": ["@python_2017_1//:python"],
+ "clion-2017.1.1": ["@clion_2017_1_1//:python"],
+ }),
+)
+
+java_library(
+ name = "python_for_tests",
+ testonly = 1,
+ exports = [":python_internal"],
+)
+
+java_library(
+ name = "python",
+ neverlink = 1,
+ exports = [":python_internal"],
+)
diff --git a/third_party/python/LICENSE b/third_party/python/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/python/LICENSE
@@ -0,0 +1,202 @@
+
+ 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/scala/BUILD b/third_party/scala/BUILD
new file mode 100644
index 0000000..9786523
--- /dev/null
+++ b/third_party/scala/BUILD
@@ -0,0 +1,25 @@
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"])
+
+load("//intellij_platform_sdk:build_defs.bzl", "select_for_plugin_api")
+
+java_library(
+ name = "scala_internal",
+ visibility = ["//visibility:private"],
+ exports = select_for_plugin_api({
+ "intellij-2017.1.1": ["@scala_2017_1//:scala"],
+ }),
+)
+
+java_library(
+ name = "scala_for_tests",
+ testonly = 1,
+ exports = [":scala_internal"],
+)
+
+java_library(
+ name = "scala",
+ neverlink = 1,
+ exports = [":scala_internal"],
+)
diff --git a/third_party/scala/LICENSE b/third_party/scala/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/scala/LICENSE
@@ -0,0 +1,202 @@
+
+ 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/zip-wrap/unzip.sh b/third_party/zip-wrap/unzip.sh
new file mode 100755
index 0000000..f1be34d
--- /dev/null
+++ b/third_party/zip-wrap/unzip.sh
@@ -0,0 +1,15 @@
+# Copyright 2015 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+unzip "$@"
diff --git a/version.bzl b/version.bzl
index 85514a2..667e07a 100644
--- a/version.bzl
+++ b/version.bzl
@@ -1,3 +1,3 @@
"""Version of the blaze plugin."""
-VERSION = "2017.01.30.4"
+VERSION = "2017.05.17.1"