diff options
Diffstat (limited to 'plugins/svn4idea/src/org')
58 files changed, 796 insertions, 780 deletions
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java index 06138b345b74..c33dd38f2eba 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/RootsToWorkingCopies.java @@ -105,7 +105,7 @@ public class RootsToWorkingCopies implements VcsListener { @CalledInBackground @Nullable - public WorkingCopy getWcRoot(final VirtualFile root) { + public WorkingCopy getWcRoot(@NotNull VirtualFile root) { assert (! ApplicationManager.getApplication().isDispatchThread()) || ApplicationManager.getApplication().isUnitTestMode(); synchronized (myLock) { @@ -117,7 +117,7 @@ public class RootsToWorkingCopies implements VcsListener { } @Nullable - private WorkingCopy calculateRoot(final VirtualFile root) { + private WorkingCopy calculateRoot(@NotNull VirtualFile root) { File workingCopyRoot = SvnUtil.getWorkingCopyRootNew(new File(root.getPath())); WorkingCopy workingCopy = null; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties index df545b0373a1..3f4ae40677ae 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBundle.properties @@ -526,6 +526,7 @@ action.Subversion.integrate.changes.alien.commit.changelist.title=Integrated action.Subversion.integrate.changes.dialog.add.wc.text=Add action.Subversion.integrate.changes.dialog.remove.wc.text=Remove action.Subversion.integrate.changes.message.files.up.to.date.text=All files are up to date +action.Subversion.integrate.changes.collecting.changes.to.commit.task.title=Collecting changes to commit action.Subversion.integrate.changes.error.unable.to.collect.changes.text=Error while collecting changes to commit: {0} error.cannot.load.revisions=Can not load revision list action.Subversion.integrate.changes.message.canceled.text=Integration was canceled diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java index 9ae90c722cb3..1fc5f9ce075a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java @@ -27,6 +27,7 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.actions.AbstractShowPropertiesDiffAction; +import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.lock.Lock; import org.jetbrains.idea.svn.status.Status; @@ -244,7 +245,13 @@ class SvnChangeProviderContext implements StatusReceiver { myChangelistBuilder.processLocallyDeletedFile(createLocallyDeletedChange(filePath, status)); } else if (status.is(StatusType.STATUS_IGNORED)) { - if (!myVcs.isWcRoot(filePath)) { + if (filePath.getVirtualFile() == null) { + filePath.hardRefresh(); + } + if (filePath.getVirtualFile() == null) { + LOG.error("No virtual file for ignored file: " + filePath.getPresentableUrl() + ", isNonLocal: " + filePath.isNonLocal()); + } + else if (!myVcs.isWcRoot(filePath)) { myChangelistBuilder.processIgnoredFile(filePath.getVirtualFile()); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java index 6f5013c4a929..9d8df6591268 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java @@ -30,6 +30,7 @@ import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; import org.jetbrains.idea.svn.auth.SvnAuthenticationProvider; import org.jetbrains.idea.svn.auth.SvnInteractiveAuthenticationProvider; +import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager; import org.jetbrains.idea.svn.config.SvnServerFileKeys; import org.jetbrains.idea.svn.diff.DiffOptions; import org.jetbrains.idea.svn.update.MergeRootInfo; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java index 11838314acbd..5c660643dc66 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFileUrlMappingImpl.java @@ -221,11 +221,16 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState } public void realRefresh(final Runnable afterRefreshCallback) { - final SvnVcs vcs = SvnVcs.getInstance(myProject); - final VirtualFile[] roots = myHelper.executeDefended(myProject); - final SvnRootsDetector rootsDetector = new SvnRootsDetector(vcs, this, myNestedCopiesHolder); - // do not send additional request for nested copies when in init state - rootsDetector.detectCopyRoots(roots, init(), afterRefreshCallback); + if (myProject.isDisposed()) { + afterRefreshCallback.run(); + } + else { + final SvnVcs vcs = SvnVcs.getInstance(myProject); + final VirtualFile[] roots = myHelper.executeDefended(myProject); + final SvnRootsDetector rootsDetector = new SvnRootsDetector(vcs, this, myNestedCopiesHolder); + // do not send additional request for nested copies when in init state + rootsDetector.detectCopyRoots(roots, init(), afterRefreshCallback); + } } public void applyDetectionResult(@NotNull SvnRootsDetector.Result result) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnScopeZipper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnScopeZipper.java index a5612a69172a..d4c98221a567 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnScopeZipper.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnScopeZipper.java @@ -19,22 +19,25 @@ import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.changes.VcsDirtyScope; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; public class SvnScopeZipper implements Runnable { - private final VcsDirtyScope myIn; - private final List<FilePath> myRecursiveDirs; + + @NotNull private final VcsDirtyScope myIn; + @NotNull private final List<FilePath> myRecursiveDirs; // instead of set and heavy equals of file path - private final Map<String, MyDirNonRecursive> myNonRecursiveDirs; - // those alone in their immediate parent - private final List<FilePath> mySingleFiles; + @NotNull private final Map<String, MyDirNonRecursive> myNonRecursiveDirs; - public SvnScopeZipper(final VcsDirtyScope in) { + public SvnScopeZipper(@NotNull VcsDirtyScope in) { myIn = in; - myRecursiveDirs = new ArrayList<FilePath>(in.getRecursivelyDirtyDirectories()); - myNonRecursiveDirs = new HashMap<String, MyDirNonRecursive>(); - mySingleFiles = new ArrayList<FilePath>(); + myRecursiveDirs = ContainerUtil.newArrayList(in.getRecursivelyDirtyDirectories()); + myNonRecursiveDirs = ContainerUtil.newHashMap(); } public void run() { @@ -46,85 +49,72 @@ public class SvnScopeZipper implements Runnable { final VirtualFile vFile = file.getVirtualFile(); // todo take care about this 'not valid' - right now keeping things as they used to be final MyDirNonRecursive me = createOrGet(file); - me.setInterestedInParent(true); if (vFile != null && vFile.isValid()) { for (VirtualFile child : vFile.getChildren()) { me.add(new FilePathImpl(child)); } } } - final FilePath parent = file.getParentPath(); - if (parent != null) { - final MyDirNonRecursive item = createOrGet(parent); - item.add(file); + else { + final FilePath parent = file.getParentPath(); + if (parent != null) { + final MyDirNonRecursive item = createOrGet(parent); + item.add(file); + } } } - - // move alone files into a separate list - /*for (Iterator<Map.Entry<String, MyDirNonRecursive>> iterator = myNonRecursiveDirs.entrySet().iterator(); iterator.hasNext();) { - final Map.Entry<String, MyDirNonRecursive> entry = iterator.next(); - final MyDirNonRecursive item = entry.getValue(); - if ((! item.isInterestedInParent()) && (item.getChildrenList().size() == 1)) { - iterator.remove(); - mySingleFiles.add(item.getChildrenList().iterator().next()); - } - }*/ } - private MyDirNonRecursive createOrGet(final FilePath parent) { - final String key = getKey(parent); - final MyDirNonRecursive result = myNonRecursiveDirs.get(key); - if (result != null) return result; - final MyDirNonRecursive newItem = new MyDirNonRecursive(parent); - myNonRecursiveDirs.put(key, newItem); - return newItem; + @NotNull + private MyDirNonRecursive createOrGet(@NotNull FilePath parent) { + String key = getKey(parent); + MyDirNonRecursive result = myNonRecursiveDirs.get(key); + + if (result == null) { + result = new MyDirNonRecursive(parent); + myNonRecursiveDirs.put(key, result); + } + + return result; } + @NotNull public List<FilePath> getRecursiveDirs() { return myRecursiveDirs; } + @NotNull public Map<String, MyDirNonRecursive> getNonRecursiveDirs() { return myNonRecursiveDirs; } - public List<FilePath> getSingleFiles() { - return mySingleFiles; + public static String getKey(@NotNull FilePath path) { + return path.getPresentableUrl(); } static class MyDirNonRecursive { - private boolean myInterestedInParent; - private final FilePath myDir; + + @NotNull private final FilePath myDir; // instead of set and heavy equals of file path - private final Map<String, FilePath> myChildren; + @NotNull private final Map<String, FilePath> myChildren; - private MyDirNonRecursive(final FilePath dir) { + private MyDirNonRecursive(@NotNull FilePath dir) { myDir = dir; - myChildren = new HashMap<String, FilePath>(); - } - - public boolean isInterestedInParent() { - return myInterestedInParent; - } - - public void setInterestedInParent(boolean interestedInParent) { - myInterestedInParent = interestedInParent; + myChildren = ContainerUtil.newHashMap(); } - public void add(final FilePath path) { + public void add(@NotNull FilePath path) { myChildren.put(getKey(path), path); } + @NotNull public Collection<FilePath> getChildrenList() { return myChildren.values(); } + @NotNull public FilePath getDir() { return myDir; } } - - public static String getKey(final FilePath path) { - return path.getPresentableUrl(); - } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java index 43407f4b2064..aaf46003c1dd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnUtil.java @@ -49,6 +49,7 @@ import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.api.EventAction; import org.jetbrains.idea.svn.api.ProgressEvent; import org.jetbrains.idea.svn.api.ProgressTracker; +import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import org.jetbrains.idea.svn.browse.DirectoryEntry; import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer; @@ -58,11 +59,15 @@ import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.status.Status; import org.tmatesoft.sqljet.core.SqlJetException; import org.tmatesoft.sqljet.core.table.SqlJetDb; -import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNFileUtil; import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc.SVNWCUtil; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -343,7 +348,7 @@ public class SvnUtil { for (T committable : committables) { final RootUrlInfo path = vcs.getSvnFileUrlMapping().getWcRootForFilePath(convertor.convert(committable)); if (path == null) { - result.putValue(new Pair<SVNURL, WorkingCopyFormat>(null, null), committable); + result.putValue(Pair.create((SVNURL)null, WorkingCopyFormat.UNKNOWN), committable); } else { result.putValue(Pair.create(path.getRepositoryUrlUrl(), path.getFormat()), committable); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index b44fd16f979f..e5018f3319d5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -68,6 +68,7 @@ import org.jetbrains.idea.svn.api.CmdClientFactory; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.api.SvnKitClientFactory; import org.jetbrains.idea.svn.auth.SvnAuthenticationNotifier; +import org.jetbrains.idea.svn.branchConfig.SvnLoadedBranchesStorage; import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment; import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider; import org.jetbrains.idea.svn.commandLine.SvnBindException; @@ -81,7 +82,6 @@ import org.jetbrains.idea.svn.history.SvnHistoryProvider; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.info.InfoConsumer; import org.jetbrains.idea.svn.properties.PropertyClient; -import org.jetbrains.idea.svn.properties.PropertyData; import org.jetbrains.idea.svn.properties.PropertyValue; import org.jetbrains.idea.svn.rollback.SvnRollbackEnvironment; import org.jetbrains.idea.svn.status.Status; @@ -89,7 +89,10 @@ import org.jetbrains.idea.svn.status.StatusType; import org.jetbrains.idea.svn.svnkit.SvnKitManager; import org.jetbrains.idea.svn.update.SvnIntegrateEnvironment; import org.jetbrains.idea.svn.update.SvnUpdateEnvironment; -import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNNodeKind; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.wc.SVNAdminUtil; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -145,7 +148,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { private final RootsToWorkingCopies myRootsToWorkingCopies; private final SvnAuthenticationNotifier myAuthNotifier; - private final SvnLoadedBrachesStorage myLoadedBranchesStorage; + private final SvnLoadedBranchesStorage myLoadedBranchesStorage; private final SvnExecutableChecker myChecker; @@ -157,7 +160,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { private final boolean myLogExceptions; - public SvnVcs(final Project project, MessageBus bus, SvnConfiguration svnConfiguration, final SvnLoadedBrachesStorage storage) { + public SvnVcs(final Project project, MessageBus bus, SvnConfiguration svnConfiguration, final SvnLoadedBranchesStorage storage) { super(project, VCS_NAME); myLoadedBranchesStorage = storage; @@ -723,9 +726,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { return WorkingCopyFormat.UNKNOWN.equals(format) ? SvnFormatSelector.findRootAndGetFormat(ioFile) : format; } - public boolean isWcRoot(FilePath filePath) { + public boolean isWcRoot(@NotNull FilePath filePath) { boolean isWcRoot = false; - WorkingCopy wcRoot = myRootsToWorkingCopies.getWcRoot(filePath.getVirtualFile()); + VirtualFile file = filePath.getVirtualFile(); + WorkingCopy wcRoot = file != null ? myRootsToWorkingCopies.getWcRoot(file) : null; if (wcRoot != null) { isWcRoot = wcRoot.getFile().getAbsolutePath().equals(filePath.getIOFile().getAbsolutePath()); } @@ -917,7 +921,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { } @Override - public boolean isVcsBackgroundOperationsAllowed(VirtualFile root) { + public boolean isVcsBackgroundOperationsAllowed(@NotNull VirtualFile root) { // TODO: Currently myAuthNotifier.isAuthenticatedFor directly uses SVNKit to check credentials - so assume for now that background // TODO: operations are always allowed for command line. As sometimes this leads to errors - for instance, incoming changes are not // TODO: displayed in "Incoming" tab - incoming changes are collected using command line but not displayed because diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractIntegrateChangesAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractIntegrateChangesAction.java index ff0f158f32a8..468399e93679 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractIntegrateChangesAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractIntegrateChangesAction.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vcs.changes.committed.CommittedChangesBrowserUseCase import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; +import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup; import org.jetbrains.idea.svn.integrate.MergerFactory; import org.jetbrains.idea.svn.integrate.SelectedCommittedStuffChecker; import org.jetbrains.idea.svn.integrate.SvnIntegrateChangesActionPerformer; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java index ddd9bd572f0e..ee4f807c2570 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java @@ -26,6 +26,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsRunnable; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnRevisionNumber; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; @@ -33,7 +34,6 @@ import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.properties.PropertyClient; import org.jetbrains.idea.svn.properties.PropertyValue; -import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -162,8 +162,8 @@ public class SvnMergeProvider implements MergeProvider { File ioFile = new File(file.getPath()); PropertyClient client = vcs.getFactory(ioFile).createPropertyClient(); - PropertyValue value = client.getProperty(SvnTarget.fromFile(ioFile), SVNProperty.MIME_TYPE, false, SVNRevision.WORKING); - if (value != null && SVNProperty.isBinaryMimeType(value.toString())) { + PropertyValue value = client.getProperty(SvnTarget.fromFile(ioFile), SvnPropertyKeys.SVN_MIME_TYPE, false, SVNRevision.WORKING); + if (value != null && isBinaryMimeType(value.toString())) { return true; } } @@ -173,4 +173,8 @@ public class SvnMergeProvider implements MergeProvider { return false; } + + private static boolean isBinaryMimeType(@NotNull String mimeType) { + return !mimeType.startsWith("text/"); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java index a615fd4e3afa..e40569d720de 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java @@ -70,7 +70,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn if (! svnRevision.isValid()) { throw new VcsException("Can not get last changed revision for file: " + file.getPath() + "\nPlease run svn info for this file and file an issue."); } - return annotate(file, new SvnFileRevision(myVcs, currentRevision, currentRevision, null, null, null, null, null, file.getCharset()), + return annotate(file, new SvnFileRevision(myVcs, currentRevision, currentRevision, null, null, null, null, null), lastChangedRevision.getRevisionNumber(), true); } @@ -438,7 +438,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn myProgress.checkCanceled(); myProgress.setText2(SvnBundle.message("progress.text2.revision.processed", logEntry.getRevision())); } - myResult.setRevision(logEntry.getRevision(), new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, myUrl, "", myCharset)); + myResult.setRevision(logEntry.getRevision(), new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, myUrl, "")); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java index 57c835daef2f..ffc21a011334 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/auth/SvnAuthenticationNotifier.java @@ -223,7 +223,7 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica /** * Bases on presence of notifications! */ - public ThreeState isAuthenticatedFor(final VirtualFile vf) { + public ThreeState isAuthenticatedFor(@NotNull VirtualFile vf) { final WorkingCopy wcCopy = myRootsToWorkingCopies.getWcRoot(vf); if (wcCopy == null) return ThreeState.UNSURE; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.form index a416aa145505..b68010c827db 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.form @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.idea.svn.dialogs.BranchConfigurationDialog"> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.idea.svn.branchConfig.BranchConfigurationDialog"> <grid id="27dc6" binding="myTopPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java index 50ddd9615d41..0e0fce947088 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchConfigurationDialog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.idea.svn.dialogs; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.actionSystem.ActionToolbarPosition; import com.intellij.openapi.project.Project; @@ -32,12 +32,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; -import org.jetbrains.idea.svn.branchConfig.InfoReliability; -import org.jetbrains.idea.svn.branchConfig.InfoStorage; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigManager; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import org.jetbrains.idea.svn.commandLine.SvnBindException; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; +import org.jetbrains.idea.svn.dialogs.SelectLocationDialog; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNURLUtil; @@ -59,7 +55,7 @@ public class BranchConfigurationDialog extends DialogWrapper { private JList myLocationList; private JPanel myListPanel; private JLabel myErrorPrompt; - private final SvnBranchConfigManager mySvnBranchConfigManager; + private final NewRootBunch mySvnBranchConfigManager; private final VirtualFile myRoot; public BranchConfigurationDialog(@NotNull final Project project, @@ -115,7 +111,7 @@ public class BranchConfigurationDialog extends DialogWrapper { if (!configuration.getBranchUrls().contains(selectedUrl)) { configuration .addBranches(selectedUrl, new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(), InfoReliability.empty)); - mySvnBranchConfigManager.reloadBranches(myRoot, selectedUrl, null); + mySvnBranchConfigManager.reloadBranchesAsync(myRoot, selectedUrl, InfoReliability.setByUser); listModel.fireItemAdded(); myLocationList.setSelectedIndex(listModel.getSize() - 1); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java index 10f4574c7f39..ba0288da9699 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/BranchesLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. @@ -16,14 +16,16 @@ package org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnConfiguration; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.browse.DirectoryEntry; import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.SVNLogClient; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -33,27 +35,60 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -public class BranchesLoader { +/** + * @author Konstantin Kolosovsky. + */ +public class BranchesLoader implements Runnable { + @NotNull private final Project myProject; + @NotNull private final NewRootBunch myBunch; + @NotNull private final VirtualFile myRoot; + @NotNull private final String myUrl; + @NotNull private final InfoReliability myInfoReliability; + private final boolean myPassive; + + public BranchesLoader(@NotNull Project project, + @NotNull NewRootBunch bunch, + @NotNull String url, + @NotNull InfoReliability infoReliability, + @NotNull VirtualFile root, + boolean passive) { + myProject = project; + myBunch = bunch; + myUrl = url; + myInfoReliability = infoReliability; + myRoot = root; + myPassive = passive; + } - private BranchesLoader() { + public void run() { + try { + List<SvnBranchItem> branches = loadBranches(); + myBunch.updateBranches(myRoot, myUrl, new InfoStorage<List<SvnBranchItem>>(branches, myInfoReliability)); + } + catch (VcsException e) { + showError(e); + } + catch (SVNException e) { + showError(e); + } } - public static List<SvnBranchItem> loadBranches(final Project project, final String url, boolean passive) throws SVNException, - VcsException { - final SvnConfiguration configuration = SvnConfiguration.getInstance(project); - final SvnVcs vcs = SvnVcs.getInstance(project); - SVNURL branchesUrl = SVNURL.parseURIEncoded(url); + @NotNull + public List<SvnBranchItem> loadBranches() throws SVNException, VcsException { + final SvnConfiguration configuration = SvnConfiguration.getInstance(myProject); + final SvnVcs vcs = SvnVcs.getInstance(myProject); + SVNURL branchesUrl = SVNURL.parseURIEncoded(myUrl); List<SvnBranchItem> result = new LinkedList<SvnBranchItem>(); SvnTarget target = SvnTarget.fromURL(branchesUrl); - if (!passive) { + if (!myPassive) { // TODO: Implement ability to specify interactive/non-interactive auth mode for clients DirectoryEntryConsumer handler = createConsumer(branchesUrl, result); vcs.getFactory(target).createBrowseClient().list(target, SVNRevision.HEAD, Depth.IMMEDIATES, handler); } else { ISVNDirEntryHandler handler = createHandler(branchesUrl, result); - SVNLogClient client = vcs.getSvnKitManager().createLogClient(configuration.getPassiveAuthenticationManager(project)); + SVNLogClient client = vcs.getSvnKitManager().createLogClient(configuration.getPassiveAuthenticationManager(myProject)); client .doList(target.getURL(), target.getPegRevision(), SVNRevision.HEAD, false, SVNDepth.IMMEDIATES, SVNDirEntry.DIRENT_ALL, handler); } @@ -62,6 +97,13 @@ public class BranchesLoader { return result; } + private void showError(Exception e) { + // already logged inside + if (InfoReliability.setByUser.equals(myInfoReliability)) { + VcsBalloonProblemNotifier.showOverChangesView(myProject, "Branches load error: " + e.getMessage(), MessageType.ERROR); + } + } + @NotNull private static ISVNDirEntryHandler createHandler(@NotNull final SVNURL branchesUrl, @NotNull final List<SvnBranchItem> result) { return new ISVNDirEntryHandler() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/ConfigureBranchesAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java index 1993a1caa0fe..3615c4b4792d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/ConfigureBranchesAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/ConfigureBranchesAction.java @@ -13,12 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn.actions; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; @@ -28,7 +27,6 @@ import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import icons.SvnIcons; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.dialogs.BranchConfigurationDialog; import org.jetbrains.idea.svn.history.SvnChangeList; public class ConfigureBranchesAction extends AnAction implements DumbAware { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/CreateBranchOrTagAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagAction.java index c6f633416a15..da1557922a44 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/CreateBranchOrTagAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagAction.java @@ -15,7 +15,7 @@ */ -package org.jetbrains.idea.svn.actions; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.Application; @@ -35,10 +35,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnStatusUtil; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.actions.BasicAction; import org.jetbrains.idea.svn.checkin.CommitEventHandler; import org.jetbrains.idea.svn.checkin.IdeaCommitHandler; import org.jetbrains.idea.svn.commandLine.SvnBindException; -import org.jetbrains.idea.svn.dialogs.CreateBranchOrTagDialog; import org.jetbrains.idea.svn.update.AutoSvnUpdater; import org.jetbrains.idea.svn.update.SingleRootSwitcher; import org.tmatesoft.svn.core.SVNErrorCode; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.form index 6dfcae6c9f6f..96eaeaaf2c4c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.form @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.idea.svn.dialogs.CreateBranchOrTagDialog"> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.idea.svn.branchConfig.CreateBranchOrTagDialog"> <grid id="9287c" binding="myTopPanel" layout-manager="GridBagLayout"> <constraints> <xy x="10" y="10" width="561" height="502"/> diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java index a09de54fdbc4..95ae986dd72d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CreateBranchOrTagDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/CreateBranchOrTagDialog.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn.dialogs; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.icons.AllIcons; import com.intellij.openapi.diagnostic.Logger; @@ -33,10 +33,9 @@ import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.RootUrlInfo; -import org.jetbrains.idea.svn.SvnBranchConfigurationManager; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; +import org.jetbrains.idea.svn.dialogs.SelectLocationDialog; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.update.SvnRevisionPanel; import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultBranchConfigInitializer.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultBranchConfigInitializer.java new file mode 100644 index 000000000000..37b78459448c --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultBranchConfigInitializer.java @@ -0,0 +1,155 @@ +/* + * 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.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +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 org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.api.Depth; +import org.jetbrains.idea.svn.browse.DirectoryEntry; +import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.internal.util.SVNPathUtil; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +import java.util.ArrayList; +import java.util.List; + +/** +* @author Konstantin Kolosovsky. +*/ +public class DefaultBranchConfigInitializer implements Runnable { + + private static final Logger LOG = Logger.getInstance(DefaultBranchConfigInitializer.class); + + @NonNls private static final String DEFAULT_TRUNK_NAME = "trunk"; + @NonNls private static final String DEFAULT_BRANCHES_NAME = "branches"; + @NonNls private static final String DEFAULT_TAGS_NAME = "tags"; + + @NotNull private final Project myProject; + @NotNull private final NewRootBunch myBunch; + @NotNull private final VirtualFile myRoot; + + public DefaultBranchConfigInitializer(@NotNull Project project, @NotNull NewRootBunch bunch, @NotNull VirtualFile root) { + myProject = project; + myRoot = root; + myBunch = bunch; + } + + public void run() { + SvnBranchConfigurationNew configuration = getDefaultConfiguration(); + + if (configuration != null) { + for (String url : configuration.getBranchUrls()) { + myBunch.reloadBranchesAsync(myRoot, url, InfoReliability.defaultValues); + } + + myBunch.updateForRoot(myRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.defaultValues), false); + } + } + + @Nullable + public SvnBranchConfigurationNew getDefaultConfiguration() { + SvnBranchConfigurationNew result = null; + SvnVcs vcs = SvnVcs.getInstance(myProject); + SVNURL rootUrl = SvnUtil.getUrl(vcs, VfsUtilCore.virtualToIoFile(myRoot)); + + if (rootUrl != null) { + try { + result = getDefaultConfiguration(vcs, rootUrl); + } + catch (SVNException e) { + LOG.info(e); + } + catch (VcsException e) { + LOG.info(e); + } + } + else { + LOG.info("Directory is not a working copy: " + myRoot.getPresentableUrl()); + } + + return result; + } + + @NotNull + private static SvnBranchConfigurationNew getDefaultConfiguration(@NotNull SvnVcs vcs, @NotNull SVNURL url) + throws SVNException, VcsException { + SvnBranchConfigurationNew result = new SvnBranchConfigurationNew(); + result.setTrunkUrl(url.toString()); + + SVNURL branchLocationsParent = getBranchLocationsParent(url); + if (branchLocationsParent != null) { + SvnTarget target = SvnTarget.fromURL(branchLocationsParent); + + vcs.getFactory(target).createBrowseClient().list(target, SVNRevision.HEAD, Depth.IMMEDIATES, createHandler(result, target.getURL())); + } + + return result; + } + + @Nullable + private static SVNURL getBranchLocationsParent(@NotNull SVNURL url) throws SVNException { + while (!hasEmptyName(url) && !hasDefaultName(url)) { + url = url.removePathTail(); + } + + return hasDefaultName(url) ? url.removePathTail() : null; + } + + private static boolean hasEmptyName(@NotNull SVNURL url) { + return StringUtil.isEmpty(SVNPathUtil.tail(url.getPath())); + } + + private static boolean hasDefaultName(@NotNull SVNURL url) { + String name = SVNPathUtil.tail(url.getPath()); + + return name.equalsIgnoreCase(DEFAULT_TRUNK_NAME) || + name.equalsIgnoreCase(DEFAULT_BRANCHES_NAME) || + name.equalsIgnoreCase(DEFAULT_TAGS_NAME); + } + + @NotNull + private static DirectoryEntryConsumer createHandler(@NotNull final SvnBranchConfigurationNew result, @NotNull final SVNURL rootPath) { + return new DirectoryEntryConsumer() { + + @Override + public void consume(final DirectoryEntry entry) throws SVNException { + if (entry.isDirectory()) { + SVNURL childUrl = rootPath.appendPath(entry.getName(), false); + + if (StringUtil.endsWithIgnoreCase(entry.getName(), DEFAULT_TRUNK_NAME)) { + result.setTrunkUrl(childUrl.toString()); + } + else { + result.addBranches(childUrl.toString(), + new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(0), InfoReliability.defaultValues)); + } + } + } + }; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java deleted file mode 100644 index d52798e6bfc3..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/DefaultConfigLoader.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.branchConfig; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.api.Depth; -import org.jetbrains.idea.svn.browse.DirectoryEntry; -import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer; -import org.jetbrains.idea.svn.info.Info; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; -import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.internal.util.SVNPathUtil; -import org.tmatesoft.svn.core.wc.SVNRevision; -import org.tmatesoft.svn.core.wc2.SvnTarget; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class DefaultConfigLoader { - - private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.DefaultConfigLoader"); - - @NonNls private static final String DEFAULT_TRUNK_NAME = "trunk"; - @NonNls private static final String DEFAULT_BRANCHES_NAME = "branches"; - @NonNls private static final String DEFAULT_TAGS_NAME = "tags"; - - private DefaultConfigLoader() { - } - - @Nullable - public static SvnBranchConfigurationNew loadDefaultConfiguration(final Project project, final VirtualFile vcsRoot) { - try { - final SvnVcs vcs = SvnVcs.getInstance(project); - - File rootFile = new File(vcsRoot.getPath()); - final Info info = vcs.getInfo(rootFile); - if (info == null || info.getURL() == null) { - LOG.info("Directory is not a working copy: " + vcsRoot.getPresentableUrl()); - return null; - } - SVNURL baseUrl = info.getURL(); - - final SvnBranchConfigurationNew result = new SvnBranchConfigurationNew(); - result.setTrunkUrl(baseUrl.toString()); - while(true) { - final String s = SVNPathUtil.tail(baseUrl.getPath()); - if (s.equalsIgnoreCase(DEFAULT_TRUNK_NAME) || s.equalsIgnoreCase(DEFAULT_BRANCHES_NAME) || s.equalsIgnoreCase(DEFAULT_TAGS_NAME)) { - SVNURL rootPath = baseUrl.removePathTail(); - SvnTarget target = SvnTarget.fromURL(rootPath); - - vcs.getFactory(target).createBrowseClient().list(target, SVNRevision.HEAD, Depth.IMMEDIATES, createHandler(result, rootPath)); - break; - } - if (SVNPathUtil.removeTail(baseUrl.getPath()).length() == 0) { - break; - } - baseUrl = baseUrl.removePathTail(); - } - return result; - } - catch (SVNException e) { - LOG.info(e); - return null; - } - catch (VcsException e) { - LOG.info(e); - return null; - } - } - - @NotNull - private static DirectoryEntryConsumer createHandler(final SvnBranchConfigurationNew result, final SVNURL rootPath) { - return new DirectoryEntryConsumer() { - - @Override - public void consume(final DirectoryEntry entry) throws SVNException { - if (entry.isDirectory()) { - SVNURL childUrl = rootPath.appendPath(entry.getName(), false); - - if (StringUtil.endsWithIgnoreCase(entry.getName(), DEFAULT_TRUNK_NAME)) { - result.setTrunkUrl(childUrl.toString()); - } - else { - result.addBranches(childUrl.toString(), - new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(0), InfoReliability.defaultValues)); - } - } - } - }; - } -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/InfoStorage.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/InfoStorage.java index 493721e3a8d1..fe10696768c1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/InfoStorage.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/InfoStorage.java @@ -15,9 +15,6 @@ */ package org.jetbrains.idea.svn.branchConfig; -import com.intellij.util.PairConsumer; -import org.jetbrains.annotations.Nullable; - public class InfoStorage<T> { public T myT; public InfoReliability myInfoReliability; @@ -27,14 +24,15 @@ public class InfoStorage<T> { myInfoReliability = infoReliability; } - public void accept(final InfoStorage<T> infoStorage, @Nullable final PairConsumer<T, T> callbackOnUpdate) { - if (infoStorage.myInfoReliability.shouldOverride(myInfoReliability)) { - if (callbackOnUpdate != null) { - callbackOnUpdate.consume(myT, infoStorage.myT); - } + public boolean accept(final InfoStorage<T> infoStorage) { + boolean override = infoStorage.myInfoReliability.shouldOverride(myInfoReliability); + + if (override) { myT = infoStorage.myT; myInfoReliability = infoStorage.myInfoReliability; } + + return override; } public T getValue() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java index 2c7444ed85b0..6f7f4185a815 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/NewRootBunch.java @@ -15,31 +15,23 @@ */ package org.jetbrains.idea.svn.branchConfig; -import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManagerQueue; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.CalledInBackground; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; -import com.intellij.util.PairConsumer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; +import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; // synch is here -public class NewRootBunch implements SvnBranchConfigManager { +public class NewRootBunch { private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.NewRootBunch"); private final Object myLock = new Object(); private final Project myProject; @@ -52,17 +44,31 @@ public class NewRootBunch implements SvnBranchConfigManager { myMap = new HashMap<VirtualFile, InfoStorage<SvnBranchConfigurationNew>>(); } - public void updateForRoot(@NotNull final VirtualFile root, @NotNull final InfoStorage<SvnBranchConfigurationNew> config, - @Nullable final PairConsumer<SvnBranchConfigurationNew, SvnBranchConfigurationNew> callbackOnUpdate) { + public void updateForRoot(@NotNull final VirtualFile root, + @NotNull final InfoStorage<SvnBranchConfigurationNew> config, + boolean reload) { synchronized (myLock) { + final SvnBranchConfigurationNew previous; + boolean override; final InfoStorage<SvnBranchConfigurationNew> existing = myMap.get(root); + if (existing == null) { + previous = null; + override = true; myMap.put(root, config); - if (callbackOnUpdate != null) { - callbackOnUpdate.consume(null, config.getValue()); - } - } else { - existing.accept(config, callbackOnUpdate); + } + else { + previous = existing.getValue(); + override = existing.accept(config); + } + + if (reload && override) { + myBranchesLoader.run(new Runnable() { + @Override + public void run() { + reloadBranches(root, previous, config.getValue()); + } + }); } } } @@ -88,17 +94,44 @@ public class NewRootBunch implements SvnBranchConfigManager { result = new SvnBranchConfigurationNew(); myMap.put(root, new InfoStorage<SvnBranchConfigurationNew>(result, InfoReliability.empty)); myBranchesLoader.run(new DefaultBranchConfigInitializer(myProject, this, root)); - } else { + } + else { result = value.getValue(); } return result; } } - public void reloadBranches(@NotNull final VirtualFile root, @NotNull final String branchParentUrl, - final Consumer<List<SvnBranchItem>> callback) { - ApplicationManager.getApplication().executeOnPooledThread(new BranchesLoadRunnable(myProject, this, branchParentUrl, - InfoReliability.setByUser, root, callback, true)); + public void reloadBranchesAsync(@NotNull final VirtualFile root, + @NotNull final String branchLocation, + @NotNull final InfoReliability reliability) { + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + reloadBranches(root, branchLocation, reliability, true); + } + }); + } + + public void reloadBranches(@NotNull VirtualFile root, @Nullable SvnBranchConfigurationNew prev, @NotNull SvnBranchConfigurationNew next) { + final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<String>(prev.getBranchUrls()); + final SvnVcs vcs = SvnVcs.getInstance(myProject); + if (!vcs.isVcsBackgroundOperationsAllowed(root)) return; + + for (String newBranchUrl : next.getBranchUrls()) { + // check if cancel had been put + if (!vcs.isVcsBackgroundOperationsAllowed(root)) return; + if (!oldUrls.contains(newBranchUrl)) { + reloadBranches(root, newBranchUrl, InfoReliability.defaultValues, true); + } + } + } + + public void reloadBranches(@NotNull VirtualFile root, + @NotNull String branchLocation, + @NotNull InfoReliability reliability, + boolean passive) { + new BranchesLoader(myProject, this, branchLocation, reliability, root, passive).run(); } @Nullable @@ -108,28 +141,11 @@ public class NewRootBunch implements SvnBranchConfigManager { try { final SvnBranchConfigurationNew configuration = myMap.get(root).getValue(); final String group = configuration.getGroupToLoadToReachUrl(svnurl); - final Runnable runnable = new Runnable() { - public void run() { - final SvnBranchConfigurationNew reloadedConfiguration = myMap.get(root).getValue(); - try { - result.set(reloadedConfiguration.getWorkingBranch(svnurl)); - } - catch (SVNException e) { - // - } - } - }; - if (group == null) { - runnable.run(); - } else { - new BranchesLoadRunnable(myProject, this, group, InfoReliability.setByUser, root, - new Consumer<List<SvnBranchItem>>() { - public void consume(List<SvnBranchItem> svnBranchItems) { - runnable.run(); - } - }, true).run(); + if (group != null) { + reloadBranches(root, group, InfoReliability.setByUser, true); } + result.set(myMap.get(root).getValue().getWorkingBranch(svnurl)); } catch (SVNException e) { // @@ -137,88 +153,6 @@ public class NewRootBunch implements SvnBranchConfigManager { return result.get(); } - public static class BranchesLoadRunnable implements Runnable { - private final Project myProject; - private final SvnBranchConfigManager myBunch; - private final VirtualFile myRoot; - @Nullable - private final Consumer<List<SvnBranchItem>> myCallback; - private final String myUrl; - private final InfoReliability myInfoReliability; - private boolean myPassive; - - public BranchesLoadRunnable(final Project project, - final SvnBranchConfigManager bunch, - final String url, - final InfoReliability infoReliability, - final VirtualFile root, - @Nullable final Consumer<List<SvnBranchItem>> callback, - boolean passive) { - myProject = project; - myBunch = bunch; - myUrl = url; - myInfoReliability = infoReliability; - myRoot = root; - myCallback = callback; - myPassive = passive; - } - - public void run() { - boolean callbackCalled = false; - try { - final List<SvnBranchItem> items = BranchesLoader.loadBranches(myProject, myUrl, myPassive); - myBunch.updateBranches(myRoot, myUrl, new InfoStorage<List<SvnBranchItem>>(items, myInfoReliability)); - if (myCallback != null) { - myCallback.consume(items); - callbackCalled = true; - } - } - catch (VcsException e) { - showError(e); - } - catch (SVNException e) { - showError(e); - } - finally { - // callback must be called by contract - if (myCallback != null && (! callbackCalled)) { - myCallback.consume(null); - } - } - } - - private void showError(Exception e) { - // already logged inside - if (InfoReliability.setByUser.equals(myInfoReliability)) { - VcsBalloonProblemNotifier.showOverChangesView(myProject, "Branches load error: " + e.getMessage(), MessageType.ERROR); - } - } - } - - private static class DefaultBranchConfigInitializer implements Runnable { - private final Project myProject; - private final SvnBranchConfigManager myBunch; - private final VirtualFile myRoot; - - private DefaultBranchConfigInitializer(final Project project, final SvnBranchConfigManager bunch, final VirtualFile root) { - myProject = project; - myRoot = root; - myBunch = bunch; - } - - public void run() { - final SvnBranchConfigurationNew result = DefaultConfigLoader.loadDefaultConfiguration(myProject, myRoot); - if (result != null) { - final Application application = ApplicationManager.getApplication(); - for (String url : result.getBranchUrls()) { - application.executeOnPooledThread(new BranchesLoadRunnable(myProject, myBunch, url, InfoReliability.defaultValues, myRoot, null, - true)); - } - myBunch.updateForRoot(myRoot, new InfoStorage<SvnBranchConfigurationNew>(result, InfoReliability.defaultValues), null); - } - } - } - public Map<VirtualFile, SvnBranchConfigurationNew> getMapCopy() { synchronized (myLock) { final Map<VirtualFile, SvnBranchConfigurationNew> result = new HashMap<VirtualFile, SvnBranchConfigurationNew>(); @@ -228,4 +162,4 @@ public class NewRootBunch implements SvnBranchConfigManager { return result; } } -} +}
\ No newline at end of file diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SelectBranchPopup.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java index 5e634f3b9b87..445ce4e9afe3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SelectBranchPopup.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SelectBranchPopup.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn.actions; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -30,13 +30,10 @@ import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.*; -import org.jetbrains.idea.svn.branchConfig.InfoReliability; -import org.jetbrains.idea.svn.branchConfig.NewRootBunch; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigManager; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; -import org.jetbrains.idea.svn.dialogs.BranchConfigurationDialog; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; +import org.jetbrains.idea.svn.RootUrlInfo; +import org.jetbrains.idea.svn.SvnBundle; +import org.jetbrains.idea.svn.SvnFileUrlMapping; +import org.jetbrains.idea.svn.SvnVcs; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; @@ -221,8 +218,9 @@ public class SelectBranchPopup { @Override protected void runImpl(@NotNull ProgressIndicator indicator) { - final SvnBranchConfigManager manager = SvnBranchConfigurationManager.getInstance(myProject).getSvnBranchConfigManager(); - new NewRootBunch.BranchesLoadRunnable(myProject, manager, selectedBranchesHolder, InfoReliability.setByUser, myVcsRoot, null, false).run(); + final NewRootBunch manager = SvnBranchConfigurationManager.getInstance(myProject).getSvnBranchConfigManager(); + + manager.reloadBranches(myVcsRoot, selectedBranchesHolder, InfoReliability.setByUser, false); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java deleted file mode 100644 index 0a47a7771171..000000000000 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigManager.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.branchConfig; - -import com.intellij.openapi.vcs.CalledInBackground; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; -import com.intellij.util.PairConsumer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; -import org.tmatesoft.svn.core.SVNURL; - -import java.util.List; -import java.util.Map; - -public interface SvnBranchConfigManager { - void updateForRoot(@NotNull VirtualFile root, @NotNull InfoStorage<SvnBranchConfigurationNew> config, - @Nullable final PairConsumer<SvnBranchConfigurationNew, SvnBranchConfigurationNew> callbackOnUpdate); - - void updateBranches(@NotNull VirtualFile root, @NotNull String branchesParent, - @NotNull InfoStorage<List<SvnBranchItem>> items); - - @NotNull - SvnBranchConfigurationNew getConfig(@NotNull VirtualFile root); - - void reloadBranches(@NotNull VirtualFile root, @NotNull String branchParentUrl, - Consumer<List<SvnBranchItem>> callback); - @Nullable - @CalledInBackground - SVNURL getWorkingBranchWithReload(final SVNURL svnurl, final VirtualFile root); - - Map<VirtualFile, SvnBranchConfigurationNew> getMapCopy(); -} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfiguration.java index c167fd868531..0c6138fd08c2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchConfiguration.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfiguration.java @@ -14,24 +14,36 @@ * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.branchConfig; + +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** + * Default constructor and setters are necessary for serialization purposes. + * * @author yole */ +@SuppressWarnings("UnusedDeclaration") public class SvnBranchConfiguration { private String myTrunkUrl; - private List<String> myBranchUrls; + @NotNull private List<String> myBranchUrls; private boolean myUserinfoInUrl; public SvnBranchConfiguration() { myBranchUrls = new ArrayList<String>(); } + public SvnBranchConfiguration(String trunkUrl, @NotNull List<String> branchUrls, boolean userinfoInUrl) { + myTrunkUrl = trunkUrl; + myBranchUrls = branchUrls; + Collections.sort(myBranchUrls); + myUserinfoInUrl = userinfoInUrl; + } + public boolean isUserinfoInUrl() { return myUserinfoInUrl; } @@ -39,8 +51,8 @@ public class SvnBranchConfiguration { public void setUserinfoInUrl(final boolean userinfoInUrl) { myUserinfoInUrl = userinfoInUrl; } - - public void setBranchUrls(final List<String> branchUrls) { + + public void setBranchUrls(@NotNull List<String> branchUrls) { myBranchUrls = branchUrls; Collections.sort(myBranchUrls); } @@ -53,6 +65,7 @@ public class SvnBranchConfiguration { return myTrunkUrl; } + @NotNull public List<String> getBranchUrls() { return myBranchUrls; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchConfigurationManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationManager.java index f13ed5a97a03..772e5edd2755 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchConfigurationManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; @@ -27,7 +27,6 @@ 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.util.Ref; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.committed.VcsConfigurationChangeListener; @@ -35,14 +34,10 @@ 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.PairConsumer; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBus; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.branchConfig.*; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; -import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNURL; +import org.jetbrains.idea.svn.SvnVcs; import java.io.File; import java.util.*; @@ -58,15 +53,16 @@ import java.util.*; )} ) public class SvnBranchConfigurationManager implements PersistentStateComponent<SvnBranchConfigurationManager.ConfigurationBean> { - private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnBranchConfigurationManager"); + private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager"); private final Project myProject; private final ProjectLevelVcsManager myVcsManager; - private final SvnLoadedBrachesStorage myStorage; + private final SvnLoadedBranchesStorage myStorage; private final ProgressManagerQueue myBranchesLoader; + private boolean myIsInitialized; public SvnBranchConfigurationManager(final Project project, final ProjectLevelVcsManager vcsManager, - final SvnLoadedBrachesStorage storage) { + final SvnLoadedBranchesStorage storage) { myProject = project; myVcsManager = vcsManager; myStorage = storage; @@ -91,7 +87,13 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S } public static SvnBranchConfigurationManager getInstance(final Project project) { - return PeriodicalTasksCloser.getInstance().safeGetService(project, SvnBranchConfigurationManager.class); + SvnBranchConfigurationManager result = PeriodicalTasksCloser.getInstance().safeGetService(project, SvnBranchConfigurationManager.class); + + if (result != null) { + result.initialize(); + } + + return result; } public static class ConfigurationBean { @@ -108,19 +110,18 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S } private ConfigurationBean myConfigurationBean = new ConfigurationBean(); - private final SvnBranchConfigManager myBunch; + private final NewRootBunch myBunch; public SvnBranchConfigurationNew get(@NotNull final VirtualFile vcsRoot) throws VcsException { return myBunch.getConfig(vcsRoot); } - public SvnBranchConfigManager getSvnBranchConfigManager() { + public NewRootBunch getSvnBranchConfigManager() { return myBunch; } public void setConfiguration(final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) { - myBunch.updateForRoot(vcsRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.setByUser), - new BranchesPreloader(myProject, myBunch, vcsRoot, myBranchesLoader)); + myBunch.updateForRoot(vcsRoot, new InfoStorage<SvnBranchConfigurationNew>(configuration, InfoReliability.setByUser), true); SvnBranchMapperManager.getInstance().notifyBranchesChanged(myProject, vcsRoot, configuration); @@ -136,71 +137,33 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S for (VirtualFile root : myBunch.getMapCopy().keySet()) { final String key = root.getPath(); final SvnBranchConfigurationNew configOrig = myBunch.getConfig(root); - final SvnBranchConfiguration configuration = new SvnBranchConfiguration(); - configuration.setTrunkUrl(configOrig.getTrunkUrl()); - configuration.setUserinfoInUrl(configOrig.isUserinfoInUrl()); - configuration.setBranchUrls(configOrig.getBranchUrls()); - final HashMap<String, List<SvnBranchItem>> map = new HashMap<String, List<SvnBranchItem>>(); - final Map<String, InfoStorage<List<SvnBranchItem>>> origMap = configOrig.getBranchMap(); - for (String origKey : origMap.keySet()) { - map.put(origKey, origMap.get(origKey).getValue()); - } + final SvnBranchConfiguration configuration = + new SvnBranchConfiguration(configOrig.getTrunkUrl(), configOrig.getBranchUrls(), configOrig.isUserinfoInUrl()); + result.myConfigurationMap.put(key, helper.prepareForSerialization(configuration)); } result.mySupportsUserInfoFilter = true; return result; } - private static class BranchesPreloader implements PairConsumer<SvnBranchConfigurationNew, SvnBranchConfigurationNew> { - private final Project myProject; - private final VirtualFile myRoot; - private final ProgressManagerQueue myQueue; - private final SvnBranchConfigManager myBunch; - private boolean myAll; + public void loadState(ConfigurationBean object) { + myConfigurationBean = object; + } - public BranchesPreloader(Project project, @NotNull final SvnBranchConfigManager bunch, VirtualFile root, - final ProgressManagerQueue queue) { - myBunch = bunch; - myProject = project; - myRoot = root; - myQueue = queue; - } + private synchronized void initialize() { + if (!myIsInitialized) { + myIsInitialized = true; - public void consume(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) { - myQueue.run(new Runnable() { - public void run() { - loadImpl(prev, next); - } - }); - } - - protected void loadImpl(final SvnBranchConfigurationNew prev, final SvnBranchConfigurationNew next) { - final Set<String> oldUrls = (prev == null) ? Collections.<String>emptySet() : new HashSet<String>(prev.getBranchUrls()); - final SvnVcs vcs = SvnVcs.getInstance(myProject); - if (! vcs.isVcsBackgroundOperationsAllowed(myRoot)) return; - - for (String newBranchUrl : next.getBranchUrls()) { - // check if cancel had been put - if (! vcs.isVcsBackgroundOperationsAllowed(myRoot)) return; - if (myAll || (! oldUrls.contains(newBranchUrl))) { - new NewRootBunch.BranchesLoadRunnable(myProject, myBunch, newBranchUrl, InfoReliability.defaultValues, myRoot, null, true).run(); - } - } - } - - public void setAll(boolean all) { - myAll = all; + preloadBranches(resolveAllBranchPoints()); } } - public void loadState(final ConfigurationBean object) { - final UrlSerializationHelper helper = new UrlSerializationHelper(SvnVcs.getInstance(myProject)); - final Map<String, SvnBranchConfiguration> map = object.myConfigurationMap; - final Map<String, SvnBranchConfiguration> newMap = new HashMap<String, SvnBranchConfiguration>(map.size(), 1); + @NotNull + private Set<Pair<VirtualFile, SvnBranchConfigurationNew>> resolveAllBranchPoints() { final LocalFileSystem lfs = LocalFileSystem.getInstance(); - - final Set<Pair<VirtualFile, SvnBranchConfigurationNew>> whatToInit = new HashSet<Pair<VirtualFile, SvnBranchConfigurationNew>>(); - for (Map.Entry<String, SvnBranchConfiguration> entry : map.entrySet()) { + 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) { @@ -222,22 +185,24 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S if (stored != null && ! stored.isEmpty()) { newConfig.addBranches(branchUrl, new InfoStorage<List<SvnBranchItem>>(stored, InfoReliability.setByUser)); } else { - whatToInit.add(Pair.create(root, newConfig)); + 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), null); + 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 : whatToInit) { - final BranchesPreloader branchesPreloader = new BranchesPreloader(myProject, myBunch, pair.getFirst(), myBranchesLoader); - branchesPreloader.setAll(true); - branchesPreloader.loadImpl(null, pair.getSecond()); + for (Pair<VirtualFile, SvnBranchConfigurationNew> pair : branchPoints) { + myBunch.reloadBranches(pair.getFirst(), null, pair.getSecond()); } } catch (ProcessCanceledException e) { @@ -247,9 +212,6 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S }); } }); - object.myConfigurationMap.clear(); - object.myConfigurationMap.putAll(newMap); - myConfigurationBean = object; } private List<SvnBranchItem> getStored(String branchUrl) { @@ -259,93 +221,4 @@ public class SvnBranchConfigurationManager implements PersistentStateComponent<S Collections.sort(items); return items; } - - private static class UrlSerializationHelper { - private final SvnVcs myVcs; - - private UrlSerializationHelper(final SvnVcs vcs) { - myVcs = vcs; - } - - public SvnBranchConfiguration prepareForSerialization(final SvnBranchConfiguration configuration) { - final Ref<Boolean> withUserInfo = new Ref<Boolean>(); - final String trunkUrl = serializeUrl(configuration.getTrunkUrl(), withUserInfo); - - if (Boolean.FALSE.equals(withUserInfo.get())) { - return configuration; - } - - final List<String> branches = configuration.getBranchUrls(); - final List<String> newBranchesList = new ArrayList<String>(branches.size()); - for (String s : branches) { - newBranchesList.add(serializeUrl(s, withUserInfo)); - } - - final SvnBranchConfiguration result = new SvnBranchConfiguration(); - result.setTrunkUrl(trunkUrl); - result.setBranchUrls(newBranchesList); - result.setUserinfoInUrl(withUserInfo.isNull() ? false : withUserInfo.get()); - return result; - } - - public SvnBranchConfiguration afterDeserialization(final String path, final SvnBranchConfiguration configuration) { - if (! configuration.isUserinfoInUrl()) { - return configuration; - } - final String userInfo = getUserInfo(path); - if (userInfo == null) { - return configuration; - } - - final String newTrunkUrl = deserializeUrl(configuration.getTrunkUrl(), userInfo); - final List<String> branches = configuration.getBranchUrls(); - final List<String> newBranchesList = new ArrayList<String>(branches.size()); - for (String s : branches) { - newBranchesList.add(deserializeUrl(s, userInfo)); - } - - final SvnBranchConfiguration result = new SvnBranchConfiguration(); - result.setTrunkUrl(newTrunkUrl); - result.setBranchUrls(newBranchesList); - result.setUserinfoInUrl(userInfo != null && userInfo.length() > 0); - return result; - } - - private static String serializeUrl(final String url, final Ref<Boolean> withUserInfo) { - if (Boolean.FALSE.equals(withUserInfo.get())) { - return url; - } - try { - final SVNURL svnurl = SVNURL.parseURIEncoded(url); - if (withUserInfo.isNull()) { - final String userInfo = svnurl.getUserInfo(); - withUserInfo.set((userInfo != null) && (userInfo.length() > 0)); - } - if (withUserInfo.get()) { - return SVNURL.create(svnurl.getProtocol(), null, svnurl.getHost(), SvnUtil.resolvePort(svnurl), svnurl.getURIEncodedPath(), true) - .toString(); - } - } - catch (SVNException e) { - // - } - return url; - } - - @Nullable - private String getUserInfo(final String path) { - final SVNURL svnurl = myVcs.getSvnFileUrlMapping().getUrlForFile(new File(path)); - return svnurl != null ? svnurl.getUserInfo() : null; - } - - private static String deserializeUrl(final String url, final String userInfo) { - try { - final SVNURL svnurl = SVNURL.parseURIEncoded(url); - return SVNURL.create(svnurl.getProtocol(), userInfo, svnurl.getHost(), SvnUtil.resolvePort(svnurl), svnurl.getURIEncodedPath(), - true).toString(); - } catch (SVNException e) { - return url; - } - } - } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java index 4102210a657a..3ce3c986c8ae 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchConfigurationNew.java @@ -24,7 +24,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.info.Info; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; @@ -98,7 +97,7 @@ public class SvnBranchConfigurationNew { LOG.info("Branches list not updated for : '" + branchParentName + "; since config has changed."); return; } - current.accept(items, null); + current.accept(items); } public Map<String, InfoStorage<List<SvnBranchItem>>> getBranchMap() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnBranchItem.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchItem.java index f9e428d1becf..a0bd0868b6d2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnBranchItem.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchItem.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn.integrate; +package org.jetbrains.idea.svn.branchConfig; import java.util.Date; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchMapperManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchMapperManager.java index e82e363f598a..f9f99bea1e17 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnBranchMapperManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnBranchMapperManager.java @@ -13,17 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.branchConfig; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.messages.Topic; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import java.io.File; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; /** * Holds what working copies we have for URLs @@ -56,7 +56,6 @@ public class SvnBranchMapperManager implements PersistentStateComponent<SvnBranc public void put(final String url, final String value) { myStateHolder.put(url, value); - notifyWcRootsChanged(url, Collections.unmodifiableCollection(myStateHolder.get(url))); } public void remove(final String url, final File value) { @@ -64,11 +63,6 @@ public class SvnBranchMapperManager implements PersistentStateComponent<SvnBranc if (set != null) { set.remove(value.getAbsolutePath()); } - notifyWcRootsChanged(url, Collections.unmodifiableCollection(set)); - } - - private static void notifyWcRootsChanged(final String url, final Collection<String> roots) { - ApplicationManager.getApplication().getMessageBus().syncPublisher(WC_ROOTS_CHANGED).rootsChanged(url, roots); } public void notifyBranchesChanged(final Project project, final VirtualFile vcsRoot, final SvnBranchConfigurationNew configuration) { @@ -104,11 +98,4 @@ public class SvnBranchMapperManager implements PersistentStateComponent<SvnBranc return myMapping.get(key); } } - - public static interface WcRootsChangeConsumer { - void rootsChanged(final String url, final Collection<String> roots); - } - - public static final Topic<WcRootsChangeConsumer> WC_ROOTS_CHANGED = - new Topic<WcRootsChangeConsumer>("SVN_WC_ROOTS_CHANGED", WcRootsChangeConsumer.class); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnLoadedBranchesStorage.java index 8fe1fa52a938..041e33cc5ac7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnLoadedBrachesStorage.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/SvnLoadedBranchesStorage.java @@ -13,19 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.jetbrains.idea.svn; +package org.jetbrains.idea.svn.branchConfig; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.persistent.SmallMapSerializer; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; 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.branchConfig.InfoStorage; -import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; import java.io.DataInput; import java.io.DataOutput; @@ -39,13 +37,13 @@ import java.util.*; * Date: 8/24/11 * Time: 1:21 PM */ -public class SvnLoadedBrachesStorage { +public class SvnLoadedBranchesStorage { private final Object myLock; private SmallMapSerializer<String, Map<String, Collection<SvnBranchItem>>> myState; private final File myFile; private final Project myProject; - public SvnLoadedBrachesStorage(final Project project) { + public SvnLoadedBranchesStorage(final Project project) { myProject = project; final File vcsFile = new File(PathManager.getSystemPath(), "vcs"); File file = new File(vcsFile, "svn_branches"); @@ -63,18 +61,6 @@ public class SvnLoadedBrachesStorage { } } - public void put(final String url, final Collection<SvnBranchItem> items) { - synchronized (myLock) { - if (myState == null) return; - Map<String, Collection<SvnBranchItem>> map = myState.get(""); - if (map == null) { - map = new HashMap<String, Collection<SvnBranchItem>>(); - myState.put("", map); - } - map.put(url, items); - } - } - public void activate() { synchronized (myLock) { myState = new SmallMapSerializer<String, Map<String, Collection<SvnBranchItem>>>(myFile, new EnumeratorStringDescriptor(), createExternalizer()); @@ -83,15 +69,19 @@ public class SvnLoadedBrachesStorage { public void deactivate() { + Map<String, Collection<SvnBranchItem>> branchLocationToBranchItemsMap = ContainerUtil.newHashMap(); SvnBranchConfigurationManager manager = SvnBranchConfigurationManager.getInstance(myProject); Map<VirtualFile,SvnBranchConfigurationNew> mapCopy = manager.getSvnBranchConfigManager().getMapCopy(); for (Map.Entry<VirtualFile, SvnBranchConfigurationNew> entry : mapCopy.entrySet()) { Map<String,InfoStorage<List<SvnBranchItem>>> branchMap = entry.getValue().getBranchMap(); for (Map.Entry<String, InfoStorage<List<SvnBranchItem>>> storageEntry : branchMap.entrySet()) { - put(storageEntry.getKey(), storageEntry.getValue().getValue()); + branchLocationToBranchItemsMap.put(storageEntry.getKey(), storageEntry.getValue().getValue()); } } synchronized (myLock) { + // TODO: Possibly implement optimization - do not perform save if there are no changes in branch locations and branch items + // ensure myState.put() is called - so myState will treat itself as dirty and myState.force() will invoke real persisting + myState.put("", branchLocationToBranchItemsMap); myState.force(); myState = null; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/UrlSerializationHelper.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/UrlSerializationHelper.java new file mode 100644 index 000000000000..36c16f33a0fc --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/branchConfig/UrlSerializationHelper.java @@ -0,0 +1,111 @@ +/* + * 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.openapi.util.Ref; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** +* @author Konstantin Kolosovsky. +*/ +public class UrlSerializationHelper { + private final SvnVcs myVcs; + + public UrlSerializationHelper(final SvnVcs vcs) { + myVcs = vcs; + } + + public SvnBranchConfiguration prepareForSerialization(final SvnBranchConfiguration configuration) { + final Ref<Boolean> withUserInfo = new Ref<Boolean>(); + final String trunkUrl = serializeUrl(configuration.getTrunkUrl(), withUserInfo); + + if (Boolean.FALSE.equals(withUserInfo.get())) { + return configuration; + } + + final List<String> branches = configuration.getBranchUrls(); + final List<String> newBranchesList = new ArrayList<String>(branches.size()); + for (String s : branches) { + newBranchesList.add(serializeUrl(s, withUserInfo)); + } + + return new SvnBranchConfiguration(trunkUrl, newBranchesList, withUserInfo.isNull() ? false : withUserInfo.get()); + } + + public SvnBranchConfiguration afterDeserialization(final String path, final SvnBranchConfiguration configuration) { + if (! configuration.isUserinfoInUrl()) { + return configuration; + } + final String userInfo = getUserInfo(path); + if (userInfo == null) { + return configuration; + } + + final String newTrunkUrl = deserializeUrl(configuration.getTrunkUrl(), userInfo); + final List<String> branches = configuration.getBranchUrls(); + final List<String> newBranchesList = new ArrayList<String>(branches.size()); + for (String s : branches) { + newBranchesList.add(deserializeUrl(s, userInfo)); + } + + return new SvnBranchConfiguration(newTrunkUrl, newBranchesList, userInfo.length() > 0); + } + + private static String serializeUrl(final String url, final Ref<Boolean> withUserInfo) { + if (Boolean.FALSE.equals(withUserInfo.get())) { + return url; + } + try { + final SVNURL svnurl = SVNURL.parseURIEncoded(url); + if (withUserInfo.isNull()) { + final String userInfo = svnurl.getUserInfo(); + withUserInfo.set((userInfo != null) && (userInfo.length() > 0)); + } + if (withUserInfo.get()) { + return SVNURL.create(svnurl.getProtocol(), null, svnurl.getHost(), SvnUtil.resolvePort(svnurl), svnurl.getURIEncodedPath(), true) + .toString(); + } + } + catch (SVNException e) { + // + } + return url; + } + + @Nullable + private String getUserInfo(final String path) { + final SVNURL svnurl = myVcs.getSvnFileUrlMapping().getUrlForFile(new File(path)); + return svnurl != null ? svnurl.getUserInfo() : null; + } + + private static String deserializeUrl(final String url, final String userInfo) { + try { + final SVNURL svnurl = SVNURL.parseURIEncoded(url); + return SVNURL.create(svnurl.getProtocol(), userInfo, svnurl.getHost(), SvnUtil.resolvePort(svnurl), svnurl.getURIEncodedPath(), + true).toString(); + } catch (SVNException e) { + return url; + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java index c9a843501253..3f43d7452b5e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkin/SvnCheckinEnvironment.java @@ -124,7 +124,7 @@ public class SvnCheckinEnvironment implements CheckinEnvironment { String comment, List<VcsException> exception, final Set<String> feedback, - final WorkingCopyFormat format) + @NotNull WorkingCopyFormat format) throws VcsException { if (committables.isEmpty()) { return; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java index 602a6e8c460e..cfb4a935bc14 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/UpdateOutputLineConverter.java @@ -16,6 +16,9 @@ package org.jetbrains.idea.svn.commandLine; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Stack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.api.EventAction; @@ -43,17 +46,13 @@ public class UpdateOutputLineConverter { private final static String RECORDING_MERGE_INFO = "--- Recording mergeinfo"; private final static String UPDATING = "Updating"; - private final static String AT_REVISION = "At revision (\\d+)\\."; - private final static String UPDATED_TO_REVISION = "Updated to revision (\\d+)\\."; private final static String SKIPPED = "Skipped"; private final static String RESTORED = "Restored"; private final static String FETCHING_EXTERNAL = "Fetching external"; - private final static String EXTERNAL = "External at (\\d+)\\."; - private final static String UPDATED_EXTERNAL = "Updated external to revision (\\d+)\\."; - - private final static Pattern ourAtRevision = Pattern.compile(AT_REVISION); - private final static Pattern ourUpdatedToRevision = Pattern.compile(UPDATED_TO_REVISION); + + private final static Pattern ourAtRevision = Pattern.compile("At revision (\\d+)\\."); + private final static Pattern ourUpdatedToRevision = Pattern.compile("Updated to revision (\\d+)\\."); private final static Pattern ourCheckedOutRevision = Pattern.compile("Checked out revision (\\d+)\\."); // export from repository @@ -61,8 +60,8 @@ public class UpdateOutputLineConverter { // export from working copy private final static Pattern ourExportComplete = Pattern.compile("Export complete\\."); - private final static Pattern ourExternal = Pattern.compile(EXTERNAL); - private final static Pattern ourUpdatedExternal = Pattern.compile(UPDATED_EXTERNAL); + private final static Pattern ourExternal = Pattern.compile("External at (\\d+)\\."); + private final static Pattern ourUpdatedExternal = Pattern.compile("Updated external to revision (\\d+)\\."); private final static Pattern ourCheckedOutExternal = Pattern.compile("Checked out external at revision (\\d+)\\."); private final static Pattern[] ourCompletePatterns = @@ -70,15 +69,14 @@ public class UpdateOutputLineConverter { ourCheckedOutExternal, ourExportComplete}; private final File myBase; - private File myCurrentFile; + @NotNull private final Stack<File> myRootsUnderProcessing; public UpdateOutputLineConverter(File base) { myBase = base; - // checkout output does not have special line like "Updating '.'" on start - so set current file directly - // to correctly detect complete event - myCurrentFile = base; + myRootsUnderProcessing = ContainerUtil.newStack(); } + @Nullable public ProgressEvent convert(final String line) { // TODO: Add direct processing of "Summary of conflicts" lines at the end of "svn update" output (if there are conflicts). // TODO: Now it works ok because parseNormalLine could not determine necessary statuses from that and further lines @@ -87,35 +85,45 @@ public class UpdateOutputLineConverter { if (line.startsWith(MERGING) || line.startsWith(RECORDING_MERGE_INFO)) { return null; } else if (line.startsWith(UPDATING)) { - myCurrentFile = parseForPath(line); - return new ProgressEvent(myCurrentFile, -1, null, null, EventAction.UPDATE_NONE, null, null); + myRootsUnderProcessing.push(parseForPath(line)); + return createEvent(myRootsUnderProcessing.peek(), EventAction.UPDATE_NONE); } else if (line.startsWith(RESTORED)) { - myCurrentFile = parseForPath(line); - return new ProgressEvent(myCurrentFile, -1, null, null, EventAction.RESTORE, null, null); + return createEvent(parseForPath(line), EventAction.RESTORE); } else if (line.startsWith(SKIPPED)) { // called, for instance, when folder is not working copy - myCurrentFile = parseForPath(line); final String comment = parseComment(line); - return new ProgressEvent(myCurrentFile, -1, null, null, EventAction.SKIP, - comment == null ? null : SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, comment), null); + return createEvent(parseForPath(line), -1, EventAction.SKIP, + comment == null ? null : SVNErrorMessage.create(SVNErrorCode.WC_OBSTRUCTED_UPDATE, comment)); } else if (line.startsWith(FETCHING_EXTERNAL)) { - myCurrentFile = parseForPath(line); - return new ProgressEvent(myCurrentFile, -1, null, null, EventAction.UPDATE_EXTERNAL, null, null); + myRootsUnderProcessing.push(parseForPath(line)); + return createEvent(myRootsUnderProcessing.peek(), EventAction.UPDATE_EXTERNAL); } - for (int i = 0; i < ourCompletePatterns.length; i++) { - final Pattern pattern = ourCompletePatterns[i]; + for (final Pattern pattern : ourCompletePatterns) { final long revision = matchAndGetRevision(pattern, line); if (revision != -1) { - // TODO: seems that myCurrentFile will not always be correct - complete update message could be right after complete externals update - // TODO: check this and use Stack instead - return new ProgressEvent(myCurrentFile, revision, null, null, EventAction.UPDATE_COMPLETED, null, null); + // checkout output does not have special line like "Updating '.'" on start - so stack could be empty and we should use myBase + File currentRoot = myRootsUnderProcessing.size() > 0 ? myRootsUnderProcessing.pop() : myBase; + return createEvent(currentRoot, revision, EventAction.UPDATE_COMPLETED, null); } } return parseNormalString(line); } + @NotNull + private static ProgressEvent createEvent(File file, @NotNull EventAction action) { + return createEvent(file, -1, action, null); + } + + @NotNull + private static ProgressEvent createEvent(File file, + long revision, + @NotNull EventAction action, + @Nullable SVNErrorMessage error) { + return new ProgressEvent(file, revision, null, null, action, error, null); + } + private final static Set<Character> ourActions = new HashSet<Character>(Arrays.asList(new Character[] {'A', 'D', 'U', 'C', 'G', 'E', 'R'})); @Nullable @@ -134,7 +142,7 @@ public class UpdateOutputLineConverter { final String path = line.substring(4).trim(); if (StringUtil.isEmptyOrSpaces(path)) return null; - final File file = createFile(path); + final File file = SvnUtil.resolvePath(myBase, path); if (StatusType.STATUS_OBSTRUCTED.equals(contentsStatus)) { // obstructed return new ProgressEvent(file, -1, contentsStatus, propertiesStatus, EventAction.UPDATE_SKIP_OBSTRUCTION, null, null); @@ -157,12 +165,7 @@ public class UpdateOutputLineConverter { return new ProgressEvent(file, -1, contentsStatus, propertiesStatus, action, null, null); } - private File createFile(String path) { - return SvnUtil.resolvePath(myBase, path); - } - - @Nullable - private long matchAndGetRevision(final Pattern pattern, final String line) { + private static long matchAndGetRevision(final Pattern pattern, final String line) { final Matcher matcher = pattern.matcher(line); if (matcher.matches()) { if (pattern == ourExportComplete) { @@ -181,22 +184,26 @@ public class UpdateOutputLineConverter { } @Nullable - private String parseComment(final String line) { - final int idx = line.lastIndexOf("--"); - if (idx != -1 && idx < (line.length() - 2)) { - return line.substring(idx + 2).trim(); - } - return null; + private static String parseComment(final String line) { + int index = line.lastIndexOf("--"); + + return index != -1 && index < line.length() - 2 ? line.substring(index + 2).trim() : null; } @Nullable - private File parseForPath(final String line) { - final int idx1 = line.indexOf('\''); - if (idx1 == -1) return null; - final int idx2 = line.indexOf('\'', idx1 + 1); - if (idx2 == -1) return null; - final String substring = line.substring(idx1 + 1, idx2); - if (".".equals(substring)) return myBase; - return createFile(substring); + private File parseForPath(@NotNull String line) { + File result = null; + int start = line.indexOf('\''); + + if (start != -1) { + int end = line.indexOf('\'', start + 1); + + if (end != -1) { + String path = line.substring(start + 1, end); + result = SvnUtil.resolvePath(myBase, path); + } + } + + return result; } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java index 9ca5b89d517a..1b48f9d70e5b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java @@ -45,7 +45,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; import org.jetbrains.idea.svn.actions.CleanupWorker; -import org.jetbrains.idea.svn.actions.SelectBranchPopup; +import org.jetbrains.idea.svn.branchConfig.BranchConfigurationDialog; +import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup; import org.jetbrains.idea.svn.api.ClientFactory; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java index cd504be56077..437e7f57e464 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java @@ -41,7 +41,6 @@ import org.jetbrains.idea.svn.properties.PropertyConsumer; import org.jetbrains.idea.svn.properties.PropertyData; import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNProperty; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -309,7 +308,7 @@ public class PropertiesComponent extends JPanel { PropertyValue propValue = null; try { propValue = myVcs.getFactory(myFile).createPropertyClient() - .getProperty(SvnTarget.fromFile(myFile), SVNProperty.KEYWORDS, false, SVNRevision.WORKING); + .getProperty(SvnTarget.fromFile(myFile), SvnPropertyKeys.SVN_KEYWORDS, false, SVNRevision.WORKING); } catch (VcsException e1) { // show erorr message diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java index 163be4922224..f7e54a64f0ad 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java @@ -266,7 +266,7 @@ public class RepositoryBrowserComponent extends JPanel implements Disposable, Da if (entry.getName().lastIndexOf('.') > 0 && !manager.getFileTypeByFileName(name).isBinary()) { SVNURL url = node.getURL(); final SvnFileRevision revision = new SvnFileRevision(myVCS, SVNRevision.UNDEFINED, SVNRevision.HEAD, url.toString(), - entry.getAuthor(), entry.getDate(), null, null, null); + entry.getAuthor(), entry.getDate(), null, null); return new VcsVirtualFile(node.getSVNDirEntry().getName(), revision, VcsFileSystem.getInstance()); } else { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CompareWithBranchAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CompareWithBranchAction.java index a8e0ca9e5e7a..278c7d0b5e1c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CompareWithBranchAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CompareWithBranchAction.java @@ -26,7 +26,7 @@ import com.intellij.openapi.vcs.FileStatusManager; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.*; -import org.jetbrains.idea.svn.actions.SelectBranchPopup; +import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; /** diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LoadedRevisionsCache.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LoadedRevisionsCache.java index 5da830f0ca87..7e1c9d155a0e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LoadedRevisionsCache.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/LoadedRevisionsCache.java @@ -22,13 +22,13 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vcs.RepositoryLocation; -import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.committed.ChangesBunch; +import com.intellij.openapi.vcs.changes.committed.CommittedChangesAdapter; import com.intellij.openapi.vcs.changes.committed.CommittedChangesCache; -import com.intellij.openapi.vcs.changes.committed.CommittedChangesListener; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.util.containers.SoftHashMap; import com.intellij.util.messages.MessageBusConnection; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -51,7 +51,9 @@ public class LoadedRevisionsCache implements Disposable { myMap = (ApplicationManager.getApplication().isUnitTestMode()) ? new HashMap<String, Bunch>() : new SoftHashMap<String, Bunch>(); myConnection = project.getMessageBus().connect(); - myConnection.subscribe(CommittedChangesCache.COMMITTED_TOPIC, new CommittedChangesListener() { + myConnection.subscribe(CommittedChangesCache.COMMITTED_TOPIC, new CommittedChangesAdapter() { + + @Override public void changesLoaded(final RepositoryLocation location, final List<CommittedChangeList> changes) { ApplicationManager.getApplication().invokeLater(new Runnable() { public void run() { @@ -60,20 +62,6 @@ public class LoadedRevisionsCache implements Disposable { } }); } - - @Override - public void changesCleared() { - } - - @Override - public void presentationChanged() { - } - - public void incomingChangesUpdated(@Nullable final List<CommittedChangeList> receivedChanges) { - } - - public void refreshErrorStatusChanged(@Nullable final VcsException lastError) { - } }); Disposer.register(myProject, this); setRefreshTime(0); @@ -90,18 +78,20 @@ public class LoadedRevisionsCache implements Disposable { myRefreshTime = refreshTime; } } - - private void debugInfo(final List<CommittedChangeList> data, final boolean consistentWithPrevious, final Bunch bindTo) { + + private static void debugInfo(@NotNull List<CommittedChangeList> data, final boolean consistentWithPrevious, final Bunch bindTo) { LOG.debug(">>> cache internal >>> consistent: " + consistentWithPrevious + " bindTo: " + bindTo + " oldest list: " + data.get(data.size() - 1).getNumber() + ", youngest list: " + data.get(0).getNumber()); } public void dispose() { + // TODO: Seems that dispose could be removed as connection will be disposed anyway on project dispose and clearing map is not necessary myConnection.disconnect(); myMap.clear(); } - private List<List<CommittedChangeList>> split(final List<CommittedChangeList> list, final int size) { + @NotNull + private static List<List<CommittedChangeList>> split(final List<CommittedChangeList> list, final int size) { final int listSize = list.size(); if (listSize < size) { return Collections.singletonList(list); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 83642894711e..4712a080ad36 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -48,7 +48,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; -import org.jetbrains.idea.svn.actions.ConfigureBranchesAction; +import org.jetbrains.idea.svn.branchConfig.ConfigureBranchesAction; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.status.Status; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java index 007df92a403b..e636c9c0a8ef 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnFileRevision.java @@ -22,10 +22,10 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Throwable2Computable; import com.intellij.openapi.vcs.RepositoryLocation; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.openapi.vcs.history.VcsFileRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vcs.impl.ContentRevisionCache; +import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; @@ -37,7 +37,6 @@ import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.IOException; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -55,7 +54,6 @@ public class SvnFileRevision implements VcsFileRevision { private final SVNRevision myRevision; private final String myCopyFromPath; private final List<SvnFileRevision> myMergeSources; - private final Charset myCharset; public SvnFileRevision(SvnVcs vcs, SVNRevision pegRevision, @@ -64,8 +62,7 @@ public class SvnFileRevision implements VcsFileRevision { String author, Date date, String commitMessage, - String copyFromPath, Charset charset) { - myCharset = charset; + String copyFromPath) { myRevisionNumber = new SvnRevisionNumber(revision); myPegRevision = pegRevision; myRevision = revision; @@ -82,8 +79,7 @@ public class SvnFileRevision implements VcsFileRevision { SVNRevision pegRevision, LogEntry logEntry, String url, - String copyFromPath, Charset charset) { - myCharset = charset; + String copyFromPath) { final SVNRevision revision = SVNRevision.create(logEntry.getRevision()); myRevisionNumber = new SvnRevisionNumber(revision); myPegRevision = pegRevision; @@ -155,30 +151,37 @@ public class SvnFileRevision implements VcsFileRevision { else { loader.run(); } - if (loader.getException() == null) { + + VcsException exception = loader.getException(); + if (exception == null) { final byte[] contents = loader.getContents(); ContentRevisionCache.checkContentsSize(myURL, contents.length); return contents; } else { - final VcsException vcsException = loader.getException(); - LOG.info("Failed to load file '" + myURL + "' content at revision: " + myRevision + "\n" + vcsException.getMessage(), vcsException); - throw vcsException; + LOG.info("Failed to load file '" + myURL + "' content at revision: " + myRevision + "\n" + exception.getMessage(), exception); + throw exception; } } public byte[] getContent() throws IOException, VcsException { - return ContentRevisionCache.getOrLoadAsBytes(myVCS.getProject(), VcsContextFactory.SERVICE.getInstance() - .createFilePathOnNonLocal(myURL, false), - getRevisionNumber(), myVCS.getKeyInstanceMethod(), ContentRevisionCache.UniqueType.REMOTE_CONTENT, - new Throwable2Computable<byte[], VcsException, IOException>() { - @Override - public byte[] compute() throws VcsException, IOException { - byte[] bytes = loadContent(); - return bytes; - //return SvnUtil.decode(myCharset, bytes); - } - }); + byte[] result; + + if (SVNRevision.HEAD.equals(myRevision)) { + result = loadContent(); + } + else { + result = ContentRevisionCache.getOrLoadAsBytes(myVCS.getProject(), VcsUtil.getFilePathOnNonLocal(myURL, false), getRevisionNumber(), + myVCS.getKeyInstanceMethod(), ContentRevisionCache.UniqueType.REMOTE_CONTENT, + new Throwable2Computable<byte[], VcsException, IOException>() { + @Override + public byte[] compute() throws VcsException, IOException { + return loadContent(); + } + }); + } + + return result; } public String getCopyFromPath() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index b23b57772535..2ff19fcc56e6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -614,7 +614,7 @@ public class SvnHistoryProvider final SVNURL url = myRepositoryRoot.appendPath(myLastPath, true); // final SVNURL url = entryPath != null ? myRepositoryRoot.appendPath(entryPath.getPath(), true) : // myRepositoryRoot.appendPath(myLastPathCorrector.getBefore(), false); - return new SvnFileRevision(myVcs, myPegRevision, rev, url.toString(), author, date, message, copyPath, myCharset); + return new SvnFileRevision(myVcs, myPegRevision, rev, url.toString(), author, date, message, copyPath); } } @@ -633,7 +633,7 @@ public class SvnHistoryProvider throws SVNException { 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); + return new SvnFileRevision(myVcs, SVNRevision.UNDEFINED, logEntry, url.toString(), copyPath); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java index c6ed3c59a5c7..d4b48281f7ca 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnMergeInfoRootPanelManual.java @@ -24,10 +24,10 @@ import com.intellij.util.NullableFunction; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.svn.SvnBranchMapperManager; +import org.jetbrains.idea.svn.branchConfig.SvnBranchMapperManager; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnUtil; -import org.jetbrains.idea.svn.actions.SelectBranchPopup; +import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import org.jetbrains.idea.svn.dialogs.WCInfoWithBranches; import org.jetbrains.idea.svn.integrate.IntegratedSelectedOptionsDialog; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/WcInfoLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/WcInfoLoader.java index e0ab6ff02ae5..bbac377776b8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/WcInfoLoader.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/WcInfoLoader.java @@ -23,10 +23,11 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import org.jetbrains.idea.svn.dialogs.WCInfo; import org.jetbrains.idea.svn.dialogs.WCInfoWithBranches; -import org.jetbrains.idea.svn.integrate.SvnBranchItem; +import org.jetbrains.idea.svn.branchConfig.SvnBranchItem; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import java.io.File; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/info/Info.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/info/Info.java index 96dbdbbcbc99..71fb0a9ec51f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/info/Info.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/info/Info.java @@ -35,6 +35,8 @@ import java.util.Date; */ public class Info extends BaseNodeDescription { + public static final String SCHEDULE_ADD = "add"; + private final File myFile; private final String myPath; private final SVNURL myURL; @@ -49,10 +51,10 @@ public class Info extends BaseNodeDescription { private final String mySchedule; private final SVNURL myCopyFromURL; private final SVNRevision myCopyFromRevision; - private final File myConflictOldFile; - private final File myConflictNewFile; - private final File myConflictWrkFile; - private final File myPropConflictFile; + @Nullable private final File myConflictOldFile; + @Nullable private final File myConflictNewFile; + @Nullable private final File myConflictWrkFile; + @Nullable private final File myPropConflictFile; private final Depth myDepth; @Nullable private final TreeConflictDescription myTreeConflict; @@ -69,8 +71,8 @@ public class Info extends BaseNodeDescription { result = new Info(info.getFile(), info.getURL(), info.getRepositoryRootURL(), info.getRevision().getNumber(), NodeKind.from(info.getKind()), info.getRepositoryUUID(), info.getCommittedRevision().getNumber(), toString(info.getCommittedDate()), info.getAuthor(), - info.getSchedule(), info.getCopyFromURL(), info.getCopyFromRevision().getNumber(), getPath(info.getConflictOldFile()), - getPath(info.getConflictNewFile()), getPath(info.getConflictWrkFile()), getPath(info.getPropConflictFile()), + info.getSchedule(), info.getCopyFromURL(), info.getCopyFromRevision().getNumber(), getName(info.getConflictOldFile()), + getName(info.getConflictNewFile()), getName(info.getConflictWrkFile()), getName(info.getPropConflictFile()), Lock.create(info.getLock()), Depth.from(info.getDepth()), TreeConflictDescription.create(info.getTreeConflict())); } @@ -89,10 +91,10 @@ public class Info extends BaseNodeDescription { String schedule, SVNURL copyFromURL, long copyFromRevision, - String conflictOld, - String conflictNew, - String conflictWorking, - String propRejectFile, + @Nullable String conflictOldFileName, + @Nullable String conflictNewFileName, + @Nullable String conflictWorkingFileName, + @Nullable String propRejectFileName, @Nullable Lock lock, Depth depth, @Nullable TreeConflictDescription treeConflict) { @@ -115,10 +117,10 @@ public class Info extends BaseNodeDescription { myLock = lock; myTreeConflict = treeConflict; - myConflictOldFile = resolveConflictFile(file, conflictOld); - myConflictNewFile = resolveConflictFile(file, conflictNew); - myConflictWrkFile = resolveConflictFile(file, conflictWorking); - myPropConflictFile = resolveConflictFile(file, propRejectFile); + myConflictOldFile = resolveConflictFile(file, conflictOldFileName); + myConflictNewFile = resolveConflictFile(file, conflictNewFileName); + myConflictWrkFile = resolveConflictFile(file, conflictWorkingFileName); + myPropConflictFile = resolveConflictFile(file, propRejectFileName); myIsRemote = false; myDepth = depth; @@ -175,14 +177,17 @@ public class Info extends BaseNodeDescription { return myCommittedRevision; } + @Nullable public File getConflictNewFile() { return myConflictNewFile; } + @Nullable public File getConflictOldFile() { return myConflictOldFile; } + @Nullable public File getConflictWrkFile() { return myConflictWrkFile; } @@ -222,6 +227,7 @@ public class Info extends BaseNodeDescription { return myPath; } + @Nullable public File getPropConflictFile() { return myPropConflictFile; } @@ -256,8 +262,8 @@ public class Info extends BaseNodeDescription { } @Nullable - private static String getPath(@Nullable File file) { - return file != null ? file.getPath() : null; + private static String getName(@Nullable File file) { + return file != null ? file.getName() : null; } @Nullable diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java index 3b2184c22484..7ff6e71ab75a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/IntegratedSelectedOptionsDialog.java @@ -32,6 +32,7 @@ import com.intellij.util.PlatformIcons; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; +import org.jetbrains.idea.svn.branchConfig.SvnBranchMapperManager; import org.jetbrains.idea.svn.info.Info; import org.tmatesoft.svn.core.SVNURL; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SourceUrlCorrectionTask.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SourceUrlCorrectionTask.java index 39d51de62943..99d4696ede3f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SourceUrlCorrectionTask.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SourceUrlCorrectionTask.java @@ -18,7 +18,7 @@ package org.jetbrains.idea.svn.integrate; import com.intellij.util.continuation.ContinuationContext; import com.intellij.util.continuation.Where; import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.svn.SvnBranchConfigurationManager; +import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationManager; import org.jetbrains.idea.svn.dialogs.MergeContext; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesActionPerformer.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesActionPerformer.java index e07fac011c9e..2ccd2242db10 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesActionPerformer.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesActionPerformer.java @@ -23,7 +23,7 @@ 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.actions.SelectBranchPopup; +import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java index 5dd6f24b10ba..0dd27d442ae5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/SvnIntegrateChangesTask.java @@ -19,7 +19,9 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; @@ -28,6 +30,7 @@ import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vcs.changes.ui.CommitChangeListDialog; import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx; +import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.openapi.vcs.update.*; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; @@ -330,18 +333,37 @@ public class SvnIntegrateChangesTask extends Task.Backgroundable { }); } - final SvnChangeProvider provider = new SvnChangeProvider(myVcs); - final GatheringChangelistBuilder clb = new GatheringChangelistBuilder(myVcs, myAccomulatedFiles); - try { - provider.getChanges(dirtyScope, clb, ProgressManager.getInstance().getProgressIndicator(), null); - } catch (VcsException e) { - Messages.showErrorDialog(SvnBundle.message("action.Subversion.integrate.changes.error.unable.to.collect.changes.text", - e.getMessage()), myTitle); - return; - } + new Task.Backgroundable(myVcs.getProject(), + SvnBundle.message("action.Subversion.integrate.changes.collecting.changes.to.commit.task.title")) { - if (! clb.getChanges().isEmpty()) { - CommitChangeListDialog.commitAlienChanges(myProject, clb.getChanges(), myVcs, myMerger.getComment(), myMerger.getComment()); - } + private final GatheringChangelistBuilder changesBuilder = new GatheringChangelistBuilder(myVcs, myAccomulatedFiles); + private final Ref<String> caughtError = new Ref<String>(); + + @Override + public void run(@NotNull ProgressIndicator indicator) { + indicator.setIndeterminate(true); + if (!myVcs.getProject().isDisposed()) { + final SvnChangeProvider provider = new SvnChangeProvider(myVcs); + + try { + provider.getChanges(dirtyScope, changesBuilder, indicator, null); + } + catch (VcsException e) { + caughtError.set(SvnBundle.message("action.Subversion.integrate.changes.error.unable.to.collect.changes.text", e.getMessage())); + } + } + } + + @Override + public void onSuccess() { + if (!caughtError.isNull()) { + VcsBalloonProblemNotifier.showOverVersionControlView(myVcs.getProject(), caughtError.get(), MessageType.ERROR); + } + else if (!changesBuilder.getChanges().isEmpty()) { + CommitChangeListDialog + .commitAlienChanges(myProject, changesBuilder.getChanges(), myVcs, myMerger.getComment(), myMerger.getComment()); + } + } + }.queue(); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java index 701bb2575001..f69aac4a4133 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java @@ -19,11 +19,15 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.MultiMap; +import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.history.SvnChangeList; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.properties.PropertyValue; -import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNMergeRange; +import org.tmatesoft.svn.core.SVNMergeRangeList; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNMergeInfoUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -209,7 +213,8 @@ public class BranchInfo { SvnTarget target = SvnTarget.fromURL(branchUrl); try { - mergeinfoProperty = myVcs.getFactory(target).createPropertyClient().getProperty(target, SVNProperty.MERGE_INFO, false, SVNRevision.create(targetRevision)); + mergeinfoProperty = myVcs.getFactory(target).createPropertyClient().getProperty(target, SvnPropertyKeys.MERGE_INFO, false, + SVNRevision.create(targetRevision)); } catch (VcsException e) { LOG.info(e); @@ -283,13 +288,13 @@ public class BranchInfo { // look in WC SvnTarget target = SvnTarget.fromFile(pathFile, SVNRevision.WORKING); mergeinfoProperty = - myVcs.getFactory(target).createPropertyClient().getProperty(target, SVNProperty.MERGE_INFO, false, SVNRevision.WORKING); + myVcs.getFactory(target).createPropertyClient().getProperty(target, SvnPropertyKeys.MERGE_INFO, false, SVNRevision.WORKING); } else { // in repo myMixedRevisionsFound = true; SvnTarget target = SvnTarget.fromURL(svnInfo.getURL()); mergeinfoProperty = myVcs.getFactory(target).createPropertyClient() - .getProperty(target, SVNProperty.MERGE_INFO, false, SVNRevision.create(targetRevisionCorrected)); + .getProperty(target, SvnPropertyKeys.MERGE_INFO, false, SVNRevision.create(targetRevisionCorrected)); } } catch (VcsException e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java index 225bc6ad0396..b17d3317a801 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java @@ -21,12 +21,16 @@ import com.intellij.openapi.vcs.AreaMap; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.PairProcessor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.dialogs.MergeContext; import org.jetbrains.idea.svn.properties.PropertyConsumer; import org.jetbrains.idea.svn.properties.PropertyData; import org.jetbrains.idea.svn.properties.PropertyValue; -import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNMergeRange; +import org.tmatesoft.svn.core.SVNMergeRangeList; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNMergeInfoUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -83,7 +87,7 @@ public class OneRecursiveShotMergeInfoWorker implements MergeInfoWorker { File path = new File(myMergeContext.getWcInfo().getPath()); myMergeContext.getVcs().getFactory(path).createPropertyClient() - .getProperty(SvnTarget.fromFile(path), SVNProperty.MERGE_INFO, SVNRevision.WORKING, depth, handler); + .getProperty(SvnTarget.fromFile(path), SvnPropertyKeys.MERGE_INFO, SVNRevision.WORKING, depth, handler); } public SvnMergeInfoCache.MergeCheckResult isMerged(final String relativeToRepoURLPath, final long revisionNumber) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java index e053776d14ce..f00c4bd7341d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java @@ -1,5 +1,7 @@ package org.jetbrains.idea.svn.properties; +import com.intellij.openapi.diagnostic.Attachment; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,6 +32,8 @@ import java.util.Map; */ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { + private static final Logger LOG = Logger.getInstance(CmdPropertyClient.class); + @Nullable @Override public PropertyValue getProperty(@NotNull SvnTarget target, @@ -57,7 +61,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { parameters.add("--xml"); CommandExecutor command = execute(myVcs, target, SvnCommandName.propget, parameters, null); - PropertyData data = parseSingleProperty(target, command.getOutput()); + PropertyData data = parseSingleProperty(target, command); return data != null ? data.getValue() : null; } @@ -74,7 +78,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { fillListParameters(target, revision, depth, parameters, false); CommandExecutor command = execute(myVcs, target, SvnCommandName.propget, parameters, null); - parseOutput(target, command.getOutput(), handler); + parseOutput(target, command, handler); } @Override @@ -86,7 +90,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { fillListParameters(target, revision, depth, parameters, true); CommandExecutor command = execute(myVcs, target, SvnCommandName.proplist, parameters, null); - parseOutput(target, command.getOutput(), handler); + parseOutput(target, command, handler); } @Override @@ -183,7 +187,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { } @Nullable - private PropertyData parseSingleProperty(SvnTarget target, String output) throws VcsException { + private PropertyData parseSingleProperty(SvnTarget target, @NotNull CommandExecutor command) throws VcsException { final PropertyData[] data = new PropertyData[1]; PropertyConsumer handler = new PropertyConsumer() { @Override @@ -202,14 +206,14 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { } }; - parseOutput(target, output, handler); + parseOutput(target, command, handler); return data[0]; } - private static void parseOutput(SvnTarget target, String output, PropertyConsumer handler) throws VcsException { + private static void parseOutput(SvnTarget target, @NotNull CommandExecutor command, PropertyConsumer handler) throws VcsException { try { - Properties properties = CommandUtil.parse(output, Properties.class); + Properties properties = CommandUtil.parse(command.getOutput(), Properties.class); if (properties != null) { for (Target childInfo : properties.targets) { @@ -227,6 +231,8 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { } } catch (JAXBException e) { + LOG.error("Could not parse properties. Command: " + command.getCommandText() + ", Warning: " + command.getErrorOutput(), + new Attachment("output.xml", command.getOutput())); throw new VcsException(e); } catch (SVNException e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java index 7b09461b3766..16904b673b5f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java @@ -37,8 +37,10 @@ import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.properties.PropertiesMap; import org.jetbrains.idea.svn.properties.PropertyConsumer; import org.jetbrains.idea.svn.properties.PropertyData; -import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; @@ -312,7 +314,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { if (info.isFile()) { doRevert(file, false); } else { - if (SVNProperty.SCHEDULE_ADD.equals(info.getSchedule())) { + if (Info.SCHEDULE_ADD.equals(info.getSchedule())) { doRevert(file, true); } else { boolean is17OrGreater = is17OrGreaterCopy(file, info); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/status/CmdStatusClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/status/CmdStatusClient.java index 4030c83005ea..8100d73da220 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/status/CmdStatusClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/status/CmdStatusClient.java @@ -103,6 +103,7 @@ public class CmdStatusClient extends BaseSvnClient implements StatusClient { // so it does not contain any <entry> element and current parsing logic returns null PortableStatus status = new PortableStatus(); + status.setFile(path); status.setPath(path.getAbsolutePath()); status.setContentsStatus(StatusType.STATUS_NORMAL); status.setInfoGetter(new Getter<Info>() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java index b4e788c75260..ef3529aec092 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/AbstractSvnUpdateIntegrateEnvironment.java @@ -46,7 +46,6 @@ public abstract class AbstractSvnUpdateIntegrateEnvironment implements UpdateEnv protected final SvnVcs myVcs; private final ProjectLevelVcsManager myVcsManager; @NonNls public static final String REPLACED_ID = "replaced"; - @NonNls public static final String EXTERNAL_ID = "external"; protected AbstractSvnUpdateIntegrateEnvironment(final SvnVcs vcs) { myVcs = vcs; @@ -145,6 +144,7 @@ public abstract class AbstractSvnUpdateIntegrateEnvironment implements UpdateEnv } public void onRefreshFilesCompleted() { + // TODO: why do we need to mark all roots as dirty here??? dirtyRoots(); for (Runnable groupWorker : myGroupWorkers) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java index 554b2c29bc48..41bfd61fded1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateEnvironment.java @@ -89,8 +89,6 @@ public class SvnUpdateEnvironment extends AbstractSvnUpdateIntegrateEnvironment rev = updateClient.doUpdate(root, updateTo, configuration.getUpdateDepth(), configuration.isForceUpdate(), false); } - myPostUpdateFiles.setRevisions(root.getAbsolutePath(), myVcs, new SvnRevisionNumber(SVNRevision.create(rev))); - return rev; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateRootOptionsPanel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateRootOptionsPanel.java index d232fdc3037f..9103c845ae75 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateRootOptionsPanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/SvnUpdateRootOptionsPanel.java @@ -22,7 +22,7 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vcs.FilePath; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; -import org.jetbrains.idea.svn.actions.SelectBranchPopup; +import org.jetbrains.idea.svn.branchConfig.SelectBranchPopup; import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew; import org.jetbrains.idea.svn.dialogs.SelectLocationDialog; import org.jetbrains.idea.svn.history.SvnChangeList; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateEventHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateEventHandler.java index fc552dbd1655..aff94e123a31 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateEventHandler.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/update/UpdateEventHandler.java @@ -16,10 +16,13 @@ package org.jetbrains.idea.svn.update; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.update.FileGroup; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.wm.StatusBar; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.Stack; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnFileUrlMapping; @@ -32,11 +35,12 @@ import org.jetbrains.idea.svn.status.StatusType; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.util.SVNLogType; import java.io.File; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -49,6 +53,10 @@ public class UpdateEventHandler implements ProgressTracker { private final SvnVcs myVCS; @Nullable private final SvnUpdateContext mySequentialUpdatesContext; private final Map<File, SVNURL> myUrlToCheckForSwitch; + // pair.first - group id, pair.second - file path + // Stack is used to correctly handle cases when updates of externals occur during ordinary update, because these inner updates could have + // its own revisions. + private final Stack<List<Pair<String, String>>> myFilesWaitingForRevision; protected String myText; protected String myText2; @@ -60,6 +68,11 @@ public class UpdateEventHandler implements ProgressTracker { mySequentialUpdatesContext = sequentialUpdatesContext; myExternalsCount = 1; myUrlToCheckForSwitch = new HashMap<File, SVNURL>(); + myFilesWaitingForRevision = ContainerUtil.newStack(); + // It is more suitable to make this push while handling UPDATE_NONE event - for command line like "svn update <folder>" this event will + // be fired when update of <folder> is started. But it's not clear if this event won't be fired in other cases by SVNKit. So currently + // first push is made here. If further we want to support commands like "svn update <folder1> <folder2>" this logic should be revised. + myFilesWaitingForRevision.push(ContainerUtil.<Pair<String, String>>newArrayList()); } public void addToSwitch(final File file, final SVNURL url) { @@ -153,13 +166,8 @@ public class UpdateEventHandler implements ProgressTracker { if (mySequentialUpdatesContext != null) { mySequentialUpdatesContext.registerExternalRootBeingUpdated(event.getFile()); } + myFilesWaitingForRevision.push(ContainerUtil.<Pair<String, String>>newArrayList()); myExternalsCount++; - if (myUpdatedFiles.getGroupById(AbstractSvnUpdateIntegrateEnvironment.EXTERNAL_ID) == null) { - myUpdatedFiles.registerGroup(new FileGroup(SvnBundle.message("status.group.name.externals"), - SvnBundle.message("status.group.name.externals"), - false, AbstractSvnUpdateIntegrateEnvironment.EXTERNAL_ID, true)); - } - addFileToGroup(AbstractSvnUpdateIntegrateEnvironment.EXTERNAL_ID, event); myText = SvnBundle.message("progress.text.updating.external.location", event.getFile().getAbsolutePath()); } else if (event.getAction() == EventAction.RESTORE) { @@ -168,6 +176,7 @@ public class UpdateEventHandler implements ProgressTracker { } else if (event.getAction() == EventAction.UPDATE_COMPLETED && event.getRevision() >= 0) { possiblySwitched(event); + setRevisionForWaitingFiles(event.getRevision()); myExternalsCount--; myText2 = SvnBundle.message("progres.text2.updated.to.revision", event.getRevision()); if (myExternalsCount == 0) { @@ -218,12 +227,22 @@ public class UpdateEventHandler implements ProgressTracker { protected void addFileToGroup(final String id, final ProgressEvent event) { final FileGroup fileGroup = myUpdatedFiles.getGroupById(id); final String path = event.getFile().getAbsolutePath(); - fileGroup.add(path, SvnVcs.getKey(), new SvnRevisionNumber(SVNRevision.create(event.getRevision()))); + myFilesWaitingForRevision.peek().add(Pair.create(id, path)); if (event.getErrorMessage() != null) { fileGroup.addError(path, event.getErrorMessage().getMessage()); } } + private void setRevisionForWaitingFiles(long revisionNumber) { + SvnRevisionNumber revision = new SvnRevisionNumber(SVNRevision.create(revisionNumber)); + + for (Pair<String, String> pair : myFilesWaitingForRevision.pop()) { + FileGroup fileGroup = myUpdatedFiles.getGroupById(pair.getFirst()); + + fileGroup.add(pair.getSecond(), SvnVcs.getKey(), revision); + } + } + public void checkCancelled() throws SVNCancelException { if (myProgressIndicator != null) { myProgressIndicator.checkCanceled(); |