diff --git a/.idea/modules.xml b/.idea/modules.xml
index ce8d7ca005f3..c7736ee6aa66 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -11,6 +11,7 @@
+
diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant
index 6dc01096ba64..a092e36f46eb 100644
--- a/build/scripts/layouts.gant
+++ b/build/scripts/layouts.gant
@@ -366,6 +366,10 @@ public def layoutCommunityPlugins(String home) {
}
jar("android_rt.jar") {module("android-rt")}
+
+ dir("jps") {
+ jar("android-jps-plugin.jar") { module("android-jps-plugin") }
+ }
}
}
}
diff --git a/jps/model/src/org/jetbrains/jps/JavaSdk.groovy b/jps/model/src/org/jetbrains/jps/JavaSdk.groovy
index 2bd8812ce617..17aa8457d59c 100644
--- a/jps/model/src/org/jetbrains/jps/JavaSdk.groovy
+++ b/jps/model/src/org/jetbrains/jps/JavaSdk.groovy
@@ -1,21 +1,11 @@
package org.jetbrains.jps
/**
- * @author nik
+ * @author Eugene.Kudelevsky
*/
-class JavaSdk extends Sdk {
- String jdkPath
+public interface JavaSdk {
- def JavaSdk(Project project, String name, String jdkPath, Closure initializer) {
- super(project, name, initializer)
- this.jdkPath = jdkPath
- }
+ String getJavacExecutable();
- String getJavacExecutable() {
- return jdkPath + File.separator + "bin" + File.separator + "javac";
- }
-
- String getJavaExecutable() {
- return jdkPath + File.separator + "bin" + File.separator + "java";
- }
-}
+ String getJavaExecutable();
+}
\ No newline at end of file
diff --git a/jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy b/jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy
new file mode 100644
index 000000000000..9caa1092f55d
--- /dev/null
+++ b/jps/model/src/org/jetbrains/jps/JavaSdkImpl.groovy
@@ -0,0 +1,21 @@
+package org.jetbrains.jps
+
+/**
+ * @author nik
+ */
+class JavaSdkImpl extends Sdk implements JavaSdk {
+ String jdkPath
+
+ def JavaSdkImpl(Project project, String name, String jdkPath, Closure initializer) {
+ super(project, name, initializer)
+ this.jdkPath = jdkPath
+ }
+
+ String getJavacExecutable() {
+ return jdkPath + File.separator + "bin" + File.separator + "javac";
+ }
+
+ String getJavaExecutable() {
+ return jdkPath + File.separator + "bin" + File.separator + "java";
+ }
+}
diff --git a/jps/model/src/org/jetbrains/jps/Project.groovy b/jps/model/src/org/jetbrains/jps/Project.groovy
index 60f0fdc74af5..3a89242c5f6a 100644
--- a/jps/model/src/org/jetbrains/jps/Project.groovy
+++ b/jps/model/src/org/jetbrains/jps/Project.groovy
@@ -43,7 +43,7 @@ class Project {
}
def JavaSdk createJavaSdk(String name, String path, Closure initializer) {
- def sdk = new JavaSdk(this, name, path, initializer)
+ def sdk = new JavaSdkImpl(this, name, path, initializer)
sdks[name] = sdk
return sdk
}
diff --git a/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy b/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy
index 6f8f80dc8032..c300e9235363 100644
--- a/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy
+++ b/jps/model/src/org/jetbrains/jps/idea/JavaSdkType.groovy
@@ -1,8 +1,8 @@
package org.jetbrains.jps.idea
+import org.jetbrains.jps.JavaSdkImpl
import org.jetbrains.jps.Project
import org.jetbrains.jps.Sdk
-import org.jetbrains.jps.JavaSdk
/**
* @author nik
@@ -14,6 +14,6 @@ class JavaSdkType extends SdkTypeService {
@Override
Sdk createSdk(Project project, String name, String homePath, Node additionalData) {
- return new JavaSdk(project, name, homePath, {})
+ return new JavaSdkImpl(project, name, homePath, {})
}
}
diff --git a/platform/platform-api/src/com/intellij/util/Alarm.java b/platform/platform-api/src/com/intellij/util/Alarm.java
index 8f0117dd4844..ce2f46875680 100644
--- a/platform/platform-api/src/com/intellij/util/Alarm.java
+++ b/platform/platform-api/src/com/intellij/util/Alarm.java
@@ -92,21 +92,21 @@ public class Alarm implements Disposable {
}
}
- public void addRequest(final Runnable request, int delayMillis) {
+ public void addRequest(final Runnable request, long delayMillis) {
_addRequest(request, delayMillis, myThreadToUse == ThreadToUse.SWING_THREAD ? ModalityState.current() : null);
}
- public void addComponentRequest(Runnable request, int delay) {
+ public void addComponentRequest(Runnable request, long delayMillis) {
assert myActivationComponent != null;
- _addRequest(request, delay, ModalityState.stateForComponent(myActivationComponent));
+ _addRequest(request, delayMillis, ModalityState.stateForComponent(myActivationComponent));
}
- public void addRequest(final Runnable request, int delayMillis, @Nullable final ModalityState modalityState) {
+ public void addRequest(final Runnable request, long delayMillis, @Nullable final ModalityState modalityState) {
LOG.assertTrue(myThreadToUse == ThreadToUse.SWING_THREAD);
_addRequest(request, delayMillis, modalityState);
}
- private void _addRequest(final Runnable request, int delayMillis, ModalityState modalityState) {
+ private void _addRequest(final Runnable request, long delayMillis, ModalityState modalityState) {
synchronized (LOCK) {
LOG.assertTrue(!myDisposed, "Already disposed");
final Request requestToSchedule = new Request(request, modalityState, delayMillis);
@@ -191,9 +191,9 @@ public class Alarm implements Disposable {
private Runnable myTask;
private final ModalityState myModalityState;
private Future> myFuture;
- private final int myDelay;
+ private final long myDelay;
- private Request(final Runnable task, final ModalityState modalityState, int delayMillis) {
+ private Request(final Runnable task, final ModalityState modalityState, long delayMillis) {
myTask = task;
myModalityState = modalityState;
myDelay = delayMillis;
diff --git a/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java b/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java
index cdbb5a984407..7bfa6c2caeb8 100644
--- a/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java
+++ b/platform/platform-impl/src/com/intellij/idea/IdeaApplication.java
@@ -31,8 +31,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.updateSettings.impl.CheckForUpdateResult;
-import com.intellij.openapi.updateSettings.impl.PluginDownloader;
import com.intellij.openapi.updateSettings.impl.UpdateChecker;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.IconLoader;
@@ -49,7 +47,6 @@ import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.Arrays;
-import java.util.List;
@SuppressWarnings({"CallToPrintStackTrace"})
@@ -217,7 +214,7 @@ public class IdeaApplication {
if (UpdateChecker.isMyVeryFirstOpening() && UpdateChecker.checkNeeded()) {
UpdateChecker.setMyVeryFirstOpening(false);
- updatePlugins(true);
+ UpdateChecker.updateAndShowResult();
}
SwingUtilities.invokeLater(new Runnable() {
@@ -229,23 +226,6 @@ public class IdeaApplication {
}, ModalityState.NON_MODAL);
}
- private void updatePlugins(final boolean showConfirmation) {
- final Application app = ApplicationManager.getApplication();
- app.executeOnPooledThread(new Runnable() {
- @Override
- public void run() {
- final CheckForUpdateResult checkForUpdateResult = UpdateChecker.checkForUpdates();
-
- final List updatedPlugins = UpdateChecker.updatePlugins(false, null);
- app.invokeLater(new Runnable() {
- @Override
- public void run() {
- UpdateChecker.showUpdateResult(checkForUpdateResult, updatedPlugins, showConfirmation, true, false);
- }
- });
- }
- });
- }
}
private void loadProject() {
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java
index 948b08c57038..323e15b63b1a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -419,13 +419,31 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume
* 'Token' here stands for the number of subsequent symbols that are represented using the same font by IJ editor.
*/
private void processNonFoldToken() {
+ int limit = 3 * (myContext.tokenEndOffset - myContext.lineStartPosition.offset);
+ int counter = 0;
+ int startOffset = myContext.currentPosition.offset;
while (myContext.currentPosition.offset < myContext.tokenEndOffset) {
- //for (int i = myContext.startOffset; i < myContext.endOffset; i++) {
+ if (counter++ > limit) {
+ String editorInfo = myEditor instanceof EditorImpl ? ((EditorImpl)myEditor).dumpState() : myEditor.getClass().toString();
+ LogMessageEx.error(LOG, "Cycled soft wraps recalculation detected", String.format(
+ "Start recalculation offset: %d, visible area width: %d, calculation context: %s, editor info: %s",
+ startOffset, myVisibleAreaWidth, myContext, editorInfo));
+ for (int i = myContext.currentPosition.offset; i < myContext.tokenEndOffset; i++) {
+ char c = myContext.text.charAt(i);
+ if (c == '\n') {
+ myContext.onNewLine();
+ }
+ else {
+ myContext.onNonLineFeedSymbol(c);
+ }
+ }
+ return;
+ }
int offset = myContext.currentPosition.offset;
if (offset > myContext.rangeEndOffset) {
return;
}
-
+
if (myContext.delayedSoftWrap != null && myContext.delayedSoftWrap.getStart() == offset) {
processSoftWrap(myContext.delayedSoftWrap);
myContext.delayedSoftWrap = null;
@@ -442,7 +460,7 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume
createSoftWrapIfPossible();
continue;
}
-
+
int newX = offsetToX(offset, c);
if (myContext.exceedsVisualEdge(newX) && myContext.delayedSoftWrap == null) {
createSoftWrapIfPossible();
@@ -1119,6 +1137,14 @@ public class SoftWrapApplianceManager implements SoftWrapFoldingListener, Docume
public boolean notifyListenersOnLineStartPosition;
public boolean skipToLineEnd;
+ @Override
+ public String toString() {
+ return "reserved width: " + reservedWidthInPixels + ", soft wrap start offset: " + softWrapStartOffset + ", range end offset: "
+ + rangeEndOffset + ", token offsets: [" + tokenStartOffset + "; " + tokenEndOffset + "], font type: " + fontType
+ + ", skip to line end: " + skipToLineEnd + ", delayed soft wrap: " + delayedSoftWrap + ", current position: "+ currentPosition
+ + "line start position: " + lineStartPosition;
+ }
+
public void reset() {
text = null;
lineStartPosition = null;
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/ButtonInfo.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/ButtonInfo.java
index 82820fc66cc0..6cbe0478b2dc 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/ButtonInfo.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/ButtonInfo.java
@@ -23,10 +23,12 @@ import org.jdom.Element;
public class ButtonInfo {
private final String myName;
private final String myUrl;
+ private final boolean myDownload;
public ButtonInfo(Element element) {
myName = element.getAttributeValue("name");
myUrl = element.getAttributeValue("url");
+ myDownload = element.getAttributeValue("download") != null;
}
public String getName() {
@@ -36,4 +38,13 @@ public class ButtonInfo {
public String getUrl() {
return myUrl;
}
+
+ /**
+ * The button marked with 'download=true' attribute is hidden if patch is available.
+ *
+ * @return true if the button should be hidden when the patch is available.
+ */
+ public boolean isDownload() {
+ return myDownload;
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java
index 476dde4d0714..dd6d07f04f75 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java
@@ -22,6 +22,7 @@ import com.intellij.ide.util.PropertiesComponent;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
+import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
@@ -32,6 +33,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.BuildNumber;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.SystemInfo;
@@ -143,6 +145,27 @@ public final class UpdateChecker {
return settings.CHECK_NEEDED;
}
+ public static ActionCallback updateAndShowResult() {
+ final ActionCallback result = new ActionCallback();
+ final Application app = ApplicationManager.getApplication();
+ app.executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ final CheckForUpdateResult checkForUpdateResult = checkForUpdates();
+
+ final List updatedPlugins = updatePlugins(false, null);
+ app.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ showUpdateResult(checkForUpdateResult, updatedPlugins, true, true, false);
+ result.setDone();
+ }
+ });
+ }
+ });
+ return result;
+ }
+
public static List updatePlugins(final boolean showErrorDialog,
final @Nullable PluginHostsConfigurable hostsConfigurable) {
final List downloaded = new ArrayList();
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java
new file mode 100644
index 000000000000..e625161174a0
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateCheckerComponent.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.updateSettings.impl;
+
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.util.Alarm;
+import com.intellij.util.text.DateFormatUtil;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author yole
+ */
+public class UpdateCheckerComponent implements ApplicationComponent {
+ private static final long CHECK_INTERVAL = DateFormatUtil.DAY;
+ private final Alarm myCheckForUpdatesAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
+ private final Runnable myCheckRunnable = new Runnable() {
+ @Override
+ public void run() {
+ UpdateChecker.updateAndShowResult().doWhenDone(new Runnable() {
+ @Override
+ public void run() {
+ queueNextUpdateCheck(CHECK_INTERVAL);
+ }
+ });
+ }
+ };
+
+ @Override
+ public void initComponent() {
+ queueNextUpdateCheck(UpdateChecker.checkNeeded()
+ ? CHECK_INTERVAL
+ : UpdateSettings.getInstance().LAST_TIME_CHECKED - System.currentTimeMillis() + CHECK_INTERVAL);
+ }
+
+ private void queueNextUpdateCheck(long interval) {
+ myCheckForUpdatesAlarm.addRequest(myCheckRunnable, interval);
+ }
+
+ @Override
+ public void disposeComponent() {
+ Disposer.dispose(myCheckForUpdatesAlarm);
+ }
+
+ @NotNull
+ @Override
+ public String getComponentName() {
+ return "UpdateCheckerComponent";
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java
index af11cfe29660..9f4c64875055 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateInfoDialog.java
@@ -66,11 +66,14 @@ class UpdateInfoDialog extends AbstractUpdateDialog {
}
else {
for (ButtonInfo info : buttons) {
- actions.add(new ButtonAction(info));
+ if (!info.isDownload()) {
+ actions.add(new ButtonAction(info));
+ }
}
}
}
else {
+ // the first button replaces the OK action
for (int i = 1; i < buttons.size(); i++) {
actions.add(new ButtonAction(buttons.get(i)));
}
diff --git a/platform/platform-resources/src/componentSets/UICore.xml b/platform/platform-resources/src/componentSets/UICore.xml
index 1e300df10652..74c53dfecc00 100644
--- a/platform/platform-resources/src/componentSets/UICore.xml
+++ b/platform/platform-resources/src/componentSets/UICore.xml
@@ -57,6 +57,9 @@
com.intellij.ui.switcher.QuickAccessSettings
+
+ com.intellij.openapi.updateSettings.impl.UpdateCheckerComponent
+
diff --git a/plugins/android/jps-plugin/android-jps-plugin.iml b/plugins/android/jps-plugin/android-jps-plugin.iml
new file mode 100644
index 000000000000..a2f02ccd0c76
--- /dev/null
+++ b/plugins/android/jps-plugin/android-jps-plugin.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService
new file mode 100644
index 000000000000..a75fa45b2aa4
--- /dev/null
+++ b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.FacetTypeService
@@ -0,0 +1 @@
+org.jetbrains.jps.android.AndroidFacetType
\ No newline at end of file
diff --git a/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService
new file mode 100644
index 000000000000..f3084a2b366a
--- /dev/null
+++ b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.idea.SdkTypeService
@@ -0,0 +1 @@
+org.jetbrains.jps.android.AndroidSdkType
\ No newline at end of file
diff --git a/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService
new file mode 100644
index 000000000000..59103ac8ba86
--- /dev/null
+++ b/plugins/android/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService
@@ -0,0 +1 @@
+org.jetbrains.jps.android.AndroidBuilderService
\ No newline at end of file
diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java
new file mode 100644
index 000000000000..81b9e6eba3de
--- /dev/null
+++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidBuilderService.java
@@ -0,0 +1,20 @@
+package org.jetbrains.jps.android;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.incremental.BuilderService;
+import org.jetbrains.jps.incremental.ModuleLevelBuilder;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class AndroidBuilderService extends BuilderService {
+ @NotNull
+ @Override
+ public List extends ModuleLevelBuilder> createModuleLevelBuilders(ExecutorService executorService) {
+ return Arrays.asList(new AndroidSourceGeneratingBuilder());
+ }
+}
diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy
new file mode 100644
index 000000000000..e9530f165ee7
--- /dev/null
+++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacet.groovy
@@ -0,0 +1,46 @@
+package org.jetbrains.jps.android
+
+import com.intellij.openapi.util.io.FileUtil
+import org.jetbrains.jps.Module
+import org.jetbrains.jps.idea.Facet
+
+/**
+ * @author nik
+ */
+class AndroidFacet extends Facet {
+ final Module module
+ final String resFolderRelativePath
+
+ AndroidFacet(Module module, String name, String resFolderRelativePath) {
+ this.module = module
+ this.name = name;
+ this.resFolderRelativePath = resFolderRelativePath
+ }
+
+ File getResourceDir() {
+ return findFileByRelativeModulePath(resFolderRelativePath, true)
+ }
+
+ private File findFileByRelativeModulePath(String relativePath, boolean lookInContentRoot) {
+ if (module.basePath != null) {
+ def absPath = FileUtil.toSystemIndependentName(module.basePath + relativePath)
+ def f = new File(absPath)
+
+ if (f.exists()) {
+ return f
+ }
+ }
+
+ if (lookInContentRoot) {
+ module.contentRoots.each {
+ def absPath = FileUtil.toSystemIndependentName(contentRoot + relativePath)
+ def f = new File(absPath)
+
+ if (f.exists()) {
+ return f
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy
new file mode 100644
index 000000000000..ca555e24e37e
--- /dev/null
+++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidFacetType.groovy
@@ -0,0 +1,22 @@
+package org.jetbrains.jps.android
+
+import org.jetbrains.jps.MacroExpander
+import org.jetbrains.jps.Module
+import org.jetbrains.jps.idea.Facet
+import org.jetbrains.jps.idea.FacetTypeService
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+class AndroidFacetType extends FacetTypeService {
+ public static final String ID = "android"
+
+ AndroidFacetType() {
+ super(ID)
+ }
+
+ @Override
+ Facet createFacet(Module module, String name, Node facetConfiguration, MacroExpander macroExpander) {
+ return new AndroidFacet(module, name, "");
+ }
+}
diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy
new file mode 100644
index 000000000000..b4ce00b91c41
--- /dev/null
+++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdk.groovy
@@ -0,0 +1,34 @@
+package org.jetbrains.jps.android
+
+import org.jetbrains.jps.JavaSdk
+import org.jetbrains.jps.Project
+import org.jetbrains.jps.Sdk
+import org.jetbrains.jps.JavaSdkImpl
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+class AndroidSdk extends Sdk implements JavaSdk {
+ final String sdkPath;
+ final String buildTargetHashString;
+ final String javaSdkName;
+
+ AndroidSdk(Project project, String name, String sdkPath, String javaSdkName, String buildTargetHashString) {
+ super(project, name, {})
+ this.sdkPath = sdkPath
+ this.buildTargetHashString = buildTargetHashString
+ this.javaSdkName = javaSdkName;
+ }
+
+ @Override
+ String getJavacExecutable() {
+ def javaSdk = project.sdks[javaSdkName]
+ return javaSdk instanceof JavaSdkImpl ? javaSdk.getJavacExecutable() : null
+ }
+
+ @Override
+ String getJavaExecutable() {
+ def javaSdk = project.sdks[javaSdkName]
+ return javaSdk instanceof JavaSdkImpl ? javaSdk.getJavaExecutable() : null
+ }
+}
diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy
new file mode 100644
index 000000000000..90d47d29c07c
--- /dev/null
+++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSdkType.groovy
@@ -0,0 +1,30 @@
+package org.jetbrains.jps.android
+
+import org.jetbrains.jps.idea.SdkTypeService
+import org.jetbrains.jps.Sdk
+import org.jetbrains.jps.Project
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+class AndroidSdkType extends SdkTypeService {
+ AndroidSdkType() {
+ super("Android SDK");
+ }
+
+ @Override
+ Sdk createSdk(Project project, String name, String homePath, Node additionalData) {
+ def attributes = additionalData.attributes()
+ if (attributes == null) {
+ return null;
+ }
+
+ def buildTargetHashString = (String)attributes.get("sdk")
+ def internalJdkName = (String)attributes.get("jdk")
+
+ if (internalJdkName == null || buildTargetHashString == null) {
+ return null;
+ }
+ return new AndroidSdk(project, name, homePath, internalJdkName, buildTargetHashString)
+ }
+}
diff --git a/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java
new file mode 100644
index 000000000000..77abb5082d17
--- /dev/null
+++ b/plugins/android/jps-plugin/src/org/jetbrains/jps/android/AndroidSourceGeneratingBuilder.java
@@ -0,0 +1,498 @@
+package org.jetbrains.jps.android;
+
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.containers.HashMap;
+import com.intellij.util.containers.HashSet;
+import org.jetbrains.android.compiler.tools.AndroidIdl;
+import org.jetbrains.android.compiler.tools.AndroidRenderscript;
+import org.jetbrains.android.sdk.MessageBuildingSdkLog;
+import org.jetbrains.android.util.AndroidCommonUtils;
+import org.jetbrains.android.util.AndroidCompilerMessageKind;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.*;
+import org.jetbrains.jps.idea.Facet;
+import org.jetbrains.jps.incremental.*;
+import org.jetbrains.jps.incremental.messages.BuildMessage;
+import org.jetbrains.jps.incremental.messages.CompilerMessage;
+import org.jetbrains.jps.incremental.messages.ProgressMessage;
+import org.jetbrains.jps.incremental.storage.SourceToOutputMapping;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.android.AndroidSourceGeneratingBuilder");
+
+ @NonNls private static final String BUILDER_NAME = "android-source-generator";
+ @NonNls private static final String AIDL_EXTENSION = "aidl";
+ @NonNls private static final String RENDERSCRIPT_EXTENSION = "rs";
+
+ public AndroidSourceGeneratingBuilder() {
+ super(BuilderCategory.SOURCE_GENERATOR);
+ }
+
+ @Override
+ public String getName() {
+ return BUILDER_NAME;
+ }
+
+ @Override
+ public ModuleLevelBuilder.ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
+ if (context.isCompilingTests()) {
+ return ModuleLevelBuilder.ExitCode.OK;
+ }
+
+ try {
+ return doBuild(context, chunk);
+ }
+ catch (ProjectBuildException e) {
+ throw e;
+ }
+ catch (Exception e) {
+ String message = e.getMessage();
+
+ if (message == null) {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ //noinspection IOResourceOpenedButNotSafelyClosed
+ e.printStackTrace(new PrintStream(out));
+ message = "Internal error: \n" + out.toString();
+ }
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message));
+ throw new ProjectBuildException(message, e);
+ }
+ }
+
+ private static ModuleLevelBuilder.ExitCode doBuild(CompileContext context, ModuleChunk chunk) throws Exception {
+ final Map idlFilesToCompile = new HashMap();
+ final Map rsFilesToCompile = new HashMap();
+ final Set modules = new HashSet();
+
+ context.processFilesToRecompile(chunk, new FileProcessor() {
+ @Override
+ public boolean apply(Module module, File file, String sourceRoot) throws IOException {
+ final AndroidFacet facet = getFacet(module);
+
+ if (facet == null) {
+ return true;
+ }
+ final String ext = FileUtil.getExtension(file.getName());
+
+ if (AIDL_EXTENSION.equals(ext)) {
+ idlFilesToCompile.put(file, facet);
+ modules.add(facet.getModule());
+ }
+ else if (RENDERSCRIPT_EXTENSION.equals(ext)) {
+ rsFilesToCompile.put(file, facet);
+ modules.add(facet.getModule());
+ }
+
+ return true;
+ }
+ });
+
+ final Map moduleDataMap = computeModuleDatas(modules, context);
+
+ if (moduleDataMap == null) {
+ return ExitCode.OK;
+ }
+
+ if (!runAidlCompiler(context, idlFilesToCompile, moduleDataMap)) {
+ return ExitCode.OK;
+ }
+
+ if (!runRenderscriptCompiler(context, rsFilesToCompile, moduleDataMap)) {
+ return ExitCode.OK;
+ }
+
+ return ExitCode.OK;
+ }
+
+ private static boolean runAidlCompiler(@NotNull final CompileContext context,
+ @NotNull Map files,
+ @NotNull Map moduleDataMap) {
+ context.processMessage(new ProgressMessage("Processing AIDL files..."));
+
+ boolean success = true;
+
+ for (Map.Entry entry : files.entrySet()) {
+ final File file = entry.getKey();
+ final Module module = entry.getValue().getModule();
+ final String filePath = file.getPath();
+
+ final MyModuleData moduleData = moduleDataMap.get(module);
+
+ if (!LOG.assertTrue(moduleData != null)) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Internal error"));
+ success = false;
+ continue;
+ }
+ final File outputDirectory = moduleData.getOutputDirectory();
+ final File aidlOutputDirectory = new File(outputDirectory, "generated-aidl");
+ final IAndroidTarget target = moduleData.getAndroidTarget();
+
+ try {
+ final File[] sourceRoots = getSourceRootsForModuleAndDependencies(module);
+ final String[] sourceRootPaths = toPaths(sourceRoots);
+ final String packageName = computePackageForFile(context, file);
+
+ if (packageName == null) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Cannot compute package for file",
+ filePath));
+ success = false;
+ continue;
+ }
+
+ final File outputFile = new File(aidlOutputDirectory, packageName.replace('.', File.separatorChar) +
+ File.separator + FileUtil.getNameWithoutExtension(file) + ".java");
+ final String outputFilePath = outputFile.getPath();
+ final Map> messages =
+ AndroidIdl.execute(target, filePath, outputFilePath, sourceRootPaths);
+
+ addMessages(context, messages, filePath);
+
+ if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) {
+ success = false;
+ continue;
+ }
+
+ final String moduleName = getCannonicalModuleName(module);
+ final SourceToOutputMapping sourceToOutputMap = context.getDataManager().getSourceToOutputMap(moduleName, false);
+ sourceToOutputMap.update(filePath, outputFilePath);
+ }
+ catch (final IOException e) {
+ reportExceptionError(context, filePath, e);
+ success = false;
+ }
+ }
+ return success;
+ }
+
+ private static boolean runRenderscriptCompiler(@NotNull final CompileContext context,
+ @NotNull Map files,
+ @NotNull Map moduleDataMap) {
+ context.processMessage(new ProgressMessage("Processing Renderscript files..."));
+
+ boolean success = true;
+
+ for (Map.Entry entry : files.entrySet()) {
+ final File file = entry.getKey();
+ final Module module = entry.getValue().getModule();
+
+ final MyModuleData moduleData = moduleDataMap.get(module);
+ if (!LOG.assertTrue(moduleData != null)) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, "Internal error"));
+ success = false;
+ continue;
+ }
+
+ final File outputDirectory = moduleData.getOutputDirectory();
+ final File rsOutputDirectory = new File(outputDirectory, "generated-rs");
+ final File generatedResourcesDir = new File(outputDirectory, "generated-resources");
+
+ final IAndroidTarget target = moduleData.getAndroidTarget();
+ final String sdkLocation = moduleData.getSdkLocation();
+ final String filePath = file.getPath();
+
+ File tmpOutputDirectory = null;
+
+ try {
+ tmpOutputDirectory = FileUtil.createTempDirectory("generated-rs-temp", null);
+ final String depFolderPath = getDependencyFolder(context, file, tmpOutputDirectory);
+ final File rawDir = new File(generatedResourcesDir, "raw");
+
+ final Map> messages =
+ AndroidRenderscript.execute(sdkLocation, target, filePath, tmpOutputDirectory.getPath(), depFolderPath, rawDir.getPath());
+
+ addMessages(context, messages, filePath);
+
+ if (messages.get(AndroidCompilerMessageKind.ERROR).size() > 0) {
+ success = false;
+ }
+ else {
+ final List newFiles = new ArrayList();
+ AndroidCommonUtils.moveAllFiles(tmpOutputDirectory, rsOutputDirectory, newFiles);
+
+ final File bcFile = new File(rawDir, FileUtil.getNameWithoutExtension(file) + ".bc");
+ if (bcFile.exists()) {
+ newFiles.add(bcFile);
+ }
+ final List newFilePaths = Arrays.asList(toPaths(newFiles.toArray(new File[newFiles.size()])));
+
+ final String moduleName = getCannonicalModuleName(module);
+ final SourceToOutputMapping sourceToOutputMap = context.getDataManager().getSourceToOutputMap(moduleName, false);
+ sourceToOutputMap.update(filePath, newFilePaths);
+ }
+ }
+ catch (IOException e) {
+ reportExceptionError(context, filePath, e);
+ success = false;
+ }
+ finally {
+ if (tmpOutputDirectory != null) {
+ FileUtil.delete(tmpOutputDirectory);
+ }
+ }
+ }
+ return success;
+ }
+
+ private static void reportExceptionError(@NotNull CompileContext context, @NotNull String filePath, @NotNull Exception exception) {
+ final String message = exception.getMessage();
+
+ if (message != null) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message, filePath));
+ LOG.debug(exception);
+ }
+ else {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, exception));
+ }
+ }
+
+ @NotNull
+ private static String getCannonicalModuleName(@NotNull Module module) {
+ return module.getName().toLowerCase(Locale.US);
+ }
+
+ @Nullable
+ private static String getDependencyFolder(@NotNull CompileContext context, @NotNull File sourceFile, @NotNull File genFolder) {
+ final RootDescriptor descriptor = context.getRootsIndex().getModuleAndRoot(sourceFile);
+ if (descriptor == null) {
+ return null;
+ }
+ final File sourceRoot = descriptor.root;
+
+ final File parent = FileUtil.getParentFile(sourceFile);
+ if (parent == null) {
+ return null;
+ }
+
+ if (parent.equals(sourceRoot)) {
+ return genFolder.getPath();
+ }
+ final String relativePath = FileUtil.getRelativePath(sourceRoot, parent);
+ assert relativePath != null;
+ return genFolder.getPath() + '/' + relativePath;
+ }
+
+ @Nullable
+ private static Map computeModuleDatas(@NotNull Collection modules, @NotNull CompileContext context)
+ throws Exception {
+ final Map moduleDataMap = new HashMap();
+
+ boolean success = true;
+
+ for (Module module : modules) {
+
+ final Sdk sdk = module.getSdk();
+ if (!(sdk instanceof AndroidSdk)) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
+ "Android SDK is not specified for module " + module.getName()));
+ success = false;
+ continue;
+ }
+ final AndroidSdk androidSdk = (AndroidSdk)sdk;
+
+ final IAndroidTarget target = parseAndroidTarget(androidSdk, context);
+ if (target == null) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
+ "Android SDK is invalid or not specified for module " + module.getName()));
+ success = false;
+ continue;
+ }
+
+ final File outputDir = context.getProjectPaths().getModuleOutputDir(module, false);
+ if (outputDir == null) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
+ "Cannot find output directory for module " + module.getName()));
+ success = false;
+ continue;
+ }
+
+ moduleDataMap.put(module, new MyModuleData(outputDir, androidSdk.getSdkPath(), target));
+ }
+
+ return success ? moduleDataMap : null;
+ }
+
+ private static void addMessages(@NotNull CompileContext context,
+ @NotNull Map> messages,
+ @Nullable String sourcePath) {
+ for (Map.Entry> entry : messages.entrySet()) {
+ final AndroidCompilerMessageKind kind = entry.getKey();
+ final BuildMessage.Kind buildMessageKind = toBuildMessageKind(kind);
+
+ if (buildMessageKind == null) {
+ continue;
+ }
+
+ for (String message : entry.getValue()) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, buildMessageKind, message, sourcePath));
+ }
+ }
+ }
+
+ @Nullable
+ private static BuildMessage.Kind toBuildMessageKind(@NotNull AndroidCompilerMessageKind kind) {
+ switch (kind) {
+ case ERROR:
+ return BuildMessage.Kind.ERROR;
+ case INFORMATION:
+ return BuildMessage.Kind.INFO;
+ case WARNING:
+ return BuildMessage.Kind.WARNING;
+ default:
+ LOG.error("unknown AndroidCompilerMessageKind object " + kind);
+ return null;
+ }
+ }
+
+ @Nullable
+ private static String computePackageForFile(@NotNull CompileContext context, @NotNull File file) throws IOException {
+ final RootDescriptor descriptor = context.getRootsIndex().getModuleAndRoot(file);
+ if (descriptor == null) {
+ return null;
+ }
+
+ final String relPath = FileUtil.getRelativePath(descriptor.root, FileUtil.getParentFile(file));
+ if (relPath == null) {
+ return null;
+ }
+
+ return FileUtil.toSystemIndependentName(relPath).replace('/', '.');
+ }
+
+ @Nullable
+ private static IAndroidTarget parseAndroidTarget(@NotNull AndroidSdk sdk, @NotNull CompileContext context) {
+ final String targetHashString = sdk.getBuildTargetHashString();
+ if (targetHashString == null) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
+ "Cannot parse SDK " + sdk.getName() + ": build target is not specified"));
+ return null;
+ }
+
+ final MessageBuildingSdkLog log = new MessageBuildingSdkLog();
+ final SdkManager manager = AndroidCommonUtils.createSdkManager(sdk.getSdkPath(), log);
+
+ if (manager == null) {
+ final String message = log.getErrorMessage();
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
+ "Android SDK is parsed incorrectly." +
+ (message.length() > 0 ? " Parsing log:\n" + message : "")));
+ return null;
+ }
+
+ final IAndroidTarget target = manager.getTargetFromHashString(targetHashString);
+ if (target == null) {
+ context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
+ "Cannot parse SDK '" + sdk.getName() + "': unknown target " + targetHashString));
+ return null;
+ }
+ return target;
+ }
+
+ private static void fillSourceRoots(@NotNull Module module, @NotNull Set visited, @NotNull Set result)
+ throws IOException {
+ visited.add(module);
+ final AndroidFacet facet = getFacet(module);
+ File resDir = null;
+
+ if (facet != null) {
+ resDir = facet.getResourceDir();
+ if (resDir != null) {
+ resDir = resDir.getCanonicalFile();
+ }
+ }
+
+ for (String sourceRootPath : module.getSourceRoots()) {
+ final File sourceRoot = new File(sourceRootPath).getCanonicalFile();
+
+ if (!sourceRoot.equals(resDir)) {
+ result.add(sourceRoot);
+ }
+ }
+
+ for (ClasspathItem classpathItem : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE)) {
+ if (classpathItem instanceof Module) {
+ final Module depModule = (Module)classpathItem;
+
+ if (!visited.contains(depModule)) {
+ fillSourceRoots(depModule, visited, result);
+ }
+ }
+ }
+ }
+
+ @NotNull
+ public static File[] getSourceRootsForModuleAndDependencies(@NotNull Module module) throws IOException {
+ Set result = new HashSet();
+ fillSourceRoots(module, new HashSet(), result);
+ return result.toArray(new File[result.size()]);
+ }
+
+ @Override
+ public String getDescription() {
+ return "Android Builder";
+ }
+
+ @Nullable
+ private static AndroidFacet getFacet(@NotNull Module module) {
+ AndroidFacet androidFacet = null;
+
+ for (Facet facet : module.getFacets().values()) {
+ if (facet instanceof AndroidFacet) {
+ androidFacet = (AndroidFacet)facet;
+ }
+ }
+ return androidFacet;
+ }
+
+ @NotNull
+ private static String[] toPaths(@NotNull File[] files) {
+ final String[] result = new String[files.length];
+
+ for (int i = 0; i < result.length; i++) {
+ result[i] = files[i].getPath();
+ }
+ return result;
+ }
+
+ private static class MyModuleData {
+ private final File myOutputDirectory;
+ private final String mySdkLocation;
+ private final IAndroidTarget myAndroidTarget;
+
+ private MyModuleData(@NotNull File outputDirectory,
+ @NotNull String sdkLocation,
+ @NotNull IAndroidTarget androidTarget) {
+ myOutputDirectory = outputDirectory;
+ mySdkLocation = sdkLocation;
+ myAndroidTarget = androidTarget;
+ }
+
+ @NotNull
+ public File getOutputDirectory() {
+ return myOutputDirectory;
+ }
+
+ @NotNull
+ public IAndroidTarget getAndroidTarget() {
+ return myAndroidTarget;
+ }
+
+ @NotNull
+ public String getSdkLocation() {
+ return mySdkLocation;
+ }
+ }
+}
diff --git a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java
index 16e0bc1a3175..0984f0a8e9aa 100644
--- a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java
+++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidIdl.java
@@ -16,7 +16,9 @@
package org.jetbrains.android.compiler.tools;
import com.android.sdklib.IAndroidTarget;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.ArrayUtil;
+import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidCompilerMessageKind;
import org.jetbrains.android.util.ExecutionUtil;
import org.jetbrains.annotations.NotNull;
@@ -32,6 +34,8 @@ import java.util.Map;
* @author Alexey Efimov
*/
public final class AndroidIdl {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.tools.AndroidIdl");
+
private AndroidIdl() {
}
@@ -51,6 +55,8 @@ public final class AndroidIdl {
}
commands.add(file);
commands.add(outFile);
+
+ LOG.info(AndroidCommonUtils.command2string(commands));
return ExecutionUtil.doExecute(ArrayUtil.toStringArray(commands));
}
diff --git a/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java
new file mode 100644
index 000000000000..0bd16812613e
--- /dev/null
+++ b/plugins/android/rt/src/org/jetbrains/android/compiler/tools/AndroidRenderscript.java
@@ -0,0 +1,58 @@
+package org.jetbrains.android.compiler.tools;
+
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkConstants;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.android.util.AndroidCommonUtils;
+import org.jetbrains.android.util.AndroidCompilerMessageKind;
+import org.jetbrains.android.util.ExecutionUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class AndroidRenderscript {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidRenderscriptCompiler");
+
+ public static Map> execute(@NotNull final String sdkLocation,
+ @NotNull IAndroidTarget target,
+ @NotNull String sourceFilePath,
+ @NotNull final String genFolderPath,
+ @Nullable String depFolderPath,
+ @NotNull final String rawDirPath)
+ throws IOException {
+ final List command = new ArrayList();
+ command.add(
+ FileUtil.toSystemDependentName(sdkLocation + '/' + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_RENDERSCRIPT));
+ command.add("-I");
+ command.add(target.getPath(IAndroidTarget.ANDROID_RS_CLANG));
+ command.add("-I");
+ command.add(target.getPath(IAndroidTarget.ANDROID_RS));
+ command.add("-p");
+ command.add(FileUtil.toSystemDependentName(genFolderPath));
+ command.add("-o");
+ command.add(FileUtil.toSystemDependentName(rawDirPath));
+
+ command.add("-target-api");
+ command.add(Integer.toString(target.getVersion().getApiLevel()));
+
+ if (depFolderPath != null) {
+ command.add("-d");
+ command.add(FileUtil.toSystemDependentName(depFolderPath));
+ }
+
+ command.add("-MD");
+ command.add(FileUtil.toSystemDependentName(sourceFilePath));
+
+ LOG.info(AndroidCommonUtils.command2string(command));
+ return ExecutionUtil.doExecute(ArrayUtil.toStringArray(command));
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java b/plugins/android/rt/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java
similarity index 91%
rename from plugins/android/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java
rename to plugins/android/rt/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java
index 7c36b181cd6f..49e083d10236 100644
--- a/plugins/android/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java
+++ b/plugins/android/rt/src/org/jetbrains/android/sdk/MessageBuildingSdkLog.java
@@ -21,11 +21,7 @@ import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NotNull;
/**
- * Created by IntelliJ IDEA.
- * User: Eugene.Kudelevsky
- * Date: Aug 25, 2009
- * Time: 5:54:47 PM
- * To change this template use File | Settings | File Templates.
+ * @author Eugene.Kudelevsky
*/
public class MessageBuildingSdkLog implements ISdkLog {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.sdk.MessageBuildingSdkLog");
diff --git a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java
index 450687945d47..3b54dcf9532d 100644
--- a/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java
+++ b/plugins/android/rt/src/org/jetbrains/android/util/AndroidCommonUtils.java
@@ -1,8 +1,15 @@
package org.jetbrains.android.util;
+import com.android.sdklib.ISdkLog;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.SdkManager;
+import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import java.io.File;
+import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
@@ -11,7 +18,7 @@ import java.util.Iterator;
*/
public class AndroidCommonUtils {
@NonNls public static final Object MANIFEST_JAVA_FILE_NAME = "Manifest.java";
- public static final String R_JAVA_FILENAME = "R.java";
+ @NonNls public static final String R_JAVA_FILENAME = "R.java";
private AndroidCommonUtils() {
}
@@ -29,4 +36,37 @@ public class AndroidCommonUtils {
}
return builder.toString();
}
+
+ @Nullable
+ public static SdkManager createSdkManager(@NotNull String path, @NotNull ISdkLog log) {
+ path = FileUtil.toSystemDependentName(path);
+
+ final File f = new File(path);
+ if (!f.exists() || !f.isDirectory()) {
+ return null;
+ }
+
+ final File platformsDir = new File(f, SdkConstants.FD_PLATFORMS);
+ if (!platformsDir.exists() || !platformsDir.isDirectory()) {
+ return null;
+ }
+
+ return SdkManager.createManager(path + File.separatorChar, log);
+ }
+
+ public static void moveAllFiles(@NotNull File from, @NotNull File to, @NotNull Collection newFiles) throws IOException {
+ if (from.isFile()) {
+ FileUtil.rename(from, to);
+ newFiles.add(to);
+ }
+ else {
+ final File[] children = from.listFiles();
+
+ if (children != null) {
+ for (File child : children) {
+ moveAllFiles(child, new File(to, child.getName()), newFiles);
+ }
+ }
+ }
+ }
}
diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml
index e6e625de60e8..67a616094d46 100644
--- a/plugins/android/src/META-INF/plugin.xml
+++ b/plugins/android/src/META-INF/plugin.xml
@@ -189,6 +189,12 @@
+
+
+
+
+
+
diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java
index 5121f6a31a6f..54802f56a12e 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java
@@ -20,6 +20,7 @@ import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.compiler.tools.AndroidApt;
import org.jetbrains.android.compiler.tools.AndroidIdl;
+import org.jetbrains.android.compiler.tools.AndroidRenderscript;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
@@ -448,13 +449,19 @@ public class AndroidAutogenerator {
try {
tempOutDir = FileUtil.createTempDirectory("android_renderscript_autogeneration", "tmp");
+ final VirtualFile vTempOutDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempOutDir);
- final Map> messages = AndroidRenderscriptCompiler.
- launchRenderscriptCompiler(module.getProject(), item.mySdkLocation, item.myTarget, file, tempOutDir.getPath(), item.myRawDirPath);
+ final String depFolderPath =
+ vTempOutDir != null ? AndroidRenderscriptCompiler.getDependencyFolder(context.getProject(), file, vTempOutDir) : null;
+
+ final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys(
+ AndroidRenderscript
+ .execute(item.mySdkLocation, item.myTarget, file.getPath(), tempOutDir.getPath(), depFolderPath,
+ item.myRawDirPath));
if (messages.get(CompilerMessageCategory.ERROR).size() == 0) {
final List newFiles = new ArrayList();
- moveAllFiles(tempOutDir, new File(item.myGenDirPath), newFiles);
+ AndroidCommonUtils.moveAllFiles(tempOutDir, new File(item.myGenDirPath), newFiles);
for (File newFile : newFiles) {
final VirtualFile newVFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(newFile);
@@ -502,22 +509,6 @@ public class AndroidAutogenerator {
}
}
- private static void moveAllFiles(@NotNull File from, @NotNull File to, @NotNull Collection newFiles) throws IOException {
- if (from.isFile()) {
- FileUtil.rename(from, to);
- newFiles.add(to);
- }
- else {
- final File[] children = from.listFiles();
-
- if (children != null) {
- for (File child : children) {
- moveAllFiles(child, new File(to, child.getName()), newFiles);
- }
- }
- }
- }
-
private static boolean ensureFilesWritable(@NotNull final Project project, @NotNull final Collection filesToCheck) {
if (filesToCheck.size() == 0) {
return true;
diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java
index 9dff00c3448f..d6cbc490baad 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidRenderscriptCompiler.java
@@ -2,31 +2,26 @@ package org.jetbrains.android.compiler;
import com.android.AndroidConstants;
import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.SdkConstants;
import com.intellij.facet.FacetManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.compiler.ex.CompileContextEx;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
+import org.jetbrains.android.compiler.tools.AndroidRenderscript;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
import org.jetbrains.android.sdk.AndroidPlatform;
-import org.jetbrains.android.util.AndroidBundle;
-import org.jetbrains.android.util.AndroidCommonUtils;
-import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.android.util.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,8 +35,7 @@ import java.util.*;
* @author Eugene.Kudelevsky
*/
public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler {
- private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidRenderscriptCompiler");
-
+
private static final GenerationItem[] EMPTY_GENERATION_ITEM_ARRAY = {};
@Nullable
@@ -190,13 +184,15 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler {
}
for (final VirtualFile sourceFile : genItem.myFiles) {
+ final String depFolderOsPath = getDependencyFolder(context.getProject(), sourceFile, outputRootDirectory);
+
try {
- final Map> messages = launchRenderscriptCompiler(context.getProject(),
- genItem.mySdkLocation,
- genItem.myAndroidTarget,
- sourceFile,
- genRootPath,
- genItem.myRawDirPath);
+ final Map> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys(
+ AndroidRenderscript
+ .execute(genItem.mySdkLocation, genItem.myAndroidTarget, sourceFile.getPath(), genRootPath,
+ depFolderOsPath,
+ genItem.myRawDirPath));
+
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
if (context.getProject().isDisposed()) {
@@ -235,47 +231,10 @@ public class AndroidRenderscriptCompiler implements SourceGeneratingCompiler {
}
}
- static Map> launchRenderscriptCompiler(@NotNull Project project,
- @NotNull final String sdkLocation,
- @NotNull IAndroidTarget target,
- @NotNull final VirtualFile sourceFile,
- @NotNull final String genFolderPath,
- @NotNull final String rawDirPath)
- throws IOException {
- final List command = new ArrayList();
- command.add(
- FileUtil.toSystemDependentName(sdkLocation + '/' + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_RENDERSCRIPT));
- command.add("-I");
- command.add(target.getPath(IAndroidTarget.ANDROID_RS_CLANG));
- command.add("-I");
- command.add(target.getPath(IAndroidTarget.ANDROID_RS));
- command.add("-p");
- command.add(FileUtil.toSystemDependentName(genFolderPath));
- command.add("-o");
- command.add(FileUtil.toSystemDependentName(rawDirPath));
-
- final String sourceFilePath = FileUtil.toSystemDependentName(sourceFile.getPath());
-
- final VirtualFile genFolder = LocalFileSystem.getInstance().refreshAndFindFileByPath(FileUtil.toSystemIndependentName(genFolderPath));
- if (genFolder != null) {
- final String dependencyFolderPath = getDependencyFolder(project, sourceFile, genFolder);
- if (dependencyFolderPath != null) {
- command.add("-d");
- command.add(FileUtil.toSystemDependentName(dependencyFolderPath));
- }
- }
-
- command.add("-MD");
- command.add(sourceFilePath);
-
- LOG.info(AndroidCommonUtils.command2string(command));
- return AndroidCompileUtil.execute(ArrayUtil.toStringArray(command));
- }
-
@Nullable
- private static String getDependencyFolder(@NotNull final Project project,
- @NotNull final VirtualFile sourceFile,
- @NotNull final VirtualFile genFolder) {
+ static String getDependencyFolder(@NotNull final Project project,
+ @NotNull final VirtualFile sourceFile,
+ @NotNull final VirtualFile genFolder) {
final ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex();
final VirtualFile sourceRoot = index.getSourceRootForFile(sourceFile);
diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java
index 877dc802f84c..78cd3fbf1871 100644
--- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java
+++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java
@@ -33,6 +33,7 @@ import com.intellij.reference.SoftReference;
import com.intellij.util.containers.HashMap;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.android.actions.AndroidEnableDdmsAction;
+import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.android.util.BufferingFileWrapper;
import org.jetbrains.annotations.NotNull;
@@ -152,7 +153,7 @@ public class AndroidSdk {
@Nullable
public static AndroidSdk parse(@NotNull String path, @NotNull ISdkLog log) {
- final SdkManager manager = AndroidSdkUtils.createSdkManager(path, log);
+ final SdkManager manager = AndroidCommonUtils.createSdkManager(path, log);
return manager != null ? new AndroidSdk(manager, path) : null;
}
diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java
index 766e05545306..1536eac0a5e8 100644
--- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java
+++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdkUtils.java
@@ -17,9 +17,7 @@
package org.jetbrains.android.sdk;
import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
-import com.android.sdklib.SdkManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
@@ -36,12 +34,12 @@ import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.HashSet;
+import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.File;
import java.util.*;
/**
@@ -55,7 +53,7 @@ public class AndroidSdkUtils {
}
public static boolean isAndroidSdk(@NotNull String path) {
- return createSdkManager(path, new EmptySdkLog()) != null;
+ return AndroidCommonUtils.createSdkManager(path, new EmptySdkLog()) != null;
}
@Nullable
@@ -370,21 +368,4 @@ public class AndroidSdkUtils {
public static void openModuleDependenciesConfigurable(final Module module) {
ProjectSettingsService.getInstance(module.getProject()).openModuleDependenciesSettings(module, null);
}
-
- @Nullable
- public static SdkManager createSdkManager(@NotNull String path, @NotNull ISdkLog log) {
- path = FileUtil.toSystemDependentName(path);
-
- final File f = new File(path);
- if (!f.exists() || !f.isDirectory()) {
- return null;
- }
-
- final File platformsDir = new File(f, SdkConstants.FD_PLATFORMS);
- if (!platformsDir.exists() || !platformsDir.isDirectory()) {
- return null;
- }
-
- return SdkManager.createManager(path + File.separatorChar, log);
- }
}
diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml
index ff4374eb52a2..df0d5da1f7de 100644
--- a/plugins/gradle/src/META-INF/plugin.xml
+++ b/plugins/gradle/src/META-INF/plugin.xml
@@ -49,6 +49,7 @@
+
org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper
+
+ org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesDetector
+
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java
index bbd49d974a04..701da05b145b 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java
@@ -2,6 +2,7 @@ package org.jetbrains.plugins.gradle.action;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,13 +22,13 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction {
@Override
public void update(AnActionEvent e) {
- final String path = getLinkedProjectPath(e.getDataContext());
- final boolean visible = path != null;
+ final Pair pair = deriveProjects(e.getDataContext());
+ final boolean visible = pair != null;
e.getPresentation().setVisible(visible);
if (!visible) {
return;
}
- doUpdate(e.getPresentation(), path);
+ doUpdate(e.getPresentation(), pair.first, pair.second);
}
@Override
@@ -36,16 +37,16 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction {
if (project == null) {
return;
}
- final String path = getLinkedProjectPath(e.getDataContext());
- if (path == null) {
+ final Pair pair = deriveProjects(e.getDataContext());
+ if (pair == null) {
e.getPresentation().setVisible(false);
return;
}
- doActionPerformed(project, path);
+ doActionPerformed(project, pair.second);
}
@Nullable
- protected static String getLinkedProjectPath(@Nullable DataContext context) {
+ private static Pair deriveProjects(@Nullable DataContext context) {
if (context == null) {
return null;
}
@@ -56,9 +57,12 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction {
}
final String path = GradleSettings.getInstance(project).LINKED_PROJECT_FILE_PATH;
- return (StringUtil.isEmpty(path) || !new File(path).isFile()) ? null : path;
+ if (StringUtil.isEmpty(path) || !new File(path).isFile()) {
+ return null;
+ }
+ return new Pair(project, path);
}
- protected abstract void doUpdate(@NotNull Presentation presentation, @NotNull String linkedProjectPath);
+ protected abstract void doUpdate(@NotNull Presentation presentation, @NotNull Project project, @NotNull String linkedProjectPath);
protected abstract void doActionPerformed(@NotNull Project project, @NotNull String linkedProjectPath);
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleOpenScriptAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleOpenScriptAction.java
index f010e59ebde8..79f35b14803a 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleOpenScriptAction.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleOpenScriptAction.java
@@ -1,7 +1,5 @@
package org.jetbrains.plugins.gradle.action;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
@@ -32,7 +30,7 @@ public class GradleOpenScriptAction extends AbstractGradleLinkedProjectAction im
}
@Override
- protected void doUpdate(@NotNull Presentation presentation, @NotNull String linkedProjectPath) {
+ protected void doUpdate(@NotNull Presentation presentation, @NotNull Project project, @NotNull String linkedProjectPath) {
}
@Override
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleRefreshProjectAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleRefreshProjectAction.java
index 17fa3a0fbc4e..087e1706733b 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleRefreshProjectAction.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleRefreshProjectAction.java
@@ -1,17 +1,16 @@
package org.jetbrains.plugins.gradle.action;
+import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.config.GradleSettings;
-import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
+import org.jetbrains.plugins.gradle.task.GradleTaskManager;
+import org.jetbrains.plugins.gradle.task.GradleTaskType;
import org.jetbrains.plugins.gradle.util.GradleBundle;
-
-import java.util.concurrent.atomic.AtomicBoolean;
+import org.jetbrains.plugins.gradle.util.GradleUtil;
/**
* Forces the 'gradle' plugin to retrieve the most up-to-date info about the
@@ -21,34 +20,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @author Denis Zhdanov
* @since 1/23/12 3:48 PM
*/
-public class GradleRefreshProjectAction extends AbstractGradleLinkedProjectAction implements DumbAware {
+public class GradleRefreshProjectAction extends AbstractGradleLinkedProjectAction implements DumbAware, AnAction.TransparentUpdate {
- private final AtomicBoolean myInProgress = new AtomicBoolean();
-
public GradleRefreshProjectAction() {
getTemplatePresentation().setText(GradleBundle.message("gradle.action.refresh.project.text"));
getTemplatePresentation().setDescription(GradleBundle.message("gradle.action.refresh.project.description"));
}
@Override
- protected void doUpdate(@NotNull Presentation presentation, @NotNull String linkedProjectPath) {
- presentation.setEnabled(!myInProgress.get());
+ protected void doUpdate(@NotNull Presentation presentation, @NotNull Project project, @NotNull String linkedProjectPath) {
+ boolean enabled = false;
+ final GradleTaskManager taskManager = ServiceManager.getService(GradleTaskManager.class);
+ if (taskManager != null) {
+ enabled = !taskManager.hasTaskOfTypeInProgress(GradleTaskType.RESOLVE_PROJECT);
+ }
+ presentation.setEnabled(enabled);
}
@Override
protected void doActionPerformed(@NotNull final Project project, @NotNull final String linkedProjectPath) {
- myInProgress.set(true);
- ProgressManager.getInstance().run(new Task.Backgroundable(project, GradleBundle.message("gradle.sync.progress.text")) {
- @Override
- public void run(@NotNull final ProgressIndicator indicator) {
- try {
- GradleResolveProjectTask task = new GradleResolveProjectTask(project, linkedProjectPath, true);
- task.execute(indicator);
- }
- finally {
- myInProgress.set(false);
- }
- }
- });
+ GradleUtil.refreshProject(project);
}
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java
index d8a5a8d4a29c..760166cb0194 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java
@@ -1,14 +1,10 @@
package org.jetbrains.plugins.gradle.importing;
-import com.intellij.execution.rmi.RemoteUtil;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.projectWizard.WizardContext;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.JavaSdk;
@@ -17,7 +13,6 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.packaging.artifacts.ModifiableArtifactModel;
import com.intellij.projectImport.ProjectImportBuilder;
import org.jetbrains.annotations.NotNull;
@@ -26,11 +21,9 @@ import org.jetbrains.plugins.gradle.config.GradleSettings;
import org.jetbrains.plugins.gradle.model.GradleEntity;
import org.jetbrains.plugins.gradle.model.GradleModule;
import org.jetbrains.plugins.gradle.model.GradleProject;
-import org.jetbrains.plugins.gradle.remote.GradleApiException;
-import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
import org.jetbrains.plugins.gradle.ui.GradleIcons;
import org.jetbrains.plugins.gradle.util.GradleBundle;
-import org.jetbrains.plugins.gradle.util.GradleLog;
+import org.jetbrains.plugins.gradle.util.GradleUtil;
import javax.swing.*;
import java.io.File;
@@ -156,38 +149,7 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder errorReason = new Ref();
try {
final Project project = getProject(wizardContext);
- ProgressManager.getInstance().run(new Task.Modal(project, GradleBundle.message("gradle.import.progress.text"), true) {
- @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
- @Override
- public void run(@NotNull final ProgressIndicator indicator) {
- GradleResolveProjectTask task = new GradleResolveProjectTask(project, myProjectFile.getAbsolutePath(), false);
- task.execute(indicator);
- myGradleProject = task.getProject();
- if (myGradleProject != null) {
- return;
- }
- final Throwable error = task.getError();
- if (error == null) {
- return;
- }
- Throwable unwrapped = RemoteUtil.unwrap(error);
- String reason = unwrapped.getLocalizedMessage();
- if (!StringUtil.isEmpty(reason)) {
- errorReason.set(reason);
- }
- if (unwrapped.getClass() == NoClassDefFoundError.class) {
- errorReason.set(GradleBundle.message("gradle.import.text.incomplete.tooling.api"));
- }
- else if (unwrapped.getClass() == GradleApiException.class) {
- GradleLog.LOG.warn("Can't resolve gradle project. Reason: gradle api threw an exception:\n"
- + ((GradleApiException)unwrapped).getOriginalReason()
- );
- }
- else {
- GradleLog.LOG.warn("Can't resolve gradle project", unwrapped);
- }
- }
- });
+ myGradleProject = GradleUtil.refreshProject(project, myProjectFile.getAbsolutePath(), errorReason, false, true);
}
catch (IllegalArgumentException e) {
throw new ConfigurationException(e.getMessage(), GradleBundle.message("gradle.import.text.error.cannot.parse.project"));
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManager.java
index 7c134a94f968..a048f1cead9f 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManager.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManager.java
@@ -9,6 +9,15 @@ import org.jetbrains.plugins.gradle.task.GradleTaskId;
*/
public interface GradleProgressNotificationManager {
+ /**
+ * Allows to register given listener to listen events from all tasks.
+ *
+ * @param listener listener to register
+ * @return true if given listener was not registered before for the given key;
+ * false otherwise
+ */
+ boolean addNotificationListener(@NotNull GradleTaskNotificationListener listener);
+
/**
* Allows to register given listener within the current manager for listening events from the task with the target id.
*
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManagerImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManagerImpl.java
index 80787d206f06..0eb9d5570ce4 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManagerImpl.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleProgressNotificationManagerImpl.java
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.remote.RemoteGradleProgressNotificationManager;
import org.jetbrains.plugins.gradle.task.GradleTaskId;
+import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
@@ -19,9 +20,15 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
implements GradleProgressNotificationManager, RemoteGradleProgressNotificationManager
{
- private final ConcurrentMap> myListeners
+ private final ConcurrentMap/* EMPTY_SET as a sign of 'all ids' */> myListeners
= new ConcurrentHashMap>();
+ @Override
+ public boolean addNotificationListener(@NotNull GradleTaskNotificationListener listener) {
+ Set dummy = Collections.emptySet();
+ return myListeners.put(listener, dummy) == null;
+ }
+
@Override
public boolean addNotificationListener(@NotNull GradleTaskId taskId, @NotNull GradleTaskNotificationListener listener) {
Set ids = null;
@@ -41,10 +48,22 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
return myListeners.remove(listener) != null;
}
+ @Override
+ public void onQueued(@NotNull GradleTaskId id) {
+ for (Map.Entry> entry : myListeners.entrySet()) {
+ final Set ids = entry.getValue();
+ if (Collections.EMPTY_SET == ids || ids.contains(id)) {
+ entry.getKey().onQueued(id);
+ }
+ }
+
+ }
+
@Override
public void onStart(@NotNull GradleTaskId id) {
for (Map.Entry> entry : myListeners.entrySet()) {
- if (entry.getValue().contains(id)) {
+ final Set ids = entry.getValue();
+ if (Collections.EMPTY_SET == ids || ids.contains(id)) {
entry.getKey().onStart(id);
}
}
@@ -53,7 +72,8 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
@Override
public void onStatusChange(@NotNull GradleTaskNotificationEvent event) {
for (Map.Entry> entry : myListeners.entrySet()) {
- if (entry.getValue().contains(event.getId())) {
+ final Set ids = entry.getValue();
+ if (Collections.EMPTY_SET == ids || ids.contains(event.getId())) {
entry.getKey().onStatusChange(event);
}
}
@@ -62,7 +82,8 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
@Override
public void onEnd(@NotNull GradleTaskId id) {
for (Map.Entry> entry : myListeners.entrySet()) {
- if (entry.getValue().contains(id)) {
+ final Set ids = entry.getValue();
+ if (Collections.EMPTY_SET == ids || ids.contains(id)) {
entry.getKey().onEnd(id);
}
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListener.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListener.java
index 1b4bda67e8ec..ba4a73fee1fa 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListener.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListener.java
@@ -11,6 +11,16 @@ import org.jetbrains.plugins.gradle.task.GradleTaskId;
*/
public interface GradleTaskNotificationListener {
+ /**
+ * Notifies that task with the given id is queued for the execution.
+ *
+ * 'Queued' here means that intellij process-local codebase receives request to execute the target task and even has not been
+ * sent it to the slave gradle api process.
+ *
+ * @param id target task's id
+ */
+ void onQueued(@NotNull GradleTaskId id);
+
/**
* Notifies that task with the given id is about to be started.
*
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListenerAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListenerAdapter.java
index a5ff4965a90d..c2ee8ee511b9 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListenerAdapter.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/notification/GradleTaskNotificationListenerAdapter.java
@@ -8,6 +8,11 @@ import org.jetbrains.plugins.gradle.task.GradleTaskId;
* @since 11/10/11 12:18 PM
*/
public class GradleTaskNotificationListenerAdapter implements GradleTaskNotificationListener {
+
+ @Override
+ public void onQueued(@NotNull GradleTaskId id) {
+ }
+
@Override
public void onStart(@NotNull GradleTaskId id) {
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java
index d2d5dc0e3072..2955f9e3961c 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java
@@ -1,12 +1,10 @@
package org.jetbrains.plugins.gradle.remote;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.plugins.gradle.task.GradleTaskId;
-import org.jetbrains.plugins.gradle.task.GradleTaskType;
+import org.jetbrains.plugins.gradle.task.GradleTaskAware;
import java.rmi.Remote;
import java.rmi.RemoteException;
-import java.util.Collection;
/**
* Serves as a facade for working with
@@ -18,7 +16,7 @@ import java.util.Collection;
* @author Denis Zhdanov
* @since 8/8/11 10:52 AM
*/
-public interface GradleApiFacade extends Remote {
+public interface GradleApiFacade extends Remote, GradleTaskAware {
/**
* Exposes 'resolve gradle project' service that works at another process.
@@ -45,23 +43,4 @@ public interface GradleApiFacade extends Remote {
* @throws RemoteException in case of unexpected I/O exception during processing
*/
void applyProgressManager(@NotNull RemoteGradleProgressNotificationManager progressManager) throws RemoteException;
-
- /**
- * Asks remote gradle process to check if a task with the given id is being executed right now.
- *
- * @param id target task's id
- * @return true if a task with the given id is executed at the moment; false otherwise
- * @throws RemoteException in case of unexpected I/O exception during processing
- */
- boolean isTaskInProgress(@NotNull GradleTaskId id) throws RemoteException;
-
- /**
- * Allows to ask remote gradle process for the ids of the tasks with the given type being executed now.
- *
- * @param type target task type
- * @return ids of the tasks of the target type being executed at the moment (if any)
- * @throws RemoteException in case of unexpected I/O exception during processing
- */
- @NotNull
- Collection getTasksInProgress(@NotNull GradleTaskType type) throws RemoteException;
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java
index 02a42690d19f..8972c627d369 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java
@@ -31,7 +31,9 @@ import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManager;
+import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManagerImpl;
import org.jetbrains.plugins.gradle.remote.impl.GradleApiFacadeImpl;
+import org.jetbrains.plugins.gradle.remote.wrapper.GradleApiFacadeWrapper;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleLibraryManager;
import org.jetbrains.plugins.gradle.util.GradleLog;
@@ -69,8 +71,8 @@ public class GradleApiFacadeManager {
private final AtomicReference myExportedProgressManager
= new AtomicReference();
- private final GradleLibraryManager myGradleLibraryManager;
- private final RemoteGradleProgressNotificationManager myProgressManager;
+ @NotNull private final GradleLibraryManager myGradleLibraryManager;
+ @NotNull private final GradleProgressNotificationManagerImpl myProgressManager;
// Please note that we don't use RemoteGradleProcessSettings as the 'Configuration' type parameter here because we need
// to apply the settings to the newly created process. I.e. every time new process is created we need to call
@@ -80,7 +82,7 @@ public class GradleApiFacadeManager {
public GradleApiFacadeManager(@NotNull GradleLibraryManager gradleLibraryManager, @NotNull GradleProgressNotificationManager manager) {
myGradleLibraryManager = gradleLibraryManager;
- myProgressManager = (RemoteGradleProgressNotificationManager)manager;
+ myProgressManager = (GradleProgressNotificationManagerImpl)manager;
mySupport = new RemoteProcessSupport