Merge branch 'svn1_8_new'

This commit is contained in:
Konstantin Kolosovsky
2013-09-26 21:27:14 +04:00
14 changed files with 265 additions and 113 deletions
@@ -330,6 +330,7 @@ progress.text2.exported=Exported {1} files, exporting {0}
progress.text2.checked.out.revision=Checked out revision {0}.
progress.text2.exported.revision=Exported revision {0}.
status.text.checked.out.revision=Checked out revision {0}.
message.text.cannot.load.supported.formats=Cannot load supported formats: {0}
message.text.cannot.checkout=Cannot checkout from svn: {0}
message.text.cannot.export=Cannot export from svn: {0}
message.title.check.out=Check Out from Subversion
@@ -17,12 +17,7 @@ package org.jetbrains.idea.svn;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.util.WaitForProgressToShow;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.dialogs.UpgradeFormatDialog;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
@@ -136,22 +131,6 @@ public class SvnFormatSelector implements ISVNAdminAreaFactorySelector {
return result;
}
public static WorkingCopyFormat showUpgradeDialog(final File path,
final Project project,
final boolean display13format,
@NotNull final WorkingCopyFormat defaultSelection,
@NotNull final Ref<Boolean> wasOk) {
assert ! ApplicationManager.getApplication().isUnitTestMode();
final Ref<WorkingCopyFormat> format = new Ref<WorkingCopyFormat>(defaultSelection);
WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(new Runnable() {
public void run() {
wasOk.set(displayUpgradeDialog(project, path, display13format, format));
}
});
ApplicationManager.getApplication().getMessageBus().syncPublisher(SvnVcs.WC_CONVERTED).run();
return format.get();
}
public static WorkingCopyFormat findRootAndGetFormat(final File path) {
File root = SvnUtil.getWorkingCopyRootNew(path);
@@ -189,14 +168,4 @@ public class SvnFormatSelector implements ISVNAdminAreaFactorySelector {
return WorkingCopyFormat.getInstance(format);
}
private static boolean displayUpgradeDialog(Project project, File path, final boolean dispay13format, Ref<WorkingCopyFormat> format) {
UpgradeFormatDialog dialog = new UpgradeFormatDialog(project, path, false);
dialog.setData(format.get());
dialog.show();
if (dialog.isOK()) {
format.set(dialog.getUpgradeMode());
}
return dialog.isOK();
}
}
@@ -647,6 +647,7 @@ public class SvnUtil {
}
public static boolean remoteFolderIsEmpty(final SvnVcs vcs, final String url) throws SVNException {
// TODO: Implement with command line client
SVNRepository repository = null;
try {
repository = vcs.createRepository(url);
@@ -100,4 +100,23 @@ public enum WorkingCopyFormat {
public int getFormat() {
return myFormat;
}
@NotNull
public static WorkingCopyFormat from(@NotNull Version version) {
WorkingCopyFormat result = UNKNOWN;
for (WorkingCopyFormat format : WorkingCopyFormat.values()) {
if (format.getVersion().is(version.major, version.minor)) {
result = format;
break;
}
}
return result;
}
@Override
public String toString() {
return getName();
}
}
@@ -31,18 +31,19 @@ import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.api.ClientFactory;
import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider;
import org.jetbrains.idea.svn.dialogs.ShareDialog;
import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
@@ -104,7 +105,7 @@ public class ShareProjectAction extends BasicAction {
final String parent = shareDialog.getSelectedURL();
if (shareDialog.isOK() && parent != null) {
final Ref<Boolean> actionStarted = new Ref<Boolean>(Boolean.TRUE);
final SVNException[] error = new SVNException[1];
final Exception[] error = new Exception[1];
final ShareDialog.ShareTarget shareTarget = shareDialog.getShareTarget();
final ProgressManager progressManager = ProgressManager.getInstance();
@@ -120,19 +121,23 @@ public class ShareProjectAction extends BasicAction {
}
}
final WorkingCopyFormat format = SvnCheckoutProvider.promptForWCopyFormat(VfsUtilCore.virtualToIoFile(file), project);
actionStarted.set(format != WorkingCopyFormat.UNKNOWN);
// means operation cancelled
if (format == WorkingCopyFormat.UNKNOWN) {
return true;
}
ExclusiveBackgroundVcsAction.run(project, new Runnable() {
public void run() {
progressManager.runProcessWithProgressSynchronously(new Runnable() {
public void run() {
try {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
final File path = new File(file.getPath());
if (! SvnCheckoutProvider.promptForWCFormatAndSelect(path, project)) {
// action cancelled
actionStarted.set(Boolean.FALSE);
return;
}
SvnWorkingCopyFormatHolder.setPresetFormat(format);
final SVNURL parenUrl = SVNURL.parseURIEncoded(parent);
final SVNURL checkoutUrl;
final SVNRevision revision;
@@ -160,16 +165,17 @@ public class ShareProjectAction extends BasicAction {
indicator.checkCanceled();
indicator.setText(SvnBundle.message("share.directory.checkout.back.progress.text", checkoutUrl.toString()));
}
final SVNUpdateClient client = activeVcs.createUpdateClient();
if (! WorkingCopyFormat.ONE_DOT_SEVEN.equals(SvnWorkingCopyFormatHolder.getPresetFormat())) {
client.getOperationsFactory().setPrimaryWcGeneration(SvnWcGeneration.V16);
}
client.doCheckout(checkoutUrl, path, SVNRevision.UNDEFINED, revision, SVNDepth.INFINITY, false);
SvnWorkingCopyFormatHolder.setPresetFormat(null);
addRecursively(activeVcs, file);
final ClientFactory factory = activeVcs.getFactoryFromSettings();
factory.createCheckoutClient()
.checkout(SvnTarget.fromURL(checkoutUrl), path, revision, SVNDepth.INFINITY, false, false, format, null);
addRecursively(activeVcs, factory, file);
} catch (SVNException e) {
error[0] = e;
}
catch (VcsException e) {
error[0] = e;
} finally {
activeVcs.invokeRefreshSvnRoots();
SvnWorkingCopyFormatHolder.setPresetFormat(null);
@@ -226,6 +232,7 @@ public class ShareProjectAction extends BasicAction {
indicator.checkCanceled();
indicator.setText(SvnBundle.message("share.directory.create.dir.progress.text", urlText));
}
// TODO: Implement with command line client
final SVNCommitInfo info =
vcs.createCommitClient().doMkDir(new SVNURL[]{url}, SvnBundle.message("share.directory.commit.message", folderName,
ApplicationNamesInfo.getInstance().getFullProductName(), commitText));
@@ -237,17 +244,17 @@ public class ShareProjectAction extends BasicAction {
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(file);
}
private static void addRecursively(final SvnVcs activeVcs, final VirtualFile file) throws SVNException {
final SVNWCClient wcClient = activeVcs.createWCClient();
private static void addRecursively(@NotNull final SvnVcs activeVcs, @NotNull final ClientFactory factory, final VirtualFile file)
throws VcsException {
final SvnExcludingIgnoredOperation operation = new SvnExcludingIgnoredOperation(activeVcs.getProject(), new SvnExcludingIgnoredOperation.Operation() {
public void doOperation(final VirtualFile virtualFile) throws SVNException {
public void doOperation(final VirtualFile virtualFile) throws VcsException {
final File ioFile = new File(virtualFile.getPath());
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
if (indicator != null) {
indicator.checkCanceled();
indicator.setText(SvnBundle.message("share.or.import.add.progress.text", virtualFile.getPath()));
}
wcClient.doAdd(ioFile, true, false, false, SVNDepth.EMPTY, false, false);
factory.createAddClient().add(ioFile, SVNDepth.EMPTY, false, false, true, null);
}
}, SVNDepth.INFINITY);
@@ -20,13 +20,13 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import org.jetbrains.annotations.NotNull;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
public class SvnExcludingIgnoredOperation {
private final Operation myImportAction;
@@ -79,28 +79,28 @@ public class SvnExcludingIgnoredOperation {
}
}
private boolean operation(final VirtualFile file) throws SVNException {
private boolean operation(final VirtualFile file) throws VcsException {
if (! myFilter.accept(file)) return false;
myImportAction.doOperation(file);
return true;
}
private void executeDown(final VirtualFile file) throws SVNException {
private void executeDown(final VirtualFile file) throws VcsException {
VfsUtilCore.visitChildrenRecursively(file, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
try {
return operation(file);
}
catch (SVNException e) {
catch (VcsException e) {
throw new VisitorException(e);
}
}
}, SVNException.class);
}, VcsException.class);
}
public void execute(final VirtualFile file) throws SVNException {
public void execute(final VirtualFile file) throws VcsException {
if (SVNDepth.INFINITY.equals(myDepth)) {
executeDown(file);
return;
@@ -123,6 +123,6 @@ public class SvnExcludingIgnoredOperation {
}
public interface Operation {
void doOperation(final VirtualFile file) throws SVNException;
void doOperation(final VirtualFile file) throws VcsException;
}
}
@@ -1,9 +1,14 @@
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.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.WorkingCopyFormat;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.util.Collection;
/**
* @author Konstantin Kolosovsky.
*/
@@ -44,4 +49,11 @@ public abstract class BaseSvnClient implements SvnClient {
throw new IllegalArgumentException("Target should be file " + target);
}
}
protected void validateFormat(@NotNull WorkingCopyFormat format, @NotNull Collection<WorkingCopyFormat> supported) throws VcsException {
if (!supported.contains(format)) {
throw new VcsException(
String.format("%s format is not supported. Supported formats are: %s.", format.getName(), StringUtil.join(supported, ",")));
}
}
}
@@ -11,6 +11,7 @@ import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
@@ -22,6 +23,9 @@ public interface CheckoutClient extends SvnClient {
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
boolean ignoreExternals,
@Nullable WorkingCopyFormat format,
boolean force,
@NotNull WorkingCopyFormat format,
@Nullable ISVNEventHandler handler) throws VcsException;
List<WorkingCopyFormat> getSupportedFormats() throws VcsException;
}
@@ -1,5 +1,6 @@
package org.jetbrains.idea.svn.checkout;
import com.intellij.openapi.util.Version;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,22 +28,33 @@ public class CmdCheckoutClient extends BaseSvnClient implements CheckoutClient {
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
boolean ignoreExternals,
@Nullable WorkingCopyFormat format,
boolean force,
@NotNull WorkingCopyFormat format,
@Nullable ISVNEventHandler handler) throws VcsException {
List<String> parameters = new ArrayList<String>();
validateFormat(format, getSupportedFormats());
// TODO: check format
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, source);
CommandUtil.put(parameters, destination, false);
CommandUtil.put(parameters, depth);
CommandUtil.put(parameters, revision);
CommandUtil.put(parameters, ignoreExternals, "--ignore-externals");
parameters.add("--force"); // this is to conform to currently used SVNKit behavior - allowUnversionedObstructions
CommandUtil.put(parameters, force, "--force"); // corresponds to "allowUnversionedObstructions" in SVNKit
run(source, destination, handler, parameters);
}
@Override
public List<WorkingCopyFormat> getSupportedFormats() throws VcsException {
ArrayList<WorkingCopyFormat> result = new ArrayList<WorkingCopyFormat>();
Version version = myFactory.createVersionClient().getVersion();
result.add(WorkingCopyFormat.from(version));
return result;
}
private void run(@NotNull SvnTarget source,
@NotNull File destination,
@Nullable ISVNEventHandler handler,
@@ -17,6 +17,7 @@ package org.jetbrains.idea.svn.checkout;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
@@ -26,6 +27,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.CalledInAwt;
import com.intellij.openapi.vcs.CheckoutProvider;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.VcsException;
@@ -34,6 +36,8 @@ import com.intellij.openapi.vcs.update.RefreshVFsSynchronously;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
@@ -42,6 +46,7 @@ import org.jetbrains.idea.svn.actions.SvnExcludingIgnoredOperation;
import org.jetbrains.idea.svn.checkin.IdeaCommitHandler;
import org.jetbrains.idea.svn.commandLine.CommitEventHandler;
import org.jetbrains.idea.svn.dialogs.CheckoutDialog;
import org.jetbrains.idea.svn.dialogs.UpgradeFormatDialog;
import org.tmatesoft.svn.core.SVNCancelException;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
@@ -51,6 +56,9 @@ import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.swing.*;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class SvnCheckoutProvider implements CheckoutProvider {
@@ -84,19 +92,16 @@ public class SvnCheckoutProvider implements CheckoutProvider {
final Task.Backgroundable checkoutBackgroundTask = new Task.Backgroundable(project,
SvnBundle.message("message.title.check.out"), true, VcsConfiguration.getInstance(project).getCheckoutOption()) {
public void run(@NotNull final ProgressIndicator indicator) {
SvnWorkingCopyFormatHolder.setPresetFormat(selectedFormat);
final WorkingCopyFormat format = selectedFormat == null ? WorkingCopyFormat.UNKNOWN : selectedFormat;
SvnWorkingCopyFormatHolder.setPresetFormat(format);
SvnVcs vcs = SvnVcs.getInstance(project);
// TODO: made this way to preserve existing logic, but probably this check could be omitted as setPresetFormat(selectedFormat) invoked above
WorkingCopyFormat format = !WorkingCopyFormat.ONE_DOT_SEVEN.equals(SvnWorkingCopyFormatHolder.getPresetFormat())
? WorkingCopyFormat.ONE_DOT_SIX
: selectedFormat;
ISVNEventHandler handler = new CheckoutEventHandler(vcs, false, ProgressManager.getInstance().getProgressIndicator());
ProgressManager.progress(SvnBundle.message("progress.text.checking.out", target.getAbsolutePath()));
try {
// TODO: probably rewrite some logic to force ClientFactory provide supported versions (or create special client for that)
vcs.getFactoryFromSettings().createCheckoutClient()
.checkout(SvnTarget.fromURL(SVNURL.parseURIEncoded(url)), target, revision, depth, ignoreExternals, format, handler);
.checkout(SvnTarget.fromURL(SVNURL.parseURIEncoded(url)), target, revision, depth, ignoreExternals, true, format, handler);
ProgressManager.checkCanceled();
checkoutSuccessful.set(Boolean.TRUE);
}
@@ -168,22 +173,10 @@ public class SvnCheckoutProvider implements CheckoutProvider {
}
}
public static boolean promptForWCFormatAndSelect(final File target, final Project project) {
final WorkingCopyFormat result = promptForWCopyFormat(target, project);
if (result != WorkingCopyFormat.UNKNOWN) {
SvnWorkingCopyFormatHolder.setPresetFormat(result);
}
return result != WorkingCopyFormat.UNKNOWN;
}
@CalledInAwt
@NotNull
private static WorkingCopyFormat promptForWCopyFormat(final File target, final Project project) {
WorkingCopyFormat format = WorkingCopyFormat.UNKNOWN;
final Ref<Boolean> wasOk = new Ref<Boolean>();
while ((format == WorkingCopyFormat.UNKNOWN) && (! Boolean.FALSE.equals(wasOk.get()))) {
format = SvnFormatSelector.showUpgradeDialog(target, project, true, WorkingCopyFormat.ONE_DOT_SEVEN, wasOk);
}
return Boolean.TRUE.equals(wasOk.get()) ? format : WorkingCopyFormat.UNKNOWN;
public static WorkingCopyFormat promptForWCopyFormat(final File target, final Project project) {
return new CheckoutFormatFromUserProvider(project, target).prompt();
}
public static void doExport(final Project project, final File target, final SVNURL url, final SVNDepth depth,
@@ -286,6 +279,79 @@ public class SvnCheckoutProvider implements CheckoutProvider {
return "_Subversion";
}
}
public static class CheckoutFormatFromUserProvider {
@NotNull private final Project myProject;
@NotNull private final SvnVcs myVcs;
@NotNull private final File myPath;
@NotNull private final AtomicReference<String> error;
public CheckoutFormatFromUserProvider(@NotNull Project project, @NotNull File path) {
myProject = project;
myVcs = SvnVcs.getInstance(project);
myPath = path;
error = new AtomicReference<String>();
}
@CalledInAwt
public WorkingCopyFormat prompt() {
assert !ApplicationManager.getApplication().isUnitTestMode();
final WorkingCopyFormat result = displayUpgradeDialog(WorkingCopyFormat.ONE_DOT_SEVEN);
ApplicationManager.getApplication().getMessageBus().syncPublisher(SvnVcs.WC_CONVERTED).run();
return result;
}
private WorkingCopyFormat displayUpgradeDialog(@NotNull WorkingCopyFormat defaultSelection) {
final UpgradeFormatDialog dialog = new UpgradeFormatDialog(myProject, myPath, false);
dialog.startLoading();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
final List<WorkingCopyFormat> formats = loadSupportedFormats();
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
final String errorMessage = error.get();
if (errorMessage != null) {
dialog.doCancelAction();
Messages.showErrorDialog(SvnBundle.message("message.text.cannot.load.supported.formats", errorMessage),
SvnBundle.message("message.title.check.out"));
}
else {
dialog.setSupported(formats);
dialog.setData(ContainerUtil.getFirstItem(formats, WorkingCopyFormat.UNKNOWN));
dialog.stopLoading();
}
}
}, ModalityState.stateForComponent(dialog.getWindow()));
}
});
dialog.show();
return dialog.isOK() ? dialog.getUpgradeMode() : WorkingCopyFormat.UNKNOWN;
}
private List<WorkingCopyFormat> loadSupportedFormats() {
List<WorkingCopyFormat> result;
try {
result = myVcs.getFactoryFromSettings().createCheckoutClient().getSupportedFormats();
}
catch (VcsException e) {
result = Collections.emptyList();
error.set(e.getMessage());
}
return result;
}
}
}
@@ -15,30 +15,41 @@ import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitCheckoutClient extends BaseSvnClient implements CheckoutClient {
private static final List<WorkingCopyFormat> SUPPORTED_FORMATS;
static {
List<WorkingCopyFormat> supportedFormats = new ArrayList<WorkingCopyFormat>();
supportedFormats.add(WorkingCopyFormat.ONE_DOT_SEVEN);
supportedFormats.add(WorkingCopyFormat.ONE_DOT_SIX);
SUPPORTED_FORMATS = Collections.unmodifiableList(supportedFormats);
}
@Override
public void checkout(@NotNull SvnTarget source,
@NotNull File destination,
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
boolean ignoreExternals,
@Nullable WorkingCopyFormat format,
boolean force,
@NotNull WorkingCopyFormat format,
@Nullable ISVNEventHandler handler) throws VcsException {
assertUrl(source);
if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) {
throw new IllegalArgumentException("could not check out 1.8 format with SVNKit");
}
validateFormat(format, getSupportedFormats());
SVNUpdateClient client = myVcs.createUpdateClient();
// TODO: most likely we should compare directly with WorkingCopyFormat.ONE_DOT_SIX
if (!WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) {
if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) {
client.getOperationsFactory().setPrimaryWcGeneration(SvnWcGeneration.V16);
}
@@ -46,10 +57,15 @@ public class SvnKitCheckoutClient extends BaseSvnClient implements CheckoutClien
client.setEventHandler(handler);
try {
client.doCheckout(source.getURL(), destination, source.getPegRevision(), revision, depth, true);
client.doCheckout(source.getURL(), destination, source.getPegRevision(), revision, depth, force);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
@Override
public List<WorkingCopyFormat> getSupportedFormats() throws VcsException {
return SUPPORTED_FORMATS;
}
}
@@ -42,6 +42,7 @@ public abstract class SvnCommand {
private final File myConfigDir;
private boolean myIsDestroyed;
private boolean myNeedsDestroy;
private int myExitCode;
protected final GeneralCommandLine myCommandLine;
private final File myWorkingDirectory;
@@ -210,13 +211,31 @@ public abstract class SvnCommand {
public void destroyProcess() {
synchronized (myLock) {
if (! myIsDestroyed) {
myNeedsDestroy = true;
}
}
/**
* ProcessHandler.destroyProcess() implementations could acquire read lock in its implementation - like OSProcessManager.getInstance().
* Some commands are called under write lock - which is generally bad idea, but such logic is not refactored yet.
* To prevent deadlocks this method should only be called from thread that started the process.
*/
public void doDestroyProcess() {
synchronized (myLock) {
if (!myIsDestroyed) {
LOG.info("Destroying process by command: " + getCommandText());
myIsDestroyed = true;
myHandler.destroyProcess();
}
}
}
public boolean needsDestroy() {
synchronized (myLock) {
return myNeedsDestroy;
}
}
public String getCommandText() {
synchronized (myLock) {
return myCommandLine.getCommandLineString();
@@ -62,7 +62,8 @@ public class SvnLineCommand extends SvnCommand {
public static final String AUTHENTICATION_REALM = "Authentication realm:";
public static final String CERTIFICATE_ERROR = "Error validating server certificate for";
public static final String PASSPHRASE_FOR = "Passphrase for";
public static final String UNABLE_TO_CONNECT = "svn: E170001:";
public static final String UNABLE_TO_CONNECT_CODE = "svn: E170001:";
public static final String UNABLE_TO_CONNECT_MESSAGE = "Unable to connect to a repository";
public static final String CANNOT_AUTHENTICATE_TO_PROXY = "Could not authenticate to proxy server";
public static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed";
@@ -216,7 +217,7 @@ public class SvnLineCommand extends SvnCommand {
if (errText.startsWith(PASSPHRASE_FOR)) {
return new PassphraseCallback(callback, url);
}
if (errText.startsWith(UNABLE_TO_CONNECT) && errText.contains(CANNOT_AUTHENTICATE_TO_PROXY)) {
if (errText.startsWith(UNABLE_TO_CONNECT_CODE) && errText.contains(CANNOT_AUTHENTICATE_TO_PROXY)) {
return new ProxyCallback(callback, url);
}
// http/https protocol invalid credentials
@@ -228,6 +229,10 @@ public class SvnLineCommand extends SvnCommand {
// svn protocol invalid credentials
return new UsernamePasswordCallback(callback, url);
}
// http/https protocol, svn 1.7, non-interactive
if (errText.contains(UNABLE_TO_CONNECT_MESSAGE)) {
return new UsernamePasswordCallback(callback, url);
}
// https one-way protocol untrusted server certificate
if (errText.contains(UNTRUSTED_SERVER_CERTIFICATE)) {
return new CertificateCallbackCase(callback, url);
@@ -469,23 +474,13 @@ public class SvnLineCommand extends SvnCommand {
final String trim = text.trim();
// should end in 1 second
errorReceived.set(true);
// TODO: destroy process here is called despite --non-interactive flag (so it is called even for 1.8) and then unnecessary
// TODO: cleanup is invoked - fix this
if (trim.startsWith(UNABLE_TO_CONNECT)) {
// wait for 3 lines of text then
if (myErrCnt >= 3) {
destroyProcess();
}
} else if (trim.startsWith(PASSPHRASE_FOR) || myErrCnt >= 2) {
destroyProcess();
}
}
super.onTextAvailable(text, outputType);
}
};
//command.addParameters("--non-interactive");
command.addParameters(parameters);
command.addParameters("--non-interactive");
final AtomicReference<Throwable> exceptionRef = new AtomicReference<Throwable>();
// several threads
command.addLineListener(new LineProcessEventListener() {
@@ -503,6 +498,7 @@ public class SvnLineCommand extends SvnCommand {
}
listener.onLineAvailable(line, outputType);
if (listener.isCanceled()) {
LOG.info("Cancelling command: " + command.getCommandText());
command.destroyProcess();
return;
}
@@ -530,9 +526,9 @@ public class SvnLineCommand extends SvnCommand {
boolean finished;
do {
finished = command.waitFor(500);
if (!finished && errorReceived.get()) {
if (!finished && (errorReceived.get() || command.needsDestroy())) {
command.waitFor(1000);
command.destroyProcess();
command.doDestroyProcess();
break;
}
}
@@ -19,6 +19,7 @@ import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MultiLineLabelUI;
import com.intellij.ui.components.JBLoadingPanel;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,6 +31,7 @@ import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class UpgradeFormatDialog extends DialogWrapper {
@@ -37,6 +39,8 @@ public class UpgradeFormatDialog extends DialogWrapper {
private ButtonGroup formatGroup = new ButtonGroup();
private List<JRadioButton> formatButtons = new ArrayList<JRadioButton>();
private JBLoadingPanel myLoadingPanel;
protected File myPath;
public UpgradeFormatDialog(Project project, File path, boolean canBeParent) {
@@ -64,7 +68,7 @@ public class UpgradeFormatDialog extends DialogWrapper {
return "svn.upgradeDialog";
}
public void setData(final WorkingCopyFormat selectedFormat) {
public void setData(@NotNull final WorkingCopyFormat selectedFormat) {
for (JRadioButton button : formatButtons) {
if (selectedFormat == getFormat(button)) {
button.setSelected(true);
@@ -73,6 +77,29 @@ public class UpgradeFormatDialog extends DialogWrapper {
}
}
public void setSupported(@NotNull Collection<WorkingCopyFormat> supported) {
for (JRadioButton button : formatButtons) {
button.setEnabled(supported.contains(getFormat(button)));
}
}
public void startLoading() {
enableFormatButtons(false);
getOKAction().setEnabled(false);
myLoadingPanel.startLoading();
}
private void enableFormatButtons(boolean enabled) {
for (JRadioButton button : formatButtons) {
button.setEnabled(enabled);
}
}
public void stopLoading() {
getOKAction().setEnabled(true);
myLoadingPanel.stopLoading();
}
protected String getTopMessage(final String label) {
return SvnBundle.message("label.configure." + label + ".label", ApplicationNamesInfo.getInstance().getFullProductName());
}
@@ -115,7 +142,10 @@ public class UpgradeFormatDialog extends DialogWrapper {
gb.gridy += 1;
}
return panel;
myLoadingPanel = new JBLoadingPanel(new BorderLayout(), getDisposable());
myLoadingPanel.add(panel, BorderLayout.CENTER);
return myLoadingPanel;
}
private void registerFormat(@NotNull WorkingCopyFormat format,