blob: 07e0c5bbb737f9a2a8dde2b802c9c69c9580c00d [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.integrate;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
import com.intellij.util.Consumer;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnConfiguration;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.api.Depth;
import org.jetbrains.idea.svn.api.ProgressTracker;
import org.jetbrains.idea.svn.update.UpdateEventHandler;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Merger implements IMerger {
protected final List<CommittedChangeList> myChangeLists;
protected final File myTarget;
@Nullable private final ProgressTracker myHandler;
protected int myCount;
private final ProgressIndicator myProgressIndicator;
protected CommittedChangeList myLatestProcessed;
protected final SVNURL myCurrentBranchUrl;
private final StringBuilder myCommitMessage;
protected final SvnConfiguration mySvnConfig;
private final Project myProject;
@NotNull private final SvnVcs myVcs;
private final String myBranchName;
public Merger(final SvnVcs vcs,
final List<CommittedChangeList> changeLists,
final File target,
final UpdateEventHandler handler,
final SVNURL currentBranchUrl,
String branchName) {
myBranchName = branchName;
myVcs = vcs;
myProject = vcs.getProject();
mySvnConfig = SvnConfiguration.getInstance(vcs.getProject());
myCurrentBranchUrl = currentBranchUrl;
myChangeLists = changeLists;
Collections.sort(myChangeLists, ByNumberChangeListComparator.getInstance());
myTarget = target;
myCount = 0;
myProgressIndicator = ProgressManager.getInstance().getProgressIndicator();
myHandler = handler;
myCommitMessage = new StringBuilder();
}
private static class ByNumberChangeListComparator implements Comparator<CommittedChangeList>{
private final static ByNumberChangeListComparator ourInstance = new ByNumberChangeListComparator();
public static ByNumberChangeListComparator getInstance() {
return ourInstance;
}
public int compare(final CommittedChangeList o1, final CommittedChangeList o2) {
return (int) (o1.getNumber() - o2.getNumber());
}
}
public boolean hasNext() {
return myCount < myChangeLists.size();
}
public void mergeNext() throws SVNException, VcsException {
myLatestProcessed = myChangeLists.get(myCount);
++ myCount;
if (myProgressIndicator != null) {
myProgressIndicator.setText2(SvnBundle.message("action.Subversion.integrate.changes.progress.integrating.details.text",
myLatestProcessed.getNumber()));
}
doMerge();
appendComment();
}
private void appendComment() {
if (myCommitMessage.length() == 0) {
myCommitMessage.append("Merged from ").append(myBranchName);
}
final String nextComment = myLatestProcessed.getComment();
if (nextComment.trim().length() > 0) {
myCommitMessage.append('\n').append(nextComment).append(" [from revision ").append(myLatestProcessed.getNumber()).append("]");
}
}
protected SVNRevisionRange createRange() {
return new SVNRevisionRange(SVNRevision.create(myLatestProcessed.getNumber() - 1), SVNRevision.create(myLatestProcessed.getNumber()));
}
protected boolean isRecordOnly() {
return false;
}
protected void doMerge() throws SVNException, VcsException {
SvnTarget source = SvnTarget.fromURL(myCurrentBranchUrl);
MergeClient client = myVcs.getFactory(myTarget).createMergeClient();
client.merge(source, createRange(), myTarget, Depth.INFINITY, mySvnConfig.isMergeDryRun(), isRecordOnly(), true,
mySvnConfig.getMergeOptions(), myHandler);
}
@NonNls
private List<CommittedChangeList> getTail() {
return (myCount < myChangeLists.size()) ?
new ArrayList<CommittedChangeList>(myChangeLists.subList(myCount, myChangeLists.size())) :
Collections.<CommittedChangeList>emptyList();
}
public void getInfo(final Consumer<String> holder, final boolean getLatest) {
if (getLatest && (myLatestProcessed != null)) {
holder.consume(SvnBundle.message("action.Subversion.integrate.changes.warning.failed.list.text", myLatestProcessed.getNumber(),
myLatestProcessed.getComment().replace('\n', '|')));
}
getSkipped(holder);
}
public void getSkipped(final Consumer<String> holder) {
final List<CommittedChangeList> tail = getTail();
if (! tail.isEmpty()) {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < tail.size(); i++) {
CommittedChangeList list = tail.get(i);
if (i != 0) {
sb.append(',');
}
sb.append(list.getNumber()).append(" (").append(list.getComment().replace('\n', '|')).append(')');
}
holder.consume(SvnBundle.message("action.Subversion.integrate.changes.warning.skipped.lists.text", sb.toString()));
}
}
public String getComment() {
return myCommitMessage.toString();
}
@Nullable
public File getMergeInfoHolder() {
return myTarget;
}
public void afterProcessing() {
myProject.getMessageBus().syncPublisher(COMMITTED_CHANGES_MERGED_STATE).event(new ArrayList<CommittedChangeList>(myChangeLists.subList(0, myCount)));
}
public static final Topic<CommittedChangesMergedStateChanged> COMMITTED_CHANGES_MERGED_STATE =
new Topic<CommittedChangesMergedStateChanged>("COMMITTED_CHANGES_MERGED_STATE", CommittedChangesMergedStateChanged.class);
public interface CommittedChangesMergedStateChanged {
void event(final List<CommittedChangeList> list);
}
}