Merge remote-tracking branch 'origin/master'

This commit is contained in:
Sergey Malenkov
2015-03-03 20:07:15 +03:00
11 changed files with 222 additions and 72 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -20,6 +20,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.impl.storage.ClassPathStorageUtil;
import com.intellij.openapi.roots.impl.storage.ClasspathStorage;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import org.jetbrains.annotations.NotNull;
/**
* @author yole
@@ -27,30 +28,29 @@ import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
@State(
name = "NewModuleRootManager",
storages = {
@Storage(id = ClassPathStorageUtil.DEFAULT_STORAGE, file = StoragePathMacros.MODULE_FILE),
@Storage(file = StoragePathMacros.MODULE_FILE),
@Storage(id = ClasspathStorage.SPECIAL_STORAGE, storageClass = ClasspathStorage.class)
},
storageChooser = ModuleRootManagerComponent.StorageChooser.class
}
)
public class ModuleRootManagerComponent extends ModuleRootManagerImpl implements
PersistentStateComponent<ModuleRootManagerImpl.ModuleRootManagerState> {
PersistentStateComponent<ModuleRootManagerImpl.ModuleRootManagerState>,
StateStorageChooserEx {
public ModuleRootManagerComponent(Module module,
ProjectRootManagerImpl projectRootManager,
VirtualFilePointerManager filePointerManager) {
super(module, projectRootManager, filePointerManager);
}
static class StorageChooser implements StateStorageChooser<ModuleRootManagerImpl> {
@Override
public Storage[] selectStorages(Storage[] storages, ModuleRootManagerImpl moduleRootManager, final StateStorageOperation operation) {
boolean isDefaultStorageType = ClassPathStorageUtil.isDefaultStorage(moduleRootManager.getModule());
String id = isDefaultStorageType ? ClassPathStorageUtil.DEFAULT_STORAGE : ClasspathStorage.SPECIAL_STORAGE;
for (Storage storage : storages) {
if (storage.id().equals(id)) {
return new Storage[]{storage};
}
}
throw new IllegalArgumentException();
@NotNull
@Override
public Resolution getResolution(@NotNull Storage storage, @NotNull StateStorageOperation operation) {
boolean isEffectiveStorage = storage.id().equals(ClassPathStorageUtil.isDefaultStorage(getModule()) ? ClassPathStorageUtil.DEFAULT_STORAGE : ClasspathStorage.SPECIAL_STORAGE);
if (operation == StateStorageOperation.READ) {
return isEffectiveStorage ? Resolution.DO : Resolution.SKIP;
}
else {
// IDEA-133480 Eclipse integration: .iml content is not reduced on setting Dependencies Storage Format = Eclipse
return isEffectiveStorage ? Resolution.DO : (storage.id().equals(ClassPathStorageUtil.DEFAULT_STORAGE) ? Resolution.CLEAR : Resolution.SKIP);
}
}
}
@@ -19,6 +19,7 @@ import com.intellij.openapi.application.*;
import com.intellij.openapi.application.ex.DecodeDefaultsUtil;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.components.StateStorageChooserEx.Resolution;
import com.intellij.openapi.components.impl.ComponentManagerImpl;
import com.intellij.openapi.components.impl.stores.StateStorageManager.ExternalizationSession;
import com.intellij.openapi.components.store.ReadOnlyModificationException;
@@ -301,7 +302,13 @@ public abstract class ComponentStoreImpl implements IComponentStore.Reloadable {
T state = stateSpec.defaultStateAsResource() ? getDefaultState(component, name, stateClass) : null;
Storage[] storageSpecs = getComponentStorageSpecs(component, stateSpec, StateStorageOperation.READ);
StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null;
for (Storage storageSpec : storageSpecs) {
Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.READ);
if (resolution == Resolution.SKIP) {
continue;
}
StateStorage stateStorage = getStateStorageManager().getStateStorage(storageSpec);
if (stateStorage != null && (stateStorage.hasState(component, name, stateClass, reloadData) ||
(changedStorages != null && changedStorages.contains(stateStorage)))) {
@@ -353,64 +360,67 @@ public abstract class ComponentStoreImpl implements IComponentStore.Reloadable {
}
@NotNull
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> persistentStateComponent,
@NotNull State stateSpec,
@NotNull StateStorageOperation operation) {
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> component,
@NotNull State stateSpec,
@NotNull StateStorageOperation operation) {
Storage[] storages = stateSpec.storages();
if (storages.length == 1) {
return storages;
}
assert storages.length > 0;
StateStorageChooser<PersistentStateComponent<T>> storageChooser;
Class<? extends StateStorageChooser> storageChooserClass = stateSpec.storageChooser();
if (storageChooserClass == StateStorageChooser.class) {
StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser();
if (defaultStateStorageChooser == null) {
int actualStorageCount = 0;
for (Storage storage : storages) {
if (!storage.deprecated()) {
actualStorageCount++;
}
}
if (storageChooserClass != StateStorageChooser.class) {
//noinspection unchecked
storageChooser = ReflectionUtil.newInstance(storageChooserClass);
return storageChooser.selectStorages(storages, component, operation);
}
if (actualStorageCount > 1) {
LOG.error("State chooser not specified for: " + persistentStateComponent.getClass());
}
StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser();
if (defaultStateStorageChooser != null) {
return defaultStateStorageChooser.selectStorages(storages, component, operation);
}
if (!storages[0].deprecated()) {
boolean othersAreDeprecated = true;
for (int i = 1; i < storages.length; i++) {
if (!storages[i].deprecated()) {
othersAreDeprecated = false;
break;
}
}
if (component instanceof StateStorageChooserEx) {
return storages;
}
if (othersAreDeprecated) {
return storages;
}
}
Storage[] sorted = Arrays.copyOf(storages, storages.length);
Arrays.sort(sorted, new Comparator<Storage>() {
@Override
public int compare(Storage o1, Storage o2) {
int w1 = o1.deprecated() ? 1 : 0;
int w2 = o2.deprecated() ? 1 : 0;
return w1 - w2;
}
});
return sorted;
}
else {
return defaultStateStorageChooser.selectStorages(storages, persistentStateComponent, operation);
int actualStorageCount = 0;
for (Storage storage : storages) {
if (!storage.deprecated()) {
actualStorageCount++;
}
}
else {
@SuppressWarnings("unchecked")
StateStorageChooser<PersistentStateComponent<T>> storageChooser = ReflectionUtil.newInstance(storageChooserClass);
return storageChooser.selectStorages(storages, persistentStateComponent, operation);
if (actualStorageCount > 1) {
LOG.error("State chooser not specified for: " + component.getClass());
}
if (!storages[0].deprecated()) {
boolean othersAreDeprecated = true;
for (int i = 1; i < storages.length; i++) {
if (!storages[i].deprecated()) {
othersAreDeprecated = false;
break;
}
}
if (othersAreDeprecated) {
return storages;
}
}
Storage[] sorted = Arrays.copyOf(storages, storages.length);
Arrays.sort(sorted, new Comparator<Storage>() {
@Override
public int compare(Storage o1, Storage o2) {
int w1 = o1.deprecated() ? 1 : 0;
int w2 = o2.deprecated() ? 1 : 0;
return w1 - w2;
}
});
return sorted;
}
protected boolean optimizeTestLoading() {
@@ -503,6 +503,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
private final StateStorageChooser<PersistentStateComponent<?>> myStateStorageChooser = new StateStorageChooser<PersistentStateComponent<?>>() {
@NotNull
@Override
public Storage[] selectStorages(@NotNull Storage[] storages, @NotNull PersistentStateComponent<?> component, @NotNull StateStorageOperation operation) {
if (operation == StateStorageOperation.READ) {
@@ -561,12 +562,12 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
@NotNull
@Override
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> persistentStateComponent,
protected <T> Storage[] getComponentStorageSpecs(@NotNull PersistentStateComponent<T> component,
@NotNull State stateSpec,
@NotNull StateStorageOperation operation) {
// if we create project from default, component state written not to own storage file, but to project file,
// we don't have time to fix it properly, so, ancient hack restored.
Storage[] result = super.getComponentStorageSpecs(persistentStateComponent, stateSpec, operation);
Storage[] result = super.getComponentStorageSpecs(component, stateSpec, operation);
// don't add fake storage if project file storage already listed, otherwise data will be deleted on write (because of "deprecated")
for (Storage storage : result) {
if (storage.file().equals(StoragePathMacros.PROJECT_FILE)) {
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
import com.intellij.openapi.components.StateStorage.SaveSession;
import com.intellij.openapi.components.StateStorageChooserEx.Resolution;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Disposer;
@@ -290,12 +291,18 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
@Override
public void setState(@NotNull Storage[] storageSpecs, @NotNull Object component, @NotNull String componentName, @NotNull Object state) {
StateStorageChooserEx stateStorageChooser = component instanceof StateStorageChooserEx ? (StateStorageChooserEx)component : null;
for (Storage storageSpec : storageSpecs) {
Resolution resolution = stateStorageChooser == null ? Resolution.DO : stateStorageChooser.getResolution(storageSpec, StateStorageOperation.WRITE);
if (resolution == Resolution.SKIP) {
continue;
}
StateStorage stateStorage = getStateStorage(storageSpec);
StateStorage.ExternalizationSession session = getExternalizationSession(stateStorage);
if (session != null) {
// empty element as null state, so, will be deleted
session.setState(component, componentName, storageSpec.deprecated() ? new Element("empty") : state, storageSpec);
session.setState(component, componentName, storageSpec.deprecated() || resolution == Resolution.CLEAR ? new Element("empty") : state, storageSpec);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2015 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.
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components;
import org.jetbrains.annotations.NotNull;
public interface StateStorageChooser<T> {
Storage[] selectStorages(Storage[] storages, T component, final StateStorageOperation operation);
@NotNull
Storage[] selectStorages(Storage[] storages, T component, @NotNull StateStorageOperation operation);
}
@@ -0,0 +1,27 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.components;
import org.jetbrains.annotations.NotNull;
public interface StateStorageChooserEx {
enum Resolution {
DO, SKIP, CLEAR
}
@NotNull
Resolution getResolution(@NotNull Storage storage, @NotNull StateStorageOperation operation);
}
@@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitCommit;
import git4idea.GitLocalBranch;
import git4idea.GitRemoteBranch;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import git4idea.reset.GitResetMode;
import org.jetbrains.annotations.NotNull;
@@ -150,4 +151,10 @@ public interface Git {
@NotNull
GitCommandResult lsRemote(@NotNull Project project, @NotNull File workingDir, @NotNull String url);
@NotNull
GitCommandResult lsRemote(@NotNull Project project,
@NotNull VirtualFile workingDir,
@NotNull GitRemote remote,
String... additionalParameters);
}
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.*;
@@ -507,13 +508,39 @@ public class GitImpl implements Git {
@NotNull
@Override
public GitCommandResult lsRemote(@NotNull final Project project, @NotNull final File workingDir, @NotNull final String url) {
public GitCommandResult lsRemote(@NotNull final Project project,
@NotNull final File workingDir,
@NotNull final String url) {
return doLsRemote(project, workingDir, url, url);
}
@NotNull
@Override
public GitCommandResult lsRemote(@NotNull Project project,
@NotNull VirtualFile workingDir,
@NotNull GitRemote remote,
String... additionalParameters) {
return doLsRemote(project, VfsUtilCore.virtualToIoFile(workingDir), remote.getName(), remote.getFirstUrl(), additionalParameters);
}
@NotNull
private GitCommandResult doLsRemote(@NotNull final Project project,
@NotNull final File workingDir,
@NotNull final String remoteId,
@Nullable final String authenticationUrl,
final String... additionalParameters) {
return run(new Computable<GitLineHandler>() {
@Override
public GitLineHandler compute() {
GitLineHandler h = new GitLineHandler(project, workingDir, GitCommand.LS_REMOTE);
h.addParameters(url);
h.setUrl(url);
h.addParameters(additionalParameters);
h.addParameters(remoteId);
if (authenticationUrl != null) {
h.setUrl(authenticationUrl);
}
else {
LOG.error("No valid URLs for remote " + remoteId);
}
return h;
}
});
@@ -181,7 +181,7 @@ pull.button=Pull
pull.force.reference.update=Force reference &update
pull.get.branches.tooltip=Get branch names from remote repository. Otherwise a locally cached information is used.
pull.get.branches=&Get Branches
pull.getting.remote.branches=Getting remote branches
pull.getting.remote.branches=Getting Remote Branches...
pull.remote.tooltip=Registered remote name or URL.
pull.remote=Re&mote:
pull.retrieving.remotes=Retrieving remotes
@@ -132,7 +132,7 @@
</hspacer>
</children>
</grid>
<grid id="4dcaa" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="4dcaa" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="2" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -149,6 +149,15 @@
<toolTipText resource-bundle="git4idea/i18n/GitBundle" key="pull.remote.tooltip"/>
</properties>
</component>
<component id="c7c6b" class="javax.swing.JButton" binding="myGetBranchesButton" default-binding="true">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value=""/>
<toolTipText resource-bundle="git4idea/i18n/GitBundle" key="pull.get.branches.tooltip"/>
</properties>
</component>
</children>
</grid>
<component id="843df" class="com.intellij.ide.util.ElementsChooser" binding="myBranchChooser" custom-create="true">
@@ -15,18 +15,28 @@
*/
package git4idea.merge;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.ElementsChooser;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import git4idea.GitBranch;
import git4idea.GitRemoteBranch;
import git4idea.GitUtil;
import git4idea.commands.Git;
import git4idea.commands.GitCommand;
import git4idea.commands.GitCommandResult;
import git4idea.commands.GitLineHandler;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitBranchTrackInfo;
@@ -58,15 +68,19 @@ public class GitPullDialog extends DialogWrapper {
private JCheckBox myNoFastForwardCheckBox;
private JCheckBox myAddLogInformationCheckBox;
private JComboBox myRemote;
private JButton myGetBranchesButton;
private ElementsChooser<String> myBranchChooser;
private final Project myProject;
private final GitRepositoryManager myRepositoryManager;
private final Git myGit;
public GitPullDialog(Project project, List<VirtualFile> roots, VirtualFile defaultRoot) {
super(project, true);
setTitle(GitBundle.getString("pull.title"));
myProject = project;
myRepositoryManager = GitUtil.getRepositoryManager(myProject);
myGit = ServiceManager.getService(Git.class);
GitUIUtil.setupRootChooser(myProject, roots, defaultRoot, myGitRoot, myCurrentBranch);
myGitRoot.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
@@ -76,6 +90,7 @@ public class GitPullDialog extends DialogWrapper {
setOKButtonText(GitBundle.getString("pull.button"));
updateRemotes();
updateBranches();
setupGetBranches();
myRemote.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -96,6 +111,51 @@ public class GitPullDialog extends DialogWrapper {
init();
}
private void setupGetBranches() {
myGetBranchesButton.setIcon(AllIcons.Actions.Refresh);
myGetBranchesButton.setEnabled(myRemote.getItemCount() >= 1);
myGetBranchesButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
GitRemote selectedItem = (GitRemote)myRemote.getSelectedItem();
Collection<String> remoteBranches = selectedItem != null ? getRemoteBranches(selectedItem) : null;
if (remoteBranches != null) {
myBranchChooser.removeAllElements();
for (String branch : remoteBranches) {
myBranchChooser.addElement(branch, false);
}
}
}
});
}
@Nullable
private Collection<String> getRemoteBranches(@NotNull final GitRemote remote) {
final Ref<GitCommandResult> result = Ref.create();
ProgressManager.getInstance().run(new Task.Modal(myProject, GitBundle.getString("pull.getting.remote.branches"), false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
indicator.setIndeterminate(true);
result.set(myGit.lsRemote(GitPullDialog.this.myProject, gitRoot(), remote, "--heads"));
}
});
if (!result.isNull() && result.get().success()) {
return ContainerUtil.mapNotNull(result.get().getOutput(), new Function<String, String>() {
@Override
public String fun(@NotNull String line) {
if (StringUtil.isEmptyOrSpaces(line)) return null;
String shortRemoteName = line.trim().substring(line.indexOf(GitBranch.REFS_HEADS_PREFIX) + GitBranch.REFS_HEADS_PREFIX.length());
return remote.getName() + "/" + shortRemoteName;
}
});
}
else {
String message = result.isNull() ? "" : result.get().getErrorOutputAsJoinedString();
Messages.showErrorDialog(this.getRootPane(), message, "Couldn't get the remote branches list from " + remote.getName());
return null;
}
}
private void validateDialog() {
String selectedRemote = getRemote();
if (StringUtil.isEmptyOrSpaces(selectedRemote)) {