From 4c6ae376c96687335a0959a232b0efe05fc25c7e Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 5 Dec 2012 15:20:30 +0400 Subject: [PATCH 01/10] [git] Cherry pick: use the common commit dialog. Instead of using a custom commit executor & custom commit session, use the common commit dialog. The problem is that the commit dialog "onOK"-procedure is asynchronous. To fix this provide a CommitResultHandler that is called on successful or failed commit, and wait (in the GitCherryPicker) until it reports that commit has completed. Don't show notification or report error during commit if the CommitResultHandler is set. This fixes IDEA-84825, IDEA-88236 and is necessary for IDEA-87476. --- .../com/intellij/dvcs/test/MockVcsHelper.java | 6 +- .../openapi/vcs/AbstractVcsHelper.java | 14 +- .../vcs/changes/CommitResultHandler.java | 35 ++++ .../vcs/changes/ChangeListManagerImpl.java | 2 +- .../changes/ui/CommitChangeListDialog.java | 32 +-- .../openapi/vcs/changes/ui/CommitHelper.java | 68 ++++--- .../vcs/impl/AbstractVcsHelperImpl.java | 13 +- .../history/browser/GitCherryPicker.java | 187 +++--------------- .../zmlx/hg4idea/test/HgMockVcsHelper.java | 6 +- 9 files changed, 150 insertions(+), 213 deletions(-) create mode 100644 platform/vcs-api/src/com/intellij/openapi/vcs/changes/CommitResultHandler.java diff --git a/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java b/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java index 7cf6b346d536..e14bd69fe468 100644 --- a/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java +++ b/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java @@ -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,8 +185,8 @@ public class MockVcsHelper extends AbstractVcsHelper { } @Override - public boolean commitChanges(@NotNull List changes, @NotNull LocalChangeList initialChangeList, - @NotNull String commitMessage, @Nullable CommitExecutor executor) { + public boolean commitChanges(@NotNull Collection changes, @NotNull LocalChangeList initialChangeList, + @NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) { if (myCommitHandler != null) { return myCommitHandler.commit(commitMessage); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java index fbdc14b28527..b90eee515c20 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java @@ -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. + *

Shows commit dialog, fills it with the given changes and given commit message, initially selects the given changelist.

+ *

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}.

