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