From f8096661e08821f0763cd3303ae803c155c17632 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 24 Jan 2012 17:20:10 +0400 Subject: [PATCH 01/18] deadcode --- .../git4idea/branch/GitBranchOperationsProcessor.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java index c9bc96210729..392554efbcf8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperationsProcessor.java @@ -23,14 +23,12 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ui.UIUtil; import git4idea.GitExecutionException; import git4idea.GitVcs; import git4idea.commands.Git; import git4idea.history.GitHistoryUtils; import git4idea.history.browser.GitCommit; -import git4idea.merge.GitConflictResolver; import git4idea.repo.GitRepository; import git4idea.ui.branch.GitBranchUiUtil; import git4idea.ui.branch.GitCompareBranchesDialog; @@ -125,15 +123,6 @@ public final class GitBranchOperationsProcessor { new GitCheckoutNewBranchOperation(myProject, myRepositories, name, getCurrentBranch(), indicator).execute(); } - - @NotNull - static GitConflictResolver prepareConflictResolverForUnmergedFilesBeforeCheckout(Project project, Collection roots) { - GitConflictResolver.Params params = new GitConflictResolver.Params(). - setMergeDescription("The following files have unresolved conflicts. You need to resolve them before checking out."). - setErrorNotificationTitle("Can't create new branch"); - return new GitConflictResolver(project, roots, params); - } - /** * Creates and checks out a new local branch starting from the given reference: * {@code git checkout -b }.
From d9b2350a0bd340b6c9d797f1713dc5aea75e0219 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 24 Jan 2012 18:43:57 +0400 Subject: [PATCH 02/18] GitRepository: make getFullInstance public for tests --- plugins/git4idea/src/git4idea/repo/GitRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/repo/GitRepository.java b/plugins/git4idea/src/git4idea/repo/GitRepository.java index 95213930b1b6..b3d88b4b5efc 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepository.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepository.java @@ -201,7 +201,7 @@ public final class GitRepository implements Disposable { * Returns the full-functional instance of GitRepository - with UntrackedFilesHolder and GitRepositoryUpdater. * This is used for repositories registered in project, and should be optained via {@link GitRepositoryManager}. */ - static GitRepository getFullInstance(@NotNull VirtualFile root, @NotNull Project project, @NotNull Disposable parentDisposable) { + public static GitRepository getFullInstance(@NotNull VirtualFile root, @NotNull Project project, @NotNull Disposable parentDisposable) { GitRepository repository = new GitRepository(root, project, parentDisposable); repository.myUntrackedFilesHolder.setupVfsListener(project); repository.setupUpdater(); From 0bcc0f9af71280c3838f6fa77abef891ca3931f3 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 24 Jan 2012 18:47:35 +0400 Subject: [PATCH 03/18] GitBranchOperationsTest, TestMessageManager, TestNotificationManager Use MessageManager, NotificationManager and already existing DialogManager as proxy to show Messages, Notifications and DialogWrappers. Declare them as services and substitute by TestMessageManager, TestNotificationManager and TestDialogManager when needed (by GitTestUtil methods). Introduce GitExec - the third attempt to make a handy framework to call Git from tests. GitBranchOperationsTest to test multi-root branch creation and deletion, including notifications, rollback proposals, etc. --- plugins/git4idea/src/META-INF/plugin.xml | 16 +- .../git4idea/src/git4idea/MessageManager.java | 43 +++ .../src/git4idea/NotificationManager.java | 56 +++ .../GitBranchIsNotFullyMergedDialog.java | 3 +- .../git4idea/branch/GitBranchOperation.java | 22 +- .../branch/GitBranchOperationsTest.java | 326 ++++++++++++++++++ .../git4idea/tests/git4idea/test/GitExec.java | 101 ++++++ .../test/GitTestScenarioGenerator.java | 57 +++ .../tests/git4idea/test/GitTestUtil.java | 34 ++ .../git4idea/test/TestMessageManager.java | 70 ++++ .../test/TestNotificationManager.java | 51 +++ .../tests/GitLineSeparatorsConverterTest.java | 16 +- 12 files changed, 767 insertions(+), 28 deletions(-) create mode 100644 plugins/git4idea/src/git4idea/MessageManager.java create mode 100644 plugins/git4idea/src/git4idea/NotificationManager.java create mode 100644 plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java create mode 100644 plugins/git4idea/tests/git4idea/test/GitExec.java create mode 100644 plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java create mode 100644 plugins/git4idea/tests/git4idea/test/TestMessageManager.java create mode 100644 plugins/git4idea/tests/git4idea/test/TestNotificationManager.java diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index df8c93c5bafa..cba4acd503cf 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -128,10 +128,18 @@ - - + + + + diff --git a/plugins/git4idea/src/git4idea/MessageManager.java b/plugins/git4idea/src/git4idea/MessageManager.java new file mode 100644 index 000000000000..02d9f4b1efa4 --- /dev/null +++ b/plugins/git4idea/src/git4idea/MessageManager.java @@ -0,0 +1,43 @@ +/* + * 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 git4idea; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Kirill Likhodedov + */ +public class MessageManager { + + public static MessageManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, MessageManager.class); + } + + public static int showYesNoDialog(Project project, String description, String title, String yesText, String noText, @Nullable Icon icon) { + return getInstance(project).doShowYesNoDialog(project, description, title, yesText, noText, icon); + } + + @SuppressWarnings("MethodMayBeStatic") + protected int doShowYesNoDialog(Project project, String description, String title, String yesText, String noText, @Nullable Icon icon) { + return Messages.showYesNoDialog(project, description, title, yesText, noText, icon); + } +} diff --git a/plugins/git4idea/src/git4idea/NotificationManager.java b/plugins/git4idea/src/git4idea/NotificationManager.java new file mode 100644 index 000000000000..93ad28e5b8cd --- /dev/null +++ b/plugins/git4idea/src/git4idea/NotificationManager.java @@ -0,0 +1,56 @@ +/* + * 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 git4idea; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Kirill Likhodedov + */ +public class NotificationManager { + + @NotNull private final Project myProject; + + public NotificationManager(@NotNull Project project) { + myProject = project; + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, + @NotNull NotificationType type, @Nullable NotificationListener listener) { + createNotification(notificationGroup, title, message, type, listener).notify(myProject); + } + + public static NotificationManager getInstance(@NotNull Project project) { + return ServiceManager.getService(project, NotificationManager.class); + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type) { + notify(notificationGroup, title, message, type, null); + } + + protected static Notification createNotification(NotificationGroup notificationGroup, String title, String message, + NotificationType type, NotificationListener listener) { + return notificationGroup.createNotification(title, message, type, listener); + } + +} diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java b/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java index 6fdd7bd4dce9..74d90b17b641 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchIsNotFullyMergedDialog.java @@ -21,6 +21,7 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.components.JBLabel; import com.intellij.util.ArrayUtil; +import git4idea.DialogManager; import git4idea.GitBranch; import git4idea.history.browser.GitCommit; import git4idea.i18n.GitBundle; @@ -76,7 +77,7 @@ public class GitBranchIsNotFullyMergedDialog extends DialogWrapper { @NotNull List mergedToBranches, @Nullable String currentBranch) { GitBranchIsNotFullyMergedDialog dialog = new GitBranchIsNotFullyMergedDialog(project, commits, branchToDelete, currentBranch, mergedToBranches); - dialog.show(); + DialogManager.getInstance(project).showDialog(dialog); return dialog.isOK(); } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index 13c3bc156406..7d047ce0a3b0 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -25,6 +25,8 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; import git4idea.GitVcs; +import git4idea.MessageManager; +import git4idea.NotificationManager; import git4idea.merge.GitConflictResolver; import git4idea.repo.GitRepository; import git4idea.util.GitUtil; @@ -43,7 +45,10 @@ import java.util.concurrent.atomic.AtomicBoolean; */ abstract class GitBranchOperation { - private static final String UNMERGED_FILES_ERROR_TITLE = "Can't checkout because of unmerged files"; + static final String UNMERGED_FILES_ERROR_TITLE = "Can't checkout because of unmerged files"; + static final String UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION = + "You have to resolve all merge conflicts before checkout.
" + + "After resolving conflicts you also probably would want to commit your files to the current branch."; @NotNull protected final Project myProject; @NotNull private final Collection myRepositories; @@ -129,7 +134,7 @@ abstract class GitBranchOperation { } protected void notifySuccess() { - GitVcs.NOTIFICATION_GROUP_ID.createNotification(getSuccessMessage(), NotificationType.INFORMATION).notify(myProject); + NotificationManager.getInstance(myProject).notify(GitVcs.NOTIFICATION_GROUP_ID, "", getSuccessMessage(), NotificationType.INFORMATION); } /** @@ -151,7 +156,7 @@ abstract class GitBranchOperation { public void run() { String description = message + getRollbackProposal(); ok.set(Messages.OK == - Messages.showYesNoDialog(myProject, description, title, "Rollback", "Don't rollback", Messages.getErrorIcon())); + MessageManager.showYesNoDialog(myProject, description, title, "Rollback", "Don't rollback", Messages.getErrorIcon())); } }); if (ok.get()) { @@ -164,7 +169,7 @@ abstract class GitBranchOperation { } protected void notifyError(@NotNull String title, @NotNull String message) { - GitVcs.IMPORTANT_ERROR_NOTIFICATION.createNotification(title, message, NotificationType.ERROR, null).notify(myProject); + NotificationManager.getInstance(myProject).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, title, message, NotificationType.ERROR); } @NotNull @@ -192,7 +197,7 @@ abstract class GitBranchOperation { String description = "You have to resolve all merge conflicts before checkout.
" + getRollbackProposal(); // suppressing: this message looks ugly if capitalized by words //noinspection DialogTitleCapitalization - ok.set(Messages.OK == Messages.showYesNoDialog(myProject, description, UNMERGED_FILES_ERROR_TITLE, "Rollback", "Don't rollback", Messages.getErrorIcon())); + ok.set(Messages.OK == MessageManager.showYesNoDialog(myProject, description, UNMERGED_FILES_ERROR_TITLE, "Rollback", "Don't rollback", Messages.getErrorIcon())); } }); if (ok.get()) { @@ -202,9 +207,8 @@ abstract class GitBranchOperation { private void showUnmergedFilesNotification() { String title = UNMERGED_FILES_ERROR_TITLE; - String description = "You have to resolve all merge conflicts before checkout.
" + - "After resolving conflicts you also probably would want to commit your files to the current branch."; - GitVcs.IMPORTANT_ERROR_NOTIFICATION.createNotification(title, description, NotificationType.ERROR, new NotificationListener() { + String description = UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION; + NotificationManager.getInstance(myProject).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, title, description, NotificationType.ERROR, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED && event.getDescription().equals("resolve")) { GitConflictResolver.Params params = new GitConflictResolver.Params(). @@ -213,7 +217,7 @@ abstract class GitBranchOperation { new GitConflictResolver(myProject, GitUtil.getRoots(getRepositories()), params).merge(); } } - }).notify(myProject); + }); } } diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java new file mode 100644 index 000000000000..ba57baadc8a2 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -0,0 +1,326 @@ +package git4idea.branch; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.progress.EmptyProgressIndicator; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsConfiguration; +import com.intellij.openapi.vcs.VcsShowConfirmationOption; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.AbstractVcsTestCase; +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; +import com.intellij.testFramework.fixtures.TempDirTestFixture; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcsUtil.VcsUtil; +import git4idea.GitBranch; +import git4idea.GitVcs; +import git4idea.repo.GitRepository; +import git4idea.test.*; +import git4idea.tests.TestDialogHandler; +import git4idea.tests.TestDialogManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; + +import static git4idea.test.GitExec.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +/** + * @author Kirill Likhodedov + */ +public class GitBranchOperationsTest extends AbstractVcsTestCase { + + private static final String NEW_BRANCH = "new_branch"; + private static final String MASTER = "master"; + + private Collection myRepositories; + private GitRepository myUltimate, myCommunity, myContrib; + + private TestMessageManager myMessageManager; + private TestNotificationManager myNotificationManager; + private TestDialogManager myDialogManager; + + private TempDirTestFixture myTempDirFixture; + + @BeforeMethod + public void setup() throws Exception { + final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory(); + myTempDirFixture = fixtureFactory.createTempDirTestFixture(); + myTempDirFixture.setUp(); + + final File projectDir = new File(myTempDirFixture.getTempDirPath(), "ultimate"); + projectDir.mkdir(); + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + try { + initProject(projectDir); + initRepositories(VcsUtil.getVirtualFile(projectDir)); + } + catch (Exception e) { + throw new RuntimeException("Exception initializing the test", e); + } + } + }); + + GitVcs vcs = GitVcs.getInstance(myProject); + assertNotNull(vcs); + myTraceClient = true; + doActionSilently(VcsConfiguration.StandardConfirmation.ADD); + doActionSilently(VcsConfiguration.StandardConfirmation.REMOVE); + + myDialogManager = GitTestUtil.registerDialogManager(myProject); + myNotificationManager = GitTestUtil.registerNotificationManager(myProject); + myMessageManager = GitTestUtil.registerMessageManager(myProject); + + createAddCommit(myUltimate, "a"); + createAddCommit(myCommunity, "a"); + createAddCommit(myContrib, "a"); + + myUltimate.getRoot().refresh(false, true); + } + + protected void doActionSilently(final VcsConfiguration.StandardConfirmation op) { + setStandardConfirmation(GitVcs.NAME, op, VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY); + } + + @AfterMethod + public void tearDown() throws Exception { + if (myTempDirFixture != null) { + myTempDirFixture.tearDown(); + myTempDirFixture = null; + } + } + + private void initRepositories(VirtualFile projectDir) throws IOException { + myUltimate = init(myProject, projectDir); + VirtualFile communityDir = createDirInCommand(projectDir, "community"); + VirtualFile contribDir = createDirInCommand(projectDir, "contrib"); + myCommunity = init(myProject, communityDir); + myContrib = init(myProject, contribDir); + + addProjectRoots(); + myRepositories = Arrays.asList(myUltimate, myCommunity, myContrib); + } + + private void addProjectRoots() { + ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject); + vcsManager.setDirectoryMapping(myUltimate.getRoot().getPath(), GitVcs.NAME); + vcsManager.setDirectoryMapping(myCommunity.getRoot().getPath(), GitVcs.NAME); + vcsManager.setDirectoryMapping(myContrib.getRoot().getPath(), GitVcs.NAME); + } + + @Test + public void createNewBranchWithoutProblems() throws Exception { + doCheckoutNewBranch(); + assertNotify(NotificationType.INFORMATION, "Branch new_branch was created"); + } + + @Test + public void createNewBranchWithUnmergedFilesInFirstRepoShouldShowNotification() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myUltimate); + doCheckoutNewBranch(); + assertNotify(NotificationType.ERROR, GitBranchOperation.UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION); + } + + @Test + public void createNewBranchWithUnmergedFilesInSecondRepoShouldProposeToRollback() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); + doCheckoutNewBranch(); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + } + + @Test + public void rollbackCreateNewBranch() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); + myMessageManager.nextAnswer(Messages.OK); + doCheckoutNewBranch(); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch("master"); + } + + @Test + public void denyRollbackCreateNewBranch() throws Exception { + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); + myMessageManager.nextAnswer(Messages.CANCEL); + doCheckoutNewBranch(); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch(myUltimate, NEW_BRANCH); + assertBranch(myCommunity, MASTER); + assertBranch(myContrib, MASTER); + } + + @Test + public void deleteBranchWithoutProblems() throws Exception { + for (GitRepository repository : myRepositories) { + branch(repository, "master1"); + refresh(repository); + } + doDeleteBranch("master1"); + assertNotify(NotificationType.INFORMATION, "Deleted branch master1"); + } + + @Test + public void deleteUnmergedBranchShouldShowDialog() throws Exception { + prepareUnmergedBranch(myUltimate, myCommunity, myContrib); + + final AtomicBoolean dialogShown = new AtomicBoolean(); + myDialogManager.registerDialogHandler(GitBranchIsNotFullyMergedDialog.class, new TestDialogHandler() { + @Override public int handleDialog(GitBranchIsNotFullyMergedDialog dialog) { + dialogShown.set(true); + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doDeleteBranch("unmerged_branch"); + assertTrue(dialogShown.get()); + } + + @Test + public void okInUnmergedBranchDialogShouldForceDeleteBranch() throws Exception { + prepareUnmergedBranch(myUltimate, myCommunity, myContrib); + registerNotFullyMergedDialog(DialogWrapper.OK_EXIT_CODE); + doDeleteBranch("unmerged_branch"); + for (GitRepository repository : myRepositories) { + assertTrue(!branch(repository).contains("unmerged_branch")); + } + } + + @Test + public void cancel_in_unmerged_branch_dialog_in_first_repository_should_show_notification() throws Exception { + prepareUnmergedBranch(myUltimate, myContrib); + branch(myCommunity, "unmerged_branch"); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + doDeleteBranch("unmerged_branch"); + assertNotify(NotificationType.ERROR, "Branch unmerged_branch wasn't deleted", "This branch is not fully merged to master"); + } + + @Test + public void cancel_in_unmerged_branch_dialog_in_not_first_repository_should_show_rollback_proposal() throws Exception { + branch(myUltimate, "unmerged_branch"); + prepareUnmergedBranch(myCommunity, myContrib); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + doDeleteBranch("unmerged_branch"); + assertMessage(String.format("Branch %s wasn't deleted", "unmerged_branch")); + } + + @Test + public void rollback_delete_branch_should_recreate_branches() throws Exception { + branch(myUltimate, "unmerged_branch"); + prepareUnmergedBranch(myCommunity); + branch(myContrib, "unmerged_branch"); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + myMessageManager.nextAnswer(Messages.OK); + doDeleteBranch("unmerged_branch"); + + for (GitRepository repository : myRepositories) { + assertTrue(branch(repository).contains("unmerged_branch")); + } + } + + @Test + public void deny_rollback_delete_branch_should_do_nothing() throws Exception { + branch(myUltimate, "unmerged_branch"); + prepareUnmergedBranch(myCommunity); + branch(myContrib, "unmerged_branch"); + + registerNotFullyMergedDialog(DialogWrapper.CANCEL_EXIT_CODE); + myMessageManager.nextAnswer(Messages.CANCEL); + doDeleteBranch("unmerged_branch"); + + assertTrue(branch(myCommunity).contains("unmerged_branch")); + assertTrue(branch(myContrib).contains("unmerged_branch")); + assertTrue(!branch(myUltimate).contains("unmerged_branch")); + } + + private void registerNotFullyMergedDialog(final int answer) { + myDialogManager.registerDialogHandler(GitBranchIsNotFullyMergedDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitBranchIsNotFullyMergedDialog dialog) { + return answer; + } + }); + } + + private static void prepareUnmergedBranch(GitRepository... repositories) throws IOException { + for (GitRepository repository : repositories) { + checkout(repository, "-b", "unmerged_branch"); + createAddCommit(repository, "unmerged_branch_file"); + checkout(repository, "master"); + refresh(repository); + } + } + + private void doCheckoutNewBranch() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + // call private doCheckoutNewBranch instead of public checkoutNewBranch to avoid dealing with background process creation + GitBranchOperationsProcessor processor = new GitBranchOperationsProcessor(myProject, myRepositories, myCommunity); + Method doCheckoutNewBranch = GitBranchOperationsProcessor.class.getDeclaredMethod("doCheckoutNewBranch", String.class, ProgressIndicator.class); + doCheckoutNewBranch.setAccessible(true); + doCheckoutNewBranch.invoke(processor, NEW_BRANCH, new EmptyProgressIndicator()); + } + + private void doDeleteBranch(@NotNull String branchName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + // call private doDelete instead of public deleteBranch to avoid dealing with background process creation + GitBranchOperationsProcessor processor = new GitBranchOperationsProcessor(myProject, myRepositories, myCommunity); + Method doCheckoutNewBranch = GitBranchOperationsProcessor.class.getDeclaredMethod("doDelete", String.class, ProgressIndicator.class); + doCheckoutNewBranch.setAccessible(true); + doCheckoutNewBranch.invoke(processor, branchName, new EmptyProgressIndicator()); + } + + private void assertBranch(String master) { + for (GitRepository repository : myRepositories) { + assertBranch(repository, master); + } + } + + private static void assertBranch(GitRepository repository, String branchName) { + GitBranch currentBranch = repository.getCurrentBranch(); + assertNotNull(currentBranch); + assertEquals(currentBranch.getName(), branchName); + } + + private void assertNotify(NotificationType type, String content) { + assertNotify(type, null, content); + } + + private void assertNotify(NotificationType type, @Nullable String title, String content) { + Notification notification = myNotificationManager.getLastNotification(); + assertNotNull(notification); + assertEquals(stripHtml(notification.getContent()), stripHtml(content)); + assertEquals(notification.getType(), type); + if (title != null) { + assertEquals(stripHtml(notification.getTitle()), stripHtml(title)); + } + } + + private static String stripHtml(String text) { + return StringUtil.stripHtml(text, true); + } + + private void assertMessage(String title) { + TestMessageManager.Message message = myMessageManager.getLastMessage(); + assertNotNull(message); + assertEquals(message.getTitle(), title); + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/GitExec.java b/plugins/git4idea/tests/git4idea/test/GitExec.java new file mode 100644 index 000000000000..2dab771c7927 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/GitExec.java @@ -0,0 +1,101 @@ +/* + * 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 git4idea.test; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.AbstractVcsTestCase; +import com.intellij.testFramework.VfsTestUtil; +import com.intellij.util.ui.UIUtil; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; + +/** + * @author Kirill Likhodedov + */ +public class GitExec { + + public static void refresh(@NotNull GitRepository repository) { + repository.getRoot().refresh(false, true); + } + + public static GitRepository init(@NotNull Project project, @NotNull VirtualFile root) throws IOException { + new GitTestRunEnv(new File(root.getPath())).run("init"); + root.refresh(false, true); + return GitRepository.getFullInstance(root, project, project); + } + + public static void create(@NotNull GitRepository repository, @NotNull String filePath) { + create(repository, filePath, "content"); + } + + public static void create(final GitRepository repository, final String filePath, @NotNull final String content) { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override public void run() { + VfsTestUtil.createFile(repository.getRoot(), filePath, content); + } + }); + } + + public static void edit(final GitRepository repository, String filePath, final String newContent) { + final VirtualFile file = repository.getRoot().findFileByRelativePath(filePath); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override public void run() { + AbstractVcsTestCase.editFileInCommand(repository.getProject(), file, newContent); + } + }); + } + + public static void add(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { + run(repository, "add", filePath); + } + + public static void commit(@NotNull GitRepository repository) throws IOException { + run(repository, "commit", "-m", "message"); + } + + public static void addCommit(GitRepository repository, String filePath) throws IOException { + add(repository, filePath); + commit(repository); + } + + public static void createAddCommit(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { + create(repository, filePath); + addCommit(repository, filePath); + } + + @NotNull + public static String branch(@NotNull GitRepository repository, String... params) throws IOException { + return run(repository, "branch", params); + } + + public static void checkout(@NotNull GitRepository repository, String... params) throws IOException { + run(repository, "checkout", params); + } + + public static void merge(@NotNull GitRepository repository, @NotNull String branch) throws IOException { + run(repository, "merge", branch); + } + + @NotNull + private static String run(@NotNull GitRepository repository, @NotNull String command, String... params) throws IOException { + return new GitTestRunEnv(new File(repository.getRoot().getPath())).run(command, params); + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java b/plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java new file mode 100644 index 000000000000..021535ebad9e --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/GitTestScenarioGenerator.java @@ -0,0 +1,57 @@ +/* + * 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 git4idea.test; + +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +import static git4idea.test.GitExec.*; + +/** + * @author Kirill Likhodedov + */ +public class GitTestScenarioGenerator { + + public static void prepareUnmergedFiles(@NotNull GitRepository... repositories) throws IOException { + for (GitRepository repository : repositories) { + String unmergedFile = "unmerged"; + create(repository, unmergedFile, "master content"); + addCommit(repository, unmergedFile); + + checkoutFeatureBranch(repository); + edit(repository, unmergedFile, "feature content"); + addCommit(repository, unmergedFile); + + checkout(repository, "master"); + edit(repository, unmergedFile, "master feature"); + addCommit(repository, unmergedFile); + + merge(repository, "feature"); + refresh(repository); + } + } + + private static void checkoutFeatureBranch(GitRepository repository) throws IOException { + String branches = branch(repository); + if (!branches.contains("feature")) { + checkout(repository, "-b", "feature"); + } else { + checkout(repository, "feature"); + } + } +} diff --git a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java index 97944322e044..0e6d3e3be5ba 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java +++ b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java @@ -22,9 +22,14 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.DialogManager; +import git4idea.MessageManager; +import git4idea.NotificationManager; import git4idea.tests.GitTestRepository; +import git4idea.tests.TestDialogManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.picocontainer.MutablePicoContainer; import java.io.File; import java.io.FilenameFilter; @@ -227,4 +232,33 @@ public class GitTestUtil { public static String stringifyActualExpected(@NotNull Object actual, @NotNull Object expected) { return "\nExpected:\n" + expected + "\nActual:\n" + actual; } + + /** + * Registers {@link git4idea.tests.TestDialogManager} as the {@link git4idea.DialogManager} implementation. + * @param project + */ + public static TestDialogManager registerDialogManager(@NotNull Project project) { + final String key = "git4idea.DialogManager"; + final MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); + picoContainer.unregisterComponent(key); + picoContainer.registerComponentImplementation(key, TestDialogManager.class); + return (TestDialogManager)DialogManager.getInstance(project); + } + + public static TestMessageManager registerMessageManager(@NotNull Project project) { + final String key = "git4idea.MessageManager"; + final MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); + picoContainer.unregisterComponent(key); + picoContainer.registerComponentImplementation(key, TestMessageManager.class); + return (TestMessageManager)MessageManager.getInstance(project); + } + + public static TestNotificationManager registerNotificationManager(Project project) { + final String key = "git4idea.NotificationManager"; + final MutablePicoContainer picoContainer = (MutablePicoContainer) project.getPicoContainer(); + picoContainer.unregisterComponent(key); + picoContainer.registerComponentImplementation(key, TestNotificationManager.class); + return (TestNotificationManager)NotificationManager.getInstance(project); + } + } diff --git a/plugins/git4idea/tests/git4idea/test/TestMessageManager.java b/plugins/git4idea/tests/git4idea/test/TestMessageManager.java new file mode 100644 index 000000000000..7aa87bd6fb41 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/TestMessageManager.java @@ -0,0 +1,70 @@ +/* + * 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 git4idea.test; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import git4idea.MessageManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; + +/** + * @author Kirill Likhodedov + */ +public class TestMessageManager extends MessageManager { + + private Message myLastMessage; + private int myNextAnswer = DEFAULT_ANSWER; + private static final int DEFAULT_ANSWER = Messages.CANCEL; + + public static class Message { + @NotNull private final String myTitle; + @NotNull private final String myDescription; + @NotNull private final String myYesText; + @NotNull private final String myNoText; + + public Message(@NotNull String title, @NotNull String description, @NotNull String yesText, @NotNull String noText) { + myTitle = title; + myDescription = description; + myYesText = yesText; + myNoText = noText; + } + + @NotNull + public String getTitle() { + return myTitle; + } + } + + @Nullable + public Message getLastMessage() { + return myLastMessage; + } + + public void nextAnswer(int answer) { + myNextAnswer = answer; + } + + @Override + protected int doShowYesNoDialog(Project project, String description, String title, String yesText, String noText, @Nullable Icon icon) { + myLastMessage = new Message(title, description, yesText, noText); + return myNextAnswer; + } + + +} diff --git a/plugins/git4idea/tests/git4idea/test/TestNotificationManager.java b/plugins/git4idea/tests/git4idea/test/TestNotificationManager.java new file mode 100644 index 000000000000..f7aa39522924 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/TestNotificationManager.java @@ -0,0 +1,51 @@ +/* + * 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 git4idea.test; + +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationListener; +import com.intellij.notification.NotificationType; +import com.intellij.openapi.project.Project; +import git4idea.NotificationManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Kirill Likhodedov + */ +public class TestNotificationManager extends NotificationManager { + + private Notification myLastNotification; + + public TestNotificationManager(@NotNull Project project) { + super(project); + } + + public Notification getLastNotification() { + return myLastNotification; + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, @NotNull NotificationType type) { + notify(notificationGroup, title, message, type, null); + } + + public void notify(@NotNull NotificationGroup notificationGroup, @NotNull String title, @NotNull String message, + @NotNull NotificationType type, @Nullable NotificationListener listener) { + myLastNotification = createNotification(notificationGroup, title, message, type, listener); + } + +} diff --git a/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java b/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java index e0990266e473..9236026f245a 100644 --- a/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java +++ b/plugins/git4idea/tests/git4idea/tests/GitLineSeparatorsConverterTest.java @@ -23,11 +23,10 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.CheckboxTreeBase; import com.intellij.ui.CheckedTreeNode; import com.intellij.ui.GuiUtils; -import git4idea.DialogManager; import git4idea.config.GitVcsSettings; +import git4idea.test.GitTestUtil; import git4idea.ui.GitConvertFilesDialog; import org.jetbrains.annotations.Nullable; -import org.picocontainer.MutablePicoContainer; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -63,7 +62,7 @@ public class GitLineSeparatorsConverterTest extends GitTest { myChangeListManager = ChangeListManagerImpl.getInstanceImpl(myProject); mySettings = GitVcsSettings.getInstance(myProject); myCodeStyleSeparator = CodeStyleFacade.getInstance(myProject).getLineSeparator(); - myDialogManager = registerDialogManager(); + myDialogManager = GitTestUtil.registerDialogManager(myProject); unixFile = createFileInCommand("unix_file.txt", "Unix File\n"); winFile = createFileInCommand("win_file.txt", "Windows File\r\n"); @@ -193,17 +192,6 @@ public class GitLineSeparatorsConverterTest extends GitTest { return null; } - /** - * Registers {@link TestDialogManager} as the {@link DialogManager} implementation. - */ - private TestDialogManager registerDialogManager() { - final String key = "git4idea.DialogManager"; - final MutablePicoContainer picoContainer = (MutablePicoContainer) myProject.getPicoContainer(); - picoContainer.unregisterComponent(key); - picoContainer.registerComponentImplementation(key, TestDialogManager.class); - return (TestDialogManager)DialogManager.getInstance(myProject); - } - /** * Commits via the ChangeListManager. */ From f579d28813b5686301d524710920ce630b06a36c Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 24 Jan 2012 18:53:42 +0400 Subject: [PATCH 04/18] cosmetics --- .../tests/git4idea/branch/GitBranchOperationsTest.java | 6 ++++-- plugins/git4idea/tests/testng.xml | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index ba57baadc8a2..a8987202e31e 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -50,7 +50,9 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { private static final String MASTER = "master"; private Collection myRepositories; - private GitRepository myUltimate, myCommunity, myContrib; + private GitRepository myUltimate; + private GitRepository myCommunity; + private GitRepository myContrib; private TestMessageManager myMessageManager; private TestNotificationManager myNotificationManager; @@ -65,7 +67,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { myTempDirFixture.setUp(); final File projectDir = new File(myTempDirFixture.getTempDirPath(), "ultimate"); - projectDir.mkdir(); + assertTrue(projectDir.mkdir()); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override diff --git a/plugins/git4idea/tests/testng.xml b/plugins/git4idea/tests/testng.xml index eeb43f3bd5e3..c60b4e99afd5 100644 --- a/plugins/git4idea/tests/testng.xml +++ b/plugins/git4idea/tests/testng.xml @@ -2,6 +2,7 @@ + From fc9a4196639bb2938c5a662eaa58330addceb297 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 25 Jan 2012 13:18:22 +0400 Subject: [PATCH 05/18] GitBranchOperationsTest: add some tests for checkout (successful; unmerged error; rollback) --- .../git4idea/branch/GitCheckoutOperation.java | 3 +- ...GitWouldBeOverwrittenByCheckoutDialog.java | 3 +- .../git4idea/util/UntrackedFilesNotifier.java | 6 +- .../branch/GitBranchOperationsTest.java | 97 +++++++++++++++---- 4 files changed, 87 insertions(+), 22 deletions(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index b4cd83af43b3..16466e8b9545 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -38,6 +38,7 @@ import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcsUtil.VcsUtil; +import git4idea.DialogManager; import git4idea.GitVcs; import git4idea.commands.*; import git4idea.merge.GitConflictResolver; @@ -206,7 +207,7 @@ public class GitCheckoutOperation extends GitBranchOperation { UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - dialog.show(); + DialogManager.getInstance(myProject).showDialog(dialog); } }); diff --git a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java index de968d2f59b8..f281e4a1f718 100644 --- a/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitWouldBeOverwrittenByCheckoutDialog.java @@ -22,6 +22,7 @@ import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.components.JBLabel; import com.intellij.util.ui.UIUtil; +import git4idea.DialogManager; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -49,7 +50,7 @@ class GitWouldBeOverwrittenByCheckoutDialog extends DialogWrapper { @Override public void run() { GitWouldBeOverwrittenByCheckoutDialog dialog = new GitWouldBeOverwrittenByCheckoutDialog(project, changes); - dialog.show(); + DialogManager.getInstance(project).showDialog(dialog); ok.set(dialog.isOK()); } }); diff --git a/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java b/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java index 99ab54cb9525..1ddab094a1fd 100644 --- a/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java +++ b/plugins/git4idea/src/git4idea/util/UntrackedFilesNotifier.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.changes.ui.SelectFilesDialog; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitVcs; +import git4idea.NotificationManager; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -48,7 +49,7 @@ public class UntrackedFilesNotifier { final String notificationDesc = createUntrackedFilesOverwrittenDescription(operation, false); final String dialogDesc = createUntrackedFilesOverwrittenDescription(operation, true); - GitVcs.IMPORTANT_ERROR_NOTIFICATION.createNotification(notificationTitle, notificationDesc, NotificationType.ERROR, new NotificationListener() { + NotificationManager.getInstance(project).notify(GitVcs.IMPORTANT_ERROR_NOTIFICATION, notificationTitle, notificationDesc, NotificationType.ERROR, new NotificationListener() { @Override public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) { SelectFilesDialog dlg = new SelectFilesDialog(project, new ArrayList(untrackedFiles), dialogDesc, null, false, false) { @Override protected Action[] createActions() { @@ -58,8 +59,7 @@ public class UntrackedFilesNotifier { dlg.setTitle("Untracked Files Preventing " + StringUtil.capitalize(operation)); dlg.show(); } - }).notify(project); - + }); } public static String createUntrackedFilesOverwrittenDescription(@NotNull final String operation, boolean filesAreShown) { diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index a8987202e31e..c1b7d3899c6b 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -130,47 +130,102 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void createNewBranchWithoutProblems() throws Exception { + public void create_new_branch_without_problems() throws Exception { doCheckoutNewBranch(); assertNotify(NotificationType.INFORMATION, "Branch new_branch was created"); } @Test - public void createNewBranchWithUnmergedFilesInFirstRepoShouldShowNotification() throws Exception { + public void create_new_branch_with_unmerged_files_in_first_repo_should_show_notification() throws Exception { GitTestScenarioGenerator.prepareUnmergedFiles(myUltimate); doCheckoutNewBranch(); assertNotify(NotificationType.ERROR, GitBranchOperation.UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION); } @Test - public void createNewBranchWithUnmergedFilesInSecondRepoShouldProposeToRollback() throws Exception { + public void create_new_branch_with_unmerged_files_in_second_repo_should_propose_to_rollback() throws Exception { GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); doCheckoutNewBranch(); assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); } @Test - public void rollbackCreateNewBranch() throws Exception { + public void rollback_create_new_branch_should_delete_branch() throws Exception { GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); myMessageManager.nextAnswer(Messages.OK); doCheckoutNewBranch(); assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); assertBranch("master"); + assertTrue(!branch(myUltimate).contains(NEW_BRANCH)); } @Test - public void denyRollbackCreateNewBranch() throws Exception { + public void deny_rollback_create_new_branch() throws Exception { GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity, myContrib); myMessageManager.nextAnswer(Messages.CANCEL); doCheckoutNewBranch(); assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch(myUltimate, NEW_BRANCH); assertBranch(myCommunity, MASTER); assertBranch(myContrib, MASTER); } + + @Test + public void checkout_branch_without_problems() throws Exception { + prepareBranchForSimpleCheckout(); + doCheckout("feature", null); + assertNotify(NotificationType.INFORMATION, "Checked out feature"); + } + + @Test + public void checkout_branch_with_unmerged_files_in_first_repo_should_show_notification() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myUltimate); + doCheckout("feature", null); + assertNotify(NotificationType.ERROR, GitBranchOperation.UNMERGED_FILES_ERROR_NOTIFICATION_DESCRIPTION); + } + + @Test + public void checkout_branch_with_unmerged_file_in_second_repo_should_propose_to_rollback() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); + doCheckout("feature", null); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + } @Test - public void deleteBranchWithoutProblems() throws Exception { + public void rollback_checkout_should_return_to_previous_branch() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); + myMessageManager.nextAnswer(Messages.OK); + doCheckout("feature", null); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch("master"); + } + + @Test + public void deny_rollback_checkout_should_do_nothing() throws Exception { + prepareBranchForSimpleCheckout(); + GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); + myMessageManager.nextAnswer(Messages.CANCEL); + doCheckout("feature", null); + assertMessage(GitBranchOperation.UNMERGED_FILES_ERROR_TITLE); + assertBranch(myUltimate, "feature"); + assertBranch(myCommunity, "master"); + assertBranch(myContrib, "master"); + } + + private void prepareBranchForSimpleCheckout() throws IOException { + for (GitRepository repository : myRepositories) { + checkout(repository, "-b", "feature"); + createAddCommit(repository, "feature_file.txt"); + checkout(repository, "master"); + } + } + + @Test + public void delete_branch_without_problems() throws Exception { for (GitRepository repository : myRepositories) { branch(repository, "master1"); refresh(repository); @@ -180,7 +235,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void deleteUnmergedBranchShouldShowDialog() throws Exception { + public void delete_unmerged_branch_should_show_dialog() throws Exception { prepareUnmergedBranch(myUltimate, myCommunity, myContrib); final AtomicBoolean dialogShown = new AtomicBoolean(); @@ -196,7 +251,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void okInUnmergedBranchDialogShouldForceDeleteBranch() throws Exception { + public void ok_in_unmerged_branch_dialog_should_force_delete_branch() throws Exception { prepareUnmergedBranch(myUltimate, myCommunity, myContrib); registerNotFullyMergedDialog(DialogWrapper.OK_EXIT_CODE); doDeleteBranch("unmerged_branch"); @@ -274,24 +329,32 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } private void doCheckoutNewBranch() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + callPrivateBranchOperationsProcessorMethod("doCheckoutNewBranch", NEW_BRANCH); + } + + private void callPrivateBranchOperationsProcessorMethod(String methodName, String branchName) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { // call private doCheckoutNewBranch instead of public checkoutNewBranch to avoid dealing with background process creation + // same for other branch operations GitBranchOperationsProcessor processor = new GitBranchOperationsProcessor(myProject, myRepositories, myCommunity); - Method doCheckoutNewBranch = GitBranchOperationsProcessor.class.getDeclaredMethod("doCheckoutNewBranch", String.class, ProgressIndicator.class); - doCheckoutNewBranch.setAccessible(true); - doCheckoutNewBranch.invoke(processor, NEW_BRANCH, new EmptyProgressIndicator()); + Method method = GitBranchOperationsProcessor.class.getDeclaredMethod(methodName, String.class, ProgressIndicator.class); + method.setAccessible(true); + method.invoke(processor, branchName, new EmptyProgressIndicator()); } private void doDeleteBranch(@NotNull String branchName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - // call private doDelete instead of public deleteBranch to avoid dealing with background process creation + callPrivateBranchOperationsProcessorMethod("doDelete", branchName); + } + + private void doCheckout(@NotNull String branchName, @Nullable String newBranch) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException { GitBranchOperationsProcessor processor = new GitBranchOperationsProcessor(myProject, myRepositories, myCommunity); - Method doCheckoutNewBranch = GitBranchOperationsProcessor.class.getDeclaredMethod("doDelete", String.class, ProgressIndicator.class); - doCheckoutNewBranch.setAccessible(true); - doCheckoutNewBranch.invoke(processor, branchName, new EmptyProgressIndicator()); + Method doCheckout = GitBranchOperationsProcessor.class.getDeclaredMethod("doCheckout", ProgressIndicator.class, String.class, String.class); + doCheckout.setAccessible(true); + doCheckout.invoke(processor, new EmptyProgressIndicator(), branchName, newBranch); } - private void assertBranch(String master) { + private void assertBranch(String branch) { for (GitRepository repository : myRepositories) { - assertBranch(repository, master); + assertBranch(repository, branch); } } From 990bdb62d311a1669646d8f433f86f13724f0317 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 25 Jan 2012 17:25:19 +0400 Subject: [PATCH 06/18] GitBranchOperationsTest: +checkout when untracked files would be overwritten by checkout --- .../branch/GitBranchOperationsTest.java | 76 +++++++++++++++++-- .../git4idea/test/TestMessageManager.java | 15 ++++ 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index c1b7d3899c6b..69e5e6c9a3d8 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -19,9 +19,13 @@ import com.intellij.vcsUtil.VcsUtil; import git4idea.GitBranch; import git4idea.GitVcs; import git4idea.repo.GitRepository; -import git4idea.test.*; +import git4idea.test.GitTestScenarioGenerator; +import git4idea.test.GitTestUtil; +import git4idea.test.TestMessageManager; +import git4idea.test.TestNotificationManager; import git4idea.tests.TestDialogHandler; import git4idea.tests.TestDialogManager; +import git4idea.util.UntrackedFilesNotifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testng.annotations.AfterMethod; @@ -37,9 +41,7 @@ import java.util.Collection; import java.util.concurrent.atomic.AtomicBoolean; import static git4idea.test.GitExec.*; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.*; /** * @author Kirill Likhodedov @@ -216,6 +218,55 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { assertBranch(myContrib, "master"); } + @Test + public void checkout_branch_with_untracked_files_overwritten_by_checkout_in_first_repo_should_show_notification() throws Exception { + prepareUntrackedFilesAndBranchWithSameTrackedFiles(myUltimate); + branch(myCommunity, "feature"); + branch(myContrib, "feature"); + + doCheckout("feature", null); + assertNotify(NotificationType.ERROR, UntrackedFilesNotifier.createUntrackedFilesOverwrittenDescription("checkout", false)); + } + + @Test + public void checkout_branch_with_untracked_files_overwritten_by_checkout_in_second_repo_should_show_rollback_proposal_with_file_list() throws Exception { + prepareUntrackedFilesAndBranchWithSameTrackedFiles(myCommunity); + branch(myUltimate, "feature"); + branch(myContrib, "feature"); + + Class gitCheckoutOperationClass = Class.forName("git4idea.branch.GitCheckoutOperation"); + Class[] classes = gitCheckoutOperationClass.getDeclaredClasses(); + Class untrackedFilesDialogClass = null; + for (Class aClass : classes) { + if (aClass.getName().endsWith("UntrackedFilesDialog")) { + untrackedFilesDialogClass = aClass; + } + } + assertNotNull(untrackedFilesDialogClass); + + final AtomicBoolean dialogShown = new AtomicBoolean(); + final Class finalUntrackedFilesDialogClass = untrackedFilesDialogClass; + myDialogManager.registerDialogHandler(untrackedFilesDialogClass, new TestDialogHandler() { + @Override + public int handleDialog(Object dialog) { + if (dialog.getClass().equals(finalUntrackedFilesDialogClass)) { + dialogShown.set(true); + } + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertTrue(dialogShown.get()); + } + + private static void prepareUntrackedFilesAndBranchWithSameTrackedFiles(GitRepository repository) throws IOException { + checkout(repository, "-b", "feature"); + createAddCommit(repository, "untracked.txt"); + checkout(repository, "master"); + create(repository, "untracked.txt"); + } + private void prepareBranchForSimpleCheckout() throws IOException { for (GitRepository repository : myRepositories) { checkout(repository, "-b", "feature"); @@ -383,9 +434,24 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } private void assertMessage(String title) { + assertMessage(title, null, null, null); + } + + private void assertMessage(@Nullable String title, @Nullable String description, @Nullable String yesButton, @Nullable String noButton) { TestMessageManager.Message message = myMessageManager.getLastMessage(); assertNotNull(message); - assertEquals(message.getTitle(), title); + if (title != null) { + assertEquals(message.getTitle(), title); + } + if (description != null) { + assertEquals(message.getDescription(), description); + } + if (yesButton != null) { + assertEquals(message.getYesText(), yesButton); + } + if (noButton != null) { + assertEquals(message.getNoText(), noButton); + } } } diff --git a/plugins/git4idea/tests/git4idea/test/TestMessageManager.java b/plugins/git4idea/tests/git4idea/test/TestMessageManager.java index 7aa87bd6fb41..fed1d7160f9d 100644 --- a/plugins/git4idea/tests/git4idea/test/TestMessageManager.java +++ b/plugins/git4idea/tests/git4idea/test/TestMessageManager.java @@ -49,6 +49,21 @@ public class TestMessageManager extends MessageManager { public String getTitle() { return myTitle; } + + @NotNull + public String getDescription() { + return myDescription; + } + + @NotNull + public String getYesText() { + return myYesText; + } + + @NotNull + public String getNoText() { + return myNoText; + } } @Nullable From 41ebde282e55580d1235f233ec1a8b09fbdeb6fc Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 25 Jan 2012 20:32:39 +0400 Subject: [PATCH 07/18] Dialog title capitalization --- plugins/git4idea/src/git4idea/i18n/GitBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties index 28c376b41430..241557ad2493 100644 --- a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties +++ b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties @@ -493,7 +493,7 @@ executable.error.title = Git executable problem executable.error.description = Git couldn't be started. Probably the path to Git executable is not valid. Fix it. git.commit.message.empty=Please specify commit message -git.commit.message.empty.title=Commit message is empty +git.commit.message.empty.title=Commit Message Is Empty git.executable.notification.title=Can't start Git git.executable.notification.description=Probably the path to Git executable is not valid. Fix it. From 614dac2f866395654d63ee6e447f4025eb804802 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 25 Jan 2012 20:53:26 +0400 Subject: [PATCH 08/18] GitBranchOperationsTest: local changes overwritten by checkout; smart checkout. --- .../branch/GitBranchOperationsTest.java | 110 ++++++++++++++++-- .../git4idea/tests/git4idea/test/GitExec.java | 18 ++- 2 files changed, 118 insertions(+), 10 deletions(-) diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java index 69e5e6c9a3d8..d9b6bc5a21d3 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchOperationsTest.java @@ -174,14 +174,14 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void checkout_branch_without_problems() throws Exception { + public void checkout_without_problems() throws Exception { prepareBranchForSimpleCheckout(); doCheckout("feature", null); assertNotify(NotificationType.INFORMATION, "Checked out feature"); } @Test - public void checkout_branch_with_unmerged_files_in_first_repo_should_show_notification() throws Exception { + public void checkout_with_unmerged_files_in_first_repo_should_show_notification() throws Exception { prepareBranchForSimpleCheckout(); GitTestScenarioGenerator.prepareUnmergedFiles(myUltimate); doCheckout("feature", null); @@ -189,7 +189,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void checkout_branch_with_unmerged_file_in_second_repo_should_propose_to_rollback() throws Exception { + public void checkout_with_unmerged_file_in_second_repo_should_propose_to_rollback() throws Exception { prepareBranchForSimpleCheckout(); GitTestScenarioGenerator.prepareUnmergedFiles(myCommunity); doCheckout("feature", null); @@ -219,7 +219,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void checkout_branch_with_untracked_files_overwritten_by_checkout_in_first_repo_should_show_notification() throws Exception { + public void checkout_with_untracked_files_overwritten_by_checkout_in_first_repo_should_show_notification() throws Exception { prepareUntrackedFilesAndBranchWithSameTrackedFiles(myUltimate); branch(myCommunity, "feature"); branch(myContrib, "feature"); @@ -229,7 +229,7 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { } @Test - public void checkout_branch_with_untracked_files_overwritten_by_checkout_in_second_repo_should_show_rollback_proposal_with_file_list() throws Exception { + public void checkout_with_untracked_files_overwritten_by_checkout_in_second_repo_should_show_rollback_proposal_with_file_list() throws Exception { prepareUntrackedFilesAndBranchWithSameTrackedFiles(myCommunity); branch(myUltimate, "feature"); branch(myContrib, "feature"); @@ -260,6 +260,97 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { assertTrue(dialogShown.get()); } + @Test + public void checkout_with_local_changes_overwritten_by_checkout_should_show_smart_checkout_dialog() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myUltimate); + branch(myCommunity, "feature"); + branch(myContrib, "feature"); + + final AtomicBoolean dialogShown = new AtomicBoolean(); + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + dialogShown.set(true); + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertTrue(dialogShown.get()); + } + + @Test + public void agree_to_smart_checkout_should_smart_checkout() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myUltimate); + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myCommunity); + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myContrib); + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, + new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + return DialogWrapper.OK_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertBranch("feature"); + for (GitRepository repository : myRepositories) { + refresh(repository); + assertBranch(repository, "feature"); + assertEquals(read(repository, "local.txt"), "master\ninitial content\nfeature content\n"); + } + } + + @Test + public void deny_to_smart_checkout_in_first_repo_should_show_notification() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myUltimate); + branch(myCommunity, "feature"); + branch(myContrib, "feature"); + + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertNotify(NotificationType.ERROR, "Couldn't checkout feature", stripHtmlAndBreaks("Local changes would be overwritten by checkout." + + "Stash or commit them before checking out a branch.")); + assertBranch("master"); + } + + @Test + public void deny_to_smart_checkout_in_second_repo_should_show_rollback_proposal() throws Exception { + prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(myCommunity); + branch(myUltimate, "feature"); + branch(myContrib, "feature"); + myDialogManager.registerDialogHandler(GitWouldBeOverwrittenByCheckoutDialog.class, new TestDialogHandler() { + @Override + public int handleDialog(GitWouldBeOverwrittenByCheckoutDialog dialog) { + return DialogWrapper.CANCEL_EXIT_CODE; + } + }); + + doCheckout("feature", null); + assertMessage("Couldn't checkout feature", + "Local changes would be overwritten by checkout.
Stash or commit them before checking out a branch.
" + + "However checkout has succeeded for the following repositories:
" + + myUltimate.getPresentableUrl() + + "
You may rollback (checkout back to master) not to let branches diverge.", + "Rollback", "Don't rollback"); + } + + private static void prepareLocalChangesAndBranchWithSameModifiedFilesWithoutConflicts(GitRepository repository) throws IOException { + create(repository, "local.txt", "initial content\n"); + addCommit(repository); + checkout(repository, "-b", "feature"); + edit(repository, "local.txt", "initial content\nfeature content\n"); + addCommit(repository); + checkout(repository, "master"); + edit(repository, "local.txt", "master\ninitial content\n"); + } + private static void prepareUntrackedFilesAndBranchWithSameTrackedFiles(GitRepository repository) throws IOException { checkout(repository, "-b", "feature"); createAddCommit(repository, "untracked.txt"); @@ -422,15 +513,16 @@ public class GitBranchOperationsTest extends AbstractVcsTestCase { private void assertNotify(NotificationType type, @Nullable String title, String content) { Notification notification = myNotificationManager.getLastNotification(); assertNotNull(notification); - assertEquals(stripHtml(notification.getContent()), stripHtml(content)); + assertEquals(stripHtmlAndBreaks(notification.getContent()), stripHtmlAndBreaks(content)); assertEquals(notification.getType(), type); if (title != null) { - assertEquals(stripHtml(notification.getTitle()), stripHtml(title)); + assertEquals(stripHtmlAndBreaks(notification.getTitle()), stripHtmlAndBreaks(title)); } } - private static String stripHtml(String text) { - return StringUtil.stripHtml(text, true); + @NotNull + private static String stripHtmlAndBreaks(@NotNull String text) { + return StringUtil.stripHtml(text, true).replace("\n", ""); } private void assertMessage(String title) { diff --git a/plugins/git4idea/tests/git4idea/test/GitExec.java b/plugins/git4idea/tests/git4idea/test/GitExec.java index 2dab771c7927..cacf79de5907 100644 --- a/plugins/git4idea/tests/git4idea/test/GitExec.java +++ b/plugins/git4idea/tests/git4idea/test/GitExec.java @@ -61,19 +61,35 @@ public class GitExec { } }); } + + @NotNull + public static String read(final @NotNull GitRepository repository, @NotNull String filePath) throws IOException { + final VirtualFile file = repository.getRoot().findFileByRelativePath(filePath); + assert file != null; + return new String(file.contentsToByteArray()); + } public static void add(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { run(repository, "add", filePath); } + public static void add(@NotNull GitRepository repository) throws IOException { + run(repository, "add", "."); + } + public static void commit(@NotNull GitRepository repository) throws IOException { run(repository, "commit", "-m", "message"); } - public static void addCommit(GitRepository repository, String filePath) throws IOException { + public static void addCommit(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { add(repository, filePath); commit(repository); } + + public static void addCommit(@NotNull GitRepository repository) throws IOException { + add(repository); + commit(repository); + } public static void createAddCommit(@NotNull GitRepository repository, @NotNull String filePath) throws IOException { create(repository, filePath); From 74c99a39d7b36e2a47f108bde1e1b07c6015539f Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Wed, 25 Jan 2012 20:53:41 +0400 Subject: [PATCH 09/18] log the exception --- plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 16466e8b9545..75ff2a08fa97 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -275,7 +275,7 @@ public class GitCheckoutOperation extends GitBranchOperation { catch (VcsException e) { // ignoring the exception: this is not fatal if we won't collect such a diff from other repositories. // At worst, use will get double dialog proposing the smart checkout. - LOG.warn(String.format("Couldn't collect diff between %s and %s in %s", myPreviousBranch, myStartPointReference, repository.getRoot())); + LOG.warn(String.format("Couldn't collect diff between %s and %s in %s", myPreviousBranch, myStartPointReference, repository.getRoot()), e); } } return changes; From 27e2eece0d2e38f2f83806d88ade0b0cb5e679b9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 25 Jan 2012 19:42:18 +0100 Subject: [PATCH 10/18] cosmetics --- .../src/com/intellij/uiDesigner/GeneralConfigurable.form | 4 ++-- plugins/ui-designer/src/messages/UIDesignerBundle.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/GeneralConfigurable.form b/plugins/ui-designer/src/com/intellij/uiDesigner/GeneralConfigurable.form index 30b8c75dba09..869561dda670 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/GeneralConfigurable.form +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/GeneralConfigurable.form @@ -101,11 +101,11 @@ - + - + diff --git a/plugins/ui-designer/src/messages/UIDesignerBundle.properties b/plugins/ui-designer/src/messages/UIDesignerBundle.properties index 91dcb96c7bed..cd0ead7837a8 100644 --- a/plugins/ui-designer/src/messages/UIDesignerBundle.properties +++ b/plugins/ui-designer/src/messages/UIDesignerBundle.properties @@ -546,7 +546,7 @@ action.GuiDesigner.ReloadCustomComponents.text=Reload Custom Components action.GuiDesigner.ReloadCustomComponents.description=Reload modified custom component classes and recreate forms action.NewDialog.text=Dialog action.NewForm.text=GUI Form -default.field.accessibility=Default accessibility for UI-bound fields: +default.field.accessibility=Default accessibility &for UI-bound fields\: plugin.com.intellij.uiDesigner.description=Provides visual editing support for Swing UI forms group.GuiDesigner.MainToolbarActions.text=UI Designer Toolbar Actions group.GuiDesigner.NewActions.text=New GUI Designer Actions From ea998bf77a853cdaa1dcf4d5c4c957154b2195e7 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 26 Jan 2012 11:34:15 +0100 Subject: [PATCH 11/18] more reasonable thread pool logging --- .../openapi/application/impl/ApplicationImpl.java | 8 +++++++- .../platform-resources-en/src/misc/registry.properties | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java index feeabc285a35..88e5bf57d91c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java @@ -50,6 +50,7 @@ import com.intellij.openapi.project.impl.ProjectManagerImpl; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.wm.IdeFrame; import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.ex.ProgressIndicatorEx; @@ -78,6 +79,7 @@ import java.lang.reflect.Method; import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"}) public class ApplicationImpl extends ComponentManagerImpl implements ApplicationEx { @@ -117,6 +119,8 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application private final AtomicBoolean mySaveSettingsIsInProgress = new AtomicBoolean(false); @SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"}) private static final int ourDumpThreadsOnLongWriteActionWaiting = Integer.getInteger("dump.threads.on.long.write.action.waiting", 0); + private final AtomicInteger myAliveThreads = new AtomicInteger(0); + private static final int ourReasonableThreadPoolSize = Registry.intValue("core.pooled.threads"); private final ExecutorService ourThreadExecutorsService = new ThreadPoolExecutor( 3, @@ -127,6 +131,7 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application new ThreadFactory() { int i; public Thread newThread(Runnable r) { + final int count = myAliveThreads.incrementAndGet(); final Thread thread = new Thread(r, "ApplicationImpl pooled thread "+i++) { public void interrupt() { if (LOG.isDebugEnabled()) { @@ -144,9 +149,10 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application LOG.debug("Worker exits due to exception", t); } } + myAliveThreads.decrementAndGet(); } }; - if (ApplicationInfoImpl.getShadowInstance().isEAP() && i > 10) { + if (ApplicationInfoImpl.getShadowInstance().isEAP() && count > ourReasonableThreadPoolSize) { LOG.info("Not enough pooled threads; creating one at:", new Throwable()); } thread.setPriority(Thread.NORM_PRIORITY - 1); diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index f27367c763ef..7cd59ea6ff8e 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -181,6 +181,7 @@ dump.threads.on.empty.lookup.description=Whether IDEA should issue a thread dump file.structure.tree.mode=true -python.new.style.resolve=false disable.toolwindow.overlayed=true -disable.toolwindow.overlayed.description=Disable transparent toolwindow stripes \ No newline at end of file +disable.toolwindow.overlayed.description=Disable transparent toolwindow stripes + +core.pooled.threads=20 From 8ad0a98ae3f9aa5a389cbe997faf04776650d917 Mon Sep 17 00:00:00 2001 From: Dmitry Boulytchev Date: Thu, 26 Jan 2012 15:01:24 +0400 Subject: [PATCH 12/18] Fixed bug in logging initialization (compiler server). --- jps/jps-builders/src/org/jetbrains/jps/server/Server.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java index a5c2d64754c0..bca35537efce 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java @@ -99,7 +99,9 @@ public class Server { final Server server = new Server(systemDir); - DOMConfigurator.configure("log.xml"); + if (new File("log.xml").exists()) { + DOMConfigurator.configure("log.xml"); + } Logger.setFactory(new Logger.Factory() { @Override From 6d2f6d96844de3006b64e07be3e70e47f2610a2b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 26 Jan 2012 15:17:41 +0400 Subject: [PATCH 13/18] exceptions with the default project --- .../src/com/intellij/execution/JavaExecutionUtil.java | 1 + .../src/com/intellij/ui/classFilter/ClassFilterEditor.java | 2 ++ .../src/com/intellij/codeInsight/AutoPopupController.java | 1 + .../src/com/intellij/ide/actions/UndoRedoAction.java | 5 +---- .../testng/configuration/TestNGConfigurationEditor.java | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java index 3239824d4ada..5097256ac559 100644 --- a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java +++ b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java @@ -140,6 +140,7 @@ public class JavaExecutionUtil { @Nullable public static PsiClass findMainClass(final Project project, final String mainClassName, final GlobalSearchScope scope) { + if (project.isDefault()) return null; final PsiManager psiManager = PsiManager.getInstance(project); final String shortName = StringUtil.getShortName(mainClassName); final String packageName = StringUtil.getPackageName(mainClassName); diff --git a/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java b/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java index 4ad2f7edc851..517f2a226ff4 100644 --- a/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java +++ b/java/openapi/src/com/intellij/ui/classFilter/ClassFilterEditor.java @@ -131,11 +131,13 @@ public class ClassFilterEditor extends JPanel implements ComponentWithEmptyText } }); + myAddPatternButton.setEnabled(!myProject.isDefault()); myAddPatternButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { addPatternFilter(); } }); + myAddClassButton.setEnabled(!myProject.isDefault()); myAddClassButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { addClassFilter(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java index ee1818ffa845..179f975b6ee9 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/AutoPopupController.java @@ -112,6 +112,7 @@ public class AutoPopupController implements Disposable { Runnable request = new Runnable() { @Override public void run() { + if (myProject.isDefault()) return; CompletionAutoPopupHandler.runLaterWithCommitted(myProject, editor.getDocument(), new Runnable() { @Override public void run() { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java b/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java index fde61b0ec370..0fc43b2ee49a 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/UndoRedoAction.java @@ -15,7 +15,6 @@ */ package com.intellij.ide.actions; -import com.intellij.idea.ActionsBundle; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.PlatformDataKeys; @@ -26,8 +25,6 @@ import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.annotations.Nullable; public abstract class UndoRedoAction extends DumbAwareAction { public UndoRedoAction() { @@ -56,7 +53,7 @@ public abstract class UndoRedoAction extends DumbAwareAction { } UndoManager undoManager = getUndoManager(editor, dataContext); - presentation.setEnabled(isAvailable(editor, undoManager)); + presentation.setEnabled(undoManager != null && isAvailable(editor, undoManager)); Pair pair = getActionNameAndDescription(editor, undoManager); diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java index fb8c5ef9b5e2..e1a709993f97 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGConfigurationEditor.java @@ -210,6 +210,7 @@ public class TestNGConfigurationEditor extends SettingsEditor Date: Thu, 26 Jan 2012 15:23:26 +0400 Subject: [PATCH 14/18] do not switch to packages view during package navigation --- .../PsiPackageImplementationHelperImpl.java | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java index 91f0f6be7c79..0c0abdce08d1 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java @@ -16,14 +16,16 @@ package com.intellij.psi.impl.file; import com.intellij.ide.projectView.ProjectView; -import com.intellij.ide.projectView.impl.PackageViewPane; -import com.intellij.ide.projectView.impl.ProjectRootsUtil; -import com.intellij.ide.projectView.impl.nodes.PackageElement; +import com.intellij.ide.projectView.impl.ProjectViewPane; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.undo.GlobalUndoableAction; import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.vfs.VfsUtil; @@ -31,9 +33,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.openapi.wm.ToolWindowId; import com.intellij.openapi.wm.ToolWindowManager; -import com.intellij.psi.NonClasspathClassFinder; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiPackage; +import com.intellij.psi.*; import com.intellij.psi.impl.PackagePrefixElementFinder; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiModificationTracker; @@ -137,18 +137,36 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation @Override public void run() { final ProjectView projectView = ProjectView.getInstance(project); - projectView.changeView(PackageViewPane.ID); - final PsiDirectory[] directories = psiPackage.getDirectories(); - final VirtualFile firstDir = directories[0].getVirtualFile(); - final boolean isLibraryRoot = ProjectRootsUtil.isLibraryRoot(firstDir, project); - - final Module module = ProjectRootManager.getInstance(project).getFileIndex().getModuleForFile(firstDir); - final PackageElement packageElement = new PackageElement(module, psiPackage, isLibraryRoot); - projectView.getProjectViewPaneById(PackageViewPane.ID).select(packageElement, firstDir, requestFocus); + PsiDirectory[] directories = suggestMostAppropriateDirectories(psiPackage); + if (directories.length == 0) return; + projectView.getProjectViewPaneById(ProjectViewPane.ID).select(directories[0], directories[0].getVirtualFile(), requestFocus); } }); } + private static PsiDirectory[] suggestMostAppropriateDirectories(PsiPackage psiPackage) { + final Project project = psiPackage.getProject(); + PsiDirectory[] directories = null; + final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor(); + if (editor != null) { + final Document document = editor.getDocument(); + final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document); + if (psiFile != null) { + final Module module = ModuleUtil.findModuleForPsiElement(psiFile); + if (module != null) { + directories = psiPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module)); + } else { + directories = psiPackage.getDirectories(GlobalSearchScope.notScope(GlobalSearchScope.projectScope(project))); + } + } + } + + if (directories == null || directories.length == 0) { + directories = psiPackage.getDirectories(); + } + return directories; + } + @Override public boolean packagePrefixExists(PsiPackage psiPackage) { return PackagePrefixElementFinder.getInstance(psiPackage.getProject()).packagePrefixExists(psiPackage.getQualifiedName()); From 765a8c9e0a23516767c27810ce3241420ce99a95 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Thu, 26 Jan 2012 10:34:45 +0100 Subject: [PATCH 15/18] log category --- .../impl/src/com/intellij/compiler/CompileServerManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index 025bbfbe206b..a84e31b4d552 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -73,7 +73,7 @@ import java.util.concurrent.TimeUnit; * Date: 9/6/11 */ public class CompileServerManager implements ApplicationComponent{ - private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.JpsServerManager"); + private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompileServerManager"); private static final String COMPILE_SERVER_SYSTEM_ROOT = "compile-server"; private volatile OSProcessHandler myProcessHandler; private final File mySystemDirectory; From 128bffd55fe83c9ac655f016305f6a482f909c0e Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Thu, 26 Jan 2012 11:40:51 +0100 Subject: [PATCH 16/18] better diagnostics --- .../com/intellij/compiler/CompileServerManager.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index a84e31b4d552..e18338b37be3 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -272,7 +272,7 @@ public class CompileServerManager implements ApplicationComponent{ return true; } }; - final Ref serverStartMessage = new Ref(null); + final StringBuilder serverStartMessage = new StringBuilder(); final Semaphore semaphore = new Semaphore(); semaphore.down(); processHandler.addProcessListener(new ProcessAdapter() { @@ -298,8 +298,11 @@ public class CompileServerManager implements ApplicationComponent{ if (text != null) { if (text.contains(Server.SERVER_SUCCESS_START_MESSAGE) || text.contains(Server.SERVER_ERROR_START_MESSAGE)) { processHandler.removeProcessListener(this); - serverStartMessage.set(text); } + if (serverStartMessage.length() > 0) { + serverStartMessage.append("\n"); + } + serverStartMessage.append(text); } } finally { @@ -311,8 +314,8 @@ public class CompileServerManager implements ApplicationComponent{ processHandler.startNotify(); semaphore.waitFor(); - final String startupMsg = serverStartMessage.get(); - if (startupMsg == null || !startupMsg.contains(Server.SERVER_SUCCESS_START_MESSAGE)) { + final String startupMsg = serverStartMessage.toString(); + if (!startupMsg.contains(Server.SERVER_SUCCESS_START_MESSAGE)) { throw new Exception("Server startup failed: " + startupMsg); } From dff3e98e3224a2c9dcc804e95512f66704cd5933 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Thu, 26 Jan 2012 12:27:31 +0100 Subject: [PATCH 17/18] compile server working directory initialization with log.xml --- .../compiler/CompileServerManager.java | 33 +++++ jps/jps-builders/src/defaultLogConfig.xml | 17 +++ .../src/org/jetbrains/jps/server/Server.java | 123 +++++++++--------- 3 files changed, 113 insertions(+), 60 deletions(-) create mode 100644 jps/jps-builders/src/defaultLogConfig.xml diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index e18338b37be3..fe90cf55f562 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -62,7 +62,9 @@ import org.jetbrains.jps.server.Server; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.RunnableFuture; @@ -75,6 +77,8 @@ import java.util.concurrent.TimeUnit; public class CompileServerManager implements ApplicationComponent{ private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.CompileServerManager"); private static final String COMPILE_SERVER_SYSTEM_ROOT = "compile-server"; + private static final String LOGGER_CONFIG = "log.xml"; + private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml"; private volatile OSProcessHandler myProcessHandler; private final File mySystemDirectory; private volatile CompileServerClient myClient = new CompileServerClient(); @@ -465,14 +469,43 @@ public class CompileServerManager implements ApplicationComponent{ final File workDirectory = new File(mySystemDirectory, COMPILE_SERVER_SYSTEM_ROOT); workDirectory.mkdirs(); + ensureLogConfigExists(workDirectory); cmdLine.addParameter(FileUtil.toSystemIndependentName(workDirectory.getPath())); cmdLine.setWorkDirectory(workDirectory); + return cmdLine.createProcess(); } + private static void ensureLogConfigExists(File workDirectory) { + final File logConfig = new File(workDirectory, LOGGER_CONFIG); + if (!logConfig.exists()) { + FileUtil.createIfDoesntExist(logConfig); + try { + final InputStream in = Server.class.getResourceAsStream("/" + DEFAULT_LOGGER_CONFIG); + if (in != null) { + try { + final FileOutputStream out = new FileOutputStream(logConfig); + try { + FileUtil.copy(in, out); + } + finally { + out.close(); + } + } + finally { + in.close(); + } + } + } + catch (IOException e) { + LOG.error(e); + } + } + } + public void shutdownServer() { shutdownServer(myClient, myProcessHandler); } diff --git a/jps/jps-builders/src/defaultLogConfig.xml b/jps/jps-builders/src/defaultLogConfig.xml new file mode 100644 index 000000000000..6298b4ac324a --- /dev/null +++ b/jps/jps-builders/src/defaultLogConfig.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java index bca35537efce..8cdde853f06c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/Server.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/Server.java @@ -34,6 +34,7 @@ public class Server { private static final int MAX_SIMULTANEOUS_BUILD_SESSIONS = Math.max(2, Runtime.getRuntime().availableProcessors()); public static final String SERVER_SUCCESS_START_MESSAGE = "Compile Server started successfully. Listening on port: "; public static final String SERVER_ERROR_START_MESSAGE = "Error starting Compile Server: "; + private static final String LOG_FILE_NAME = "log.xml"; private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("compile-server"); private final ChannelFactory myChannelFactory; @@ -98,72 +99,14 @@ public class Server { } final Server server = new Server(systemDir); - - if (new File("log.xml").exists()) { - DOMConfigurator.configure("log.xml"); - } - - Logger.setFactory(new Logger.Factory() { - @Override - public Logger getLoggerInstance(String category) { - final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(category); - - return new Logger(){ - @Override - public boolean isDebugEnabled() { - return logger.isDebugEnabled(); - } - - @Override - public void debug(@NonNls String message) { - logger.debug(message); - } - - @Override - public void debug(@Nullable Throwable t) { - logger.debug("", t); - } - - @Override - public void debug(@NonNls String message, @Nullable Throwable t) { - logger.debug(message, t); - } - - @Override - public void error(@NonNls String message, @Nullable Throwable t, @NonNls String... details) { - logger.debug(message, t); - } - - @Override - public void info(@NonNls String message) { - logger.info(message); - } - - @Override - public void info(@NonNls String message, @Nullable Throwable t) { - logger.info(message, t); - } - - @Override - public void warn(@NonNls String message, @Nullable Throwable t) { - logger.warn(message, t); - } - - @Override - public void setLevel(Level level) { - logger.setLevel(level); - } - }; - } - }); - - server.start(port); Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") { public void run() { server.stop(); } }); + initLoggers(); + server.start(port); ServerState.getInstance().setKeepTempCachesInMemory(System.getProperty(GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION) != null); System.out.println("Server classpath: " + System.getProperty("java.class.path")); @@ -176,6 +119,66 @@ public class Server { } } + private static void initLoggers() { + if (new File(LOG_FILE_NAME).exists()) { + DOMConfigurator.configure(LOG_FILE_NAME); + } + + Logger.setFactory(new Logger.Factory() { + @Override + public Logger getLoggerInstance(String category) { + final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(category); + + return new Logger() { + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public void debug(@NonNls String message) { + logger.debug(message); + } + + @Override + public void debug(@Nullable Throwable t) { + logger.debug("", t); + } + + @Override + public void debug(@NonNls String message, @Nullable Throwable t) { + logger.debug(message, t); + } + + @Override + public void error(@NonNls String message, @Nullable Throwable t, @NonNls String... details) { + logger.debug(message, t); + } + + @Override + public void info(@NonNls String message) { + logger.info(message); + } + + @Override + public void info(@NonNls String message, @Nullable Throwable t) { + logger.info(message, t); + } + + @Override + public void warn(@NonNls String message, @Nullable Throwable t) { + logger.warn(message, t); + } + + @Override + public void setLevel(Level level) { + logger.setLevel(level); + } + }; + } + }); + } + private class ChannelRegistrar extends SimpleChannelUpstreamHandler { public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { myAllOpenChannels.add(e.getChannel()); From 3ebdd60444e6941861bccebeb518e26c4838e556 Mon Sep 17 00:00:00 2001 From: Eugene Zhuravlev Date: Thu, 26 Jan 2012 12:36:43 +0100 Subject: [PATCH 18/18] defaults corrected --- jps/jps-builders/src/defaultLogConfig.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jps/jps-builders/src/defaultLogConfig.xml b/jps/jps-builders/src/defaultLogConfig.xml index 6298b4ac324a..c57f244f5c1c 100644 --- a/jps/jps-builders/src/defaultLogConfig.xml +++ b/jps/jps-builders/src/defaultLogConfig.xml @@ -3,14 +3,14 @@ - + - +