Merge remote branch 'origin/master'

This commit is contained in:
irengrig
2012-12-06 17:55:04 +04:00
34 changed files with 662 additions and 1198 deletions
@@ -476,14 +476,20 @@ public class JavaBuilder extends ModuleLevelBuilder {
return cached;
}
public static List<String> getCompilationOptions(CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) {
private static List<String> getCompilationOptions(CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) {
List<String> cached = JAVAC_OPTIONS.get(context);
if (cached == null) {
loadCommonJavacOptions(context);
cached = JAVAC_OPTIONS.get(context);
assert cached != null : context;
}
final List<String> options = new ArrayList<String>(cached);
List<String> options = new ArrayList<String>(cached);
addCompilationOptions(options, context, chunk, profile);
return options;
}
public static void addCompilationOptions(List<String> options, CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) {
if (!isEncodingSet(options)) {
final CompilerEncodingConfiguration config = context.getProjectDescriptor().getEncodingConfiguration();
final String encoding = config.getPreferredModuleChunkEncoding(chunk);
@@ -574,8 +580,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
else {
options.add("-proc:none");
}
return options;
}
private static String getLanguageLevel(JpsModule module) {
@@ -20,7 +20,7 @@ import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.CommitExecutor;
import com.intellij.openapi.vcs.changes.CommitResultHandler;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsHistoryProvider;
@@ -185,10 +185,22 @@ public class MockVcsHelper extends AbstractVcsHelper {
}
@Override
public boolean commitChanges(@NotNull List<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitExecutor executor) {
public boolean commitChanges(@NotNull Collection<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) {
if (myCommitHandler != null) {
return myCommitHandler.commit(commitMessage);
boolean success = myCommitHandler.commit(commitMessage);
if (customResultHandler != null) {
if (success) {
customResultHandler.onSuccess(commitMessage);
}
else {
customResultHandler.onFailure();
}
}
return success;
}
if (customResultHandler != null) {
customResultHandler.onFailure();
}
return false;
}
@@ -18,6 +18,7 @@ package com.intellij.testFramework.vcs;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -79,6 +80,12 @@ public class MockChangeList extends LocalChangeList {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Object getData() {
throw new UnsupportedOperationException();
}
@Override
public LocalChangeList copy() {
throw new UnsupportedOperationException();
@@ -365,4 +365,8 @@ public class MockChangeListManager extends ChangeListManagerEx {
public void freezeImmediately(@Nullable String reason) {
}
@Override
public LocalChangeList addChangeList(@NotNull String name, @Nullable String comment, @Nullable Object data) {
return addChangeList(name, comment);
}
}
@@ -21,7 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.CommitExecutor;
import com.intellij.openapi.vcs.changes.CommitResultHandler;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsHistoryProvider;
@@ -167,11 +167,11 @@ public abstract class AbstractVcsHelper {
/**
* Shows commit dialog, fills it with the given changes and given commit message, initially selects the given changelist.
* @return true if user commits the changes, and commit succeeds; false if user presses Cancel or commit fails with errors.
* <p>Shows commit dialog, fills it with the given changes and given commit message, initially selects the given changelist.</p>
* <p>Note that the method is asynchronous: it returns right after user presses "Commit" or "Cancel" and after all pre-commit handlers
* have been called. It doesn't wait for commit itself to succeed or fail - for this use the {@code customResultHandler}.</p>
* @return true if user decides to commit the changes, false if user presses Cancel.
*/
public abstract boolean commitChanges(@NotNull List<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitExecutor executor);
public abstract boolean commitChanges(@NotNull Collection<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler);
}
@@ -0,0 +1,35 @@
/*
* 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.vcs.changes;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* CommitResultHandler may be passed to {@link AbstractVcsHelper#commitChanges(Collection, LocalChangeList, String, CommitResultHandler)}.
* It is called after commit is performed: successful or failed.
*
* @author Kirill Likhodedov
*/
public interface CommitResultHandler {
void onSuccess(@NotNull String commitMessage);
void onFailure();
}
@@ -63,6 +63,12 @@ public abstract class LocalChangeList implements Cloneable, ChangeList {
public abstract void setReadOnly(boolean isReadOnly);
/**
* Get additional data associated with this changelist.
*/
@Nullable
public abstract Object getData();
public abstract LocalChangeList copy();
public boolean hasDefaultName() {
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.vcs.changes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
@@ -31,4 +32,6 @@ public abstract class ChangeListManagerEx extends ChangeListManager {
public abstract void freezeImmediately(@Nullable String reason);
public abstract LocalChangeList addChangeList(@NotNull String name, @Nullable final String comment, @Nullable Object data);
}
@@ -230,7 +230,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
public void run() {
synchronized (myDataLock) {
if (myWorker.isEmpty()) {
final LocalChangeList list = myWorker.addChangeList(VcsBundle.message("changes.default.changlist.name"), null);
final LocalChangeList list = myWorker.addChangeList(VcsBundle.message("changes.default.changlist.name"), null, null);
setDefaultChangeList(list);
if (myIgnoredIdeaLevel.isEmpty()) {
@@ -829,11 +829,16 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
}
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String comment) {
return addChangeList(name, comment, null);
}
@Override
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String comment, @Nullable final Object data) {
return ApplicationManager.getApplication().runReadAction(new Computable<LocalChangeList>() {
@Override
public LocalChangeList compute() {
synchronized (myDataLock) {
final LocalChangeList changeList = myModifier.addChangeList(name, comment);
final LocalChangeList changeList = myModifier.addChangeList(name, comment, data);
myChangesViewManager.scheduleRefresh();
return changeList;
}
@@ -841,6 +846,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
});
}
public void removeChangeList(final String name) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
@@ -1158,7 +1164,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
private boolean doCommit(final LocalChangeList changeList, final List<Change> changes, final boolean synchronously) {
return new CommitHelper(myProject, changeList, changes, changeList.getName(),
changeList.getComment(), new ArrayList<CheckinHandler>(), false, synchronously, NullableFunction.NULL).doCommit();
changeList.getComment(), new ArrayList<CheckinHandler>(), false, synchronously, NullableFunction.NULL, null).doCommit();
}
public void commitChangesSynchronously(LocalChangeList changeList, List<Change> changes) {
@@ -70,7 +70,8 @@ class ChangeListManagerSerialization {
final String changeListName = listNode.getAttributeValue(ATT_NAME);
LocalChangeList list = myWorker.getCopyByName(changeListName);
if (list == null) {
list = myWorker.addChangeList(listNode.getAttributeValue(ATT_ID), changeListName, listNode.getAttributeValue(ATT_COMMENT), false);
list = myWorker.addChangeList(listNode.getAttributeValue(ATT_ID), changeListName, listNode.getAttributeValue(ATT_COMMENT), false,
null);
}
//noinspection unchecked
final List<Element> changeNodes = (List<Element>)listNode.getChildren(NODE_CHANGE);
@@ -198,14 +198,16 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
return list != null;
}
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String description) {
return addChangeList(null, name, description, false);
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String comment, @Nullable Object data) {
return addChangeList(null, name, comment, false, data);
}
LocalChangeList addChangeList(String id, @NotNull final String name, @Nullable final String description, final boolean inUpdate) {
LocalChangeList addChangeList(String id, @NotNull final String name, @Nullable final String description, final boolean inUpdate,
@Nullable Object data) {
final boolean contains = myMap.containsKey(name);
LOG.assertTrue(! contains, "Attempt to create duplicate changelist " + name);
final LocalChangeListImpl newList = (LocalChangeListImpl) LocalChangeList.createEmptyChangeList(myProject, name);
newList.setData(data);
if (description != null) {
newList.setCommentImpl(description);
@@ -751,7 +753,7 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
}
public LocalChangeList addChangeList(final String name, final String comment) {
return myWorker.addChangeList(null, name, comment, true);
return myWorker.addChangeList(null, name, comment, true, null);
}
public LocalChangeList findOrCreateList(final String name, final String comment) {
@@ -23,7 +23,7 @@ public interface ChangeListsWriteOperations {
@Nullable
String setDefault(String name);
boolean setReadOnly(String name, boolean value);
LocalChangeList addChangeList(@NotNull String name, @Nullable String description);
LocalChangeList addChangeList(@NotNull String name, @Nullable String comment, @Nullable Object data);
boolean removeChangeList(@NotNull String name);
@Nullable
MultiMap<LocalChangeList, Change> moveChangesTo(String name, Change[] changes);
@@ -29,6 +29,7 @@ public class LocalChangeListImpl extends LocalChangeList {
private String myId;
@NotNull private String myName;
private String myComment = "";
@Nullable private Object myData;
private boolean myIsDefault = false;
private boolean myIsReadOnly = false;
@@ -116,6 +117,16 @@ public class LocalChangeListImpl extends LocalChangeList {
myIsReadOnly = isReadOnly;
}
void setData(@Nullable Object data) {
myData = data;
}
@Nullable
@Override
public Object getData() {
return myData;
}
void addChange(Change change) {
if (ChangeListManagerImpl.DEBUG) {
ChangeListManagerImpl.log("LocalChangeListImpl.addChange: this = " + this + ", change = " + change);
@@ -260,6 +271,7 @@ public class LocalChangeListImpl extends LocalChangeList {
copy.myComment = myComment;
copy.myIsDefault = myIsDefault;
copy.myIsReadOnly = myIsReadOnly;
copy.myData = myData;
if (myChanges != null) {
copy.myChanges = new HashSet<Change>(myChanges);
@@ -39,8 +39,8 @@ public class Modifier implements ChangeListsWriteOperations {
myCommandQueue = new LinkedList<ChangeListCommand>();
}
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String comment) {
final AddList command = new AddList(name, comment);
public LocalChangeList addChangeList(@NotNull final String name, @Nullable final String comment, @Nullable Object data) {
final AddList command = new AddList(name, comment, data);
impl(command);
return command.getNewListCopy();
}
@@ -25,17 +25,19 @@ import org.jetbrains.annotations.Nullable;
public class AddList implements ChangeListCommand {
@NotNull private final String myName;
@Nullable private final String myComment;
@Nullable private final Object myData;
private LocalChangeList myNewListCopy;
public AddList(@NotNull final String name, @Nullable final String comment) {
public AddList(@NotNull final String name, @Nullable final String comment, @Nullable Object data) {
myName = name;
myComment = comment;
myData = data;
}
public void apply(final ChangeListWorker worker) {
if (! worker.findListByName(myName)) {
myNewListCopy = worker.addChangeList(myName, myComment);
myNewListCopy = worker.addChangeList(myName, myComment, myData);
} else {
worker.editComment(myName, myComment);
myNewListCopy = worker.getCopyByName(myName);
@@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes.ui;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
@@ -67,6 +68,12 @@ public class AlienLocalChangeList extends LocalChangeList {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Object getData() {
throw new UnsupportedOperationException();
}
public LocalChangeList copy() {
throw new UnsupportedOperationException();
}
@@ -111,6 +111,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
private final ZipperUpdater myZipperUpdater;
private final Runnable myRefreshDetails;
private CommitAction myCommitAction;
@Nullable private CommitResultHandler myResultHandler;
private static class MyUpdateButtonsRunnable implements Runnable {
private CommitChangeListDialog myDialog;
@@ -139,7 +140,8 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
private final MyUpdateButtonsRunnable myUpdateButtonsRunnable = new MyUpdateButtonsRunnable(this);
private static boolean commit(final Project project, final List<Change> changes, final LocalChangeList initialSelection,
final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment) {
final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment,
@Nullable CommitResultHandler customResultHandler) {
final AbstractVcs[] allActiveVcss = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss();
final List<VcsCheckinHandlerFactory> factoryList =
CheckinHandlersManager.getInstance().getMatchingVcsFactories(Arrays.<AbstractVcs>asList(allActiveVcss));
@@ -155,7 +157,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
final ArrayList<LocalChangeList> changeLists = new ArrayList<LocalChangeList>(manager.getChangeListsCopy());
CommitChangeListDialog dialog =
new CommitChangeListDialog(project, changes, initialSelection, executors, showVcsCommit, defaultList, changeLists, null, false,
comment);
comment, customResultHandler);
if (!ApplicationManager.getApplication().isUnitTestMode()) {
dialog.show();
}
@@ -179,10 +181,10 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
public static boolean commitChanges(final Project project, final Collection<Change> changes, final LocalChangeList initialSelection,
@Nullable final CommitExecutor executor, final String comment) {
if (executor == null) {
return commitChanges(project, changes, initialSelection, collectExecutors(project, changes), true, comment);
return commitChanges(project, changes, initialSelection, collectExecutors(project, changes), true, comment, null);
}
else {
return commitChanges(project, changes, initialSelection, Collections.singletonList(executor), false, comment);
return commitChanges(project, changes, initialSelection, Collections.singletonList(executor), false, comment, null);
}
}
@@ -197,22 +199,29 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
return result;
}
/**
* Shows the commit dialog, and performs the selected action: commit, commit & push, create patch, etc.
* @param customResultHandler If this is not null, after commit is completed, custom result handler is called instead of
* showing the default notification in case of commit or failure.
* @return true if user agreed to commit, false if he pressed "Cancel".
*/
public static boolean commitChanges(final Project project, final Collection<Change> changes, final LocalChangeList initialSelection,
final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment) {
final List<CommitExecutor> executors, final boolean showVcsCommit, final String comment,
@Nullable CommitResultHandler customResultHandler) {
if (changes.isEmpty() && !ApplicationManager.getApplication().isUnitTestMode()) {
Messages.showInfoMessage(project, VcsBundle.message("commit.dialog.no.changes.detected.text") ,
VcsBundle.message("commit.dialog.no.changes.detected.title"));
return false;
}
return commit(project, new ArrayList<Change>(changes), initialSelection, executors, showVcsCommit, comment);
return commit(project, new ArrayList<Change>(changes), initialSelection, executors, showVcsCommit, comment, customResultHandler);
}
public static void commitAlienChanges(final Project project, final List<Change> changes, final AbstractVcs vcs,
final String changelistName, final String comment) {
final LocalChangeList lcl = new AlienLocalChangeList(changes, changelistName);
new CommitChangeListDialog(project, changes, null, null, true, AlienLocalChangeList.DEFAULT_ALIEN, Collections.singletonList(lcl), vcs,
true, comment).show();
true, comment, null).show();
}
private CommitChangeListDialog(final Project project,
@@ -221,13 +230,14 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
final List<CommitExecutor> executors,
final boolean showVcsCommit, final LocalChangeList defaultChangeList,
final List<LocalChangeList> changeLists, final AbstractVcs singleVcs, final boolean isAlien,
final String comment) {
final String comment, @Nullable CommitResultHandler customResultHandler) {
super(project, true);
myCommitContext = new CommitContext();
myProject = project;
myExecutors = executors;
myShowVcsCommit = showVcsCommit;
myVcs = singleVcs;
myResultHandler = customResultHandler;
myListComments = new HashMap<String, String>();
myAdditionalData = new PseudoMap<Object, Object>();
myDiffDetails = new ShortDiffDetails(myProject, new Getter<Change[]>() {
@@ -570,7 +580,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
runBeforeCommitHandlers(new Runnable() {
public void run() {
CommitChangeListDialog.super.doOKAction();
doCommit();
doCommit(myResultHandler);
}
}, null);
@@ -925,7 +935,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
super.doCancelAction();
}
private void doCommit() {
private void doCommit(@Nullable CommitResultHandler customResultHandler) {
final CommitHelper helper = new CommitHelper(
myProject,
myBrowser.getSelectedChangeList(),
@@ -933,7 +943,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
myActionName,
getCommitMessage(),
myHandlers,
myAllOfDefaultChangeListChangesIncluded, false, myAdditionalData);
myAllOfDefaultChangeListChangesIncluded, false, myAdditionalData, customResultHandler);
if (myIsAlien) {
helper.doAlienCommit(myVcs);
@@ -44,6 +44,7 @@ import com.intellij.util.NullableFunction;
import com.intellij.util.WaitForProgressToShow;
import com.intellij.util.ui.ConfirmationDialog;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -66,6 +67,7 @@ public class CommitHelper {
private final boolean myAllOfDefaultChangeListChangesIncluded;
private final boolean myForceSyncCommit;
private final NullableFunction<Object, Object> myAdditionalData;
@Nullable private final CommitResultHandler myCustomResultHandler;
private final List<Document> myCommittingDocuments = new ArrayList<Document>();
private final VcsConfiguration myConfiguration;
private final VcsDirtyScopeManager myDirtyScopeManager;
@@ -78,7 +80,8 @@ public class CommitHelper {
final String commitMessage,
final List<CheckinHandler> handlers,
final boolean allOfDefaultChangeListChangesIncluded,
final boolean synchronously, final NullableFunction<Object, Object> additionalDataHolder) {
final boolean synchronously, final NullableFunction<Object, Object> additionalDataHolder,
@Nullable CommitResultHandler customResultHandler) {
myProject = project;
myChangeList = changeList;
myIncludedChanges = includedChanges;
@@ -88,6 +91,7 @@ public class CommitHelper {
myAllOfDefaultChangeListChangesIncluded = allOfDefaultChangeListChangesIncluded;
myForceSyncCommit = synchronously;
myAdditionalData = additionalDataHolder;
myCustomResultHandler = customResultHandler;
myConfiguration = VcsConfiguration.getInstance(myProject);
myDirtyScopeManager = VcsDirtyScopeManager.getInstance(myProject);
myFeedback = new HashSet<String>();
@@ -133,8 +137,11 @@ public class CommitHelper {
@Override
public NotificationInfo notifyFinished() {
String text = reportSuccess(processor);
return new NotificationInfo("VCS Commit", "VCS Commit Finished", text, true);
if (myCustomResultHandler == null) {
String text = reportSuccess(processor);
return new NotificationInfo("VCS Commit", "VCS Commit Finished", text, true);
}
return null;
}
};
ProgressManager.getInstance().run(task);
@@ -202,14 +209,18 @@ public class CommitHelper {
processor.doBeforeRefresh();
AbstractVcsHelper.getInstance(myProject).showErrors(processor.getVcsExceptions(), myActionName);
} catch (Exception e) {
}
catch (RuntimeException e) {
LOG.error(e);
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else {
throw new RuntimeException(e);
}
} finally {
processor.myVcsExceptions.add(new VcsException(e));
throw e;
}
catch (Throwable e) {
LOG.error(e);
processor.myVcsExceptions.add(new VcsException(e));
throw new RuntimeException(e);
}
finally {
commitCompleted(processor.getVcsExceptions(), processor);
processor.customRefresh();
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
@@ -511,6 +522,9 @@ public class CommitHelper {
}
processor.afterSuccessfulCheckIn();
if (myCustomResultHandler != null) {
myCustomResultHandler.onSuccess(myCommitMessage);
}
}
else {
for (CheckinHandler handler : myHandlers) {
@@ -523,28 +537,38 @@ public class CommitHelper {
if (indicator != null) {
indicator.setText(VcsBundle.message("commit.dialog.completed.successfully"));
}
} else {
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
public void run() {
final String message;
if (errorsSize > 0 && warningsSize > 0) {
message = VcsBundle.message("message.text.commit.failed.with.errors.and.warnings");
}
else if (errorsSize > 0) {
message = VcsBundle.message("message.text.commit.failed.with.errors");
}
else {
message = VcsBundle.message("message.text.commit.finished.with.warnings");
}
//new VcsBalloonProblemNotifier(myProject, message, MessageType.ERROR).run();
Messages.showErrorDialog(message, VcsBundle.message("message.title.commit"));
if (errorsSize > 0) {
processor.afterFailedCheckIn();
}
}
}, null, myProject);
}
else {
if (myCustomResultHandler == null) {
showErrorDialogAndMoveToAnotherList(processor, errorsSize, warningsSize);
}
else {
myCustomResultHandler.onFailure();
}
}
}
private void showErrorDialogAndMoveToAnotherList(final GeneralCommitProcessor processor, final int errorsSize, final int warningsSize) {
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
public void run() {
final String message;
if (errorsSize > 0 && warningsSize > 0) {
message = VcsBundle.message("message.text.commit.failed.with.errors.and.warnings");
}
else if (errorsSize > 0) {
message = VcsBundle.message("message.text.commit.failed.with.errors");
}
else {
message = VcsBundle.message("message.text.commit.finished.with.warnings");
}
//new VcsBalloonProblemNotifier(myProject, message, MessageType.ERROR).run();
Messages.showErrorDialog(message, VcsBundle.message("message.title.commit"));
if (errorsSize > 0) {
processor.afterFailedCheckIn();
}
}
}, null, myProject);
}
public static void moveToFailedList(final ChangeList changeList,
@@ -47,10 +47,7 @@ import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.actions.AnnotateToggleAction;
import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.CommitExecutor;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.committed.*;
import com.intellij.openapi.vcs.changes.ui.*;
import com.intellij.openapi.vcs.history.*;
@@ -225,9 +222,11 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
}
@Override
public boolean commitChanges(@NotNull List<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitExecutor executor) {
return CommitChangeListDialog.commitChanges(myProject, changes, initialChangeList, executor, commitMessage);
public boolean commitChanges(@NotNull Collection<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) {
return CommitChangeListDialog.commitChanges(myProject, changes, initialChangeList,
CommitChangeListDialog.collectExecutors(myProject, changes), true, commitMessage,
customResultHandler);
}
private static void addDirectMessages(VcsErrorViewPanel vcsErrorViewPanel, List<VcsException> abstractVcsExceptions) {
@@ -1,74 +0,0 @@
/*
* Copyright 2000-2009 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 git4idea.changes;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Git change list
*/
public class GitChangeList extends LocalChangeList {
private String name;
private String comment;
private final Collection<Change> changes;
public GitChangeList(@NotNull String name, String comment, Collection<Change> changes) {
super();
setName(name);
setComment(comment);
this.changes = changes;
}
@NotNull
public String getName() {
return name;
}
public void setName(@NotNull String name) {
this.name = name;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public boolean isDefault() {
return true;
}
public boolean isReadOnly() {
return true;
}
public void setReadOnly(boolean isReadOnly) {
}
public Collection<Change> getChanges() {
return changes;
}
public LocalChangeList copy() {
return new GitChangeList(name, comment, changes);
}
}
@@ -25,10 +25,8 @@ import com.intellij.openapi.vcs.CheckinProjectPanel;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeList;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.checkin.CheckinChangeListSpecificComponent;
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
import com.intellij.openapi.vfs.VirtualFile;
@@ -49,6 +47,7 @@ import git4idea.commands.GitSimpleHandler;
import git4idea.config.GitConfigUtil;
import git4idea.config.GitVcsSettings;
import git4idea.history.NewGitUsersComponent;
import git4idea.history.browser.GitCommit;
import git4idea.i18n.GitBundle;
import git4idea.push.GitPusher;
import git4idea.repo.GitRepositoryFiles;
@@ -61,6 +60,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
@@ -73,13 +73,14 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
@NonNls private static final String GIT_COMMIT_MSG_FILE_EXT = ".txt"; // the file extension for commit message file
private final Project myProject;
public static final SimpleDateFormat COMMIT_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private final VcsDirtyScopeManager myDirtyScopeManager;
private final GitVcsSettings mySettings;
private String myNextCommitAuthor = null; // The author for the next commit
private boolean myNextCommitAmend; // If true, the next commit is amended
private Boolean myNextCommitIsPushed = null; // The push option of the next commit
private Date myNextCommitAuthorDate;
public GitCheckinEnvironment(@NotNull Project project, @NotNull final VcsDirtyScopeManager dirtyScopeManager, final GitVcsSettings settings) {
myProject = project;
@@ -178,7 +179,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
Set<FilePath> files = new HashSet<FilePath>();
files.addAll(added);
files.addAll(removed);
commit(myProject, root, files, messageFile, myNextCommitAuthor, myNextCommitAmend);
commit(myProject, root, files, messageFile, myNextCommitAuthor, myNextCommitAmend, myNextCommitAuthorDate);
}
catch (VcsException ex) {
if (!isMergeCommit(ex)) {
@@ -440,12 +441,15 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
/**
* Prepare delete files handler.
*
* @param project the project
* @param root a vcs root
* @param files a files to commit
* @param message a message file to use
* @param nextCommitAuthor a author for the next commit
* @param nextCommitAmend true, if the commit should be amended
*
*
* @param project the project
* @param root a vcs root
* @param files a files to commit
* @param message a message file to use
* @param nextCommitAuthor a author for the next commit
* @param nextCommitAmend true, if the commit should be amended
* @param nextCommitAuthorDate Author date timestamp to override the date of the commit or null if this overriding is not needed.
* @return a simple handler that does the task
* @throws VcsException in case of git problem
*/
@@ -454,7 +458,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
Collection<FilePath> files,
File message,
final String nextCommitAuthor,
boolean nextCommitAmend)
boolean nextCommitAmend, Date nextCommitAuthorDate)
throws VcsException {
boolean amend = nextCommitAmend;
for (List<String> paths : VcsFileUtil.chunkPaths(root, files)) {
@@ -470,6 +474,9 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
if (nextCommitAuthor != null) {
handler.addParameters("--author=" + nextCommitAuthor);
}
if (nextCommitAuthorDate != null) {
handler.addParameters("--date", COMMIT_DATE_FORMAT.format(nextCommitAuthorDate));
}
handler.endOptions();
handler.addParameters(paths);
handler.run();
@@ -559,12 +566,13 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
myNextCommitAmend = false;
myNextCommitAuthor = null;
myNextCommitIsPushed = null;
myNextCommitAuthorDate = null;
}
/**
* Checkin options for git
*/
private class GitCheckinOptions implements RefreshableOnComponent {
private class GitCheckinOptions implements CheckinChangeListSpecificComponent {
/**
* A container panel
*/
@@ -577,6 +585,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
* The amend checkbox
*/
private final JCheckBox myAmend;
private Date myAuthorDate;
/**
* A constructor
@@ -661,7 +670,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
* {@inheritDoc}
*/
public void saveState() {
String author = (String)myAuthor.getSelectedItem();
String author = (String)myAuthor.getEditor().getItem();
myNextCommitAuthor = author.length() == 0 ? null : author;
if (author.length() == 0) {
myNextCommitAuthor = null;
@@ -671,6 +680,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
mySettings.saveCommitAuthor(author);
}
myNextCommitAmend = myAmend.isSelected();
myNextCommitAuthorDate = myAuthorDate;
}
/**
@@ -679,6 +689,17 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
public void restoreState() {
refresh();
}
@Override
public void onChangeListSelected(LocalChangeList list) {
Object data = list.getData();
if (data instanceof GitCommit) {
GitCommit commit = (GitCommit)data;
String author = String.format("%s <%s>", commit.getAuthor(), commit.getAuthorEmail());
myAuthor.getEditor().setItem(author);
myAuthorDate = new Date(commit.getAuthorTime());
}
}
}
public void setNextCommitIsPushed(Boolean nextCommitIsPushed) {
@@ -18,24 +18,17 @@ package git4idea.history.browser;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.changes.ui.CommitHelper;
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vcs.merge.MergeDialogCustomizer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import com.intellij.util.WaitForProgressToShow;
import git4idea.GitPlatformFacade;
import git4idea.checkin.GitCheckinEnvironment;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
import git4idea.commands.GitSimpleEventDetector;
@@ -43,15 +36,13 @@ import git4idea.commands.GitUntrackedFilesOverwrittenByOperationDetector;
import git4idea.merge.GitConflictResolver;
import git4idea.repo.GitRepository;
import git4idea.util.UntrackedFilesNotifier;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
@@ -163,7 +154,7 @@ public class GitCherryPicker {
@NotNull GitCommitWrapper commit,
@NotNull List<GitCommitWrapper> successfulCommits) {
CherryPickData data = updateChangeListManager(commit.getCommit());
boolean committed = showCommitDialog(repository, commit, data.myChangeList, data.myCommitMessage);
boolean committed = showCommitDialogAndWaitForCommit(repository, commit, data.myChangeList, data.myCommitMessage);
if (committed) {
removeChangeList(data);
successfulCommits.add(commit);
@@ -206,12 +197,12 @@ public class GitCherryPicker {
refreshChangedFiles(paths);
final String commitMessage = createCommitMessage(commit, paths);
LocalChangeList previouslyDefaultChangeList = myChangeListManager.getDefaultChangeList();
LocalChangeList changeList = createChangeListAfterUpdate(commit.getChanges(), paths, commitMessage);
LocalChangeList changeList = createChangeListAfterUpdate(commit, paths, commitMessage);
return new CherryPickData(changeList, commitMessage, previouslyDefaultChangeList);
}
@NotNull
private LocalChangeList createChangeListAfterUpdate(@NotNull final List<Change> changes, @NotNull final Collection<FilePath> paths,
private LocalChangeList createChangeListAfterUpdate(@NotNull final GitCommit commit, @NotNull final Collection<FilePath> paths,
@NotNull final String commitMessage) {
final AtomicReference<LocalChangeList> changeList = new AtomicReference<LocalChangeList>();
myPlatformFacade.invokeAndWait(new Runnable() {
@@ -219,7 +210,7 @@ public class GitCherryPicker {
public void run() {
myChangeListManager.invokeAfterUpdate(new Runnable() {
public void run() {
changeList.set(createChangeList(changes, commitMessage));
changeList.set(createChangeList(commit, commitMessage));
}
}, InvokeAfterUpdateMode.SYNCHRONOUS_NOT_CANCELLABLE, "Cherry-pick",
new Consumer<VcsDirtyScopeManager>() {
@@ -243,29 +234,53 @@ public class GitCherryPicker {
return message;
}
private boolean showCommitDialog(@NotNull final GitRepository repository, @NotNull final GitCommitWrapper commit,
@NotNull final LocalChangeList changeList, @NotNull final String commitMessage) {
private boolean showCommitDialogAndWaitForCommit(@NotNull final GitRepository repository, @NotNull final GitCommitWrapper commit,
@NotNull final LocalChangeList changeList, @NotNull final String commitMessage) {
final AtomicBoolean commitSucceeded = new AtomicBoolean();
final Semaphore sem = new Semaphore(0);
myPlatformFacade.invokeAndWait(new Runnable() {
@Override
public void run() {
cancelCherryPick(repository);
List<Change> changes = commit.getCommit().getChanges();
CherryPickCommitExecutor executor = new CherryPickCommitExecutor(myProject, myPlatformFacade, changes, commitMessage);
boolean commitNotCancelled = myPlatformFacade.getVcsHelper(myProject).commitChanges(changes, changeList, commitMessage, executor);
boolean success = commitNotCancelled && !executor.hasCommitFailed();
if (success) {
commit.setActualSubject(getSubjectFromCommitMessage(executor.getActualCommitMessage()));
try {
cancelCherryPick(repository);
List<Change> changes = commit.getCommit().getChanges();
boolean commitNotCancelled = myPlatformFacade.getVcsHelper(myProject).commitChanges(changes, changeList, commitMessage,
new CommitResultHandler() {
@Override
public void onSuccess(@NotNull String commitMessage) {
commit.setActualSubject(commitMessage);
commitSucceeded.set(true);
sem.release();
}
@Override
public void onFailure() {
commitSucceeded.set(false);
sem.release();
}
});
if (!commitNotCancelled) {
commitSucceeded.set(false);
sem.release();
}
} catch (Throwable t) {
LOG.error(t);
commitSucceeded.set(false);
sem.release();
}
commitSucceeded.set(success);
}
}, ModalityState.NON_MODAL);
return commitSucceeded.get();
}
private static String getSubjectFromCommitMessage(String commitMessage) {
int newLine = commitMessage.indexOf("\n");
return newLine < 0 ? commitMessage : commitMessage.substring(0, newLine);
// need additional waiting, because commitChanges is asynchronous
try {
sem.acquire();
}
catch (InterruptedException e) {
LOG.error(e);
return false;
}
return commitSucceeded.get();
}
/**
@@ -334,7 +349,7 @@ public class GitCherryPicker {
@NotNull
private static String commitDetails(@NotNull GitCommitWrapper commit) {
return commit.getCommit().getShortHash().toString() + " \"" + commit.getSubject() + "\"";
return commit.getCommit().getShortHash().toString() + " \"" + commit.getOriginalSubject() + "\"";
}
private void refreshChangedFiles(@NotNull Collection<FilePath> filePaths) {
@@ -347,9 +362,10 @@ public class GitCherryPicker {
}
@NotNull
private LocalChangeList createChangeList(@NotNull List<Change> changes, @NotNull String commitMessage) {
private LocalChangeList createChangeList(@NotNull GitCommit commit, @NotNull String commitMessage) {
List<Change> changes = commit.getChanges();
if (!changes.isEmpty()) {
final LocalChangeList changeList = myChangeListManager.addChangeList(commitMessage, commitMessage);
final LocalChangeList changeList = ((ChangeListManagerEx)myChangeListManager).addChangeList(commitMessage, commitMessage, commit);
myChangeListManager.moveChangesTo(changeList, changes.toArray(new Change[changes.size()]));
myChangeListManager.setDefaultChangeList(changeList);
return changeList;
@@ -451,142 +467,6 @@ public class GitCherryPicker {
}
}
/*
Commit procedure is overridden by the executor with its own CommitSession.
The reason of that is the asynchronous nature of the CommitHelper: it returns, we continue cherry-picking and occasionally pick
the next commit in the queue, and only then Git is called for commit. Thus it commits two cherry-picks at once, which is wrong.
Here we call GitCheckinEnvironment manually
*/
private static class CherryPickCommitExecutor implements CommitExecutor {
@NotNull private final Project myProject;
@NotNull private final GitPlatformFacade myPlatformFacade;
@NotNull private final List<Change> myChanges;
@NotNull private final String myOriginalCommitMessage;
private boolean myCommitFailed;
@Nullable private CherryPickCommitExecutor.CherryPickCommitSession myCommitSession;
CherryPickCommitExecutor(@NotNull Project project, @NotNull GitPlatformFacade platformFacade,
@NotNull List<Change> changes, @NotNull String originalCommitMessage) {
myProject = project;
myPlatformFacade = platformFacade;
myChanges = changes;
myOriginalCommitMessage = originalCommitMessage;
}
@Nls
@Override
public String getActionText() {
return "Commit";
}
@NotNull
@Override
public CommitSession createCommitSession() {
myCommitSession = new CherryPickCommitSession();
return myCommitSession;
}
public boolean hasCommitFailed() {
return myCommitFailed;
}
@NotNull
public String getActualCommitMessage() {
return myCommitSession == null ? myOriginalCommitMessage : myCommitSession.getActualCommitMessage();
}
private class CherryPickCommitSession implements CommitSession {
private String myActualCommitMessage;
@Override
public JComponent getAdditionalConfigurationUI() {
return null;
}
@Override
public JComponent getAdditionalConfigurationUI(Collection<Change> changes, String commitMessage) {
return null;
}
@Override
public boolean canExecute(Collection<Change> changes, String commitMessage) {
return true;
}
@Override
public void execute(Collection<Change> changes, String commitMessage) {
final Collection<Document> committingDocs = markCommittingDocs();
try {
GitCheckinEnvironment ce = ServiceManager.getService(myProject, GitCheckinEnvironment.class);
try {
ce.reset();
List<VcsException> exceptions = ce.commit(myChanges, commitMessage);
VcsDirtyScopeManager.getInstance(myProject).filePathsDirty(ChangesUtil.getPaths(myChanges), null);
if (exceptions != null && !exceptions.isEmpty()) {
VcsException exception = exceptions.get(0);
handleError(exception);
}
myActualCommitMessage = commitMessage;
}
catch (Throwable e) {
LOG.error(e);
handleError(e);
}
}
finally {
unmarkCommittingDocs(committingDocs);
}
}
private void handleError(Throwable exception) {
myCommitFailed = true;
final String errorMessage = exception.getMessage();
WaitForProgressToShow.runOrInvokeLaterAboveProgress(new Runnable() {
public void run() {
Messages.showErrorDialog(myProject, errorMessage, "Commit Failed");
}
}, null, myProject);
}
@Override
public void executionCanceled() {
}
@Override
public String getHelpId() {
return null;
}
private void unmarkCommittingDocs(final Collection<Document> committingDocs) {
myPlatformFacade.runReadAction(new Runnable() {
@Override
public void run() {
CommitHelper.unmarkCommittingDocuments(committingDocs);
}
});
}
@NotNull
private Collection<Document> markCommittingDocs() {
final Collection<Document> committingDocs = new ArrayList<Document>();
myPlatformFacade.runReadAction(new Runnable() {
@Override
public void run() {
committingDocs.addAll(CommitHelper.markCommittingDocuments(myProject, myChanges));
}
});
return committingDocs;
}
public String getActualCommitMessage() {
return myActualCommitMessage;
}
}
}
/**
* This class is needed to hold both the original GitCommit, and the commit message which could be changed by the user.
* Only the subject of the commit message is needed.
@@ -613,6 +493,10 @@ public class GitCherryPicker {
public GitCommit getCommit() {
return myOriginalCommit;
}
public String getOriginalSubject() {
return myOriginalCommit.getSubject();
}
}
}
@@ -1,18 +1,18 @@
package org.jetbrains.plugins.gradle.manage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.model.gradle.GradleContentRoot;
import org.jetbrains.plugins.gradle.model.gradle.SourceType;
import org.jetbrains.plugins.gradle.model.intellij.ModuleAwareContentRoot;
import org.jetbrains.plugins.gradle.util.GradleUtil;
import java.util.Collection;
import java.util.Collections;
/**
@@ -28,76 +28,59 @@ public class GradleContentRootManager {
}
@SuppressWarnings("MethodMayBeStatic")
public void importContentRoots(@NotNull final Iterable<GradleContentRoot> contentRoots, @NotNull final Module module) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
doImportContentRoots(contentRoots, module);
}
});
}
private static void doImportContentRoots(@NotNull final Iterable<GradleContentRoot> contentRoots, @NotNull final Module module) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void importContentRoots(@NotNull final Collection<GradleContentRoot> contentRoots, @NotNull final Module module) {
if (contentRoots.isEmpty()) {
return;
}
GradleUtil.executeProjectChangeAction(module.getProject(), contentRoots, new Runnable() {
@Override
public void run() {
final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel model = moduleRootManager.getModifiableModel();
GradleUtil.executeProjectChangeAction(module.getProject(), contentRoots, new Runnable() {
@Override
public void run() {
try {
for (GradleContentRoot contentRoot : contentRoots) {
ContentEntry contentEntry = model.addContentEntry(toVfsUrl(contentRoot.getRootPath()));
for (String path : contentRoot.getPaths(SourceType.SOURCE)) {
contentEntry.addSourceFolder(toVfsUrl(path), false);
}
for (String path : contentRoot.getPaths(SourceType.TEST)) {
contentEntry.addSourceFolder(toVfsUrl(path), true);
}
for (String path : contentRoot.getPaths(SourceType.EXCLUDED)) {
contentEntry.addExcludeFolder(toVfsUrl(path));
}
}
try {
for (GradleContentRoot contentRoot : contentRoots) {
ContentEntry contentEntry = model.addContentEntry(toVfsUrl(contentRoot.getRootPath()));
for (String path : contentRoot.getPaths(SourceType.SOURCE)) {
contentEntry.addSourceFolder(toVfsUrl(path), false);
}
for (String path : contentRoot.getPaths(SourceType.TEST)) {
contentEntry.addSourceFolder(toVfsUrl(path), true);
}
for (String path : contentRoot.getPaths(SourceType.EXCLUDED)) {
contentEntry.addExcludeFolder(toVfsUrl(path));
}
finally {
model.commit();
}
}
});
}
finally {
model.commit();
}
}
});
}
private static String toVfsUrl(@NotNull String path) {
return LocalFileSystem.PROTOCOL_PREFIX + path;
}
@SuppressWarnings("MethodMayBeStatic")
public void removeContentRoots(@NotNull final Iterable<ModuleAwareContentRoot> contentRoots) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void removeContentRoots(@NotNull final Collection<ModuleAwareContentRoot> contentRoots) {
if (contentRoots.isEmpty()) {
return;
}
Project project = contentRoots.iterator().next().getModule().getProject();
GradleUtil.executeProjectChangeAction(project, contentRoots, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (final ModuleAwareContentRoot contentRoot : contentRoots) {
GradleUtil.executeProjectChangeAction(contentRoot.getModule().getProject(), contentRoot, new Runnable() {
@Override
public void run() {
final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(contentRoot.getModule());
ModifiableRootModel model = moduleRootManager.getModifiableModel();
try {
model.removeContentEntry(contentRoot);
}
finally {
model.commit();
}
}
});
}
for (ModuleAwareContentRoot contentRoot : contentRoots) {
final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(contentRoot.getModule());
ModifiableRootModel model = moduleRootManager.getModifiableModel();
try {
model.removeContentEntry(contentRoot);
}
});
finally {
model.commit();
}
}
}
});
}
@@ -1,20 +1,16 @@
package org.jetbrains.plugins.gradle.manage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.config.PlatformFacade;
import org.jetbrains.plugins.gradle.model.gradle.*;
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper;
import org.jetbrains.plugins.gradle.util.GradleUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.*;
/**
* Thread-safe.
@@ -23,17 +19,19 @@ import java.util.List;
* @since 2/7/12 3:23 PM
*/
public class GradleDependencyManager {
@NotNull private final PlatformFacade myPlatformFacade;
public GradleDependencyManager(@NotNull PlatformFacade platformFacade) {
@NotNull private final PlatformFacade myPlatformFacade;
@NotNull private final GradleLibraryManager myLibraryManager;
public GradleDependencyManager(@NotNull PlatformFacade platformFacade, @NotNull GradleLibraryManager manager) {
myPlatformFacade = platformFacade;
myLibraryManager = manager;
}
public void importDependency(@NotNull GradleDependency dependency, @NotNull Module module) {
importDependencies(Collections.singleton(dependency), module);
}
public void importDependencies(@NotNull Iterable<GradleDependency> dependencies, @NotNull Module module) {
final List<GradleModuleDependency> moduleDependencies = new ArrayList<GradleModuleDependency>();
final List<GradleLibraryDependency> libraryDependencies = new ArrayList<GradleLibraryDependency>();
@@ -56,19 +54,12 @@ public class GradleDependencyManager {
}
@SuppressWarnings("MethodMayBeStatic")
public void importModuleDependencies(@NotNull final Iterable<GradleModuleDependency> dependencies, @NotNull final Module module) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
doImportModuleDependencies(dependencies, module);
}
});
}
private static void doImportModuleDependencies(@NotNull final Iterable<GradleModuleDependency> dependencies,
@NotNull final Module module)
{
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void importModuleDependencies(@NotNull final Collection<GradleModuleDependency> dependencies, @NotNull final Module module) {
if (dependencies.isEmpty()) {
return;
}
GradleUtil.executeProjectChangeAction(module.getProject(), dependencies, new Runnable() {
@Override
public void run() {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
@@ -77,12 +68,20 @@ public class GradleDependencyManager {
final GradleProjectStructureHelper projectStructureHelper = module.getProject().getComponent(GradleProjectStructureHelper.class);
for (GradleModuleDependency dependency : dependencies) {
final String moduleName = dependency.getName();
final Module intellijModuleDependency = projectStructureHelper.findIntellijModule(moduleName);
if (intellijModuleDependency == null) {
final Module intellijModule = projectStructureHelper.findIntellijModule(moduleName);
if (intellijModule == null) {
assert false;
continue;
}
final ModuleOrderEntry orderEntry = moduleRootModel.addModuleOrderEntry(intellijModuleDependency);
else if (intellijModule.equals(module)) {
// Gradle api returns recursive module dependencies (a module depends on itself) for 'gradle' project.
continue;
}
ModuleOrderEntry orderEntry = projectStructureHelper.findIntellijModuleDependency(dependency, moduleRootModel);
if (orderEntry == null) {
orderEntry = moduleRootModel.addModuleOrderEntry(intellijModule);
}
orderEntry.setScope(dependency.getScope());
orderEntry.setExported(dependency.isExported());
}
@@ -93,97 +92,79 @@ public class GradleDependencyManager {
}
});
}
public void importLibraryDependencies(@NotNull final Iterable<GradleLibraryDependency> dependencies, @NotNull final Module module) {
final List<LibraryDependencyInfo> infos = new ArrayList<LibraryDependencyInfo>();
final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject());
for (GradleLibraryDependency dependency : dependencies) {
final Library library = libraryTable.getLibraryByName(dependency.getName());
if (library != null) {
infos.add(new LibraryDependencyInfo(library, dependency.getScope(), dependency.isExported()));
}
}
doImportLibraryDependencies(infos, module);
}
private static void doImportLibraryDependencies(@NotNull final Iterable<LibraryDependencyInfo> infos, @NotNull final Module module) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
GradleUtil.executeProjectChangeAction(module.getProject(), dependencies, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
GradleUtil.executeProjectChangeAction(module.getProject(), infos, new Runnable() {
@Override
public void run() {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
try {
for (LibraryDependencyInfo info : infos) {
LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(info.library);
orderEntry.setExported(info.exported);
orderEntry.setScope(info.scope);
}
}
finally {
moduleRootModel.commit();
}
}
});
LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject());
Set<GradleLibrary> librariesToImport = new HashSet<GradleLibrary>();
for (GradleLibraryDependency dependency : dependencies) {
final Library library = libraryTable.getLibraryByName(dependency.getName());
if (library == null) {
librariesToImport.add(dependency.getTarget());
}
});
}
if (!librariesToImport.isEmpty()) {
myLibraryManager.importLibraries(librariesToImport, module.getProject());
}
for (GradleLibraryDependency dependency : dependencies) {
GradleProjectStructureHelper helper = module.getProject().getComponent(GradleProjectStructureHelper.class);
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
try {
libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject());
final Library library = libraryTable.getLibraryByName(dependency.getName());
if (library == null) {
assert false;
continue;
}
LibraryOrderEntry orderEntry = helper.findIntellijLibraryDependency(dependency.getName(), moduleRootModel);
if (orderEntry == null) {
// We need to get the most up-to-date Library object due to our project model restrictions.
orderEntry = moduleRootModel.addLibraryEntry(library);
}
orderEntry.setExported(dependency.isExported());
orderEntry.setScope(dependency.getScope());
}
finally {
moduleRootModel.commit();
}
}
}
});
}
@SuppressWarnings("MethodMayBeStatic")
public void removeDependencies(@NotNull final Iterable<ExportableOrderEntry> dependencies) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (final ExportableOrderEntry dependency : dependencies) {
final Module module = dependency.getOwnerModule();
GradleUtil.executeProjectChangeAction(module.getProject(), dependency, new Runnable() {
@Override
public void run() {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
try {
// The thing is that intellij created order entry objects every time new modifiable model is created,
// that's why we can't use target dependency object as is but need to get a reference to the current
// entry object from the model instead.
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
if (entry.getPresentableName().equals(dependency.getPresentableName())) {
moduleRootModel.removeOrderEntry(entry);
break;
}
}
}
finally {
moduleRootModel.commit();
}
}
});
public void removeDependencies(@NotNull final Collection<ExportableOrderEntry> dependencies) {
if (dependencies.isEmpty()) {
return;
}
for (final ExportableOrderEntry dependency : dependencies) {
final Module module = dependency.getOwnerModule();
GradleUtil.executeProjectChangeAction(module.getProject(), dependency, new Runnable() {
@Override
public void run() {
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
try {
// The thing is that intellij created order entry objects every time new modifiable model is created,
// that's why we can't use target dependency object as is but need to get a reference to the current
// entry object from the model instead.
for (OrderEntry entry : moduleRootModel.getOrderEntries()) {
if (entry.getPresentableName().equals(dependency.getPresentableName())) {
moduleRootModel.removeOrderEntry(entry);
break;
}
}
}
});
}
});
}
private static class LibraryDependencyInfo {
@NotNull public final Library library;
@NotNull public final DependencyScope scope;
public final boolean exported;
LibraryDependencyInfo(@NotNull Library library, @NotNull DependencyScope scope, boolean exported) {
this.library = library;
this.scope = scope;
this.exported = exported;
finally {
moduleRootModel.commit();
}
}
});
}
}
}
@@ -1,23 +1,21 @@
package org.jetbrains.plugins.gradle.manage;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.JavadocOrderRootType;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.config.PlatformFacade;
import org.jetbrains.plugins.gradle.model.gradle.GradleLibrary;
import org.jetbrains.plugins.gradle.model.gradle.LibraryPathType;
import org.jetbrains.plugins.gradle.util.GradleLog;
import org.jetbrains.plugins.gradle.util.GradleUtil;
import java.io.File;
import java.util.*;
@@ -34,8 +32,13 @@ public class GradleLibraryManager {
myPlatformFacade = platformFacade;
}
@NotNull
public Library importLibrary(@NotNull final GradleLibrary library, @NotNull final Project project) {
public void importLibraries(@NotNull Collection<? extends GradleLibrary> libraries, @NotNull Project project) {
for (GradleLibrary library : libraries) {
importLibrary(library, project);
}
}
public void importLibrary(@NotNull final GradleLibrary library, @NotNull final Project project) {
Map<OrderRootType, Collection<File>> libraryFiles = new HashMap<OrderRootType, Collection<File>>();
for (LibraryPathType pathType : LibraryPathType.values()) {
final Set<String> paths = library.getPaths(pathType);
@@ -50,47 +53,22 @@ public class GradleLibraryManager {
}
}));
}
return importLibrary(library.getName(), libraryFiles, project);
importLibrary(library.getName(), libraryFiles, project);
}
@NotNull
public Library importLibrary(@NotNull final String libraryName,
@NotNull final Map<OrderRootType, ? extends Collection<File>> libraryFiles,
@NotNull final Project project)
public void importLibrary(@NotNull final String libraryName,
@NotNull final Map<OrderRootType, ? extends Collection<File>> libraryFiles,
@NotNull final Project project)
{
final Ref<Library> result = new Ref<Library>();
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
final GradleProjectEntityChangeListener publisher = project.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC);
publisher.onChangeStart(libraryName);
try {
result.set(doImportLibrary(libraryName, libraryFiles, project));
}
finally {
publisher.onChangeEnd(libraryName);
}
}
});
return result.get();
}
@NotNull
private Library doImportLibrary(@NotNull final String libraryName,
@NotNull final Map<OrderRootType, ? extends Collection<File>> libraryFiles,
@NotNull Project project)
{
// Is assumed to be called from the EDT.
final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(project);
final Ref<Library> result = new Ref<Library>();
ApplicationManager.getApplication().runWriteAction(new Runnable() {
GradleUtil.executeProjectChangeAction(project, libraryName, new Runnable() {
@Override
public void run() {
// Is assumed to be called from the EDT.
final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(project);
final LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel();
final Library intellijLibrary;
try {
intellijLibrary = projectLibraryModel.createLibrary(libraryName);
result.set(intellijLibrary);
}
finally {
projectLibraryModel.commit();
@@ -104,7 +82,6 @@ public class GradleLibraryManager {
}
}
});
return result.get();
}
private static void registerPaths(@NotNull final Map<OrderRootType, ? extends Collection<File>> libraryFiles,
@@ -115,9 +92,9 @@ public class GradleLibraryManager {
for (File file : entry.getValue()) {
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
if (virtualFile == null) {
GradleLog.LOG.warn(
String.format("Can't find %s of the library '%s' at path '%s'", entry.getKey(), libraryName, file.getAbsolutePath())
);
//GradleLog.LOG.warn(
// String.format("Can't find %s of the library '%s' at path '%s'", entry.getKey(), libraryName, file.getAbsolutePath())
//);
continue;
}
if (virtualFile.isDirectory()) {
@@ -137,7 +114,7 @@ public class GradleLibraryManager {
}
}
public void removeLibraries(@NotNull List<Library> libraries) {
public void removeLibraries(@NotNull List<? extends Library> libraries) {
// TODO den implement
//LibraryTable table = library.getTable();
//table.removeLibrary(library);
@@ -16,6 +16,7 @@ import org.jetbrains.plugins.gradle.util.GradleLog;
import org.jetbrains.plugins.gradle.util.GradleUtil;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -50,7 +51,13 @@ public class GradleModuleManager {
importModules(Collections.singleton(module), project, false);
}
public void importModules(@NotNull final Iterable<GradleModule> modules, @NotNull final Project project, final boolean recursive) {
public void importModules(@NotNull final Collection<? extends GradleModule> modules,
@NotNull final Project project,
final boolean recursive)
{
if (modules.isEmpty()) {
return;
}
if (!project.isInitialized()) {
myAlarm.addRequest(new ImportModulesTask(project, modules, recursive), PROJECT_INITIALISATION_DELAY_MS);
return;
@@ -65,7 +72,7 @@ public class GradleModuleManager {
@Override
public void run() {
final ModuleManager moduleManager = ModuleManager.getInstance(project);
final GradleProjectEntityChangeListener publisher
final GradleProjectEntityChangeListener publisher
= project.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC);
for (GradleModule module : modules) {
publisher.onChangeStart(module);
@@ -121,7 +128,7 @@ public class GradleModuleManager {
});
}
private static void removeExistingModulesConfigs(@NotNull Iterable<GradleModule> modules) {
private static void removeExistingModulesConfigs(@NotNull Collection<? extends GradleModule> modules) {
for (GradleModule module : modules) {
// Remove existing '*.iml' file if necessary.
final String moduleFilePath = module.getModuleFilePath();
@@ -136,43 +143,37 @@ public class GradleModuleManager {
}
@SuppressWarnings("MethodMayBeStatic")
public void removeModules(@NotNull final Iterable<Module> modules) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void removeModules(@NotNull final Collection<? extends Module> modules) {
if (modules.isEmpty()) {
return;
}
Project project = modules.iterator().next().getProject();
GradleUtil.executeProjectChangeAction(project, modules, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (final Module module : modules) {
GradleUtil.executeProjectChangeAction(module.getProject(), module, new Runnable() {
@Override
public void run() {
ModuleManager moduleManager = ModuleManager.getInstance(module.getProject());
String path = module.getModuleFilePath();
moduleManager.disposeModule(module);
File file = new File(path);
if (file.isFile()) {
boolean success = file.delete();
if (!success) {
GradleLog.LOG.warn("Can't remove module file at '" + path + "'");
}
}
}
});
}
for (Module module : modules) {
ModuleManager moduleManager = ModuleManager.getInstance(module.getProject());
String path = module.getModuleFilePath();
moduleManager.disposeModule(module);
File file = new File(path);
if (file.isFile()) {
boolean success = file.delete();
if (!success) {
GradleLog.LOG.warn("Can't remove module file at '" + path + "'");
}
}
});
}
}
});
}
private class ImportModulesTask implements Runnable {
private final Project myProject;
private final Iterable<GradleModule> myModules;
private final boolean myRecursive;
private final Project myProject;
private final Collection<? extends GradleModule> myModules;
private final boolean myRecursive;
ImportModulesTask(@NotNull Project project, @NotNull Iterable<GradleModule> modules, boolean recursive) {
ImportModulesTask(@NotNull Project project, @NotNull Collection<? extends GradleModule> modules, boolean recursive) {
myProject = project;
myModules = modules;
myRecursive = recursive;
@@ -192,5 +193,4 @@ public class GradleModuleManager {
importModules(myModules, myProject, myRecursive);
}
}
}
@@ -1,564 +0,0 @@
package org.jetbrains.plugins.gradle.manage;
import com.intellij.openapi.application.*;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.StdModuleTypes;
import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
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.roots.*;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Alarm;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.model.gradle.*;
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel;
import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleLog;
import java.io.File;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Encapsulates functionality of creating IntelliJ IDEA modules on the basis of {@link GradleModule gradle modules}.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 8/26/11 10:01 AM
*/
// TODO den remove
public class GradleModulesImporter {
private static final Map<LibraryPathType, OrderRootType> LIBRARY_ROOT_MAPPINGS
= new EnumMap<LibraryPathType, OrderRootType>(LibraryPathType.class);
static {
LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.BINARY, OrderRootType.CLASSES);
LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.SOURCE, OrderRootType.SOURCES);
LIBRARY_ROOT_MAPPINGS.put(LibraryPathType.DOC, JavadocOrderRootType.getInstance());
assert LibraryPathType.values().length == LIBRARY_ROOT_MAPPINGS.size();
}
/**
* We can't modify project modules (add/remove) until it's initialised, so, we delay that activity. Current constant
* holds number of milliseconds to wait between 'after project initialisation' processing attempts.
*/
private static final int PROJECT_INITIALISATION_DELAY_MS = (int)TimeUnit.SECONDS.toMillis(1);
private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
/**
* Entry point for the whole 'import modules' procedure.
*
* @param modules module info containers received from the gradle api
* @param project project that should host the modules
* @param model modules model
* @param gradleProjectPath file system path to the gradle project file being imported
* @return mappings between the given gradle modules and newly created intellij modules
*/
@NotNull
public Map<GradleModule, Module> importModules(@NotNull final Iterable<GradleModule> modules, @Nullable final Project project,
@Nullable final ModifiableModuleModel model, @NotNull String gradleProjectPath)
{
if (project == null) {
return Collections.emptyMap();
}
removeExistingModulesSettings(modules);
if (!project.isInitialized()) {
myAlarm.addRequest(new ImportModulesTask(project, modules, gradleProjectPath), PROJECT_INITIALISATION_DELAY_MS);
return Collections.emptyMap();
}
if (model == null) {
return Collections.emptyMap();
}
return importModules(modules, model, project, gradleProjectPath);
}
private static void removeExistingModulesSettings(@NotNull Iterable<GradleModule> modules) {
for (GradleModule module : modules) {
// Remove existing '*.iml' file if necessary.
final String moduleFilePath = module.getModuleFilePath();
File file = new File(moduleFilePath);
if (file.isFile()) {
boolean success = file.delete();
if (!success) {
GradleLog.LOG.warn("Can't remove existing module file at '" + moduleFilePath + "'");
}
}
}
}
public Map<GradleModule, Module> importModules(@NotNull final Iterable<GradleModule> modules,
@NotNull final ModifiableModuleModel model,
@NotNull final Project intellijProject,
@NotNull final String gradleProjectPath)
{
final Map<GradleModule, Module> result = new HashMap<GradleModule, Module>();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
Application application = ApplicationManager.getApplication();
AccessToken writeLock = application.acquireWriteActionLock(getClass());
try {
final List<ModifiableRootModel> rootModels = new ArrayList<ModifiableRootModel>();
final GradleProjectEntityChangeListener publisher =
intellijProject.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC);
for (GradleModule module : modules) {
publisher.onChangeStart(module);
}
try {
Map<GradleModule, Module> moduleMappings = doImportModules(modules, model, rootModels);
result.putAll(moduleMappings);
myAlarm.cancelAllRequests();
myAlarm.addRequest(
new SetupExternalLibrariesTask(moduleMappings, gradleProjectPath, intellijProject),
PROJECT_INITIALISATION_DELAY_MS
);
}
finally {
ModifiableRootModel[] modelsAsArray = rootModels.toArray(new ModifiableRootModel[rootModels.size()]);
ModifiableModelCommitter.multiCommit(modelsAsArray, model);
for (GradleModule module : modules) {
publisher.onChangeEnd(module);
}
}
}
finally {
writeLock.finish();
}
}
});
return result;
}
/**
* Actual implementation of {@link #importModules(Iterable, Project, ModifiableModuleModel, String)}.
* Insists on all arguments to be ready to use.
*
* @param modules modules to import
* @param model modules model
* @param rootModels holder for the module root modules. Is expected to be populated during the current method processing
* @return mappings between the given gradle modules and corresponding intellij modules
*/
@NotNull
@SuppressWarnings("MethodMayBeStatic")
private Map<GradleModule, Module> doImportModules(@NotNull Iterable<GradleModule> modules,
@NotNull ModifiableModuleModel model,
@NotNull List<ModifiableRootModel> rootModels)
{
Map<GradleModule, Module> result = new HashMap<GradleModule, Module>();
for (GradleModule moduleToImport : modules) {
Module createdModule = createModule(moduleToImport, model);
result.put(moduleToImport, createdModule);
}
for (GradleModule moduleToImport : modules) {
ModifiableRootModel rootModel = configureModule(moduleToImport, result);
rootModels.add(rootModel);
}
return result;
}
/**
* We need to create module objects for all modules at first and then configure them. That is necessary for setting up
* module dependencies.
*
* @param module gradle module to import
* @param model module model
* @return newly created IJ module
*/
@NotNull
private static Module createModule(@NotNull GradleModule module, @NotNull ModifiableModuleModel model) {
Application application = ApplicationManager.getApplication();
application.assertWriteAccessAllowed();
final String moduleFilePath = module.getModuleFilePath();
return model.newModule(moduleFilePath, StdModuleTypes.JAVA.getId());
}
/**
* Applies module settings received from the gradle api (encapsulate at the given {@link GradleModule} object) to the
* target intellij module (retrieved from the given module mappings).
*
* @param module target gradle module which corresponding intellij module should be configured
* @param modules gradle module to intellij modules mappings. Is assumed to have a value for the given gradle modules used as a key
* @return module roots model used during configuration
*/
@NotNull
private static ModifiableRootModel configureModule(@NotNull GradleModule module, @NotNull Map<GradleModule, Module> modules) {
Application application = ApplicationManager.getApplication();
application.assertWriteAccessAllowed();
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(modules.get(module));
ModifiableRootModel rootModel = moduleRootManager.getModifiableModel();
configureModule(module, rootModel, modules);
return rootModel;
}
/**
* Contains actual logic of {@link #configureModule(GradleModule, Map)}.
*
* @param module target module settings holder
* @param model intellij module setting manager
* @param modules modules mappings
*/
private static void configureModule(@NotNull GradleModule module, @NotNull final ModifiableRootModel model,
@NotNull final Map<GradleModule, Module> modules)
{
// Ensure that dependencies are clear.
final Object key = new Object();
final Object dummy = new Object();
RootPolicy<Object> policy = new RootPolicy<Object>() {
@Override
public Object visitModuleSourceOrderEntry(ModuleSourceOrderEntry moduleSourceOrderEntry, Object value) {
return key;
}
};
for (OrderEntry orderEntry : model.getOrderEntries()) {
// Don't remove 'module source' order entry (configured automatically on module creation).
if (key != orderEntry.accept(policy, dummy)) {
model.removeOrderEntry(orderEntry);
}
}
// Configure SDK.
model.inheritSdk();
// Compile output.
CompilerModuleExtension compilerExtension = model.getModuleExtension(CompilerModuleExtension.class);
compilerExtension.inheritCompilerOutputPath(module.isInheritProjectCompileOutputPath());
if (!module.isInheritProjectCompileOutputPath()) {
String compileOutputPath = module.getCompileOutputPath(SourceType.SOURCE);
String testCompileOutputPath = module.getCompileOutputPath(SourceType.TEST);
if (StringUtil.isEmpty(compileOutputPath) || StringUtil.isEmpty(testCompileOutputPath)) {
GradleLog.LOG.warn(String.format(
"Module '%s' doesn't inherit project compile output path but has incomplete local setup. Falling back to the project "
+ "compile output path. Local compile output path: '%s', local test compile output path: '%s'",
module.getName(), compileOutputPath, testCompileOutputPath
));
compilerExtension.inheritCompilerOutputPath(true);
}
else {
compilerExtension.setCompilerOutputPath(compileOutputPath);
compilerExtension.setCompilerOutputPathForTests(testCompileOutputPath);
}
}
// Content roots.
for (GradleContentRoot contentRoot : module.getContentRoots()) {
ContentEntry contentEntry = model.addContentEntry(toVfsUrl(contentRoot.getRootPath()));
for (String path : contentRoot.getPaths(SourceType.SOURCE)) {
contentEntry.addSourceFolder(toVfsUrl(path), false);
}
for (String path : contentRoot.getPaths(SourceType.TEST)) {
contentEntry.addSourceFolder(toVfsUrl(path), true);
}
for (String path : contentRoot.getPaths(SourceType.EXCLUDED)) {
contentEntry.addExcludeFolder(toVfsUrl(path));
}
}
// Module dependencies.
for (GradleDependency dependency : module.getDependencies()) {
dependency.invite(new GradleEntityVisitorAdapter() {
@Override
public void visit(@NotNull GradleModuleDependency dependency) {
ModuleOrderEntry orderEntry = model.addModuleOrderEntry(modules.get(dependency.getTarget()));
orderEntry.setExported(dependency.isExported());
orderEntry.setScope(dependency.getScope());
}
});
}
}
/**
* Resolves (downloads if necessary) external libraries necessary for the gradle project located at the given path and configures
* them for the corresponding intellij project.
* <p/>
* <b>Note:</b> is assumed to be executed under write action.
*
* @param moduleMappings gradle-intellij module mappings
* @param intellijProject intellij project for the target gradle project
* @param gradleProjectPath file system path to the target gradle project
*/
private static void setupLibraries(@NotNull final Map<GradleModule, Module> moduleMappings,
@NotNull final Project intellijProject,
@NotNull final String gradleProjectPath)
{
final Ref<GradleProject> gradleProjectRef = new Ref<GradleProject>();
final Ref<Library> libraryToPreserve = new Ref<Library>();
final Runnable setupExternalDependenciesTask = new Runnable() {
@Override
public void run() {
final GradleProject gradleProject = gradleProjectRef.get();
if (gradleProject == null) {
return;
}
Application application = ApplicationManager.getApplication();
AccessToken writeLock = application.acquireWriteActionLock(getClass());
try {
doSetupLibraries(moduleMappings, gradleProject, intellijProject, libraryToPreserve.get());
}
finally {
writeLock.finish();
}
if (intellijProject.isDisposed()) {
return;
}
// Force refresh the infrastructure in order to apply newly introduce intellij project structure changes
final GradleProjectStructureChangesModel changesModel = intellijProject.getComponent(GradleProjectStructureChangesModel.class);
if (changesModel != null) {
final GradleProject project = changesModel.getGradleProject();
if (project != null) {
changesModel.update(project);
}
}
}
};
final Runnable resolveDependenciesTask = new Runnable() {
@Override
public void run() {
ProgressManager.getInstance().run(
new Task.Backgroundable(intellijProject, GradleBundle.message("gradle.library.resolve.progress.text"), false) {
@Override
public void run(@NotNull final ProgressIndicator indicator) {
GradleResolveProjectTask task = new GradleResolveProjectTask(intellijProject, gradleProjectPath, true);
task.execute(indicator);
GradleProject projectWithResolvedLibraries = task.getGradleProject();
gradleProjectRef.set(projectWithResolvedLibraries);
ApplicationManager.getApplication().invokeLater(setupExternalDependenciesTask, ModalityState.NON_MODAL);
}
});
}
};
UIUtil.invokeLaterIfNeeded(resolveDependenciesTask);
}
private static void doSetupLibraries(@NotNull Map<GradleModule, Module> moduleMappings,
@NotNull GradleProject gradleProject,
@NotNull Project intellijProject,
@Nullable Library libraryToPreserve) {
if (intellijProject.isDisposed()) {
return;
}
Application application = ApplicationManager.getApplication();
application.assertWriteAccessAllowed();
LibraryTable projectLibraryTable = ProjectLibraryTable.getInstance(intellijProject);
if (projectLibraryTable == null) {
GradleLog.LOG.warn(
"Can't resolve external dependencies of the target gradle project (" + intellijProject + "). Reason: project "
+ "library table is undefined"
);
return;
}
LibraryTable.ModifiableModel model = projectLibraryTable.getModifiableModel();
// Clean existing libraries (if any).
try {
for (Library library : model.getLibraries()) {
if (libraryToPreserve != library) {
model.removeLibrary(library);
}
}
}
finally {
model.commit();
}
model = projectLibraryTable.getModifiableModel();
List<ModifiableRootModel> modelsToCommit = new ArrayList<ModifiableRootModel>();
Map<GradleLibrary, Library> libraryMappings = registerProjectLibraries(gradleProject, model);
final GradleProjectEntityChangeListener publisher
= intellijProject.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC);
try {
if (libraryMappings == null) {
return;
}
for (GradleLibrary library : libraryMappings.keySet()) {
publisher.onChangeStart(library);
}
modelsToCommit.addAll(configureModulesLibraryDependencies(moduleMappings, libraryMappings, gradleProject));
}
finally {
model.commit();
ProjectRootManager projectRootManager = ProjectRootManager.getInstance(intellijProject);
ModifiableRootModel[] modelsAsArray = modelsToCommit.toArray(new ModifiableRootModel[modelsToCommit.size()]);
if (modelsAsArray.length > 0) {
ModifiableModelCommitter.multiCommit(modelsAsArray, ModuleManager.getInstance(modelsAsArray[0].getProject()).getModifiableModel());
}
if (libraryMappings != null) {
for (GradleLibrary library : libraryMappings.keySet()) {
publisher.onChangeEnd(library);
}
}
}
}
/**
* Registers {@link GradleProject#getLibraries() libraries} of the given gradle project at the intellij project.
*
* @param gradleProject target gradle project being imported
* @param librariesModel model that manages project libraries
* @return mapping between libraries of the given gradle and intellij projects
*/
@Nullable
private static Map<GradleLibrary, Library> registerProjectLibraries(@NotNull GradleProject gradleProject,
@NotNull LibraryTable.ModifiableModel librariesModel)
{
Map<GradleLibrary, Library> libraryMappings = new HashMap<GradleLibrary, Library>();
for (GradleLibrary gradleLibrary : gradleProject.getLibraries()) {
Library intellijLibrary = librariesModel.createLibrary(gradleLibrary.getName());
libraryMappings.put(gradleLibrary, intellijLibrary);
Library.ModifiableModel model = intellijLibrary.getModifiableModel();
try {
registerPath(gradleLibrary, model);
}
finally {
model.commit();
}
}
return libraryMappings;
}
private static Collection<ModifiableRootModel> configureModulesLibraryDependencies(
@NotNull Map<GradleModule, Module> moduleMappings,
@NotNull final Map<GradleLibrary, Library> libraryMappings,
@NotNull GradleProject gradleProject)
{
List<ModifiableRootModel> result = new ArrayList<ModifiableRootModel>();
for (GradleModule gradleModule : gradleProject.getModules()) {
Module intellijModule = moduleMappings.get(gradleModule);
if (intellijModule == null) {
GradleLog.LOG.warn(String.format(
"Can't find intellij module for the gradle module '%s'. Registered mappings: %s", gradleModule, moduleMappings
));
continue;
}
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(intellijModule);
final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
result.add(moduleRootModel);
GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() {
@Override
public void visit(@NotNull GradleLibraryDependency dependency) {
GradleLibrary gradleLibrary = dependency.getTarget();
Library intellijLibrary = libraryMappings.get(gradleLibrary);
if (intellijLibrary == null) {
GradleLog.LOG.warn(String.format(
"Can't find registered intellij library for gradle library '%s'. Registered mappings: %s", gradleLibrary, libraryMappings
));
return;
}
LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(intellijLibrary);
orderEntry.setExported(dependency.isExported());
orderEntry.setScope(dependency.getScope());
}
};
for (GradleDependency dependency : gradleModule.getDependencies()) {
dependency.invite(visitor);
}
}
return result;
}
private static void registerPath(@NotNull GradleLibrary gradleLibrary, @NotNull Library.ModifiableModel model) {
for (LibraryPathType pathType : LibraryPathType.values()) {
for (String path : gradleLibrary.getPaths(pathType)) {
VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(new File(path));
if (virtualFile == null) {
GradleLog.LOG.warn(String.format("Can't find %s of the library '%s' at path '%s'", pathType, gradleLibrary.getName(), path));
continue;
}
if (virtualFile.isDirectory()) {
model.addRoot(virtualFile, LIBRARY_ROOT_MAPPINGS.get(pathType));
}
else {
VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile);
if (jarRoot == null) {
GradleLog.LOG.warn(String.format(
"Can't parse contents of the jar file at path '%s' for the library '%s''", path, gradleLibrary.getName()
));
continue;
}
model.addRoot(jarRoot, LIBRARY_ROOT_MAPPINGS.get(pathType));
}
}
}
}
private static String toVfsUrl(@NotNull String path) {
return LocalFileSystem.PROTOCOL_PREFIX + path;
}
private class ImportModulesTask implements Runnable {
private final Project myProject;
private final Iterable<GradleModule> myModules;
private final String myGradleProjectPath;
ImportModulesTask(@NotNull Project project, @NotNull Iterable<GradleModule> modules, @NotNull String gradleProjectPath) {
myProject = project;
myModules = modules;
myGradleProjectPath = gradleProjectPath;
}
@Override
public void run() {
myAlarm.cancelAllRequests();
if (!myProject.isInitialized()) {
myAlarm.addRequest(
new ImportModulesTask(myProject, myModules, myGradleProjectPath),
PROJECT_INITIALISATION_DELAY_MS
);
return;
}
final ModifiableModuleModel model = new ReadAction<ModifiableModuleModel>() {
protected void run(Result<ModifiableModuleModel> result) throws Throwable {
result.setResult(ModuleManager.getInstance(myProject).getModifiableModel());
}
}.execute().getResultObject();
importModules(myModules, model, myProject, myGradleProjectPath);
}
}
private static class SetupExternalLibrariesTask implements Runnable {
private final Map<GradleModule, Module> myModules;
private final String myGradleProjectPath;
private final Project myIntellijProject;
SetupExternalLibrariesTask(@NotNull Map<GradleModule, Module> modules,
@NotNull String gradleProjectPath,
@NotNull Project intellijProject)
{
myModules = modules;
myGradleProjectPath = gradleProjectPath;
myIntellijProject = intellijProject;
}
@Override
public void run() {
setupLibraries(myModules, myIntellijProject, myGradleProjectPath);
}
}
}
@@ -4,11 +4,18 @@ 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;
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Ref;
@@ -16,14 +23,17 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.packaging.artifacts.ModifiableArtifactModel;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.projectImport.ProjectImportBuilder;
import com.intellij.util.ui.UIUtil;
import icons.GradleIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.gradle.config.GradleConfigurable;
import org.jetbrains.plugins.gradle.config.GradleSettings;
import org.jetbrains.plugins.gradle.model.gradle.GradleEntity;
import org.jetbrains.plugins.gradle.model.gradle.GradleLibrary;
import org.jetbrains.plugins.gradle.model.gradle.GradleModule;
import org.jetbrains.plugins.gradle.model.gradle.GradleProject;
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper;
import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.jetbrains.plugins.gradle.util.GradleLog;
@@ -31,7 +41,10 @@ import org.jetbrains.plugins.gradle.util.GradleUtil;
import javax.swing.*;
import java.io.File;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* GoF builder for gradle-backed projects.
@@ -42,12 +55,22 @@ import java.util.*;
@SuppressWarnings("MethodMayBeStatic")
public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProject> {
/** @see #setModuleMappings(Map) */
private final Map<GradleModule/*origin*/, GradleModule/*adjusted*/> myModuleMappings = new HashMap<GradleModule, GradleModule>();
private GradleProject myGradleProject;
@NotNull private final GradleModuleManager myModuleManager;
@NotNull private final GradleLibraryManager myLibraryManager;
@NotNull private final GradleDependencyManager myDependencyManager;
private GradleProject myGradleProject;
private GradleConfigurable myConfigurable;
public GradleProjectImportBuilder(@NotNull GradleModuleManager moduleManager,
@NotNull GradleLibraryManager libraryManager,
@NotNull GradleDependencyManager manager)
{
myModuleManager = moduleManager;
myLibraryManager = libraryManager;
myDependencyManager = manager;
}
@NotNull
@Override
public String getName() {
@@ -93,12 +116,13 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
}
myConfigurable.setLinkedGradleProjectPath(pathToUse);
}
@Override
public List<Module> commit(final Project project,
ModifiableModuleModel model,
ModulesProvider modulesProvider,
ModifiableArtifactModel artifactModel) {
ModifiableArtifactModel artifactModel)
{
System.setProperty(GradleConstants.NEWLY_IMPORTED_PROJECT, Boolean.TRUE.toString());
final GradleProject gradleProject = getGradleProject();
if (gradleProject != null) {
@@ -114,15 +138,107 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
GradleSettings.applyLinkedProjectPath(myConfigurable.getLinkedProjectPath(), project);
GradleSettings.applyPreferLocalInstallationToWrapper(myConfigurable.isPreferLocalInstallationToWrapper(), project);
GradleSettings.applyGradleHome(myConfigurable.getGradleHomePath(), project);
if (gradleProject != null) {
GradleUtil.executeProjectChangeAction(project, project, new Runnable() {
@Override
public void run() {
ProjectRootManagerEx.getInstanceEx(project).mergeRootsChangesDuring(new Runnable() {
@Override
public void run() {
myModuleManager.importModules(gradleProject.getModules(), project, true);
}
});
}
});
final Runnable resolveDependenciesTask = new Runnable() {
@Override
public void run() {
ProgressManager.getInstance().run(
new Task.Backgroundable(project, GradleBundle.message("gradle.library.resolve.progress.text"), false) {
@Override
public void run(@NotNull final ProgressIndicator indicator) {
String linkedProjectPath = myConfigurable.getLinkedProjectPath();
assert linkedProjectPath != null;
GradleResolveProjectTask task = new GradleResolveProjectTask(project, linkedProjectPath, true);
task.execute(indicator);
GradleProject projectWithResolvedLibraries = task.getGradleProject();
if (projectWithResolvedLibraries == null) {
return;
}
setupLibraries(projectWithResolvedLibraries, project);
}
});
}
};
UIUtil.invokeLaterIfNeeded(resolveDependenciesTask);
}
}
});
GradleModulesImporter importer = new GradleModulesImporter();
return Collections.emptyList();
}
File projectFile = getProjectFile();
assert projectFile != null;
Map<GradleModule, Module> mappings =
importer.importModules(myModuleMappings.values(), project, model, projectFile.getAbsolutePath());
return new ArrayList<Module>(mappings.values());
/**
* The whole import sequence looks like below:
* <p/>
* <pre>
* <ol>
* <li>Get project view from the gradle tooling api without resolving dependencies (downloading libraries);</li>
* <li>Allow to adjust project settings before importing;</li>
* <li>Create IJ project and modules;</li>
* <li>Ask gradle tooling api to resolve library dependencies (download the if necessary);</li>
* <li>Configure libraries used by the gradle project at intellij;</li>
* <li>Configure library dependencies;</li>
* </ol>
* </pre>
* <p/>
*
* @param projectWithResolvedLibraries gradle project with resolved libraries (libraries have already been downloaded and
* are available at file system under gradle service directory)
* @param project current intellij project which should be configured by libraries and module library
* dependencies information available at the given gradle project
*/
private void setupLibraries(final GradleProject projectWithResolvedLibraries, final Project project) {
final Set<? extends GradleLibrary> libraries = projectWithResolvedLibraries.getLibraries();
GradleUtil.executeProjectChangeAction(project, libraries, new Runnable() {
@Override
public void run() {
ProjectRootManagerEx.getInstanceEx(project).mergeRootsChangesDuring(new Runnable() {
@Override
public void run() {
// Clean existing libraries (if any).
LibraryTable projectLibraryTable = ProjectLibraryTable.getInstance(project);
if (projectLibraryTable == null) {
GradleLog.LOG.warn(
"Can't resolve external dependencies of the target gradle project (" + project + "). Reason: project "
+ "library table is undefined"
);
return;
}
LibraryTable.ModifiableModel model = projectLibraryTable.getModifiableModel();
try {
for (Library library : model.getLibraries()) {
model.removeLibrary(library);
}
}
finally {
model.commit();
}
// Register libraries.
myLibraryManager.importLibraries(projectWithResolvedLibraries.getLibraries(), project);
GradleProjectStructureHelper helper = project.getComponent(GradleProjectStructureHelper.class);
for (GradleModule module : projectWithResolvedLibraries.getModules()) {
Module intellijModule = helper.findIntellijModule(module);
assert intellijModule != null;
myDependencyManager.importDependencies(module.getDependencies(), intellijModule);
}
}
});
}
});
}
@Nullable
@@ -206,32 +322,6 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
context.setProjectJdk(myGradleProject.getSdk());
}
/**
* The whole import sequence looks like below:
* <p/>
* <pre>
* <ol>
* <li>Get project view from the gradle tooling api without resolving dependencies (downloading libraries);</li>
* <li>Allow to adjust project settings before importing;</li>
* <li>Create IJ project and modules;</li>
* <li>Ask gradle tooling api to resolve library dependencies (download the if necessary);</li>
* <li>Configure modules dependencies;</li>
* </ol>
* </pre>
* <p/>
* {@link GradleEntity} guarantees correct {@link #equals(Object)}/{@link #hashCode()} implementation, so, we expect
* to get {@link GradleModule modules} that are the same in terms of {@link #equals(Object)} on subsequent calls. However,
* end-user is allowed to change their settings before the importing (e.g. module name), so, we need to map modules with
* resolved libraries to the modules from project 'view'. That's why end-user adjusts settings of the cloned modules.
* Given collection holds mappings between them.
*
* @param mappings origin-adjusted modules mappings
*/
public void setModuleMappings(@NotNull Map<GradleModule/*origin module*/, GradleModule/*adjusted module*/> mappings) {
myModuleMappings.clear();
myModuleMappings.putAll(mappings);
}
/**
* Allows to get {@link Project} instance to use. Basically, there are two alternatives -
* {@link WizardContext#getProject() project from the current wizard context} and
@@ -188,15 +188,11 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza
List<GradleModule> modules = new ArrayList<GradleModule>(project.getModules());
Collections.sort(modules, Named.COMPARATOR);
List<MutableTreeNode> moduleNodes = new ArrayList<MutableTreeNode>();
Map<GradleModule, GradleModule> moduleMappings = new HashMap<GradleModule, GradleModule>();
GradleEntityCloneContext cloneContext = new GradleEntityCloneContext();
for (GradleModule module : modules) {
GradleModule moduleCopy = module.clone(cloneContext);
moduleMappings.put(module, moduleCopy);
GradleProjectStructureNode<GradleEntityId> moduleNode = buildNode(module, entity2nodes, counter++);
moduleNodes.add(moduleNode);
for (GradleContentRoot contentRoot : moduleCopy.getContentRoots()) {
for (GradleContentRoot contentRoot : module.getContentRoots()) {
moduleNode.add(buildNode(contentRoot, entity2nodes, counter++));
}
Collection<GradleDependency> dependencies = module.getDependencies();
@@ -263,7 +259,6 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza
}
myTree.expandPath(new TreePath(root.getPath()));
builder.setModuleMappings(moduleMappings);
}
private GradleProjectStructureNode<GradleEntityId> buildNode(
@@ -113,7 +113,7 @@ public class GradleApiFacadeImpl extends RemoteServer implements GradleApiFacade
try {
I stub = (I)UnicastRemoteObject.exportObject(proxy, 0);
I stored = (I)myRemotes.putIfAbsent(implClass, stub);
return stored == null ? result : stored;
return stored == null ? stub : stored;
}
catch (RemoteException e) {
Object raceResult = myRemotes.get(implClass);
@@ -3,10 +3,7 @@ package org.jetbrains.plugins.gradle.sync;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.LibraryOrderEntry;
import com.intellij.openapi.roots.ModuleOrderEntry;
import com.intellij.openapi.roots.OrderEntry;
import com.intellij.openapi.roots.RootPolicy;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Ref;
@@ -177,6 +174,21 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent {
return null;
}
@Nullable
public LibraryOrderEntry findIntellijLibraryDependency(@NotNull final String libraryName,
@NotNull ModifiableRootModel model)
{
for (OrderEntry entry : model.getOrderEntries()) {
if (entry instanceof LibraryOrderEntry) {
LibraryOrderEntry candidate = (LibraryOrderEntry)entry;
if (libraryName.equals(candidate.getLibraryName())) {
return candidate;
}
}
}
return null;
}
@Nullable
public GradleLibrary findGradleLibrary(@NotNull final String libraryName) {
final GradleProject project = myModel.getGradleProject();
@@ -268,6 +280,18 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent {
}
}
return null;
}
@Nullable
public ModuleOrderEntry findIntellijModuleDependency(@NotNull GradleModuleDependency dependency, @NotNull ModifiableRootModel model) {
for (OrderEntry entry : model.getOrderEntries()) {
if (entry instanceof ModuleOrderEntry) {
ModuleOrderEntry candidate = (ModuleOrderEntry)entry;
if (dependency.getName().equals(candidate.getModuleName())) {
return candidate;
}
}
}
return null;
}
}
@@ -74,7 +74,9 @@ public abstract class AbstractGradleTask implements GradleTask {
catch (Throwable e) {
setState(GradleTaskState.FAILED);
myError.set(e);
LOG.warn(e);
if (myIntellijProject == null || !myIntellijProject.isDisposed()) {
LOG.warn(e);
}
}
}
@@ -503,23 +503,34 @@ public class GradleUtil {
return INSTALLATION_MANAGER.getValue().getGradleHome(project) != null;
}
public static void executeProjectChangeAction(@NotNull Project project, @NotNull Object entityToChange, @NotNull Runnable task) {
executeProjectChangeAction(project, Collections.singleton(entityToChange), task);
}
public static void executeProjectChangeAction(@NotNull Project project, @NotNull Iterable<?> entitiesToChange, @NotNull Runnable task) {
final GradleProjectEntityChangeListener publisher = project.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC);
for (Object e : entitiesToChange) {
publisher.onChangeStart(e);
}
try {
task.run();
}
finally {
for (Object e : entitiesToChange) {
publisher.onChangeEnd(e);
public static void executeProjectChangeAction(@NotNull final Project project, @NotNull final Iterable<?> entitiesToChange, @NotNull final Runnable task) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
final GradleProjectEntityChangeListener publisher = project.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC);
for (Object e : entitiesToChange) {
publisher.onChangeStart(e);
}
try {
task.run();
}
finally {
for (Object e : entitiesToChange) {
publisher.onChangeEnd(e);
}
}
}
});
}
}
});
}
private interface TaskUnderProgress {
@@ -20,7 +20,7 @@ import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.annotate.AnnotationProvider;
import com.intellij.openapi.vcs.annotate.FileAnnotation;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.CommitExecutor;
import com.intellij.openapi.vcs.changes.CommitResultHandler;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vcs.history.VcsHistoryProvider;
@@ -171,8 +171,8 @@ public class HgMockVcsHelper extends AbstractVcsHelper {
}
@Override
public boolean commitChanges(@NotNull List<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitExecutor executor) {
public boolean commitChanges(@NotNull Collection<Change> changes, @NotNull LocalChangeList initialChangeList,
@NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) {
throw new UnsupportedOperationException();
}