From 35af984ea682d9281f2dd4d964d09f7e9372c8aa Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 27 Sep 2013 13:35:23 +0400 Subject: [PATCH 1/6] svn: Refactored repository url resolving for command line - use separate repository providers --- .../jetbrains/idea/svn/api/Repository.java | 21 ++++++ .../idea/svn/commandLine/CommandUtil.java | 66 ++++++++++++++++--- 2 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/api/Repository.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/Repository.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/Repository.java new file mode 100644 index 000000000000..4a697c2d7f34 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/Repository.java @@ -0,0 +1,21 @@ +package org.jetbrains.idea.svn.api; + +import org.jetbrains.annotations.NotNull; +import org.tmatesoft.svn.core.SVNURL; + +/** + * @author Konstantin Kolosovsky. + */ +public class Repository { + + @NotNull private final SVNURL myUrl; + + public Repository(@NotNull SVNURL url) { + myUrl = url; + } + + @NotNull + public SVNURL getUrl() { + return myUrl; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 0279ebaf3467..45539d2f4e7b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -10,6 +10,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.RootUrlInfo; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.api.Repository; import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNException; @@ -215,19 +216,15 @@ public class CommandUtil { } private static SVNURL resolveRepositoryUrl(@NotNull SvnVcs vcs, @NotNull SvnCommandName name, @NotNull SvnTarget target) { - RootUrlInfo rootInfo = target.isFile() - ? vcs.getSvnFileUrlMapping().getWcRootForFilePath(target.getFile()) - : vcs.getSvnFileUrlMapping().getWcRootForUrl(target.getURL().toDecodedString()); - SVNURL repositoryUrl = rootInfo != null ? rootInfo.getRepositoryUrlUrl() : null; + UrlMappingRepositoryProvider urlMappingProvider = new UrlMappingRepositoryProvider(vcs, target); + InfoCommandRepositoryProvider infoCommandProvider = new InfoCommandRepositoryProvider(vcs, target); - // resolve repository url using "svn info" command except the case when that command is executing right now. - if (repositoryUrl == null && !SvnCommandName.info.equals(name)) { - SVNInfo info = getInfo(vcs, target); - - repositoryUrl = info != null ? info.getRepositoryRootURL() : null; + Repository repository = urlMappingProvider.get(); + if (repository == null && !SvnCommandName.info.equals(name)) { + repository = infoCommandProvider.get(); } - return repositoryUrl; + return repository != null ? repository.getUrl() : null; } @NotNull @@ -296,4 +293,53 @@ public class CommandUtil { } return contentsStatus; } + + public interface RepositoryProvider { + + @Nullable + Repository get(); + } + + public static abstract class BaseRepositoryProvider implements RepositoryProvider { + + @NotNull protected final SvnVcs myVcs; + @NotNull protected final SvnTarget myTarget; + + protected BaseRepositoryProvider(@NotNull SvnVcs vcs, @NotNull SvnTarget target) { + myVcs = vcs; + myTarget = target; + } + } + + public static class UrlMappingRepositoryProvider extends BaseRepositoryProvider { + + public UrlMappingRepositoryProvider(@NotNull SvnVcs vcs, @NotNull SvnTarget target) { + super(vcs, target); + } + + @Nullable + @Override + public Repository get() { + RootUrlInfo rootInfo = myTarget.isFile() + ? myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myTarget.getFile()) + : myVcs.getSvnFileUrlMapping().getWcRootForUrl(myTarget.getURL().toDecodedString()); + + return rootInfo != null ? new Repository(rootInfo.getRepositoryUrlUrl()) : null; + } + } + + public static class InfoCommandRepositoryProvider extends BaseRepositoryProvider { + + public InfoCommandRepositoryProvider(@NotNull SvnVcs vcs, + @NotNull SvnTarget target) { + super(vcs, target); + } + + @Nullable + @Override + public Repository get() { + SVNInfo info = getInfo(myVcs, myTarget); + return info != null ? new Repository(info.getRepositoryRootURL()) : null; + } + } } From b3dd860100d940988e2d7aa2c939bb5c2695af42 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 27 Sep 2013 13:43:16 +0400 Subject: [PATCH 2/6] IDEA-113983 Fixed checkout from welcome screen (default project) --- .../idea/svn/commandLine/CommandUtil.java | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index 45539d2f4e7b..db82214b2b18 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -320,9 +320,13 @@ public class CommandUtil { @Nullable @Override public Repository get() { - RootUrlInfo rootInfo = myTarget.isFile() - ? myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myTarget.getFile()) - : myVcs.getSvnFileUrlMapping().getWcRootForUrl(myTarget.getURL().toDecodedString()); + RootUrlInfo rootInfo = null; + + if (!myVcs.getProject().isDefault()) { + rootInfo = myTarget.isFile() + ? myVcs.getSvnFileUrlMapping().getWcRootForFilePath(myTarget.getFile()) + : myVcs.getSvnFileUrlMapping().getWcRootForUrl(myTarget.getURL().toDecodedString()); + } return rootInfo != null ? new Repository(rootInfo.getRepositoryUrlUrl()) : null; } @@ -330,16 +334,26 @@ public class CommandUtil { public static class InfoCommandRepositoryProvider extends BaseRepositoryProvider { - public InfoCommandRepositoryProvider(@NotNull SvnVcs vcs, - @NotNull SvnTarget target) { + public InfoCommandRepositoryProvider(@NotNull SvnVcs vcs, @NotNull SvnTarget target) { super(vcs, target); } @Nullable @Override public Repository get() { - SVNInfo info = getInfo(myVcs, myTarget); - return info != null ? new Repository(info.getRepositoryRootURL()) : null; + Repository result; + + if (myTarget.isURL()) { + // TODO: Also could still execute info when target is url - either to use info for authentication or to just get correct repository + // TODO: url in case of "read" operations are allowed anonymously. + result = new Repository(myTarget.getURL()); + } + else { + SVNInfo info = getInfo(myVcs, myTarget); + result = info != null ? new Repository(info.getRepositoryRootURL()) : null; + } + + return result; } } } From 2b41af82f616d173b7a7ac6f023556546dd1da19 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Fri, 27 Sep 2013 16:09:32 +0400 Subject: [PATCH 3/6] IDEA-113983 Fixed infinite loading on checkout working copy format dialog (if SVNKit is used) - use ModalityState.any() --- .../jetbrains/idea/svn/checkout/SvnCheckoutProvider.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnCheckoutProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnCheckoutProvider.java index 4e703ddee543..891471e291c1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnCheckoutProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnCheckoutProvider.java @@ -63,6 +63,7 @@ import java.util.concurrent.atomic.AtomicReference; public class SvnCheckoutProvider implements CheckoutProvider { public void doCheckout(@NotNull final Project project, Listener listener) { + // TODO: Several dialogs is invoked while dialog.show() - seems code should be rewritten to be more transparent CheckoutDialog dialog = new CheckoutDialog(project, listener); dialog.show(); } @@ -308,8 +309,9 @@ public class SvnCheckoutProvider implements CheckoutProvider { private WorkingCopyFormat displayUpgradeDialog(@NotNull WorkingCopyFormat defaultSelection) { final UpgradeFormatDialog dialog = new UpgradeFormatDialog(myProject, myPath, false); - dialog.startLoading(); + final ModalityState dialogState = ModalityState.any(); + dialog.startLoading(); ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { @@ -331,7 +333,7 @@ public class SvnCheckoutProvider implements CheckoutProvider { dialog.stopLoading(); } } - }, ModalityState.stateForComponent(dialog.getWindow())); + }, dialogState); } }); From 9196b272138657db3303200e7c58a456e16f9436 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 30 Sep 2013 13:31:28 +0400 Subject: [PATCH 4/6] svn: Implemented "Change" (upgrade) action for command line client --- .../jetbrains/idea/svn/WorkingCopyFormat.java | 4 + .../jetbrains/idea/svn/api/BaseSvnClient.java | 23 +++++ .../jetbrains/idea/svn/api/ClientFactory.java | 7 ++ .../idea/svn/api/CmdClientFactory.java | 2 + .../idea/svn/api/SvnKitClientFactory.java | 2 + .../svn/checkout/SvnKitCheckoutClient.java | 2 +- .../idea/svn/commandLine/SvnCommandName.java | 3 +- .../idea/svn/dialogs/CopiesPanel.java | 54 +++++++++--- .../idea/svn/dialogs/SvnFormatWorker.java | 56 ++++++++----- .../idea/svn/upgrade/CmdUpgradeClient.java | 83 +++++++++++++++++++ .../idea/svn/upgrade/SvnKitUpgradeClient.java | 64 ++++++++++++++ .../idea/svn/upgrade/UpgradeClient.java | 21 +++++ 12 files changed, 288 insertions(+), 33 deletions(-) create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/SvnKitUpgradeClient.java create mode 100644 plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/UpgradeClient.java diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java index 595abe10a83c..26069480a341 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/WorkingCopyFormat.java @@ -101,6 +101,10 @@ public enum WorkingCopyFormat { return myFormat; } + public boolean isOrGreater(@NotNull WorkingCopyFormat format) { + return myVersion.isOrGreaterThan(format.getVersion().major, format.getVersion().minor); + } + @NotNull public static WorkingCopyFormat from(@NotNull Version version) { WorkingCopyFormat result = UNKNOWN; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java index e6bca33d617f..4076a729d88a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/BaseSvnClient.java @@ -3,10 +3,17 @@ package org.jetbrains.idea.svn.api; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.WorkingCopyFormat; +import org.jetbrains.idea.svn.commandLine.SvnBindException; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNEvent; +import org.tmatesoft.svn.core.wc.SVNEventAction; import org.tmatesoft.svn.core.wc2.SvnTarget; +import java.io.File; import java.util.Collection; /** @@ -56,4 +63,20 @@ public abstract class BaseSvnClient implements SvnClient { String.format("%s format is not supported. Supported formats are: %s.", format.getName(), StringUtil.join(supported, ","))); } } + + protected static void callHandler(@Nullable ISVNEventHandler handler, @NotNull SVNEvent event) throws VcsException { + if (handler != null) { + try { + handler.handleEvent(event, 0); + } + catch (SVNException e) { + throw new SvnBindException(e); + } + } + } + + @NotNull + protected static SVNEvent createEvent(@NotNull File path, @Nullable SVNEventAction action) { + return new SVNEvent(path, null, null, 0, null, null, null, null, action, null, null, null, null, null, null); + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java index 27c0d1e30885..7f16724806b2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/ClientFactory.java @@ -22,6 +22,7 @@ import org.jetbrains.idea.svn.portable.SvnWcClientI; import org.jetbrains.idea.svn.properties.PropertyClient; import org.jetbrains.idea.svn.revert.RevertClient; import org.jetbrains.idea.svn.update.RelocateClient; +import org.jetbrains.idea.svn.upgrade.UpgradeClient; /** * @author Konstantin Kolosovsky. @@ -51,6 +52,7 @@ public abstract class ClientFactory { protected VersionClient myVersionClient; protected ImportClient myImportClient; protected ExportClient myExportClient; + protected UpgradeClient myUpgradeClient; protected ClientFactory(@NotNull SvnVcs vcs) { myVcs = vcs; @@ -166,6 +168,11 @@ public abstract class ClientFactory { return prepare(myExportClient); } + @NotNull + public UpgradeClient createUpgradeClient() { + return prepare(myUpgradeClient); + } + @NotNull protected T prepare(@NotNull T client) { client.setVcs(myVcs); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java index 8b73377b6f9f..de5c33e2b9eb 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/CmdClientFactory.java @@ -23,6 +23,7 @@ import org.jetbrains.idea.svn.update.UpdateClient; import org.jetbrains.idea.svn.properties.CmdPropertyClient; import org.jetbrains.idea.svn.revert.CmdRevertClient; import org.jetbrains.idea.svn.update.CmdRelocateClient; +import org.jetbrains.idea.svn.upgrade.CmdUpgradeClient; /** * @author Konstantin Kolosovsky. @@ -53,6 +54,7 @@ public class CmdClientFactory extends ClientFactory { myVersionClient = new CmdVersionClient(); myImportClient = new CmdImportClient(); myExportClient = new CmdExportClient(); + myUpgradeClient = new CmdUpgradeClient(); statusClient = new SvnCommandLineStatusClient(myVcs); infoClient = new SvnCommandLineInfoClient(myVcs); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java index 002820d47f9a..27e025cc57f3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/api/SvnKitClientFactory.java @@ -23,6 +23,7 @@ import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient; import org.jetbrains.idea.svn.properties.SvnKitPropertyClient; import org.jetbrains.idea.svn.revert.SvnKitRevertClient; import org.jetbrains.idea.svn.update.SvnKitRelocateClient; +import org.jetbrains.idea.svn.upgrade.SvnKitUpgradeClient; /** * @author Konstantin Kolosovsky. @@ -53,6 +54,7 @@ public class SvnKitClientFactory extends ClientFactory { myVersionClient = new SvnKitVersionClient(); myImportClient = new SvnKitImportClient(); myExportClient = new SvnKitExportClient(); + myUpgradeClient = new SvnKitUpgradeClient(); statusClient = new SvnkitSvnStatusClient(myVcs, null); infoClient = new SvnkitSvnWcClient(myVcs); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnKitCheckoutClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnKitCheckoutClient.java index 54e9063e1937..796d30a80a3a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnKitCheckoutClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/checkout/SvnKitCheckoutClient.java @@ -24,7 +24,7 @@ import java.util.List; */ public class SvnKitCheckoutClient extends BaseSvnClient implements CheckoutClient { - private static final List SUPPORTED_FORMATS; + public static final List SUPPORTED_FORMATS; static { List supportedFormats = new ArrayList(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java index 9182d9371c4e..1932d041c26c 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/SvnCommandName.java @@ -49,7 +49,8 @@ public enum SvnCommandName { lock("lock", true), unlock("unlock", true), importFolder("import", false), - export("export", false); + export("export", false), + upgrade("upgrade", true); private final String myName; private final boolean myWriteable; 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 f88c8ebf13eb..1ec176990c87 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/CopiesPanel.java @@ -17,12 +17,14 @@ package org.jetbrains.idea.svn.dialogs; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.ObjectsConvertor; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; @@ -61,11 +63,13 @@ import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.File; -import java.util.Collections; -import java.util.Comparator; +import java.util.*; import java.util.List; public class CopiesPanel { + + private static final Logger LOG = Logger.getInstance(CopiesPanel.class); + private final Project myProject; private MessageBusConnection myConnection; private SvnVcs myVcs; @@ -98,6 +102,7 @@ public class CopiesPanel { @Override public void run() { final List infoList = myVcs.getAllWcInfos(); + final List supportedFormats = getSupportedFormats(); Runnable runnable = new Runnable() { @Override public void run() { @@ -117,7 +122,7 @@ public class CopiesPanel { myCurrentInfoList = newList; } Collections.sort(infoList, WCComparator.getInstance()); - updateList(infoList); + updateList(infoList, supportedFormats); myRefreshLabel.setEnabled(true); SwingUtilities.invokeLater(focus); } @@ -178,7 +183,7 @@ public class CopiesPanel { return myRefreshLabel; } - private void updateList(final List infoList) { + private void updateList(@NotNull final List infoList, @NotNull final List supportedFormats) { myPanel.removeAll(); final Insets nullIndent = new Insets(1, 3, 1, 0); final GridBagConstraints gb = @@ -217,7 +222,7 @@ public class CopiesPanel { SVNDepth.INFINITY, false, null, wcInfo.getFormat()); } } else if (CHANGE_FORMAT.equals(e.getDescription())) { - changeFormat(wcInfo); + changeFormat(wcInfo, supportedFormats); } else if (MERGE_FROM.equals(e.getDescription())) { if (! checkRoot(root, wcInfo.getPath(), " invoke Merge From")) return; mergeFrom(wcInfo, root, editorPane); @@ -237,7 +242,7 @@ public class CopiesPanel { } }); editorPane.setBorder(null); - editorPane.setText(formatWc(wcInfo)); + editorPane.setText(formatWc(wcInfo, supportedFormats)); final JPanel copyPanel = new JPanel(new GridBagLayout()); @@ -263,14 +268,14 @@ public class CopiesPanel { } @SuppressWarnings("MethodMayBeStatic") - private String formatWc(WCInfo info) { + private String formatWc(@NotNull WCInfo info, @NotNull List supportedFormats) { final StringBuilder sb = new StringBuilder().append("").append(UIUtil.getCssFontDeclaration(UIUtil.getLabelFont())) .append(""); sb.append(""); sb.append(""); - if (! WorkingCopyFormat.ONE_DOT_SEVEN.equals(info.getFormat())) { - // can convert + Collection upgradeFormats = getUpgradeFormats(info, supportedFormats); + if (upgradeFormats.size() > 1) { sb.append(""); } else { @@ -302,6 +307,33 @@ public class CopiesPanel { return sb.toString(); } + @NotNull + private List getSupportedFormats() { + List result = Collections.emptyList(); + + try { + result = myVcs.getFactory().createUpgradeClient().getSupportedFormats(); + } + catch (VcsException e) { + LOG.info(e); + } + + return result; + } + + public static Set getUpgradeFormats(@NotNull WCInfo info, @NotNull List supportedFormats) { + Set canUpgradeTo = EnumSet.noneOf(WorkingCopyFormat.class); + + for (WorkingCopyFormat format : supportedFormats) { + if (format.isOrGreater(info.getFormat())) { + canUpgradeTo.add(format); + } + } + canUpgradeTo.add(info.getFormat()); + + return canUpgradeTo; + } + private void mergeFrom(@NotNull final WCInfo wcInfo, @NotNull final VirtualFile root, @Nullable final Component mergeLabel) { SelectBranchPopup.showForBranchRoot(myProject, root, new SelectBranchPopup.BranchSelectedCallback() { @Override @@ -338,8 +370,10 @@ public class CopiesPanel { }); } - private void changeFormat(final WCInfo wcInfo) { + private void changeFormat(@NotNull final WCInfo wcInfo, @NotNull final List supportedFormats) { ChangeFormatDialog dialog = new ChangeFormatDialog(myProject, new File(wcInfo.getPath()), false, ! wcInfo.isIsWcRoot()); + + dialog.setSupported(supportedFormats); dialog.setData(wcInfo.getFormat()); dialog.show(); if (! dialog.isOK()) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java index f1310cdd7fd9..d6ccdcf13e7d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnFormatWorker.java @@ -37,7 +37,6 @@ import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.SVNEvent; import org.tmatesoft.svn.core.wc.SVNEventAction; -import org.tmatesoft.svn.core.wc.SVNWCClient; import java.io.File; import java.util.ArrayList; @@ -122,20 +121,7 @@ public class SvnFormatWorker extends Task.Backgroundable { if (supportsChangelists) { myBeforeChangeLists = ChangeListManager.getInstance(myProject).getChangeListsCopy(); } - final SVNWCClient wcClient = myVcs.createWCClient(); - wcClient.setEventHandler(new ISVNEventHandler() { - @Override - public void handleEvent(SVNEvent event, double progress) throws SVNException { - if (SVNEventAction.UPGRADED_PATH.equals(event.getAction()) && event.getFile() != null) { - indicator.setText2("Upgraded path " + VcsUtil.getPathForProgressPresentation(event.getFile())); - } - } - @Override - public void checkCancelled() throws SVNCancelException { - indicator.checkCanceled(); - } - }); try { for (WCInfo wcInfo : myWcInfos) { File path = new File(wcInfo.getPath()); @@ -143,13 +129,13 @@ public class SvnFormatWorker extends Task.Backgroundable { path = SvnUtil.getWorkingCopyRoot(path); } try { - if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(myNewFormat)) { - indicator.setText(SvnBundle.message("action.Subversion.cleanup.progress.text", path.getAbsolutePath())); - wcClient.doCleanup(path); - } - indicator.setText(SvnBundle.message("action.change.wcopy.format.task.progress.text", path.getAbsolutePath(), - SvnUtil.formatRepresentation(wcInfo.getFormat()), SvnUtil.formatRepresentation(myNewFormat))); - wcClient.doSetWCFormat(path, myNewFormat.getFormat()); + String cleanupMessage = SvnBundle.message("action.Subversion.cleanup.progress.text", path.getAbsolutePath()); + String upgradeMessage = SvnBundle.message("action.change.wcopy.format.task.progress.text", path.getAbsolutePath(), + SvnUtil.formatRepresentation(wcInfo.getFormat()), + SvnUtil.formatRepresentation(myNewFormat)); + ISVNEventHandler handler = createUpgradeHandler(indicator, cleanupMessage, upgradeMessage); + + myVcs.getFactory(path).createUpgradeClient().upgrade(path, myNewFormat, handler); } catch (Throwable e) { myExceptions.add(e); } @@ -166,4 +152,32 @@ public class SvnFormatWorker extends Task.Backgroundable { ApplicationManager.getApplication().getMessageBus().syncPublisher(SvnVcs.WC_CONVERTED).run(); } } + + private static ISVNEventHandler createUpgradeHandler(@NotNull final ProgressIndicator indicator, + @NotNull final String cleanupMessage, + @NotNull final String upgradeMessage) { + return new ISVNEventHandler() { + @Override + public void handleEvent(SVNEvent event, double progress) throws SVNException { + if (event.getFile() != null) { + if (SVNEventAction.UPGRADED_PATH.equals(event.getAction())) { + indicator.setText2("Upgraded path " + VcsUtil.getPathForProgressPresentation(event.getFile())); + } + // fake event indicating cleanup start + if (SVNEventAction.UPDATE_STARTED.equals(event.getAction())) { + indicator.setText(cleanupMessage); + } + // fake event indicating upgrade start + if (SVNEventAction.UPDATE_COMPLETED.equals(event.getAction())) { + indicator.setText(upgradeMessage); + } + } + } + + @Override + public void checkCancelled() throws SVNCancelException { + indicator.checkCanceled(); + } + }; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java new file mode 100644 index 000000000000..4e40fe79578b --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java @@ -0,0 +1,83 @@ +package org.jetbrains.idea.svn.upgrade; + +import com.intellij.openapi.vcs.VcsException; +import com.intellij.util.containers.Convertor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.WorkingCopyFormat; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.api.FileStatusResultParser; +import org.jetbrains.idea.svn.commandLine.CommandUtil; +import org.jetbrains.idea.svn.commandLine.SvnCommand; +import org.jetbrains.idea.svn.commandLine.SvnCommandName; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNEvent; +import org.tmatesoft.svn.core.wc.SVNEventAction; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Konstantin Kolosovsky. + */ +public class CmdUpgradeClient extends BaseSvnClient implements UpgradeClient { + + private static final String STATUS = "\\s*(.+?)\\s*"; + private static final String PATH = "\\s*\'(.*?)\'\\s*"; + private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH); + + @Override + public void upgrade(@NotNull File path, @NotNull WorkingCopyFormat format, @Nullable ISVNEventHandler handler) throws VcsException { + validateFormat(format, getSupportedFormats()); + + // fake event indicating upgrade start + callHandler(handler, createEvent(path, SVNEventAction.UPDATE_COMPLETED)); + + List parameters = new ArrayList(); + + CommandUtil.put(parameters, path); + + // TODO: handler should be called in parallel with command execution, but this will be in other thread + // TODO: check if that is ok for current handler implementation + // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed + // for 1.8 - no output + // for 1.7 - output in format "Upgraded ''" + SvnCommand command = CommandUtil.execute(myVcs, SvnTarget.fromFile(path), SvnCommandName.upgrade, parameters, null); + FileStatusResultParser parser = new FileStatusResultParser(CHANGED_PATH, handler, new UpgradeStatusConvertor()); + parser.parse(command.getOutput()); + } + + @Override + public List getSupportedFormats() throws VcsException { + List result = new ArrayList(); + + result.add(WorkingCopyFormat.from(myFactory.createVersionClient().getVersion())); + + return result; + } + + private static class UpgradeStatusConvertor implements Convertor { + + public SVNEvent convert(@NotNull Matcher matcher) { + String statusMessage = matcher.group(1); + String path = matcher.group(2); + + return createEvent(new File(path), createAction(statusMessage)); + } + + @Nullable + public static SVNEventAction createAction(@NotNull String code) { + SVNEventAction result = null; + + if ("Upgraded".equals(code)) { + result = SVNEventAction.UPGRADED_PATH; + } + + return result; + } + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/SvnKitUpgradeClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/SvnKitUpgradeClient.java new file mode 100644 index 000000000000..1aa2ebd687ac --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/SvnKitUpgradeClient.java @@ -0,0 +1,64 @@ +package org.jetbrains.idea.svn.upgrade; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.WorkingCopyFormat; +import org.jetbrains.idea.svn.api.BaseSvnClient; +import org.jetbrains.idea.svn.checkout.SvnKitCheckoutClient; +import org.jetbrains.idea.svn.commandLine.SvnBindException; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; +import org.tmatesoft.svn.core.wc.SVNEventAction; +import org.tmatesoft.svn.core.wc.SVNWCClient; + +import java.io.File; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitUpgradeClient extends BaseSvnClient implements UpgradeClient { + + @Override + public void upgrade(@NotNull File path, @NotNull WorkingCopyFormat format, @Nullable ISVNEventHandler handler) throws VcsException { + validateFormat(format, getSupportedFormats()); + + SVNWCClient client = myVcs.createWCClient(); + + client.setEventHandler(handler); + try { + cleanupIfNecessary(path, format, client, handler); + upgrade(path, format, client, handler); + } + catch (SVNException e) { + throw new SvnBindException(e); + } + } + + @Override + public List getSupportedFormats() throws VcsException { + return SvnKitCheckoutClient.SUPPORTED_FORMATS; + } + + private static void cleanupIfNecessary(@NotNull File path, + @NotNull WorkingCopyFormat format, + @NotNull SVNWCClient client, + @Nullable ISVNEventHandler handler) throws SVNException, VcsException { + // cleanup is executed only for SVNKit as it could handle both 1.6 and 1.7 formats + if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) { + // fake event indicating cleanup start + callHandler(handler, createEvent(path, SVNEventAction.UPDATE_STARTED)); + client.doCleanup(path); + } + } + + private static void upgrade(@NotNull File path, + @NotNull WorkingCopyFormat format, + @NotNull SVNWCClient client, + @Nullable ISVNEventHandler handler) throws SVNException, VcsException { + // fake event indicating upgrade start + callHandler(handler, createEvent(path, SVNEventAction.UPDATE_COMPLETED)); + client.doSetWCFormat(path, format.getFormat()); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/UpgradeClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/UpgradeClient.java new file mode 100644 index 000000000000..2d22acf08c45 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/UpgradeClient.java @@ -0,0 +1,21 @@ +package org.jetbrains.idea.svn.upgrade; + +import com.intellij.openapi.vcs.VcsException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.WorkingCopyFormat; +import org.jetbrains.idea.svn.api.SvnClient; +import org.tmatesoft.svn.core.wc.ISVNEventHandler; + +import java.io.File; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public interface UpgradeClient extends SvnClient { + + void upgrade(@NotNull File path, @NotNull WorkingCopyFormat format, @Nullable ISVNEventHandler handler) throws VcsException; + + List getSupportedFormats() throws VcsException; +} From 82c67228445be2623556ba54993209d55701afcb Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 30 Sep 2013 13:32:42 +0400 Subject: [PATCH 5/6] svn: Refactored revert client for command line - use utility method for event creation --- .../src/org/jetbrains/idea/svn/revert/CmdRevertClient.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java index 2548cecc9a5b..89626215fb1b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/revert/CmdRevertClient.java @@ -60,8 +60,7 @@ public class CmdRevertClient extends BaseSvnClient implements RevertClient { String statusMessage = matcher.group(1); String path = matcher.group(2); - return new SVNEvent(new File(path), null, null, 0, null, null, null, null, createAction(statusMessage), null, null, null, null, null, - null); + return createEvent(new File(path), createAction(statusMessage)); } @Nullable From 62434c5e81d9ba5f7ecf4de7f70bf617dff0638f Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Mon, 30 Sep 2013 14:09:40 +0400 Subject: [PATCH 6/6] svn: Refactored "upgrade" for command line client - parse output in parallel with command execution --- .../idea/svn/upgrade/CmdUpgradeClient.java | 47 ++++++++++++++++--- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java index 4e40fe79578b..0e1a672bb1ef 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/upgrade/CmdUpgradeClient.java @@ -1,5 +1,7 @@ package org.jetbrains.idea.svn.upgrade; +import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.openapi.util.Key; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.NotNull; @@ -8,7 +10,7 @@ import org.jetbrains.idea.svn.WorkingCopyFormat; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.jetbrains.idea.svn.api.FileStatusResultParser; import org.jetbrains.idea.svn.commandLine.CommandUtil; -import org.jetbrains.idea.svn.commandLine.SvnCommand; +import org.jetbrains.idea.svn.commandLine.LineCommandListener; import org.jetbrains.idea.svn.commandLine.SvnCommandName; import org.tmatesoft.svn.core.wc.ISVNEventHandler; import org.tmatesoft.svn.core.wc.SVNEvent; @@ -18,6 +20,7 @@ import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -41,14 +44,15 @@ public class CmdUpgradeClient extends BaseSvnClient implements UpgradeClient { CommandUtil.put(parameters, path); - // TODO: handler should be called in parallel with command execution, but this will be in other thread - // TODO: check if that is ok for current handler implementation - // TODO: add possibility to invoke "handler.checkCancelled" - process should be killed + // TODO: Add general possibility to invoke "handler.checkCancelled" (process should be killed). But currently upgrade process is not + // TODO: cancellable from UI - and this makes sense. // for 1.8 - no output // for 1.7 - output in format "Upgraded ''" - SvnCommand command = CommandUtil.execute(myVcs, SvnTarget.fromFile(path), SvnCommandName.upgrade, parameters, null); FileStatusResultParser parser = new FileStatusResultParser(CHANGED_PATH, handler, new UpgradeStatusConvertor()); - parser.parse(command.getOutput()); + UpgradeLineCommandListener listener = new UpgradeLineCommandListener(parser); + + CommandUtil.execute(myVcs, SvnTarget.fromFile(path), SvnCommandName.upgrade, parameters, listener); + listener.throwIfException(); } @Override @@ -80,4 +84,35 @@ public class CmdUpgradeClient extends BaseSvnClient implements UpgradeClient { return result; } } + + private static class UpgradeLineCommandListener extends LineCommandListener { + + @NotNull private final FileStatusResultParser parser; + @NotNull private final AtomicReference exception; + + private UpgradeLineCommandListener(@NotNull FileStatusResultParser parser) { + this.parser = parser; + exception = new AtomicReference(); + } + + @Override + public void onLineAvailable(String line, Key outputType) { + if (ProcessOutputTypes.STDOUT.equals(outputType)) { + try { + parser.onLine(line); + } + catch (VcsException e) { + exception.set(e); + } + } + } + + public void throwIfException() throws VcsException { + VcsException e = exception.get(); + + if (e != null) { + throw e; + } + } + } }
").append(info.getPath()).append("
URL:").append(info.getRootUrl()).append("
Format:").append(info.getFormat().getName()).append("Change