mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-75800 SVN "Merge from..." not working
This commit is contained in:
@@ -27,6 +27,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -144,7 +145,7 @@ public class PatchReader {
|
||||
myPatches = myPatchContentParser.getResult();
|
||||
}
|
||||
|
||||
public TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> getAdditionalInfo(final Set<String> filterByPaths) {
|
||||
public TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> getAdditionalInfo(final Set<String> filterByPaths) {
|
||||
final TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException>
|
||||
value = new TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException>();
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ConcurrentTasks<T> {
|
||||
final List<Future<?>> futures = new LinkedList<Future<?>>();
|
||||
for (final Consumer<Consumer<T>> task : myTasks) {
|
||||
if (myResultKnown) {
|
||||
myCntAlive.decrementAndGet();
|
||||
final int decremented = myCntAlive.decrementAndGet();
|
||||
continue;
|
||||
}
|
||||
final Runnable computableProxy = new Runnable() {
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vcs.changes;
|
||||
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/30/12
|
||||
* Time: 8:19 PM
|
||||
*/
|
||||
public class ThreadSafeTransparentlyFailedValue<T,E extends Exception> implements TransparentlyFailedValueI<T,E> {
|
||||
private final AtomicReference<ThrowableComputable<T, E>> myRef;
|
||||
|
||||
public ThreadSafeTransparentlyFailedValue() {
|
||||
myRef = new AtomicReference<ThrowableComputable<T, E>>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(T t) {
|
||||
if (t != null) {
|
||||
myRef.set(new Value<T, E>(t));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(E e) {
|
||||
myRef.set(new ExceptionHolder<T, E>(e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failRuntime(RuntimeException e) {
|
||||
myRef.set(new RuntimeExceptionHolder<T, E>(e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws E {
|
||||
return myRef.get() == null ? null : myRef.get().compute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean haveSomething() { // todo correct here
|
||||
return myRef.get() != null;
|
||||
}
|
||||
|
||||
private static class Value<T,E extends Exception> implements ThrowableComputable<T,E> {
|
||||
private final T myT;
|
||||
|
||||
private Value(final T t) {
|
||||
myT = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T compute() throws E {
|
||||
return myT;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExceptionHolder<T,E extends Exception> implements ThrowableComputable<T,E> {
|
||||
private final E myE;
|
||||
|
||||
private ExceptionHolder(E e) {
|
||||
myE = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T compute() throws E {
|
||||
throw myE;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RuntimeExceptionHolder<T,E extends Exception> implements ThrowableComputable<T,E> {
|
||||
private final RuntimeException myException;
|
||||
|
||||
private RuntimeExceptionHolder(RuntimeException exception) {
|
||||
myException = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T compute() throws E {
|
||||
throw myException;
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-1
@@ -20,25 +20,41 @@ package com.intellij.openapi.vcs.changes;
|
||||
* Date: 7/5/11
|
||||
* Time: 3:35 PM
|
||||
*/
|
||||
public class TransparentlyFailedValue<T, E extends Exception> {
|
||||
public class TransparentlyFailedValue<T, E extends Exception> implements TransparentlyFailedValueI<T,E> {
|
||||
private T t;
|
||||
private E e;
|
||||
private RuntimeException myRuntime;
|
||||
|
||||
@Override
|
||||
public void set(final T t) {
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(final E e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failRuntime(final RuntimeException e) {
|
||||
myRuntime = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws E {
|
||||
if (this.e != null) throw this.e;
|
||||
if (myRuntime != null) throw myRuntime;
|
||||
return this.t;
|
||||
}
|
||||
|
||||
public void take(final TransparentlyFailedValue<T,E> value) {
|
||||
this.t = value.t;
|
||||
this.e = value.e;
|
||||
myRuntime = value.myRuntime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean haveSomething() {
|
||||
return e != null || myRuntime != null || t != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vcs.changes;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/30/12
|
||||
* Time: 8:18 PM
|
||||
*/
|
||||
public interface TransparentlyFailedValueI<T, E extends Exception> {
|
||||
void set(T t);
|
||||
|
||||
void fail(E e);
|
||||
|
||||
T get() throws E;
|
||||
|
||||
void failRuntime(RuntimeException e);
|
||||
|
||||
boolean haveSomething();
|
||||
}
|
||||
+5
-5
@@ -26,7 +26,7 @@ import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.changes.CommitContext;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -61,7 +61,7 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor {
|
||||
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
|
||||
LocalChangeList localList,
|
||||
String fileName,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final Collection<PatchApplier> appliers = new LinkedList<PatchApplier>();
|
||||
final CommitContext commitContext = new CommitContext();
|
||||
applyAdditionalInfoBefore(myProject, additionalInfo, commitContext);
|
||||
@@ -82,7 +82,7 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor {
|
||||
}
|
||||
|
||||
public static void applyAdditionalInfoBefore(final Project project,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo,
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo,
|
||||
CommitContext commitContext) {
|
||||
applyAdditionalInfoImpl(project, additionalInfo, commitContext, new Consumer<InfoGroup>() {
|
||||
@Override
|
||||
@@ -93,7 +93,7 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor {
|
||||
}
|
||||
|
||||
private static void applyAdditionalInfo(final Project project,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo,
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo,
|
||||
CommitContext commitContext) {
|
||||
applyAdditionalInfoImpl(project, additionalInfo, commitContext, new Consumer<InfoGroup>() {
|
||||
@Override
|
||||
@@ -104,7 +104,7 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor {
|
||||
}
|
||||
|
||||
public static void applyAdditionalInfoImpl(final Project project,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo,
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo,
|
||||
CommitContext commitContext, final Consumer<InfoGroup> worker) {
|
||||
final PatchEP[] extensions = Extensions.getExtensions(PatchEP.EP_NAME, project);
|
||||
if (extensions == null && extensions.length == 0) return;
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ package com.intellij.openapi.vcs.changes.patch;
|
||||
|
||||
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
|
||||
@@ -33,5 +33,5 @@ public interface ApplyPatchExecutor {
|
||||
void apply(final MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
|
||||
final LocalChangeList localList,
|
||||
String fileName,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo);
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo);
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.CommitContext;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager;
|
||||
import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList;
|
||||
import com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager;
|
||||
@@ -65,7 +65,7 @@ public class ImportToShelfExecutor implements ApplyPatchExecutor {
|
||||
public void apply(final MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
|
||||
LocalChangeList localList,
|
||||
final String fileName,
|
||||
final TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final VcsCatchingRunnable vcsCatchingRunnable = new VcsCatchingRunnable() {
|
||||
@Override
|
||||
public void runImpl() throws VcsException {
|
||||
|
||||
+1
-1
@@ -669,7 +669,7 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
|
||||
char[] text = FileUtil.loadFileText(new File(patchPath), CharsetToolkit.UTF8);
|
||||
PatchReader reader = new PatchReader(new CharArrayCharSequence(text));
|
||||
final List<TextFilePatch> textFilePatches = reader.readAllPatches();
|
||||
final TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo = reader.getAdditionalInfo(
|
||||
final TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo = reader.getAdditionalInfo(
|
||||
null);
|
||||
ApplyPatchDefaultExecutor.applyAdditionalInfoBefore(project, additionalInfo, commitContext);
|
||||
return textFilePatches;
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
|
||||
import org.jetbrains.idea.svn.dialogs.LockDialog;
|
||||
import org.tmatesoft.svn.core.*;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
|
||||
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
|
||||
@@ -609,12 +610,22 @@ public class SvnUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static String appendMultiParts(@NotNull final String base, @NotNull final String subPath) throws SVNException {
|
||||
if (StringUtil.isEmpty(subPath)) return base;
|
||||
final List<String> parts = StringUtil.split(subPath.replace('\\', '/'), "/", true);
|
||||
String result = base;
|
||||
for (String part : parts) {
|
||||
result = SVNPathUtil.append(result, part);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SVNURL appendMultiParts(@NotNull final SVNURL base, @NotNull final String subPath) throws SVNException {
|
||||
if (StringUtil.isEmpty(subPath)) return base;
|
||||
final List<String> parts = StringUtil.split(subPath.replace('\\', '/'), "/", true);
|
||||
SVNURL result = base;
|
||||
for (String part : parts) {
|
||||
result = result.appendPath(part, true);
|
||||
result = result.appendPath(part, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -17,19 +17,20 @@ package org.jetbrains.idea.svn.dialogs;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ThrowableConvertor;
|
||||
import com.intellij.util.ValueHolder;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
|
||||
// cache. persistent. by request
|
||||
public class FactsCalculator<In, Out> {
|
||||
public class FactsCalculator<In, Out, E extends Exception> {
|
||||
private final Project myProject;
|
||||
private final String myTaskTitle;
|
||||
private final ValueHolder<Out, In> myCache;
|
||||
private final Convertor<In, Out> myLive;
|
||||
private final ThrowableConvertor<In, Out, E> myLive;
|
||||
|
||||
public FactsCalculator(Project project, String taskTitle, ValueHolder<Out, In> cache, Convertor<In, Out> live) {
|
||||
public FactsCalculator(Project project, String taskTitle, ValueHolder<Out, In> cache, ThrowableConvertor<In, Out, E> live) {
|
||||
myProject = project;
|
||||
myTaskTitle = taskTitle;
|
||||
myCache = cache;
|
||||
@@ -37,33 +38,35 @@ public class FactsCalculator<In, Out> {
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public void get(final In in, final Consumer<Out> resultConsumer) {
|
||||
createRunOrContinuation(in, resultConsumer).execute();
|
||||
public void get(final In in, final Consumer<TransparentlyFailedValueI<Out, E>> resultConsumer, final Class<E> clazzE) {
|
||||
createRunOrContinuation(in, resultConsumer, clazzE).execute();
|
||||
}
|
||||
|
||||
private RunOrContinuation<Out> createRunOrContinuation(final In in, final Consumer<Out> resultConsumer) {
|
||||
return new RunOrContinuation<Out>(myProject, myTaskTitle) {
|
||||
private RunOrContinuation<Out,E> createRunOrContinuation(final In in, final Consumer<TransparentlyFailedValueI<Out, E>> resultConsumer,
|
||||
final Class<E> clazzE) {
|
||||
return new RunOrContinuation<Out,E>(myProject, myTaskTitle, clazzE) {
|
||||
@Override
|
||||
protected Out calculate() {
|
||||
return myCache.getValue(in);
|
||||
}
|
||||
@Override
|
||||
protected Out calculateLong() {
|
||||
protected Out calculateLong() throws E {
|
||||
final Out result = myLive.convert(in);
|
||||
if (result != null) {
|
||||
myCache.setValue(result, in);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processResult(Out out) {
|
||||
resultConsumer.consume(out);
|
||||
protected void processResult(TransparentlyFailedValueI<Out, E> t) {
|
||||
resultConsumer.consume(t);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public TaskDescriptor getTask(final In in, final Consumer<Out> resultConsumer) {
|
||||
return createRunOrContinuation(in, resultConsumer).getTask();
|
||||
public TaskDescriptor getTask(final In in, final Consumer<TransparentlyFailedValueI<Out, E>> resultConsumer, final Class<E> clazzE) {
|
||||
return createRunOrContinuation(in, resultConsumer, clazzE).getTask();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +191,8 @@ public class QuickMerge {
|
||||
finishWithError(context, e.getMessage(), true);
|
||||
return;
|
||||
}
|
||||
context.next(myVcs.getSvnBranchPointsCalculator().getFirstCopyPointTask(myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl(), mySourceUrl, calculator),
|
||||
calculator);
|
||||
context.next(myVcs.getSvnBranchPointsCalculator().getFirstCopyPointTask(
|
||||
myWcInfo.getRepositoryRoot(), myWcInfo.getRootUrl(), mySourceUrl, calculator), calculator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,42 +254,52 @@ public class QuickMerge {
|
||||
queue.add(mergeAllExecutor);
|
||||
}
|
||||
|
||||
private class MergeAllWithBranchCopyPoint extends TaskDescriptor implements Consumer<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>> {
|
||||
private SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> myData;
|
||||
private class MergeAllWithBranchCopyPoint extends TaskDescriptor implements Consumer<TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException>> {
|
||||
private AtomicReference<TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException>> myData;
|
||||
|
||||
private MergeAllWithBranchCopyPoint() {
|
||||
super("merge all", Where.AWT);
|
||||
}
|
||||
|
||||
public void consume(SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> data) {
|
||||
myData = data;
|
||||
@Override
|
||||
public void consume(TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException> value) {
|
||||
myData.set(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
if (myData == null) {
|
||||
SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> invertor;
|
||||
try {
|
||||
invertor = myData.get().get();
|
||||
}
|
||||
catch (SVNException e) {
|
||||
finishWithError(context, "Merge start wasn't found", Collections.singletonList(new VcsException(e)));
|
||||
return;
|
||||
}
|
||||
if (invertor == null) {
|
||||
finishWithError(context, "Merge start wasn't found", true);
|
||||
return;
|
||||
}
|
||||
final boolean reintegrate = myData.isInvertedSense();
|
||||
final boolean reintegrate = invertor.isInvertedSense();
|
||||
if (reintegrate && (! prompt("<html><body>You are going to reintegrate changes.<br><br>This will make branch '" + mySourceUrl +
|
||||
"' <b>no longer usable for further work</b>." +
|
||||
"<br>It will not be able to correctly absorb new trunk (" + myData.inverted().getTarget() +
|
||||
"<br>It will not be able to correctly absorb new trunk (" + invertor.inverted().getTarget() +
|
||||
") changes,<br>nor can this branch be properly reintegrated to trunk again.<br><br>Are you sure?</body></html>"))) {
|
||||
context.cancelEverything();
|
||||
return;
|
||||
}
|
||||
final MergerFactory mergerFactory = createBranchMergerFactory(reintegrate);
|
||||
final MergerFactory mergerFactory = createBranchMergerFactory(reintegrate, invertor);
|
||||
|
||||
final String title = "Merging all from " + myBranchName + (reintegrate ? " (reintegrate)" : "");
|
||||
context.next(new MergeTask(mergerFactory, title));
|
||||
}
|
||||
|
||||
private MergerFactory createBranchMergerFactory(final boolean reintegrate) {
|
||||
private MergerFactory createBranchMergerFactory(final boolean reintegrate,
|
||||
final SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> invertor) {
|
||||
return new MergerFactory() {
|
||||
public IMerger createMerger(SvnVcs vcs, File target, UpdateEventHandler handler, SVNURL currentBranchUrl, String branchName) {
|
||||
return new BranchMerger(vcs, currentBranchUrl, myWcInfo.getUrl(), myWcInfo.getPath(), handler, reintegrate, myBranchName,
|
||||
reintegrate ? myData.getWrapped().getTargetRevision() : myData.getWrapped().getSourceRevision());
|
||||
reintegrate ? invertor.getWrapped().getTargetRevision() : invertor.getWrapped().getSourceRevision());
|
||||
}
|
||||
@Nullable
|
||||
public List<CommittedChangeList> getListsToMerge() {
|
||||
@@ -366,20 +376,24 @@ public class QuickMerge {
|
||||
}
|
||||
}
|
||||
|
||||
private class MergeCalculator extends TaskDescriptor implements Consumer<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>> {
|
||||
private class MergeCalculator extends TaskDescriptor implements
|
||||
Consumer<TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException>> {
|
||||
private final static String ourOneShotStrategy = "svn.quickmerge.oneShotStrategy";
|
||||
private final WCInfo myWcInfo;
|
||||
private final String mySourceUrl;
|
||||
private final String myBranchName;
|
||||
private final AtomicReference<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>> myCopyData;
|
||||
private final
|
||||
AtomicReference<TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException>>
|
||||
myCopyData;
|
||||
private boolean myIsReintegrate;
|
||||
|
||||
private final List<CommittedChangeList> myNotMerged;
|
||||
private String myMergeTitle;
|
||||
private final MergeChecker myMergeChecker;
|
||||
|
||||
public void consume(SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> branchCopyDataWrapperInvertor) {
|
||||
myCopyData.set(branchCopyDataWrapperInvertor);
|
||||
@Override
|
||||
public void consume(TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException> value) {
|
||||
myCopyData.set(value);
|
||||
}
|
||||
|
||||
private MergeCalculator(WCInfo wcInfo, String sourceUrl, String branchName) throws SVNException {
|
||||
@@ -397,13 +411,20 @@ public class QuickMerge {
|
||||
myWcInfo.getRootUrl(), mySourceUrl,
|
||||
mySourceUrl, myVcs.createWCClient()));
|
||||
}*/
|
||||
myCopyData = new AtomicReference<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>>();
|
||||
myCopyData = new AtomicReference<TransparentlyFailedValueI<SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData>, SVNException>>();
|
||||
}
|
||||
|
||||
//"Calculating not merged revisions"
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> copyDataValue = myCopyData.get();
|
||||
SvnBranchPointsCalculator.WrapperInvertor<SvnBranchPointsCalculator.BranchCopyData> copyDataValue = null;
|
||||
try {
|
||||
copyDataValue = myCopyData.get().get();
|
||||
}
|
||||
catch (SVNException e) {
|
||||
finishWithError(context, "Merge start wasn't found", Collections.singletonList(new VcsException(e)));
|
||||
return;
|
||||
}
|
||||
if (copyDataValue == null) {
|
||||
finishWithError(context, "Merge start wasn't found", true);
|
||||
return;
|
||||
|
||||
@@ -15,65 +15,89 @@
|
||||
*/
|
||||
package org.jetbrains.idea.svn.dialogs;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vcs.CalledInAwt;
|
||||
import com.intellij.openapi.vcs.CalledInBackground;
|
||||
import com.intellij.openapi.vcs.changes.ThreadSafeTransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public abstract class RunOrContinuation<T> {
|
||||
public abstract class RunOrContinuation<T, E extends Exception> {
|
||||
private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.dialogs.RunOrContinuation");
|
||||
protected final Project myProject;
|
||||
private final String myTaskTitle;
|
||||
private final Class<E> myClazzE;
|
||||
private volatile boolean myWasCanceled;
|
||||
private TransparentlyFailedValueI<T,E> myTransparentlyFailedValue;
|
||||
|
||||
protected RunOrContinuation(final Project project, final String taskTitle) {
|
||||
protected RunOrContinuation(final Project project, final String taskTitle, final Class<E> clazzE) {
|
||||
myProject = project;
|
||||
myTaskTitle = taskTitle;
|
||||
myClazzE = clazzE;
|
||||
myTransparentlyFailedValue = new ThreadSafeTransparentlyFailedValue<T, E>();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@CalledInAwt
|
||||
protected abstract T calculate();
|
||||
protected abstract T calculate() throws E;
|
||||
@Nullable
|
||||
@CalledInBackground
|
||||
protected abstract T calculateLong();
|
||||
protected abstract T calculateLong() throws E;
|
||||
@CalledInAwt
|
||||
protected abstract void processResult(final T t);
|
||||
protected abstract void processResult(final TransparentlyFailedValueI<T, E> t);
|
||||
|
||||
protected void cancel() {
|
||||
myWasCanceled = true;
|
||||
}
|
||||
|
||||
private void setException(Exception e) {
|
||||
if (myClazzE.isAssignableFrom(e.getClass())) {
|
||||
myTransparentlyFailedValue.fail((E)e);
|
||||
} else {
|
||||
LOG.info(e);
|
||||
myTransparentlyFailedValue.failRuntime((e instanceof RuntimeException ? (RuntimeException)e : new RuntimeException(e)));
|
||||
}
|
||||
}
|
||||
|
||||
@CalledInAwt
|
||||
public TaskDescriptor getTask() {
|
||||
final AtomicReference<T> refT = new AtomicReference<T>();
|
||||
|
||||
final TaskDescriptor pooled = new TaskDescriptor(myTaskTitle, Where.POOLED) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
refT.set(calculateLong());
|
||||
try {
|
||||
myTransparentlyFailedValue.set(calculateLong());
|
||||
}
|
||||
catch (Exception e) {
|
||||
setException(e);
|
||||
}
|
||||
if (! myWasCanceled) {
|
||||
context.next(new TaskDescriptor("final part", Where.AWT) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
processResult(refT.get());
|
||||
processResult(myTransparentlyFailedValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return new TaskDescriptor("short part", Where.AWT) {
|
||||
@Override
|
||||
public void run(ContinuationContext context) {
|
||||
refT.set(calculate());
|
||||
if ((! myWasCanceled) && (refT.get() != null)) {
|
||||
processResult(refT.get());
|
||||
try {
|
||||
myTransparentlyFailedValue.set(calculate());
|
||||
}
|
||||
catch (Exception e) {
|
||||
setException(e);
|
||||
}
|
||||
if ((! myWasCanceled) && (myTransparentlyFailedValue.haveSomething())) {
|
||||
processResult(myTransparentlyFailedValue);
|
||||
return;
|
||||
}
|
||||
context.next(pooled);
|
||||
@@ -85,25 +109,4 @@ public abstract class RunOrContinuation<T> {
|
||||
public void execute() {
|
||||
Continuation.createFragmented(myProject, true).run(getTask());
|
||||
}
|
||||
|
||||
/*@CalledInAwt
|
||||
public void execute() {
|
||||
final Ref<T> refT = new Ref<T>();
|
||||
refT.set(calculate());
|
||||
if ((! myWasCanceled) && (! refT.isNull())) {
|
||||
processResult(refT.get());
|
||||
return;
|
||||
}
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, myTaskTitle, true, BackgroundFromStartOption.getInstance()) {
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
refT.set(calculateLong());
|
||||
}
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
if (! myWasCanceled) {
|
||||
processResult(refT.get());
|
||||
}
|
||||
}
|
||||
});
|
||||
} */
|
||||
}
|
||||
|
||||
+33
-41
@@ -18,21 +18,21 @@ package org.jetbrains.idea.svn.dialogs;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.openapi.vcs.persistent.SmallMapSerializer;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ThrowableConvertor;
|
||||
import com.intellij.util.ValueHolder;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
import org.jetbrains.idea.svn.history.CopyData;
|
||||
import org.jetbrains.idea.svn.history.FirstInBranch;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -42,7 +42,7 @@ import java.util.*;
|
||||
|
||||
public class SvnBranchPointsCalculator {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.dialogs.SvnBranchPointsCalculator");
|
||||
private FactsCalculator<KeyData, WrapperInvertor<BranchCopyData>> myCalculator;
|
||||
private FactsCalculator<KeyData, WrapperInvertor<BranchCopyData>, SVNException> myCalculator;
|
||||
private PersistentHolder myPersistentHolder;
|
||||
private File myFile;
|
||||
private final Project myProject;
|
||||
@@ -77,7 +77,8 @@ public class SvnBranchPointsCalculator {
|
||||
}
|
||||
};
|
||||
|
||||
myCalculator = new FactsCalculator<KeyData, WrapperInvertor<BranchCopyData>>(myProject, "Looking for branch origin", cache, new Loader(myProject));
|
||||
myCalculator = new FactsCalculator<KeyData, WrapperInvertor<BranchCopyData>, SVNException>(
|
||||
myProject, "Looking for branch origin", cache, new Loader(myProject));
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
@@ -238,38 +239,39 @@ public class SvnBranchPointsCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Loader implements Convertor<KeyData, WrapperInvertor<BranchCopyData>> {
|
||||
private static class Loader implements ThrowableConvertor<KeyData, WrapperInvertor<BranchCopyData>, SVNException> {
|
||||
private SvnVcs myVcs;
|
||||
|
||||
private Loader(final Project project) {
|
||||
myVcs = SvnVcs.getInstance(project);
|
||||
}
|
||||
|
||||
public WrapperInvertor<BranchCopyData> convert(final KeyData keyData) {
|
||||
final Ref<WrapperInvertor<BranchCopyData>> result = new Ref<WrapperInvertor<BranchCopyData>>();
|
||||
@Override
|
||||
public WrapperInvertor<BranchCopyData> convert(final KeyData keyData) throws SVNException {
|
||||
final TransparentlyFailedValue<CopyData, SVNException> consumer = new TransparentlyFailedValue<CopyData, SVNException>();
|
||||
new FirstInBranch(myVcs, keyData.getRepoUrl(), keyData.getTargetUrl(), keyData.getSourceUrl(), consumer).run();
|
||||
|
||||
new FirstInBranch(myVcs, keyData.getRepoUrl(), keyData.getTargetUrl(), keyData.getSourceUrl(), new Consumer<CopyData>() {
|
||||
public void consume(CopyData copyData) {
|
||||
if (copyData != null) {
|
||||
final boolean correct = copyData.isTrunkSupposedCorrect();
|
||||
final BranchCopyData branchCopyData;
|
||||
if (correct) {
|
||||
branchCopyData = new BranchCopyData(keyData.getSourceUrl(), copyData.getCopySourceRevision(), keyData.getTargetUrl(),
|
||||
copyData.getCopyTargetRevision());
|
||||
} else {
|
||||
branchCopyData = new BranchCopyData(keyData.getTargetUrl(), copyData.getCopySourceRevision(), keyData.getSourceUrl(),
|
||||
copyData.getCopyTargetRevision());
|
||||
}
|
||||
result.set(new WrapperInvertor<BranchCopyData>(! correct, branchCopyData));
|
||||
}
|
||||
final CopyData copyData = consumer.get();
|
||||
if (copyData != null) {
|
||||
final boolean correct = copyData.isTrunkSupposedCorrect();
|
||||
final BranchCopyData branchCopyData;
|
||||
if (correct) {
|
||||
branchCopyData = new BranchCopyData(keyData.getSourceUrl(), copyData.getCopySourceRevision(), keyData.getTargetUrl(),
|
||||
copyData.getCopyTargetRevision());
|
||||
} else {
|
||||
branchCopyData = new BranchCopyData(keyData.getTargetUrl(), copyData.getCopySourceRevision(), keyData.getSourceUrl(),
|
||||
copyData.getCopyTargetRevision());
|
||||
}
|
||||
}).run();
|
||||
|
||||
final WrapperInvertor<BranchCopyData> invertor = result.get();
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Loader17 returned: for key: " + keyData.toString() + " result: " + (invertor == null ? null : invertor.toString()));
|
||||
WrapperInvertor<BranchCopyData> invertor = new WrapperInvertor<BranchCopyData>(! correct, branchCopyData);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Loader17 returned: for key: " + keyData.toString() + " result: " + (invertor.toString()));
|
||||
}
|
||||
return invertor;
|
||||
}
|
||||
return invertor;
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Loader17 returned: for key: " + keyData.toString() + " result: null");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,18 +347,8 @@ public class SvnBranchPointsCalculator {
|
||||
T invertSelf();
|
||||
}
|
||||
|
||||
public void getFirstCopyPoint(final String repoUID, final String sourceUrl, final String targetUrl, Consumer<WrapperInvertor<BranchCopyData>> consumer) {
|
||||
myCalculator.get(new KeyData(repoUID, sourceUrl, targetUrl), consumer);
|
||||
}
|
||||
|
||||
public TaskDescriptor getFirstCopyPointTask(final String repoUID, final String sourceUrl, final String targetUrl,
|
||||
final Consumer<WrapperInvertor<BranchCopyData>> consumer) {
|
||||
return myCalculator.getTask(new KeyData(repoUID, sourceUrl, targetUrl), consumer);
|
||||
}
|
||||
|
||||
public static abstract class CopyPointAcceptorTask extends TaskDescriptor implements Consumer<WrapperInvertor<BranchCopyData>> {
|
||||
protected CopyPointAcceptorTask(String name, @NotNull Where where) {
|
||||
super(name, where);
|
||||
}
|
||||
final Consumer<TransparentlyFailedValueI<WrapperInvertor<BranchCopyData>, SVNException>> consumer) {
|
||||
return myCalculator.getTask(new KeyData(repoUID, sourceUrl, targetUrl), consumer, SVNException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
package org.jetbrains.idea.svn.history;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.vcs.ConcurrentTasks;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.hash.HashSet;
|
||||
import org.jetbrains.idea.svn.SvnVcs;
|
||||
import org.tmatesoft.svn.core.*;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
@@ -28,21 +28,22 @@ import org.tmatesoft.svn.core.wc.SVNLogClient;
|
||||
import org.tmatesoft.svn.core.wc.SVNRevision;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class FirstInBranch implements Runnable {
|
||||
private final SvnVcs myVcs;
|
||||
private final String myFullBranchUrl;
|
||||
private final String myFullTrunkUrl;
|
||||
private final String myBranchUrl;
|
||||
private final String myTrunkUrl;
|
||||
private final Consumer<CopyData> myConsumer;
|
||||
private final String myRepositoryRoot;
|
||||
private final TransparentlyFailedValueI<CopyData, SVNException> myConsumer;
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.FirstInBranch");
|
||||
|
||||
public FirstInBranch(final SvnVcs vcs, final String repositoryRoot, final String branchUrl, final String trunkUrl, final Consumer<CopyData> consumer) {
|
||||
public FirstInBranch(final SvnVcs vcs, final String repositoryRoot, final String branchUrl, final String trunkUrl,
|
||||
final TransparentlyFailedValueI<CopyData, SVNException> consumer) {
|
||||
myVcs = vcs;
|
||||
myRepositoryRoot = repositoryRoot;
|
||||
myConsumer = consumer;
|
||||
|
||||
myFullBranchUrl = branchUrl;
|
||||
myFullTrunkUrl = trunkUrl;
|
||||
myBranchUrl = relativePath(repositoryRoot, branchUrl);
|
||||
myTrunkUrl = relativePath(repositoryRoot, trunkUrl);
|
||||
}
|
||||
@@ -53,28 +54,37 @@ public class FirstInBranch implements Runnable {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
final SVNURL branchURL;
|
||||
final SVNURL trunkURL;
|
||||
final Set<SVNException> exceptions = new HashSet<SVNException>();
|
||||
final boolean [] called = new boolean[1];
|
||||
try {
|
||||
branchURL = SVNURL.parseURIEncoded(myFullBranchUrl);
|
||||
trunkURL = SVNURL.parseURIEncoded(myFullTrunkUrl);
|
||||
createTask(SVNURL.parseURIDecoded(myRepositoryRoot), exceptions).consume(new Consumer<CopyData>() {
|
||||
@Override
|
||||
public void consume(CopyData data) {
|
||||
if (data != null) {
|
||||
myConsumer.set(data);
|
||||
called[0] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (SVNException e) {
|
||||
myConsumer.consume(null);
|
||||
myConsumer.fail(e);
|
||||
return;
|
||||
}
|
||||
if (called[0]) return;
|
||||
|
||||
final ConcurrentTasks<CopyData> tasks =
|
||||
new ConcurrentTasks<CopyData>(ProgressManager.getInstance().getProgressIndicator(), createTask(branchURL), createTask(trunkURL));
|
||||
tasks.compute();
|
||||
if (tasks.isResultKnown()) {
|
||||
myConsumer.consume(tasks.getResult());
|
||||
} else {
|
||||
myConsumer.consume(null);
|
||||
if (! exceptions.isEmpty()) {
|
||||
LOG.info("Wasn't able to find branch point, exception(s) below");
|
||||
for (SVNException exception : exceptions) {
|
||||
LOG.info(exception);
|
||||
}
|
||||
myConsumer.fail(exceptions.iterator().next());
|
||||
} else if (! called[0]) {
|
||||
myConsumer.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
private Consumer<Consumer<CopyData>> createTask(final SVNURL branchURL) {
|
||||
private Consumer<Consumer<CopyData>> createTask(final SVNURL branchURL, final Set<SVNException> exceptions) {
|
||||
return new Consumer<Consumer<CopyData>>() {
|
||||
public void consume(final Consumer<CopyData> copyDataConsumer) {
|
||||
final SVNLogClient logClient = ApplicationManager.getApplication().runReadAction(new Computable<SVNLogClient>() {
|
||||
@@ -85,59 +95,67 @@ public class FirstInBranch implements Runnable {
|
||||
}
|
||||
});
|
||||
if (logClient == null) return;
|
||||
final long start1 = getStart(logClient, branchURL);
|
||||
if (start1 > 0) {
|
||||
final SVNRevision start1Rev = SVNRevision.create(start1);
|
||||
try {
|
||||
logClient.doLog(branchURL, null, SVNRevision.UNDEFINED, start1Rev, start1Rev, true, true, 1, new ISVNLogEntryHandler() {
|
||||
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
|
||||
checkForCopy(logEntry, copyDataConsumer);
|
||||
}
|
||||
});
|
||||
} catch (SVNException e) {
|
||||
//
|
||||
}
|
||||
try {
|
||||
logClient.doLog(branchURL, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, SVNRevision.create(0), false, true, -1,
|
||||
new MyLogEntryHandler(copyDataConsumer, myTrunkUrl, myBranchUrl));
|
||||
} catch (SVNCancelException e) {
|
||||
//
|
||||
} catch (SVNException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static long getStart(final SVNLogClient logClient, final SVNURL url) {
|
||||
final Ref<Long> myRevisionCandidate = new Ref<Long>(0L);
|
||||
try {
|
||||
logClient.doLog(url, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, SVNRevision.create(0),
|
||||
true, false, 0, new ISVNLogEntryHandler() {
|
||||
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
|
||||
ProgressManager.checkCanceled();
|
||||
private static class MyLogEntryHandler implements ISVNLogEntryHandler {
|
||||
private final SvnPathThroughHistoryCorrection myTrunkCorrector;
|
||||
private final SvnPathThroughHistoryCorrection myBranchCorrector;
|
||||
private final Consumer<CopyData> myCopyDataConsumer;
|
||||
|
||||
myRevisionCandidate.set(logEntry.getRevision());
|
||||
}
|
||||
});
|
||||
public MyLogEntryHandler(Consumer<CopyData> copyDataConsumer, String trunkUrl, String branchUrl) {
|
||||
myCopyDataConsumer = copyDataConsumer;
|
||||
myTrunkCorrector = new SvnPathThroughHistoryCorrection(trunkUrl);
|
||||
myBranchCorrector = new SvnPathThroughHistoryCorrection(branchUrl);
|
||||
}
|
||||
catch (SVNException e) {
|
||||
//
|
||||
|
||||
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
|
||||
final Map map = logEntry.getChangedPaths();
|
||||
checkEntries(logEntry, map);
|
||||
myTrunkCorrector.handleLogEntry(logEntry);
|
||||
myBranchCorrector.handleLogEntry(logEntry);
|
||||
checkEntries(logEntry, map);
|
||||
}
|
||||
return myRevisionCandidate.get();
|
||||
}
|
||||
|
||||
private void checkForCopy(final SVNLogEntry logEntry, final Consumer<CopyData> result) {
|
||||
final Map map = logEntry.getChangedPaths();
|
||||
for (Object o : map.values()) {
|
||||
final SVNLogEntryPath path = (SVNLogEntryPath) o;
|
||||
final String localPath = path.getPath();
|
||||
final String copyPath = path.getCopyPath();
|
||||
private void checkEntries(SVNLogEntry logEntry, Map map) throws SVNCancelException {
|
||||
for (Object o : map.values()) {
|
||||
final SVNLogEntryPath path = (SVNLogEntryPath) o;
|
||||
final String localPath = path.getPath();
|
||||
final String copyPath = path.getCopyPath();
|
||||
|
||||
if ('A' == path.getType()) {
|
||||
if ((myBranchUrl.equals(localPath) || SVNPathUtil.isAncestor(localPath, myBranchUrl)) &&
|
||||
((myTrunkUrl.equals(copyPath)) || SVNPathUtil.isAncestor(copyPath, myTrunkUrl))) {
|
||||
result.consume(new CopyData(path.getCopyRevision(), logEntry.getRevision(), true));
|
||||
} else {
|
||||
if ((myBranchUrl.equals(copyPath) || SVNPathUtil.isAncestor(copyPath, myBranchUrl)) &&
|
||||
((myTrunkUrl.equals(localPath)) || SVNPathUtil.isAncestor(localPath, myTrunkUrl))) {
|
||||
result.consume(new CopyData(path.getCopyRevision(), logEntry.getRevision(), false));
|
||||
if ('A' == path.getType()) {
|
||||
if (checkForCopyCase(logEntry, path, localPath, copyPath, myTrunkCorrector.getCurrentPath(), myBranchCorrector.getCurrentPath())) {
|
||||
throw new SVNCancelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkForCopyCase(SVNLogEntry logEntry, SVNLogEntryPath path, String localPath, String copyPath,
|
||||
final String trunkUrl, final String branchUrl) {
|
||||
if (equalOrParent(localPath, branchUrl) && equalOrParent(copyPath, trunkUrl)) {
|
||||
myCopyDataConsumer.consume(new CopyData(path.getCopyRevision(), logEntry.getRevision(), true));
|
||||
return true;
|
||||
} else {
|
||||
if ((equalOrParent(copyPath, branchUrl)) && equalOrParent(localPath, trunkUrl)) {
|
||||
myCopyDataConsumer.consume(new CopyData(path.getCopyRevision(), logEntry.getRevision(), false));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean equalOrParent(String localPath, final String targetPath) {
|
||||
return targetPath.equals(localPath) || SVNPathUtil.isAncestor(localPath, targetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SvnHistoryProvider
|
||||
implements VcsHistoryProvider, VcsCacheableHistorySessionFactory<Boolean, SvnHistorySession> {
|
||||
@@ -476,7 +475,7 @@ public class SvnHistoryProvider
|
||||
private static class MyLogEntryHandler implements ISVNLogEntryHandler {
|
||||
private final ProgressIndicator myIndicator;
|
||||
protected final SvnVcs myVcs;
|
||||
protected String myLastPath;
|
||||
protected final SvnPathThroughHistoryCorrection myLastPathCorrector;
|
||||
private final Charset myCharset;
|
||||
protected final ThrowableConsumer<VcsFileRevision, SVNException> myResult;
|
||||
private VcsFileRevision myPrevious;
|
||||
@@ -497,7 +496,7 @@ public class SvnHistoryProvider
|
||||
SVNURL repoRootURL, Charset charset)
|
||||
throws SVNException, VcsException {
|
||||
myVcs = vcs;
|
||||
myLastPath = lastPath;
|
||||
myLastPathCorrector = new SvnPathThroughHistoryCorrection(lastPath);
|
||||
myCharset = charset;
|
||||
myIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
myResult = result;
|
||||
@@ -514,24 +513,19 @@ public class SvnHistoryProvider
|
||||
}
|
||||
myIndicator.setText2(SvnBundle.message("progress.text2.revision.processed", logEntry.getRevision()));
|
||||
}
|
||||
myLastPathCorrector.handleLogEntry(logEntry);
|
||||
SVNLogEntryPath entryPath = myLastPathCorrector.getDirectlyMentioned();
|
||||
String copyPath = null;
|
||||
SVNLogEntryPath entryPath = (SVNLogEntryPath)logEntry.getChangedPaths().get(myLastPath);
|
||||
if (entryPath != null) {
|
||||
copyPath = entryPath.getCopyPath();
|
||||
} else {
|
||||
// if there are no path with exact match, check whether parent or child paths had changed
|
||||
// "entry path" is allowed to be null now; if it is null, last pa in th would be taken for revision construction
|
||||
// if parent path was renamed, last path would be corrected below in correctLastPathAccordingToFolderRenames
|
||||
// "entry path" is allowed to be null now; if it is null, last path would be taken for revision construction
|
||||
if (! checkForChildChanges(logEntry) && ! checkForParentChanges(logEntry)) return;
|
||||
}
|
||||
|
||||
final int mergeLevel = svnLogEntryIntegerPair.getSecond();
|
||||
final SvnFileRevision revision = createRevision(logEntry, copyPath, entryPath);
|
||||
if (copyPath != null) {
|
||||
myLastPath = copyPath;
|
||||
} else if (entryPath == null) {
|
||||
myLastPath = correctLastPathAccordingToFolderRenames(myLastPath, logEntry);
|
||||
}
|
||||
if (mergeLevel >= 0) {
|
||||
addToListByLevel((SvnFileRevision)myPrevious, revision, mergeLevel);
|
||||
}
|
||||
@@ -548,12 +542,12 @@ public class SvnHistoryProvider
|
||||
}
|
||||
|
||||
private boolean checkForParentChanges(SVNLogEntry logEntry) {
|
||||
String relativePath = null;
|
||||
String path = SVNPathUtil.removeTail(myLastPath);
|
||||
final String lastPathBefore = myLastPathCorrector.getBefore();
|
||||
String path = SVNPathUtil.removeTail(lastPathBefore);
|
||||
while (path.length() > 0) {
|
||||
final SVNLogEntryPath entryPath = (SVNLogEntryPath)logEntry.getChangedPaths().get(path);
|
||||
final SVNLogEntryPath entryPath = logEntry.getChangedPaths().get(path);
|
||||
// A & D are checked since we are not interested in parent folders property changes, only in structure changes
|
||||
if (entryPath != null && (entryPath.getType() == 'A' || entryPath.getType() == 'D')) {
|
||||
relativePath = SVNPathUtil.getRelativePath(entryPath.getPath(), myLastPath);
|
||||
if (entryPath.getCopyPath() != null) {
|
||||
return true;
|
||||
}
|
||||
@@ -565,30 +559,15 @@ public class SvnHistoryProvider
|
||||
}
|
||||
|
||||
private boolean checkForChildChanges(SVNLogEntry logEntry) {
|
||||
final String lastPathBefore = myLastPathCorrector.getBefore();
|
||||
for (String key : logEntry.getChangedPaths().keySet()) {
|
||||
if (SVNPathUtil.isAncestor(myLastPath, key)) {
|
||||
if (SVNPathUtil.isAncestor(lastPathBefore, key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String correctLastPathAccordingToFolderRenames(String lastPath, SVNLogEntry logEntry) {
|
||||
final Map<String,SVNLogEntryPath> paths = logEntry.getChangedPaths();
|
||||
for (Map.Entry<String, SVNLogEntryPath> entry : paths.entrySet()) {
|
||||
final SVNLogEntryPath value = entry.getValue();
|
||||
final String copyPath = value.getCopyPath();
|
||||
if (copyPath != null) {
|
||||
final String entryPath = value.getPath();
|
||||
if (SVNPathUtil.isAncestor(entryPath, lastPath)) {
|
||||
final String relativePath = SVNPathUtil.getRelativePath(entryPath, lastPath);
|
||||
return SVNPathUtil.append(copyPath, relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return lastPath;
|
||||
}
|
||||
|
||||
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
|
||||
myTracker.consume(logEntry);
|
||||
}
|
||||
@@ -614,7 +593,7 @@ public class SvnHistoryProvider
|
||||
SVNRevision rev = SVNRevision.create(logEntry.getRevision());
|
||||
// final SVNURL url = myRepositoryRoot.appendPath(myLastPath, true);
|
||||
final SVNURL url = entryPath != null ? myRepositoryRoot.appendPath(entryPath.getPath(), true) :
|
||||
myRepositoryRoot.appendPath(myLastPath, true);
|
||||
myRepositoryRoot.appendPath(myLastPathCorrector.getBefore(), false);
|
||||
return new SvnFileRevision(myVcs, myPegRevision, rev, url.toString(), author, date, message, copyPath, myCharset);
|
||||
}
|
||||
}
|
||||
@@ -632,7 +611,7 @@ public class SvnHistoryProvider
|
||||
@Override
|
||||
protected SvnFileRevision createRevision(final SVNLogEntry logEntry, final String copyPath, SVNLogEntryPath entryPath)
|
||||
throws SVNException {
|
||||
final SVNURL url = entryPath == null ? myRepositoryRoot.appendPath(myLastPath, true) :
|
||||
final SVNURL url = entryPath == null ? myRepositoryRoot.appendPath(myLastPathCorrector.getBefore(), false) :
|
||||
myRepositoryRoot.appendPath(entryPath.getPath(), true);
|
||||
return new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, url.toString(), copyPath, null);
|
||||
}
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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 org.jetbrains.idea.svn.history;
|
||||
|
||||
import org.jetbrains.idea.svn.SvnUtil;
|
||||
import org.tmatesoft.svn.core.ISVNLogEntryHandler;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.SVNLogEntry;
|
||||
import org.tmatesoft.svn.core.SVNLogEntryPath;
|
||||
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 8/30/12
|
||||
* Time: 5:18 PM
|
||||
*
|
||||
* We consider here, that history is traversed "from now to past"
|
||||
*/
|
||||
public class SvnPathThroughHistoryCorrection implements ISVNLogEntryHandler {
|
||||
private String myBefore;
|
||||
private String myPath;
|
||||
private SVNLogEntryPath myDirectlyMentioned;
|
||||
|
||||
public SvnPathThroughHistoryCorrection(String path) {
|
||||
myPath = path;
|
||||
myBefore = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
|
||||
myBefore = myPath;
|
||||
myDirectlyMentioned = null;
|
||||
final Map<String,SVNLogEntryPath> paths = logEntry.getChangedPaths();
|
||||
final SVNLogEntryPath entryPath = paths.get(myPath);
|
||||
if (entryPath != null) {
|
||||
myDirectlyMentioned = entryPath;
|
||||
// exact match
|
||||
if (entryPath.getCopyPath() != null) {
|
||||
myPath = entryPath.getCopyPath();
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (SVNLogEntryPath path : paths.values()) {
|
||||
// "the origin path *from where* the item, ..."
|
||||
final String copyPath = path.getCopyPath();
|
||||
if (copyPath != null) {
|
||||
final String thisEntryPath = path.getPath();
|
||||
if (parentPathChanged(copyPath, thisEntryPath)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean parentPathChanged(String copyPath, String thisEntryPath) throws SVNException {
|
||||
if (SVNPathUtil.isAncestor(thisEntryPath, myPath)) {
|
||||
final String relativePath = SVNPathUtil.getRelativePath(thisEntryPath, myPath);
|
||||
myPath = SvnUtil.appendMultiParts(copyPath, relativePath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getBefore() {
|
||||
return myBefore;
|
||||
}
|
||||
|
||||
public SVNLogEntryPath getDirectlyMentioned() {
|
||||
return myDirectlyMentioned;
|
||||
}
|
||||
|
||||
public String getCurrentPath() {
|
||||
return myPath;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,10 @@ import com.intellij.lifecycle.PeriodicalTasksCloser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.openapi.ui.MessageType;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
|
||||
import com.intellij.util.containers.SoftHashMap;
|
||||
import com.intellij.util.messages.Topic;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -29,6 +32,7 @@ import org.jetbrains.idea.svn.dialogs.WCPaths;
|
||||
import org.jetbrains.idea.svn.history.CopyData;
|
||||
import org.jetbrains.idea.svn.history.FirstInBranch;
|
||||
import org.jetbrains.idea.svn.history.SvnChangeList;
|
||||
import org.tmatesoft.svn.core.SVNException;
|
||||
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
|
||||
import org.tmatesoft.svn.core.wc.SVNWCClient;
|
||||
|
||||
@@ -167,21 +171,34 @@ public class SvnMergeInfoCache {
|
||||
myPath = path;
|
||||
myRevision = -1;
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new FirstInBranch(vcs, repositoryRoot, branchUrl, trunkUrl,
|
||||
new Consumer<CopyData>() {
|
||||
public void consume(CopyData copyData) {
|
||||
if (copyData == null) return;
|
||||
myRevision = copyData.getCopySourceRevision();
|
||||
if (myRevision != -1) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
if (vcs.getProject().isDisposed()) return;
|
||||
vcs.getProject().getMessageBus().syncPublisher(SVN_MERGE_INFO_CACHE).copyRevisionUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
final TransparentlyFailedValueI<CopyData, SVNException> result = new TransparentlyFailedValue<CopyData, SVNException>() {
|
||||
@Override
|
||||
public void set(CopyData copyData) {
|
||||
if (copyData == null) return;
|
||||
myRevision = copyData.getCopySourceRevision();
|
||||
if (myRevision != -1) {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
if (vcs.getProject().isDisposed()) return;
|
||||
vcs.getProject().getMessageBus().syncPublisher(SVN_MERGE_INFO_CACHE).copyRevisionUpdated();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(SVNException e) {
|
||||
LOG.info(e);
|
||||
VcsBalloonProblemNotifier.showOverChangesView(vcs.getProject(), e.getMessage(), MessageType.ERROR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failRuntime(RuntimeException e) {
|
||||
LOG.info(e);
|
||||
VcsBalloonProblemNotifier.showOverChangesView(vcs.getProject(), e.getMessage(), MessageType.ERROR);
|
||||
}
|
||||
};
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new FirstInBranch(vcs, repositoryRoot, branchUrl, trunkUrl, result));
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
|
||||
+11
-8
@@ -17,18 +17,21 @@ package org.jetbrains.idea.svn.treeConflict;
|
||||
|
||||
import com.intellij.CommonBundle;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.diff.impl.patch.*;
|
||||
import com.intellij.openapi.fileChooser.*;
|
||||
import com.intellij.openapi.diff.impl.patch.BaseRevisionTextPatchEP;
|
||||
import com.intellij.openapi.diff.impl.patch.FilePatch;
|
||||
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
|
||||
import com.intellij.openapi.diff.impl.patch.TextFilePatch;
|
||||
import com.intellij.openapi.fileChooser.FileChooserFactory;
|
||||
import com.intellij.openapi.fileChooser.FileSaverDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileSaverDialog;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.FilePathImpl;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchDefaultExecutor;
|
||||
import com.intellij.openapi.vcs.changes.CommitContext;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.TransparentlyFailedValueI;
|
||||
import com.intellij.openapi.vcs.changes.patch.ApplyPatchExecutor;
|
||||
import com.intellij.openapi.vcs.changes.patch.FilePatchInProgress;
|
||||
import com.intellij.openapi.vcs.changes.patch.PatchWriter;
|
||||
@@ -71,7 +74,7 @@ public class ApplyPatchSaveToFileExecutor implements ApplyPatchExecutor {
|
||||
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
|
||||
LocalChangeList localList,
|
||||
String fileName,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final FileSaverDialog dialog = FileChooserFactory.getInstance().createSaveFileDialog(
|
||||
new FileSaverDescriptor("Save patch to", ""), myProject);
|
||||
final VirtualFile baseDir = myProject.getBaseDir();
|
||||
|
||||
+5
-2
@@ -45,7 +45,10 @@ import com.intellij.util.Consumer;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.continuation.*;
|
||||
import com.intellij.util.continuation.Continuation;
|
||||
import com.intellij.util.continuation.ContinuationContext;
|
||||
import com.intellij.util.continuation.TaskDescriptor;
|
||||
import com.intellij.util.continuation.Where;
|
||||
import org.jetbrains.idea.svn.*;
|
||||
import org.jetbrains.idea.svn.history.SvnChangeList;
|
||||
import org.jetbrains.idea.svn.history.SvnRepositoryLocation;
|
||||
@@ -249,7 +252,7 @@ public class MergeFromTheirsResolver {
|
||||
|
||||
@Override
|
||||
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups, LocalChangeList localList, String fileName,
|
||||
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
TransparentlyFailedValueI<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
|
||||
final List<FilePatch> patches;
|
||||
try {
|
||||
patches = ApplyPatchSaveToFileExecutor.patchGroupsToOneGroup(patchGroups, myBaseDir);
|
||||
|
||||
Reference in New Issue
Block a user