blob: 772e5edd2755ef13b84247f9611d8ed498731278 [file] [log] [blame]
/*
* Copyright 2000-2014 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 org.jetbrains.idea.svn.branchConfig;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManagerQueue;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.committed.VcsConfigurationChangeListener;
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
import com.intellij.openapi.vcs.impl.VcsInitObject;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnVcs;
import java.io.File;
import java.util.*;
/**
* @author yole
*/
@State(
name = "SvnBranchConfigurationManager",
storages = {
@Storage(
file = StoragePathMacros.PROJECT_FILE
)}
)
public class SvnBranchConfigurationManager implements PersistentStateComponent<SvnBranchConfigurationManager.ConfigurationBean> {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager");
private final Project myProject;
private final ProjectLevelVcsManager myVcsManager;
private final SvnLoadedBranchesStorage myStorage;
private final ProgressManagerQueue myBranchesLoader;
private boolean myIsInitialized;
public SvnBranchConfigurationManager(final Project project,
final ProjectLevelVcsManager vcsManager,
final SvnLoadedBranchesStorage storage) {
myProject = project;
myVcsManager = vcsManager;
myStorage = storage;
myBranchesLoader = new ProgressManagerQueue(myProject, "Subversion Branches Preloader");
// TODO: Seems that ProgressManagerQueue is not suitable here at least for some branches loading tasks. For instance,
// TODO: for DefaultConfigLoader it would be better to run modal cancellable task - so branches structure could be detected and
// TODO: shown in dialog. Currently when "Configure Branches" is invoked for the first time - no branches are shown.
// TODO: If "Cancel" is pressed and "Configure Branches" invoked once again - already detected (in background) branches are shown.
((ProjectLevelVcsManagerImpl) vcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
if (myProject.isDisposed()) return;
myBranchesLoader.start();
}
});
}
});
myBunch = new NewRootBunch(project, myBranchesLoader);
}
public static SvnBranchConfigurationManager getInstance(final Project project) {
SvnBranchConfigurationManager result = PeriodicalTasksCloser.getInstance().safeGetService(project, SvnBranchConfigurationManager.class);
if (result != null) {
result.initialize();
}
return result;
}
public static class ConfigurationBean {
public Map<String, SvnBranchConfiguration> myConfigurationMap = new TreeMap<String, SvnBranchConfiguration>();
/**
* version of "support SVN in IDEA". for features tracking. should grow
*/
public Long myVersion;
public boolean mySupportsUserInfoFilter;
}
public Long getSupportValue() {
return myConfigurationBean.myVersion;
}
private ConfigurationBean myConfigurationBean = new ConfigurationBean();
private final NewRootBunch myBunch;
public SvnBranchConfigurationNew get(@NotNull final VirtualFile vcsRoot) throws VcsException {
return myBunch.getConfig(vcsRoot);
}
public NewRootBunch getSvnBranchConfigManager() {
return myBunch;
}
public void setConfiguration(final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) {
myBunch.updateForRoot(vcsRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.setByUser), true);
SvnBranchMapperManager.getInstance().notifyBranchesChanged(myProject, vcsRoot, configuration);
final MessageBus messageBus = myProject.getMessageBus();
messageBus.syncPublisher(VcsConfigurationChangeListener.BRANCHES_CHANGED).execute(myProject, vcsRoot);
}
public ConfigurationBean getState() {
final ConfigurationBean result = new ConfigurationBean();
result.myVersion = myConfigurationBean.myVersion;
final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs.getInstance(myProject));
for (VirtualFile root : myBunch.getMapCopy().keySet()) {
final String key = root.getPath();
final SvnBranchConfigurationNew configOrig = myBunch.getConfig(root);
final SvnBranchConfiguration configuration =
new SvnBranchConfiguration(configOrig.getTrunkUrl(), configOrig.getBranchUrls(), configOrig.isUserinfoInUrl());
result.myConfigurationMap.put(key, helper.prepareForSerialization(configuration));
}
result.mySupportsUserInfoFilter = true;
return result;
}
public void loadState(ConfigurationBean object) {
myConfigurationBean = object;
}
private synchronized void initialize() {
if (!myIsInitialized) {
myIsInitialized = true;
preloadBranches(resolveAllBranchPoints());
}
}
@NotNull
private Set<Pair<VirtualFile, SvnBranchConfigurationNew>> resolveAllBranchPoints() {
final LocalFileSystem lfs = LocalFileSystem.getInstance();
final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs.getInstance(myProject));
final Set<Pair<VirtualFile, SvnBranchConfigurationNew>> branchPointsToLoad = ContainerUtil.newHashSet();
for (Map.Entry<String, SvnBranchConfiguration> entry : myConfigurationBean.myConfigurationMap.entrySet()) {
final SvnBranchConfiguration configuration = entry.getValue();
final VirtualFile root = lfs.refreshAndFindFileByIoFile(new File(entry.getKey()));
if (root == null) {
LOG.info("root not found: " + entry.getKey());
continue;
}
final SvnBranchConfiguration configToConvert;
if ((! myConfigurationBean.mySupportsUserInfoFilter) || configuration.isUserinfoInUrl()) {
configToConvert = helper.afterDeserialization(entry.getKey(), configuration);
} else {
configToConvert = configuration;
}
final SvnBranchConfigurationNew newConfig = new SvnBranchConfigurationNew();
newConfig.setTrunkUrl(configToConvert.getTrunkUrl());
newConfig.setUserinfoInUrl(configToConvert.isUserinfoInUrl());
for (String branchUrl : configToConvert.getBranchUrls()) {
List<SvnBranchItem> stored = getStored(branchUrl);
if (stored != null && ! stored.isEmpty()) {
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(stored, InfoReliability.setByUser));
} else {
branchPointsToLoad.add(Pair.create(root, newConfig));
newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(), InfoReliability.empty));
}
}
myBunch.updateForRoot(root, new InfoStorage<SvnBranchConfigurationNew>(newConfig, InfoReliability.setByUser), false);
}
return branchPointsToLoad;
}
private void preloadBranches(@NotNull final Collection<Pair<VirtualFile, SvnBranchConfigurationNew>> branchPoints) {
((ProjectLevelVcsManagerImpl) myVcsManager).addInitializationRequest(VcsInitObject.BRANCHES, new Runnable() {
public void run() {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
public void run() {
try {
for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : branchPoints) {
myBunch.reloadBranches(pair.getFirst(), null, pair.getSecond());
}
}
catch (ProcessCanceledException e) {
//
}
}
});
}
});
}
private List<SvnBranchItem> getStored(String branchUrl) {
Collection<SvnBranchItem> collection = myStorage.get(branchUrl);
if (collection == null) return null;
final List<SvnBranchItem> items = new ArrayList<SvnBranchItem>(collection);
Collections.sort(items);
return items;
}
}