+ * @return true if user decides to commit the changes, false if user presses Cancel. */ - public abstract boolean commitChanges(@NotNull List changes, @NotNull LocalChangeList initialChangeList, - @NotNull String commitMessage, @Nullable CommitExecutor executor); - - + public abstract boolean commitChanges(@NotNull Collection changes, @NotNull LocalChangeList initialChangeList, + @NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler); } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/CommitResultHandler.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/CommitResultHandler.java new file mode 100644 index 000000000000..aaf7575de301 --- /dev/null +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/CommitResultHandler.java @@ -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(); + +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index eb615cd57a33..232301901c35 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -1158,7 +1158,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec private boolean doCommit(final LocalChangeList changeList, final List changes, final boolean synchronously) { return new CommitHelper(myProject, changeList, changes, changeList.getName(), - changeList.getComment(), new ArrayList(), false, synchronously, NullableFunction.NULL).doCommit(); + changeList.getComment(), new ArrayList(), false, synchronously, NullableFunction.NULL, null).doCommit(); } public void commitChangesSynchronously(LocalChangeList changeList, List changes) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java index 065b05204d95..561ec3170e12 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java @@ -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 changes, final LocalChangeList initialSelection, - final List executors, final boolean showVcsCommit, final String comment) { + final List executors, final boolean showVcsCommit, final String comment, + @Nullable CommitResultHandler customResultHandler) { final AbstractVcs[] allActiveVcss = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss(); final List factoryList = CheckinHandlersManager.getInstance().getMatchingVcsFactories(Arrays.asList(allActiveVcss)); @@ -155,7 +157,7 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj final ArrayList changeLists = new ArrayList(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 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 changes, final LocalChangeList initialSelection, - final List executors, final boolean showVcsCommit, final String comment) { + final List 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(changes), initialSelection, executors, showVcsCommit, comment); + return commit(project, new ArrayList(changes), initialSelection, executors, showVcsCommit, comment, customResultHandler); } public static void commitAlienChanges(final Project project, final List 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 executors, final boolean showVcsCommit, final LocalChangeList defaultChangeList, final List 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(); myAdditionalData = new PseudoMap(); myDiffDetails = new ShortDiffDetails(myProject, new Getter() { @@ -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); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java index e84293f2bbee..df86e92215db 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java @@ -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 myAdditionalData; + @Nullable private final CommitResultHandler myCustomResultHandler; private final List myCommittingDocuments = new ArrayList(); private final VcsConfiguration myConfiguration; private final VcsDirtyScopeManager myDirtyScopeManager; @@ -78,7 +80,8 @@ public class CommitHelper { final String commitMessage, final List handlers, final boolean allOfDefaultChangeListChangesIncluded, - final boolean synchronously, final NullableFunction additionalDataHolder) { + final boolean synchronously, final NullableFunction 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(); @@ -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); @@ -511,6 +518,9 @@ public class CommitHelper { } processor.afterSuccessfulCheckIn(); + if (myCustomResultHandler != null) { + myCustomResultHandler.onSuccess(myCommitMessage); + } } else { for (CheckinHandler handler : myHandlers) { @@ -523,28 +533,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, diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java index 1cbbae8458f8..2ee68e92031c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java @@ -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 changes, @NotNull LocalChangeList initialChangeList, - @NotNull String commitMessage, @Nullable CommitExecutor executor) { - return CommitChangeListDialog.commitChanges(myProject, changes, initialChangeList, executor, commitMessage); + public boolean commitChanges(@NotNull Collection 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 abstractVcsExceptions) { diff --git a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java index c13413180501..66728c5a2354 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java @@ -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; @@ -246,26 +237,44 @@ public class GitCherryPicker { private boolean showCommitDialog(@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 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())); + 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) { + sem.release(); + commitSucceeded.set(false); } - 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(); } /** @@ -451,142 +460,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 myChanges; - @NotNull private final String myOriginalCommitMessage; - private boolean myCommitFailed; - - @Nullable private CherryPickCommitExecutor.CherryPickCommitSession myCommitSession; - - CherryPickCommitExecutor(@NotNull Project project, @NotNull GitPlatformFacade platformFacade, - @NotNull List 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 changes, String commitMessage) { - return null; - } - - @Override - public boolean canExecute(Collection changes, String commitMessage) { - return true; - } - - @Override - public void execute(Collection changes, String commitMessage) { - final Collection committingDocs = markCommittingDocs(); - try { - GitCheckinEnvironment ce = ServiceManager.getService(myProject, GitCheckinEnvironment.class); - try { - ce.reset(); - List 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 committingDocs) { - myPlatformFacade.runReadAction(new Runnable() { - @Override - public void run() { - CommitHelper.unmarkCommittingDocuments(committingDocs); - } - }); - } - - @NotNull - private Collection markCommittingDocs() { - final Collection committingDocs = new ArrayList(); - 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. diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMockVcsHelper.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMockVcsHelper.java index 4c75d27c207c..c8ffe9e6b71d 100644 --- a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMockVcsHelper.java +++ b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMockVcsHelper.java @@ -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 changes, @NotNull LocalChangeList initialChangeList, - @NotNull String commitMessage, @Nullable CommitExecutor executor) { + public boolean commitChanges(@NotNull Collection changes, @NotNull LocalChangeList initialChangeList, + @NotNull String commitMessage, @Nullable CommitResultHandler customResultHandler) { throw new UnsupportedOperationException(); } From 12613503fa1fc32a5c47debd57ba1ba054773069 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 5 Dec 2012 15:36:05 +0400 Subject: [PATCH 02/10] [git] cherry-pick: release semaphore if exception is thrown. --- .../history/browser/GitCherryPicker.java | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java index 66728c5a2354..93abb620c5d4 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java @@ -241,27 +241,33 @@ public class GitCherryPicker { myPlatformFacade.invokeAndWait(new Runnable() { @Override public void run() { - cancelCherryPick(repository); - List 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(); - } + try { + cancelCherryPick(repository); + List 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() { + @Override + public void onFailure() { + commitSucceeded.set(false); + sem.release(); + } + }); + + if (!commitNotCancelled) { commitSucceeded.set(false); sem.release(); } - }); - - if (!commitNotCancelled) { - sem.release(); + } catch (Throwable t) { + LOG.error(t); commitSucceeded.set(false); + sem.release(); } } }, ModalityState.NON_MODAL); From 25a7e4c52f350ad999b05a2661c4f3330d48cdb4 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Dec 2012 13:13:09 +0400 Subject: [PATCH 03/10] [git] IDEA-87476 Persist author on cherry-pick. * Let LocalChangeList have arbitrary data associated with it. * When a changelist is created via ChangeListManager#addChangeList, only a copy is returned, therefore there is no way to set data after changelist has been created. To solve this introduce addChangeList extension that accepts the data parameter. * On cherry-pick pass the GitCommit being cherry-picked as a data to the changelist. * When displaying the commit dialog get the author from the provided data (GitCheckinEnvironment) and set it to the combobox. * Fix GitCheckinOptions#saveState to take the value from the editor instead of the list. This should solve IDEA-81181 as well. * Remove GitChangeList - not used. --- .../testFramework/vcs/MockChangeList.java | 7 ++ .../vcs/MockChangeListManager.java | 4 + .../openapi/vcs/changes/LocalChangeList.java | 6 ++ .../vcs/changes/ChangeListManagerEx.java | 3 + .../vcs/changes/ChangeListManagerImpl.java | 10 ++- .../ChangeListManagerSerialization.java | 3 +- .../openapi/vcs/changes/ChangeListWorker.java | 10 ++- .../changes/ChangeListsWriteOperations.java | 2 +- .../vcs/changes/LocalChangeListImpl.java | 12 +++ .../openapi/vcs/changes/Modifier.java | 4 +- .../openapi/vcs/changes/local/AddList.java | 6 +- .../vcs/changes/ui/AlienLocalChangeList.java | 7 ++ .../src/git4idea/changes/GitChangeList.java | 74 ------------------- .../checkin/GitCheckinEnvironment.java | 21 ++++-- .../history/browser/GitCherryPicker.java | 11 +-- 15 files changed, 83 insertions(+), 97 deletions(-) delete mode 100644 plugins/git4idea/src/git4idea/changes/GitChangeList.java diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeList.java b/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeList.java index f1242a36fa58..c2fb7749ea35 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeList.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeList.java @@ -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(); diff --git a/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java b/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java index 8514ec50d46a..470b3ccbc155 100644 --- a/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java +++ b/platform/testFramework/testSrc/com/intellij/testFramework/vcs/MockChangeListManager.java @@ -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); + } } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/LocalChangeList.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/LocalChangeList.java index fbb3cfbf6302..002c0163321c 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/LocalChangeList.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/LocalChangeList.java @@ -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() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerEx.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerEx.java index b95b94cf323e..bab36f26697b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerEx.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerEx.java @@ -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); } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java index 232301901c35..d34ae8db6eb0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerImpl.java @@ -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() { @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 diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java index 2a4ee9a8d071..71e271d07a38 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListManagerSerialization.java @@ -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 changeNodes = (List)listNode.getChildren(NODE_CHANGE); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java index 350a4e7ef77e..2082443edc24 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListWorker.java @@ -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) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListsWriteOperations.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListsWriteOperations.java index d7caa4f60cb0..2256393ce7d5 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListsWriteOperations.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangeListsWriteOperations.java @@ -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 moveChangesTo(String name, Change[] changes); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java index ab74f53e7856..9be47384272b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/LocalChangeListImpl.java @@ -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(myChanges); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/Modifier.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/Modifier.java index ded8c2013286..de2cb4003360 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/Modifier.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/Modifier.java @@ -39,8 +39,8 @@ public class Modifier implements ChangeListsWriteOperations { myCommandQueue = new LinkedList(); } - 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(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/local/AddList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/local/AddList.java index fc4ee4e530df..5be08d54c56a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/local/AddList.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/local/AddList.java @@ -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); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/AlienLocalChangeList.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/AlienLocalChangeList.java index cefeb54a9da1..18130b616ca8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/AlienLocalChangeList.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/AlienLocalChangeList.java @@ -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(); } diff --git a/plugins/git4idea/src/git4idea/changes/GitChangeList.java b/plugins/git4idea/src/git4idea/changes/GitChangeList.java deleted file mode 100644 index 61452047d3ee..000000000000 --- a/plugins/git4idea/src/git4idea/changes/GitChangeList.java +++ /dev/null @@ -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 changes; - - public GitChangeList(@NotNull String name, String comment, Collection 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 getChanges() { - return changes; - } - - public LocalChangeList copy() { - return new GitChangeList(name, comment, changes); - } -} diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 6bfeb56dd7d4..91fb4ea99c2b 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -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; @@ -564,7 +563,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { /** * Checkin options for git */ - private class GitCheckinOptions implements RefreshableOnComponent { + private class GitCheckinOptions implements CheckinChangeListSpecificComponent { /** * A container panel */ @@ -661,7 +660,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; @@ -679,6 +678,16 @@ 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); + } + } } public void setNextCommitIsPushed(Boolean nextCommitIsPushed) { diff --git a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java index 93abb620c5d4..1920cafdabfb 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java @@ -197,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 changes, @NotNull final Collection paths, + private LocalChangeList createChangeListAfterUpdate(@NotNull final GitCommit commit, @NotNull final Collection paths, @NotNull final String commitMessage) { final AtomicReference changeList = new AtomicReference(); myPlatformFacade.invokeAndWait(new Runnable() { @@ -210,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() { @@ -362,9 +362,10 @@ public class GitCherryPicker { } @NotNull - private LocalChangeList createChangeList(@NotNull List changes, @NotNull String commitMessage) { + private LocalChangeList createChangeList(@NotNull GitCommit commit, @NotNull String commitMessage) { + List 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; From 50deed4a16e9c4a99d6c6da3a1088bb7b5621ce3 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Dec 2012 15:54:53 +0400 Subject: [PATCH 04/10] [git] IDEA-90566 Persist author date on cherry-pick Remember the date on commit dialog show and use it on commit. Transform the date to ISO 8601 standard accepted by Git. --- .../checkin/GitCheckinEnvironment.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 91fb4ea99c2b..3516dd0e4a82 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -60,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; @@ -72,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; @@ -177,7 +179,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { Set files = new HashSet(); 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)) { @@ -439,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 */ @@ -453,7 +458,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { Collection files, File message, final String nextCommitAuthor, - boolean nextCommitAmend) + boolean nextCommitAmend, Date nextCommitAuthorDate) throws VcsException { boolean amend = nextCommitAmend; for (List paths : VcsFileUtil.chunkPaths(root, files)) { @@ -469,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(); @@ -558,6 +566,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { myNextCommitAmend = false; myNextCommitAuthor = null; myNextCommitIsPushed = null; + myNextCommitAuthorDate = null; } /** @@ -576,6 +585,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { * The amend checkbox */ private final JCheckBox myAmend; + private Date myAuthorDate; /** * A constructor @@ -670,6 +680,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { mySettings.saveCommitAuthor(author); } myNextCommitAmend = myAmend.isSelected(); + myNextCommitAuthorDate = myAuthorDate; } /** @@ -686,6 +697,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { GitCommit commit = (GitCommit)data; String author = String.format("%s <%s>", commit.getAuthor(), commit.getAuthorEmail()); myAuthor.getEditor().setItem(author); + myAuthorDate = new Date(commit.getAuthorTime()); } } } From 723a71a9aecde087ad1efc59fa9f89d645f38d4d Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Dec 2012 15:56:23 +0400 Subject: [PATCH 05/10] [git] rename method --- .../src/git4idea/history/browser/GitCherryPicker.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java index 1920cafdabfb..68a6a210f852 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java @@ -154,7 +154,7 @@ public class GitCherryPicker { @NotNull GitCommitWrapper commit, @NotNull List 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); @@ -234,8 +234,8 @@ 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() { From afe5252868145601cb1bbf495e653121d6e4949b Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Dec 2012 16:16:50 +0400 Subject: [PATCH 06/10] [vcs] If a RuntimeException happens on commit, treat it as failure not a success Just add the exception to the processor. --- .../openapi/vcs/changes/ui/CommitHelper.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java index df86e92215db..7d591bde1e52 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitHelper.java @@ -209,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() { From d4e2a395eb052036c8d30ce8c6e72c2a0f17df77 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Dec 2012 16:53:31 +0400 Subject: [PATCH 07/10] [git] Fix tests on cherry-pick Process customResultHandler in MockVcsHelper#commit. --- .../com/intellij/dvcs/test/MockVcsHelper.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java b/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java index e14bd69fe468..da3acfb17603 100644 --- a/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java +++ b/platform/dvcs/testFramework/com/intellij/dvcs/test/MockVcsHelper.java @@ -188,7 +188,19 @@ public class MockVcsHelper extends AbstractVcsHelper { public boolean commitChanges(@NotNull Collection 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; } From 317b8d46952312ef3b996b7b902e9ca5d83c02cb Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Thu, 6 Dec 2012 16:54:26 +0400 Subject: [PATCH 08/10] [git] Display the original commit message on cherry-pick (without "cherry-picked from"). --- .../src/git4idea/history/browser/GitCherryPicker.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java index 68a6a210f852..e29c20aae7b2 100644 --- a/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java +++ b/plugins/git4idea/src/git4idea/history/browser/GitCherryPicker.java @@ -349,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 filePaths) { @@ -493,6 +493,10 @@ public class GitCherryPicker { public GitCommit getCommit() { return myOriginalCommit; } + + public String getOriginalSubject() { + return myOriginalCommit.getSubject(); + } } } From 49b71d0b8152a12223aa049fba519dd4a3a1e29e Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 6 Dec 2012 12:37:19 +0100 Subject: [PATCH 09/10] Do not mix Java/AspectJ compiler options --- .../jetbrains/jps/incremental/java/JavaBuilder.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java index 40c5c958a766..7c70eb85064c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java @@ -476,14 +476,20 @@ public class JavaBuilder extends ModuleLevelBuilder { return cached; } - public static List getCompilationOptions(CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) { + private static List getCompilationOptions(CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) { List cached = JAVAC_OPTIONS.get(context); if (cached == null) { loadCommonJavacOptions(context); cached = JAVAC_OPTIONS.get(context); + assert cached != null : context; } - final List options = new ArrayList(cached); + List options = new ArrayList(cached); + addCompilationOptions(options, context, chunk, profile); + return options; + } + + public static void addCompilationOptions(List 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) { From 72eb77b4bc2c5f61a32e19064aa755c778474545 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Thu, 6 Dec 2012 17:41:19 +0400 Subject: [PATCH 10/10] IDEA-96743 Gradle: Avoid unnecessary refresh on initial project import 1. Project entities import is performed in a way that 'auto-refresh on project roots change' is not triggered; 2. Legacy code is removed; --- .../manage/GradleContentRootManager.java | 93 ++- .../manage/GradleDependencyManager.java | 191 +++--- .../gradle/manage/GradleLibraryManager.java | 61 +- .../gradle/manage/GradleModuleManager.java | 62 +- .../gradle/manage/GradleModulesImporter.java | 564 ------------------ .../manage/GradleProjectImportBuilder.java | 170 ++++-- .../GradleAdjustImportSettingsStep.java | 7 +- .../remote/impl/GradleApiFacadeImpl.java | 2 +- .../sync/GradleProjectStructureHelper.java | 32 +- .../gradle/task/AbstractGradleTask.java | 4 +- .../plugins/gradle/util/GradleUtil.java | 35 +- 11 files changed, 360 insertions(+), 861 deletions(-) delete mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModulesImporter.java diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleContentRootManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleContentRootManager.java index 1d40834f1a14..d062f821f762 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleContentRootManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleContentRootManager.java @@ -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 contentRoots, @NotNull final Module module) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - doImportContentRoots(contentRoots, module); - } - }); - } - - private static void doImportContentRoots(@NotNull final Iterable contentRoots, @NotNull final Module module) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void importContentRoots(@NotNull final Collection 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 contentRoots) { - UIUtil.invokeLaterIfNeeded(new Runnable() { + public void removeContentRoots(@NotNull final Collection 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(); + } + } } }); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleDependencyManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleDependencyManager.java index 4fa493f1c634..f8ec9ac9121b 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleDependencyManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleDependencyManager.java @@ -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 dependencies, @NotNull Module module) { final List moduleDependencies = new ArrayList(); final List libraryDependencies = new ArrayList(); @@ -56,19 +54,12 @@ public class GradleDependencyManager { } @SuppressWarnings("MethodMayBeStatic") - public void importModuleDependencies(@NotNull final Iterable dependencies, @NotNull final Module module) { - UIUtil.invokeLaterIfNeeded(new Runnable() { - @Override - public void run() { - doImportModuleDependencies(dependencies, module); - } - }); - } - - private static void doImportModuleDependencies(@NotNull final Iterable dependencies, - @NotNull final Module module) - { - ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void importModuleDependencies(@NotNull final Collection 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 dependencies, @NotNull final Module module) { - final List infos = new ArrayList(); - 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 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 librariesToImport = new HashSet(); + 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 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 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(); + } + } + }); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleLibraryManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleLibraryManager.java index b749ebebb165..c0b38fae255e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleLibraryManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleLibraryManager.java @@ -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 libraries, @NotNull Project project) { + for (GradleLibrary library : libraries) { + importLibrary(library, project); + } + } + + public void importLibrary(@NotNull final GradleLibrary library, @NotNull final Project project) { Map> libraryFiles = new HashMap>(); for (LibraryPathType pathType : LibraryPathType.values()) { final Set 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> libraryFiles, - @NotNull final Project project) + public void importLibrary(@NotNull final String libraryName, + @NotNull final Map> libraryFiles, + @NotNull final Project project) { - final Ref result = new Ref(); - 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> libraryFiles, - @NotNull Project project) - { - // Is assumed to be called from the EDT. - final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(project); - final Ref result = new Ref(); - 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> 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 libraries) { + public void removeLibraries(@NotNull List libraries) { // TODO den implement //LibraryTable table = library.getTable(); //table.removeLibrary(library); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModuleManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModuleManager.java index 0ffc42f734cb..916ee0057597 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModuleManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModuleManager.java @@ -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 modules, @NotNull final Project project, final boolean recursive) { + public void importModules(@NotNull final Collection 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 modules) { + private static void removeExistingModulesConfigs(@NotNull Collection 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 modules) { - UIUtil.invokeLaterIfNeeded(new Runnable() { + public void removeModules(@NotNull final Collection 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 myModules; - private final boolean myRecursive; + private final Project myProject; + private final Collection myModules; + private final boolean myRecursive; - ImportModulesTask(@NotNull Project project, @NotNull Iterable modules, boolean recursive) { + ImportModulesTask(@NotNull Project project, @NotNull Collection modules, boolean recursive) { myProject = project; myModules = modules; myRecursive = recursive; @@ -192,5 +193,4 @@ public class GradleModuleManager { importModules(myModules, myProject, myRecursive); } } - } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModulesImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModulesImporter.java deleted file mode 100644 index f55af6110203..000000000000 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleModulesImporter.java +++ /dev/null @@ -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}. - *

- * Not thread-safe. - * - * @author Denis Zhdanov - * @since 8/26/11 10:01 AM - */ -// TODO den remove -public class GradleModulesImporter { - - private static final Map LIBRARY_ROOT_MAPPINGS - = new EnumMap(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 importModules(@NotNull final Iterable 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 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 importModules(@NotNull final Iterable modules, - @NotNull final ModifiableModuleModel model, - @NotNull final Project intellijProject, - @NotNull final String gradleProjectPath) - { - final Map result = new HashMap(); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - Application application = ApplicationManager.getApplication(); - AccessToken writeLock = application.acquireWriteActionLock(getClass()); - try { - final List rootModels = new ArrayList(); - final GradleProjectEntityChangeListener publisher = - intellijProject.getMessageBus().syncPublisher(GradleProjectEntityChangeListener.TOPIC); - for (GradleModule module : modules) { - publisher.onChangeStart(module); - } - try { - Map 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 doImportModules(@NotNull Iterable modules, - @NotNull ModifiableModuleModel model, - @NotNull List rootModels) - { - Map result = new HashMap(); - 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 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 modules) - { - // Ensure that dependencies are clear. - final Object key = new Object(); - final Object dummy = new Object(); - RootPolicy policy = new RootPolicy() { - @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. - *

- * Note: 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 moduleMappings, - @NotNull final Project intellijProject, - @NotNull final String gradleProjectPath) - { - final Ref gradleProjectRef = new Ref(); - final Ref libraryToPreserve = new Ref(); - - 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 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 modelsToCommit = new ArrayList(); - Map 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 registerProjectLibraries(@NotNull GradleProject gradleProject, - @NotNull LibraryTable.ModifiableModel librariesModel) - { - Map libraryMappings = new HashMap(); - 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 configureModulesLibraryDependencies( - @NotNull Map moduleMappings, - @NotNull final Map libraryMappings, - @NotNull GradleProject gradleProject) - { - List result = new ArrayList(); - 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 myModules; - private final String myGradleProjectPath; - - ImportModulesTask(@NotNull Project project, @NotNull Iterable 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() { - protected void run(Result 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 myModules; - private final String myGradleProjectPath; - private final Project myIntellijProject; - - SetupExternalLibrariesTask(@NotNull Map modules, - @NotNull String gradleProjectPath, - @NotNull Project intellijProject) - { - myModules = modules; - myGradleProjectPath = gradleProjectPath; - myIntellijProject = intellijProject; - } - - @Override - public void run() { - setupLibraries(myModules, myIntellijProject, myGradleProjectPath); - } - } -} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleProjectImportBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleProjectImportBuilder.java index 1dc7cbe3fed5..33edefceeefa 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleProjectImportBuilder.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/GradleProjectImportBuilder.java @@ -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 { - /** @see #setModuleMappings(Map) */ - private final Map myModuleMappings = new HashMap(); - - 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 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 mappings = - importer.importModules(myModuleMappings.values(), project, model, projectFile.getAbsolutePath()); - return new ArrayList(mappings.values()); + /** + * The whole import sequence looks like below: + *

+ *

+   * 
    + *
  1. Get project view from the gradle tooling api without resolving dependencies (downloading libraries);
  2. + *
  3. Allow to adjust project settings before importing;
  4. + *
  5. Create IJ project and modules;
  6. + *
  7. Ask gradle tooling api to resolve library dependencies (download the if necessary);
  8. + *
  9. Configure libraries used by the gradle project at intellij;
  10. + *
  11. Configure library dependencies;
  12. + *
+ *
+ *

+ * + * @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 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 - *

-   * 
    - *
  1. Get project view from the gradle tooling api without resolving dependencies (downloading libraries);
  2. - *
  3. Allow to adjust project settings before importing;
  4. - *
  5. Create IJ project and modules;
  6. - *
  7. Ask gradle tooling api to resolve library dependencies (download the if necessary);
  8. - *
  9. Configure modules dependencies;
  10. - *
- *
- *

- * {@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 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 diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/wizard/adjust/GradleAdjustImportSettingsStep.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/wizard/adjust/GradleAdjustImportSettingsStep.java index 44c3da214b88..39dc8f4b7400 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/wizard/adjust/GradleAdjustImportSettingsStep.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/manage/wizard/adjust/GradleAdjustImportSettingsStep.java @@ -188,15 +188,11 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza List modules = new ArrayList(project.getModules()); Collections.sort(modules, Named.COMPARATOR); List moduleNodes = new ArrayList(); - Map moduleMappings = new HashMap(); - GradleEntityCloneContext cloneContext = new GradleEntityCloneContext(); for (GradleModule module : modules) { - GradleModule moduleCopy = module.clone(cloneContext); - moduleMappings.put(module, moduleCopy); GradleProjectStructureNode 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 dependencies = module.getDependencies(); @@ -263,7 +259,6 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza } myTree.expandPath(new TreePath(root.getPath())); - builder.setModuleMappings(moduleMappings); } private GradleProjectStructureNode buildNode( diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/impl/GradleApiFacadeImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/impl/GradleApiFacadeImpl.java index 74ed43dd9c74..e753764fbc9a 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/impl/GradleApiFacadeImpl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/impl/GradleApiFacadeImpl.java @@ -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); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java index df0e73be81c5..8a0b05240b37 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java @@ -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; } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/AbstractGradleTask.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/AbstractGradleTask.java index d39d0e20d981..6be6f4448fc2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/AbstractGradleTask.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/AbstractGradleTask.java @@ -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); + } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java index 69b0ef1b7fcb..11e91135ec4f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java @@ -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 {