Merge branch 'svn1_8_new'

This commit is contained in:
Konstantin Kolosovsky
2013-09-10 14:15:47 +04:00
29 changed files with 771 additions and 254 deletions
@@ -18,11 +18,10 @@ package org.jetbrains.idea.svn;
import com.intellij.openapi.vcs.EditFileProvider;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperty;
import org.jetbrains.idea.svn.properties.PropertyClient;
import org.tmatesoft.svn.core.wc.SVNPropertyData;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
@@ -38,18 +37,16 @@ public class SvnEditFileProvider implements EditFileProvider {
public void editFiles(VirtualFile[] files) throws VcsException {
File[] ioFiles = new File[files.length];
SVNWCClient client = myVCS.createWCClient();
for (int i = 0; i < files.length; i++) {
ioFiles[i] = new File(files[i].getPath());
try {
SVNPropertyData property = client
.doGetProperty(ioFiles[i], SVNProperty.NEEDS_LOCK, SVNRevision.WORKING, SVNRevision.WORKING);
if (property == null || property.getValue() == null) {
throw new VcsException(SvnBundle.message("exception.text.file.miss.svn", ioFiles[i].getName()));
}
}
catch (SVNException e) {
throw new VcsException(e);
PropertyClient client = myVCS.getFactory(ioFiles[i]).createPropertyClient();
SVNPropertyData property = client.getProperty(SvnTarget.fromFile(ioFiles[i], SVNRevision.WORKING), SvnPropertyKeys.SVN_NEEDS_LOCK,
false, SVNRevision.WORKING);
if (property == null || property.getValue() == null) {
throw new VcsException(SvnBundle.message("exception.text.file.miss.svn", ioFiles[i].getName()));
}
}
SvnUtil.doLockFiles(myVCS.getProject(), myVCS, ioFiles);
@@ -143,12 +143,18 @@ public class SvnRecursiveStatusWalker {
}
public SvnStatusClientI getClient(final File file) {
// TODO: refactor to ClientFactory usage but carefully save all parameters passed in myClient - fileProvider and
// TODO: event handler (for cancel support)
WorkingCopyFormat format = myVcs.getWorkingCopyFormat(file);
if (format == WorkingCopyFormat.ONE_DOT_EIGHT) {
return myCommandLineClient;
}
if (format == WorkingCopyFormat.ONE_DOT_SIX) {
return mySvnClient;
}
// check format
if (CheckJavaHL.isPresent() && SvnConfiguration.UseAcceleration.javaHL.equals(myConfiguration17.myUseAcceleration) &&
Svn17Detector.is17(myProject, file)) {
@@ -30,7 +30,10 @@ import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangesUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.Convertor;
@@ -55,6 +58,8 @@ import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SvnUtil {
// TODO: ASP.NET hack behavior should be supported - http://svn.apache.org/repos/asf/subversion/trunk/notes/asp-dot-net-hack.txt
@@ -66,8 +71,25 @@ public class SvnUtil {
@NonNls public static final String PATH_TO_LOCK_FILE = SVN_ADMIN_DIR_NAME + "/lock";
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnUtil");
public static final Pattern ERROR_PATTERN = Pattern.compile("^svn: (E(\\d+)): (.*)$", Pattern.MULTILINE);
public static final Pattern WARNING_PATTERN = Pattern.compile("^svn: warning: (W(\\d+)): (.*)$", Pattern.MULTILINE);
private SvnUtil() { }
@Nullable
public static SVNErrorMessage parseWarning(@NotNull String text) {
Matcher matcher = WARNING_PATTERN.matcher(text);
SVNErrorMessage error = null;
// currently treating only first warning
if (matcher.find()) {
error = SVNErrorMessage
.create(SVNErrorCode.getErrorCode(Integer.parseInt(matcher.group(2))), matcher.group(3), SVNErrorMessage.TYPE_WARNING);
}
return error;
}
public static boolean isSvnVersioned(final Project project, File parent) {
final SVNInfo info = SvnVcs.getInstance(project).getInfo(parent);
@@ -145,7 +167,7 @@ public class SvnUtil {
force = false;
}
final SVNException[] exception = new SVNException[1];
final VcsException[] exception = new VcsException[1];
final Collection<String> failedLocks = new ArrayList<String>();
final int[] count = new int[]{ioFiles.length};
final ISVNEventHandler eventHandler = new ISVNEventHandler() {
@@ -165,11 +187,8 @@ public class SvnUtil {
Runnable command = new Runnable() {
public void run() {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
SVNWCClient wcClient;
try {
wcClient = activeVcs.createWCClient();
wcClient.setEventHandler(eventHandler);
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.locking.files"));
}
@@ -180,10 +199,10 @@ public class SvnUtil {
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
}
wcClient.doLock(new File[]{ioFile}, force, lockMessage);
activeVcs.getFactory(ioFile).createLockClient().lock(ioFile, force, lockMessage, eventHandler);
}
}
catch (SVNException e) {
catch (VcsException e) {
exception[0] = e;
}
}
@@ -207,13 +226,13 @@ public class SvnUtil {
StatusBarUtil.setStatusBarInfo(project, SvnBundle.message("message.text.files.locked", count[0]));
if (exception[0] != null) {
throw new VcsException(exception[0]);
throw exception[0];
}
}
public static void doUnlockFiles(Project project, final SvnVcs activeVcs, final File[] ioFiles) throws VcsException {
final boolean force = true;
final SVNException[] exception = new SVNException[1];
final VcsException[] exception = new VcsException[1];
final Collection<String> failedUnlocks = new ArrayList<String>();
final int[] count = new int[]{ioFiles.length};
final ISVNEventHandler eventHandler = new ISVNEventHandler() {
@@ -233,11 +252,8 @@ public class SvnUtil {
Runnable command = new Runnable() {
public void run() {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
SVNWCClient wcClient;
try {
wcClient = activeVcs.createWCClient();
wcClient.setEventHandler(eventHandler);
if (progress != null) {
progress.setText(SvnBundle.message("progress.text.unlocking.files"));
}
@@ -248,10 +264,10 @@ public class SvnUtil {
if (progress != null) {
progress.setText2(SvnBundle.message("progress.text2.processing.file", ioFile.getName()));
}
wcClient.doUnlock(new File[]{ioFile}, force);
activeVcs.getFactory(ioFile).createLockClient().unlock(ioFile, force, eventHandler);
}
}
catch (SVNException e) {
catch (VcsException e) {
exception[0] = e;
}
}
@@ -362,7 +362,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
public boolean checkCommandLineVersion() {
boolean isValid = true;
if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration) || isProject18()) {
if (!isProject16() && (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration) || isProject18())) {
isValid = myChecker.checkExecutableAndNotifyIfNeeded();
}
@@ -892,7 +892,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
public boolean fileExistsInVcs(FilePath path) {
File file = path.getIOFile();
try {
SVNStatus status = createStatusClient().doStatus(file, false);
SVNStatus status = getFactory(file).createStatusClient().doStatus(file, false);
if (status != null) {
if (svnStatusIs(status, SVNStatusType.STATUS_ADDED)) {
return status.isCopied();
@@ -903,7 +903,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
}
}
catch (SVNException e) {
//
LOG.info(e);
}
return false;
}
@@ -1341,10 +1341,20 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
}
public boolean isProject18() {
return WorkingCopyFormat.ONE_DOT_EIGHT.equals(getWorkingCopyFormat(new File(getProject().getBaseDir().getPath())));
return WorkingCopyFormat.ONE_DOT_EIGHT.equals(getProjectRootFormat());
}
public boolean isProject16() {
return WorkingCopyFormat.ONE_DOT_SIX.equals(getProjectRootFormat());
}
private WorkingCopyFormat getProjectRootFormat() {
return getWorkingCopyFormat(new File(getProject().getBaseDir().getPath()));
}
/**
* Detects appropriate client factory based on project root directory working copy format.
*
* Try to avoid usages of this method (for now) as it could not correctly for all cases
* detect svn 1.8 working copy format to guarantee command line client.
*
@@ -1355,18 +1365,23 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
*/
@NotNull
public ClientFactory getFactory() {
// check working copy format of project directory
return isProject18() ? cmdClientFactory : getFactoryFromSettings();
return getFactory(getProjectRootFormat(), false);
}
@NotNull
public ClientFactory getFactory(@NotNull File file) {
WorkingCopyFormat format = getWorkingCopyFormat(file);
return getFactory(getWorkingCopyFormat(file), true);
}
@NotNull
private ClientFactory getFactory(@NotNull WorkingCopyFormat format, boolean useProjectRootForUnknown) {
boolean is18 = WorkingCopyFormat.ONE_DOT_EIGHT.equals(format);
boolean is16 = WorkingCopyFormat.ONE_DOT_SIX.equals(format);
boolean isUnknown = WorkingCopyFormat.UNKNOWN.equals(format);
return is18 ? cmdClientFactory : (isUnknown ? getFactory() : getFactoryFromSettings());
return is18
? cmdClientFactory
: (is16 ? svnKitClientFactory : (useProjectRootForUnknown && isUnknown ? getFactory() : getFactoryFromSettings()));
}
@NotNull
@@ -1375,7 +1390,7 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
}
@NotNull
private ClientFactory getFactoryFromSettings() {
public ClientFactory getFactoryFromSettings() {
return myConfiguration.myUseAcceleration.equals(SvnConfiguration.UseAcceleration.commandLine) ? cmdClientFactory : svnKitClientFactory;
}
}
@@ -28,9 +28,9 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.dialogs.SetPropertyDialog;
import org.tmatesoft.svn.core.SVNException;
import org.jetbrains.idea.svn.properties.PropertyClient;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import java.io.File;
@@ -73,15 +73,13 @@ public class SetPropertyAction extends BasicAction {
String value = dialog.getPropertyValue();
boolean recursive = dialog.isRecursive();
SVNWCClient wcClient = activeVcs.createWCClient();
for (int i = 0; i < ioFiles.length; i++) {
File ioFile = ioFiles[i];
try {
wcClient.doSetProperty(ioFile, name, SVNPropertyValue.create(value), false, recursive, null);
}
catch (SVNException e) {
throw new VcsException(e);
}
PropertyClient client = activeVcs.getFactory(ioFile).createPropertyClient();
// TODO: most likely SVNDepth.getInfinityOrEmptyDepth should be used instead of SVNDepth.fromRecursive - to have either "infinity"
// TODO: or "empty" depth, and not "infinity" or "files" depth. But previous logic used SVNDepth.fromRecursive implicitly
client.setProperty(ioFile, name, SVNPropertyValue.create(value), SVNDepth.fromRecurse(recursive), false);
}
for(int i = 0; i < file.length; i++) {
if (recursive && file[i].isDirectory()) {
@@ -5,12 +5,14 @@ import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.add.AddClient;
import org.jetbrains.idea.svn.annotate.AnnotateClient;
import org.jetbrains.idea.svn.change.ChangeListClient;
import org.jetbrains.idea.svn.checkout.CheckoutClient;
import org.jetbrains.idea.svn.conflict.ConflictClient;
import org.jetbrains.idea.svn.content.ContentClient;
import org.jetbrains.idea.svn.copy.CopyMoveClient;
import org.jetbrains.idea.svn.delete.DeleteClient;
import org.jetbrains.idea.svn.history.HistoryClient;
import org.jetbrains.idea.svn.integrate.MergeClient;
import org.jetbrains.idea.svn.lock.LockClient;
import org.jetbrains.idea.svn.portable.SvnStatusClientI;
import org.jetbrains.idea.svn.portable.SvnWcClientI;
import org.jetbrains.idea.svn.properties.PropertyClient;
@@ -37,6 +39,8 @@ public abstract class ClientFactory {
protected PropertyClient propertyClient;
protected MergeClient mergeClient;
protected ChangeListClient changeListClient;
protected CheckoutClient checkoutClient;
protected LockClient myLockClient;
protected ClientFactory(@NotNull SvnVcs vcs) {
myVcs = vcs;
@@ -112,6 +116,16 @@ public abstract class ClientFactory {
return prepare(changeListClient);
}
@NotNull
public CheckoutClient createCheckoutClient() {
return prepare(checkoutClient);
}
@NotNull
public LockClient createLockClient() {
return prepare(myLockClient);
}
@NotNull
protected <T extends SvnClient> T prepare(@NotNull T client) {
client.setVcs(myVcs);
@@ -5,6 +5,7 @@ import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.add.CmdAddClient;
import org.jetbrains.idea.svn.annotate.CmdAnnotateClient;
import org.jetbrains.idea.svn.change.CmdChangeListClient;
import org.jetbrains.idea.svn.checkout.CmdCheckoutClient;
import org.jetbrains.idea.svn.commandLine.SvnCommandLineInfoClient;
import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient;
import org.jetbrains.idea.svn.conflict.CmdConflictClient;
@@ -13,6 +14,7 @@ import org.jetbrains.idea.svn.copy.CmdCopyMoveClient;
import org.jetbrains.idea.svn.delete.CmdDeleteClient;
import org.jetbrains.idea.svn.history.CmdHistoryClient;
import org.jetbrains.idea.svn.integrate.CmdMergeClient;
import org.jetbrains.idea.svn.lock.CmdLockClient;
import org.jetbrains.idea.svn.properties.CmdPropertyClient;
import org.jetbrains.idea.svn.revert.CmdRevertClient;
@@ -38,6 +40,8 @@ public class CmdClientFactory extends ClientFactory {
propertyClient = new CmdPropertyClient();
mergeClient = new CmdMergeClient();
changeListClient = new CmdChangeListClient();
checkoutClient = new CmdCheckoutClient();
myLockClient = new CmdLockClient();
statusClient = new SvnCommandLineStatusClient(myVcs.getProject());
infoClient = new SvnCommandLineInfoClient(myVcs.getProject());
}
@@ -5,12 +5,14 @@ import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.add.SvnKitAddClient;
import org.jetbrains.idea.svn.annotate.SvnKitAnnotateClient;
import org.jetbrains.idea.svn.change.SvnKitChangeListClient;
import org.jetbrains.idea.svn.checkout.SvnKitCheckoutClient;
import org.jetbrains.idea.svn.conflict.SvnKitConflictClient;
import org.jetbrains.idea.svn.content.SvnKitContentClient;
import org.jetbrains.idea.svn.copy.SvnKitCopyMoveClient;
import org.jetbrains.idea.svn.delete.SvnKitDeleteClient;
import org.jetbrains.idea.svn.history.SvnKitHistoryClient;
import org.jetbrains.idea.svn.integrate.SvnKitMergeClient;
import org.jetbrains.idea.svn.lock.SvnKitLockClient;
import org.jetbrains.idea.svn.portable.SvnkitSvnStatusClient;
import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient;
import org.jetbrains.idea.svn.properties.SvnKitPropertyClient;
@@ -38,6 +40,8 @@ public class SvnKitClientFactory extends ClientFactory {
propertyClient = new SvnKitPropertyClient();
mergeClient = new SvnKitMergeClient();
changeListClient = new SvnKitChangeListClient();
checkoutClient = new SvnKitCheckoutClient();
myLockClient = new SvnKitLockClient();
statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient());
infoClient = new SvnkitSvnWcClient(myVcs);
}
@@ -0,0 +1,27 @@
package org.jetbrains.idea.svn.checkout;
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.SVNDepth;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface CheckoutClient extends SvnClient {
void checkout(@NotNull SvnTarget source,
@NotNull File destination,
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
boolean ignoreExternals,
@Nullable WorkingCopyFormat format,
@Nullable ISVNEventHandler handler) throws VcsException;
}
@@ -0,0 +1,53 @@
package org.jetbrains.idea.svn.checkout;
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.commandLine.BaseUpdateCommandListener;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
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;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdCheckoutClient extends BaseSvnClient implements CheckoutClient {
@Override
public void checkout(@NotNull SvnTarget source,
@NotNull File destination,
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
boolean ignoreExternals,
@Nullable WorkingCopyFormat format,
@Nullable ISVNEventHandler handler) throws VcsException {
List<String> parameters = new ArrayList<String>();
// TODO: check format
CommandUtil.put(parameters, source);
CommandUtil.put(parameters, destination);
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
run(destination, handler, parameters);
}
private void run(@NotNull File destination, @Nullable ISVNEventHandler handler, @NotNull List<String> parameters) throws VcsException {
BaseUpdateCommandListener listener = new BaseUpdateCommandListener(destination, handler);
CommandUtil.execute(myVcs, SvnCommandName.checkout, parameters, null, listener);
listener.throwWrappedIfException();
}
}
@@ -28,6 +28,7 @@ import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.CheckoutProvider;
import com.intellij.openapi.vcs.VcsConfiguration;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.ex.ProjectLevelVcsManagerEx;
import com.intellij.openapi.vcs.update.RefreshVFsSynchronously;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -42,8 +43,8 @@ import org.tmatesoft.svn.core.SVNCancelException;
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.*;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.swing.*;
import java.io.File;
@@ -78,24 +79,23 @@ public class SvnCheckoutProvider implements CheckoutProvider {
final boolean ignoreExternals,
final Listener listener, final WorkingCopyFormat selectedFormat) {
final Ref<Boolean> checkoutSuccessful = new Ref<Boolean>();
final SVNException[] exception = new SVNException[1];
final Exception[] exception = new Exception[1];
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 SVNUpdateClient client = SvnVcs.getInstance(project).createUpdateClient();
if (! WorkingCopyFormat.ONE_DOT_SEVEN.equals(selectedFormat)) {
client.getOperationsFactory().setPrimaryWcGeneration(SvnWcGeneration.V16);
}
client.setEventHandler(new CheckoutEventHandler(SvnVcs.getInstance(project), false, ProgressManager.getInstance().getProgressIndicator()));
client.setIgnoreExternals(ignoreExternals);
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 {
ProgressManager.progress(SvnBundle.message("progress.text.checking.out", target.getAbsolutePath()));
if (! WorkingCopyFormat.ONE_DOT_SEVEN.equals(SvnWorkingCopyFormatHolder.getPresetFormat())) {
client.getOperationsFactory().setPrimaryWcGeneration(SvnWcGeneration.V16);
}
client.doCheckout(SVNURL.parseURIEncoded(url), target, SVNRevision.UNDEFINED, revision, depth, true);
// 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);
ProgressManager.checkCanceled();
checkoutSuccessful.set(Boolean.TRUE);
}
@@ -104,9 +104,10 @@ public class SvnCheckoutProvider implements CheckoutProvider {
catch (SVNException e) {
exception[0] = e;
}
catch (VcsException e) {
exception[0] = e;
}
finally {
client.setIgnoreExternals(false);
client.setEventHandler(null);
SvnWorkingCopyFormatHolder.setPresetFormat(null);
}
}
@@ -0,0 +1,55 @@
package org.jetbrains.idea.svn.checkout;
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.commandLine.SvnBindException;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNUpdateClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitCheckoutClient extends BaseSvnClient implements CheckoutClient {
@Override
public void checkout(@NotNull SvnTarget source,
@NotNull File destination,
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
boolean ignoreExternals,
@Nullable 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");
}
SVNUpdateClient client = myVcs.createUpdateClient();
// TODO: most likely we should compare directly with WorkingCopyFormat.ONE_DOT_SIX
if (!WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) {
client.getOperationsFactory().setPrimaryWcGeneration(SvnWcGeneration.V16);
}
client.setIgnoreExternals(ignoreExternals);
client.setEventHandler(handler);
try {
client.doCheckout(source.getURL(), destination, source.getPegRevision(), revision, depth, true);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
}
@@ -0,0 +1,80 @@
package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNEvent;
import java.io.File;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Konstantin Kolosovsky.
*/
public class BaseUpdateCommandListener extends LineCommandListener {
@NotNull
private final UpdateOutputLineConverter converter;
@Nullable
private final ISVNEventHandler handler;
@NotNull
private final AtomicReference<SVNException> exception;
public BaseUpdateCommandListener(@NotNull File base, @Nullable ISVNEventHandler handler) {
this.handler = handler;
this.converter = new UpdateOutputLineConverter(base);
exception = new AtomicReference<SVNException>();
}
@Override
public void baseDirectory(File file) {
}
@Override
public void onLineAvailable(String line, Key outputType) {
if (ProcessOutputTypes.STDOUT.equals(outputType)) {
final SVNEvent event = converter.convert(line);
if (event != null) {
beforeHandler(event);
try {
callHandler(event);
}
catch (SVNException e) {
cancel();
exception.set(e);
}
}
}
}
private void callHandler(SVNEvent event) throws SVNException {
if (handler != null) {
handler.handleEvent(event, 0.5);
}
}
public void throwIfException() throws SVNException {
SVNException e = exception.get();
if (e != null) {
throw e;
}
}
public void throwWrappedIfException() throws VcsException {
SVNException e = exception.get();
if (e != null) {
throw new VcsException(e);
}
}
protected void beforeHandler(@NotNull SVNEvent event) {
}
}
@@ -21,12 +21,12 @@ import com.intellij.util.LineSeparator;
import com.intellij.util.containers.hash.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnUtil;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created with IntelliJ IDEA.
@@ -38,8 +38,6 @@ import java.util.regex.Pattern;
*/
public class SvnBindException extends VcsException {
private static final Pattern ERROR_PATTERN = Pattern.compile("^svn: (E(\\d+)): (.*)$", Pattern.MULTILINE);
private Map<Integer, String> errors = new HashMap<Integer, String>();
public SvnBindException(String message) {
@@ -70,7 +68,7 @@ public class SvnBindException extends VcsException {
}
private void parseErrors(@NotNull String message) {
Matcher matcher = ERROR_PATTERN.matcher(message);
Matcher matcher = SvnUtil.ERROR_PATTERN.matcher(message);
while (matcher.find()) {
put(Integer.valueOf(matcher.group(2)), matcher.group());
@@ -143,6 +143,10 @@ public abstract class SvnCommand {
return outputAdapter.getOutput().getStdout();
}
public String getErrorOutput() {
return outputAdapter.getOutput().getStderr();
}
/**
* Wait for process termination
* @param timeout
@@ -15,12 +15,11 @@
*/
package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnApplicationSettings;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback;
@@ -88,54 +87,8 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
base = base.isDirectory() ? base : base.getParentFile();
final List<String> parameters = prepareParameters(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, makeParents);
final AtomicReference<SVNException> excRef = new AtomicReference<SVNException>();
final ISVNEventHandler handler = getEventHandler();
final UpdateOutputLineConverter converter = new UpdateOutputLineConverter(base);
final BaseUpdateCommandListener listener = createCommandListener(paths, updatedToRevision, base);
try {
final LineCommandListener listener = new LineCommandListener() {
final long[] myRevisions = new long[paths.length];
@Override
public void baseDirectory(File file) {
}
@Override
public void onLineAvailable(String line, Key outputType) {
if (ProcessOutputTypes.STDOUT.equals(outputType)) {
final SVNEvent event = converter.convert(line);
if (event != null) {
checkForUpdateCompleted(event);
try {
handler.handleEvent(event, 0.5);
}
catch (SVNException e) {
cancel();
excRef.set(e);
}
}
}
}
private void checkForUpdateCompleted(SVNEvent event) {
if (SVNEventAction.UPDATE_COMPLETED.equals(event.getAction())) {
final long eventRevision = event.getRevision();
for (int i = 0; i < paths.length; i++) {
final File path = paths[i];
if (FileUtil.filesEqual(path, event.getFile())) {
myRevisions[i] = eventRevision;
break;
}
}
}
}
@Override
public void processTerminated(int exitCode) {
super.processTerminated(exitCode);
updatedToRevision.set(myRevisions);
}
};
SvnLineCommand.runWithAuthenticationAttempt(SvnApplicationSettings.getInstance().getCommandLinePath(),
base, info.getURL(), SvnCommandName.up, listener,
new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)),
@@ -144,13 +97,40 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
catch (SvnBindException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e));
}
if (excRef.get() != null) {
throw excRef.get();
}
listener.throwIfException();
return updatedToRevision.get();
}
private BaseUpdateCommandListener createCommandListener(final File[] paths,
final AtomicReference<long[]> updatedToRevision,
final File base) {
return new BaseUpdateCommandListener(base, getEventHandler()) {
final long[] myRevisions = new long[paths.length];
@Override
protected void beforeHandler(@NotNull SVNEvent event) {
if (SVNEventAction.UPDATE_COMPLETED.equals(event.getAction())) {
final long eventRevision = event.getRevision();
for (int i = 0; i < paths.length; i++) {
final File path = paths[i];
if (FileUtil.filesEqual(path, event.getFile())) {
myRevisions[i] = eventRevision;
break;
}
}
}
}
@Override
public void processTerminated(int exitCode) {
super.processTerminated(exitCode);
updatedToRevision.set(myRevisions);
}
};
}
private List<String> prepareParameters(File[] paths,
SVNRevision revision,
SVNDepth depth,
@@ -29,6 +29,7 @@ public enum SvnCommandName {
st("st", false),
up("up", true),
ci("commit", true),
checkout("checkout", true),
cleanup("cleanup", true),
cat("cat", false),
add("add", true),
@@ -40,9 +41,13 @@ public enum SvnCommandName {
resolve("resolve", true),
propget("propget", false),
proplist("proplist", false),
propset("propset", true),
propdel("propdel", true),
blame("blame", false),
merge("merge", true),
changelist("changelist", true);
changelist("changelist", true),
lock("lock", true),
unlock("unlock", true);
private final String myName;
private final boolean myWriteable;
@@ -281,10 +281,28 @@ public class SvnInfoHandler extends DefaultHandler {
return new Lock();
}
});
myElementsMap.put("token", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new LockToken();
}
});
myElementsMap.put("owner", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new LockOwner();
}
});
myElementsMap.put("comment", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new LockComment();
}
});
myElementsMap.put("created", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new Date();
return new LockCreated();
}
});
myElementsMap.put("uuid", new Getter<ElementHandlerBase>() {
@@ -778,17 +796,76 @@ public class SvnInfoHandler extends DefaultHandler {
private static class Lock extends ElementHandlerBase {
private Lock() {
super(new String[]{"created"}, new String[]{});
super(new String[]{"token", "owner", "comment", "created"}, new String[]{});
}
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
// TODO:
structure.myLockWrapper = new SVNLockWrapper();
}
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
// TODO:
}
}
private static class LockToken extends ElementHandlerBase {
private LockToken() {
super(new String[]{}, new String[]{});
}
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
}
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.myLockWrapper.setID(s);
}
}
private static class LockOwner extends ElementHandlerBase {
private LockOwner() {
super(new String[]{}, new String[]{});
}
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
}
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.myLockWrapper.setOwner(s);
}
}
private static class LockComment extends ElementHandlerBase {
private LockComment() {
super(new String[]{}, new String[]{});
}
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
}
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.myLockWrapper.setComment(s);
}
}
private static class LockCreated extends ElementHandlerBase {
private LockCreated() {
super(new String[]{}, new String[]{});
}
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
}
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.myLockWrapper.setCreationDate(SVNDate.parseDate(s));
}
}
@@ -53,7 +53,7 @@ public class SvnInfoStructure {
public String myConflictNew;
public String myConflictWorking;
public String myPropRejectFile;
public SVNLock myLock;
public SVNLockWrapper myLockWrapper;
public SVNDepth myDepth;
public String myChangelistName;
public long myWcSize;
@@ -65,7 +65,18 @@ public class SvnInfoStructure {
public SVNInfo convert() throws SAXException, SVNException {
return new IdeaSVNInfo(myFile, myUrl, myRootURL, myRevision, myKind, myUuid, myCommittedRevision, myCommittedDate, myAuthor, mySchedule,
myCopyFromURL, myCopyFromRevision, myTextTime, myPropTime, myChecksum, myConflictOld, myConflictNew, myConflictWorking,
myPropRejectFile, myLock, myDepth, myChangelistName, myWcSize, createTreeConflict());
myPropRejectFile, getLock(), myDepth, myChangelistName, myWcSize, createTreeConflict());
}
private SVNLock getLock() {
SVNLock lock = null;
if (myLockWrapper != null) {
myLockWrapper.setPath(relativeUrl);
lock = myLockWrapper.create();
}
return lock;
}
private SVNTreeConflictDescription createTreeConflict() throws SAXException, SVNException {
@@ -53,17 +53,23 @@ public class UpdateOutputLineConverter {
private final static Pattern ourAtRevision = Pattern.compile(AT_REVISION);
private final static Pattern ourUpdatedToRevision = Pattern.compile(UPDATED_TO_REVISION);
private final static Pattern ourCheckedOutRevision = Pattern.compile("Checked out revision (\\d+)\\.");
private final static Pattern ourExternal = Pattern.compile(EXTERNAL);
private final static Pattern ourUpdatedExternal = Pattern.compile(UPDATED_EXTERNAL);
private final static Pattern[] ourCompletePatterns = new Pattern[] {ourAtRevision, ourUpdatedToRevision, ourExternal, ourUpdatedExternal};
private final static Pattern ourCheckedOutExternal = Pattern.compile("Checked out external at revision (\\d+)\\.");
private final static Pattern[] ourCompletePatterns =
new Pattern[]{ourAtRevision, ourUpdatedToRevision, ourCheckedOutRevision, ourExternal, ourUpdatedExternal, ourCheckedOutExternal};
private final File myBase;
private File myCurrentFile;
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;
}
public SVNEvent convert(final String line) {
@@ -82,6 +88,7 @@ public class UpdateOutputLineConverter {
return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE),
null, -1, null, null, null, null, SVNEventAction.RESTORE, SVNEventAction.RESTORE, null, null, null, null, null);
} else if (line.startsWith(SKIPPED)) {
// called, for instance, when folder is not working copy
myCurrentFile = parseForPath(line);
final String comment = parseComment(line);
return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE),
@@ -97,8 +104,12 @@ public class UpdateOutputLineConverter {
final Pattern pattern = ourCompletePatterns[i];
final long revision = matchAndGetRevision(pattern, line);
if (revision != -1) {
return new SVNEvent(myCurrentFile, myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE),
null, revision, null, null, null, null, SVNEventAction.UPDATE_COMPLETED, SVNEventAction.UPDATE_COMPLETED, null, null, null, null, null);
// 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 SVNEvent(myCurrentFile,
myCurrentFile == null ? null : (myCurrentFile.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE),
null, revision, null, null, null, null, SVNEventAction.UPDATE_COMPLETED, SVNEventAction.UPDATE_COMPLETED, null,
null, null, null, null);
}
}
@@ -20,6 +20,7 @@ import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
@@ -32,12 +33,13 @@ import com.intellij.ui.table.JBTable;
import com.intellij.util.IconUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnPropertyKeys;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.wc.ISVNPropertyHandler;
import org.tmatesoft.svn.core.wc.SVNPropertyData;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.swing.*;
@@ -263,7 +265,30 @@ public class PropertiesComponent extends JPanel {
}
}
private class SetKeywordsAction extends AnAction {
private abstract class BasePropertyAction extends AnAction {
protected void setProperty(@Nullable String property, @Nullable String value, boolean recursive, boolean force) {
if (!StringUtil.isEmpty(property)) {
try {
myVcs.getFactory(myFile).createPropertyClient()
.setProperty(myFile, property, value != null ? SVNPropertyValue.create(value) : null,
SVNDepth.getInfinityOrEmptyDepth(recursive), force);
}
catch (VcsException error) {
VcsBalloonProblemNotifier
.showOverChangesView(myVcs.getProject(), "Can not set property: " + error.getMessage(), MessageType.ERROR);
// show error message.
}
}
}
protected void updateFileView(boolean recursive) {
setFile(myVcs, myFile);
updateFileStatus(recursive);
}
}
private class SetKeywordsAction extends BasePropertyAction {
public void update(AnActionEvent e) {
e.getPresentation().setText("Edit Keywords");
@@ -276,7 +301,6 @@ public class PropertiesComponent extends JPanel {
public void actionPerformed(AnActionEvent e) {
Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
SVNWCClient wcClient = myVcs.createWCClient();
SVNPropertyData propValue = null;
try {
propValue = myVcs.getFactory(myFile).createPropertyClient()
@@ -290,21 +314,13 @@ public class PropertiesComponent extends JPanel {
propValue != null ? SVNPropertyValue.getPropertyAsString(propValue.getValue()) : null);
dialog.show();
if (dialog.isOK()) {
String value = dialog.getKeywords();
try {
wcClient.doSetProperty(myFile, SVNProperty.KEYWORDS, SVNPropertyValue.create(value), false, false, null);
}
catch (SVNException err) {
// show error message
VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR);
}
setProperty(SvnPropertyKeys.SVN_KEYWORDS, dialog.getKeywords(), false, false);
}
setFile(myVcs, myFile);
updateFileStatus(false);
updateFileView(false);
}
}
private class DeletePropertyAction extends AnAction {
private class DeletePropertyAction extends BasePropertyAction {
public void update(AnActionEvent e) {
e.getPresentation().setText("Delete Property");
e.getPresentation().setDescription("Delete selected property");
@@ -315,18 +331,12 @@ public class PropertiesComponent extends JPanel {
}
public void actionPerformed(AnActionEvent e) {
try {
myVcs.createWCClient().doSetProperty(myFile, getSelectedPropertyName(), null, true, false, null);
} catch (SVNException error) {
VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + error.getMessage(), MessageType.ERROR);
// show error message.
}
setFile(myVcs, myFile);
updateFileStatus(false);
setProperty(getSelectedPropertyName(), null, false, true);
updateFileView(false);
}
}
private class AddPropertyAction extends AnAction {
private class AddPropertyAction extends BasePropertyAction {
public void update(AnActionEvent e) {
e.getPresentation().setText("Add Property");
@@ -344,24 +354,14 @@ public class PropertiesComponent extends JPanel {
dialog.show();
boolean recursive = false;
if (dialog.isOK()) {
String name = dialog.getPropertyName();
String value = dialog.getPropertyValue();
recursive = dialog.isRecursive();
SVNWCClient wcClient = myVcs.createWCClient();
try {
wcClient.doSetProperty(myFile, name, SVNPropertyValue.create(value), false, recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY, null, null);
}
catch (SVNException err) {
VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR);
// show error message
}
setProperty(dialog.getPropertyName(), dialog.getPropertyValue(), recursive, false);
}
setFile(myVcs, myFile);
updateFileStatus(recursive);
updateFileView(recursive);
}
}
private class EditPropertyAction extends AnAction {
private class EditPropertyAction extends BasePropertyAction {
public void update(AnActionEvent e) {
e.getPresentation().setText("Edit Property");
e.getPresentation().setDescription("Edit selected property value");
@@ -377,20 +377,10 @@ public class PropertiesComponent extends JPanel {
dialog.show();
boolean recursive = false;
if (dialog.isOK()) {
String name = dialog.getPropertyName();
String value = dialog.getPropertyValue();
recursive = dialog.isRecursive();
SVNWCClient wcClient = myVcs.createWCClient();
try {
wcClient.doSetProperty(myFile, name, SVNPropertyValue.create(value), false, recursive, null);
}
catch (SVNException err) {
VcsBalloonProblemNotifier.showOverChangesView(myVcs.getProject(), "Can not set property: " + err.getMessage(), MessageType.ERROR);
// show error message
}
setProperty(dialog.getPropertyName(), dialog.getPropertyValue(), recursive, false);
}
setFile(myVcs, myFile);
updateFileStatus(recursive);
updateFileView(recursive);
}
}
@@ -15,22 +15,26 @@
*/
package org.jetbrains.idea.svn.dialogs;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.ui.DocumentAdapter;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnPropertyKeys;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.SVNException;
import org.jetbrains.idea.svn.properties.PropertyClient;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.ISVNPropertyHandler;
import org.tmatesoft.svn.core.wc.SVNPropertyData;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
@@ -47,6 +51,9 @@ import java.util.TreeSet;
* @author alex
*/
public class SetPropertyDialog extends DialogWrapper {
private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.dialogs.SetPropertyDialog");
private final String myPropertyName;
private final File[] myFiles;
@@ -147,14 +154,8 @@ public class SetPropertyDialog extends DialogWrapper {
return;
}
File file = myFiles[0];
SVNPropertyData property;
try {
SVNWCClient client = myVCS.createWCClient();
property = client.doGetProperty(file, name, SVNRevision.WORKING, SVNRevision.WORKING);
}
catch (SVNException e) {
property = null;
}
SVNPropertyData property = !StringUtil.isEmpty(name) ? getProperty(file, name) : null;
if (property != null) {
myValueText.setText(SVNPropertyValue.getPropertyAsString(property.getValue()));
myValueText.selectAll();
@@ -164,6 +165,21 @@ public class SetPropertyDialog extends DialogWrapper {
}
}
private SVNPropertyData getProperty(@NotNull File file, @NotNull String name) {
SVNPropertyData property;
try {
PropertyClient client = myVCS.getFactory(file).createPropertyClient();
property = client.getProperty(SvnTarget.fromFile(file, SVNRevision.WORKING), name, false, SVNRevision.WORKING);
}
catch (VcsException e) {
LOG.info(e);
property = null;
}
return property;
}
protected JComponent createCenterPanel() {
fillPropertyNames(myFiles);
if (myPropertyName != null) {
@@ -189,23 +205,26 @@ public class SetPropertyDialog extends DialogWrapper {
if (files.length == 1) {
File file = files[0];
try {
SVNWCClient client = myVCS.createWCClient();
client.doGetProperty(file, null, SVNRevision.WORKING, SVNRevision.WORKING, false,
new ISVNPropertyHandler() {
public void handleProperty(File path, SVNPropertyData property) {
String name = property.getName();
if (name != null) {
names.add(name);
}
}
public void handleProperty(SVNURL url, SVNPropertyData property) {
}
public void handleProperty(long revision, SVNPropertyData property) {
}
});
ISVNPropertyHandler handler = new ISVNPropertyHandler() {
public void handleProperty(File path, SVNPropertyData property) {
String name = property.getName();
if (name != null) {
names.add(name);
}
}
public void handleProperty(SVNURL url, SVNPropertyData property) {
}
public void handleProperty(long revision, SVNPropertyData property) {
}
};
PropertyClient client = myVCS.getFactory(file).createPropertyClient();
client.list(SvnTarget.fromFile(file, SVNRevision.WORKING), SVNRevision.WORKING, SVNDepth.EMPTY, handler);
}
catch (SVNException e) {
//
catch (VcsException e) {
LOG.info(e);
}
}
@@ -1,27 +1,19 @@
package org.jetbrains.idea.svn.integrate;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.LineCommandListener;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.jetbrains.idea.svn.commandLine.UpdateOutputLineConverter;
import org.jetbrains.idea.svn.commandLine.*;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNDiffOptions;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNRevisionRange;
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;
/**
* @author Konstantin Kolosovsky.
@@ -109,52 +101,10 @@ public class CmdMergeClient extends BaseSvnClient implements MergeClient {
}
private void run(File destination, ISVNEventHandler handler, List<String> parameters) throws VcsException {
final AtomicReference<SVNException> excRef = new AtomicReference<SVNException>();
final UpdateOutputLineConverter converter = new UpdateOutputLineConverter(destination);
LineCommandListener listener = createListener(handler, excRef, converter);
BaseUpdateCommandListener listener = new BaseUpdateCommandListener(destination, handler);
CommandUtil.execute(myVcs, SvnCommandName.merge, parameters, null, listener);
throwIfException(excRef);
}
private static void throwIfException(AtomicReference<SVNException> exception) throws VcsException {
SVNException e = exception.get();
if (e != null) {
throw new VcsException(e);
}
}
private static LineCommandListener createListener(@Nullable final ISVNEventHandler handler,
@NotNull final AtomicReference<SVNException> excRef,
@NotNull final UpdateOutputLineConverter converter) {
LineCommandListener result = null;
if (handler != null) {
result = new LineCommandListener() {
@Override
public void baseDirectory(File file) {
}
@Override
public void onLineAvailable(String line, Key outputType) {
if (ProcessOutputTypes.STDOUT.equals(outputType)) {
final SVNEvent event = converter.convert(line);
if (event != null) {
try {
handler.handleEvent(event, 0.5);
}
catch (SVNException e) {
cancel();
excRef.set(e);
}
}
}
}
};
}
return result;
listener.throwWrappedIfException();
}
}
@@ -0,0 +1,85 @@
package org.jetbrains.idea.svn.lock;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.api.BaseSvnClient;
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.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNEventAction;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdLockClient extends BaseSvnClient implements LockClient {
@Override
public void lock(@NotNull File file, boolean force, @NotNull String message, @Nullable ISVNEventHandler handler) throws VcsException {
List<String> parameters = prepareParameters(file, force);
parameters.add("--message");
parameters.add(message);
SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.lock, parameters, null);
handleCommandCompletion(command, file, SVNEventAction.LOCKED, SVNEventAction.LOCK_FAILED, handler);
}
@Override
public void unlock(@NotNull File file, boolean force, @Nullable ISVNEventHandler handler) throws VcsException {
List<String> parameters = prepareParameters(file, force);
SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.unlock, parameters, null);
handleCommandCompletion(command, file, SVNEventAction.UNLOCKED, SVNEventAction.UNLOCK_FAILED, handler);
}
private static List<String> prepareParameters(@NotNull File file, boolean force) {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, file);
CommandUtil.put(parameters, force, "--force");
return parameters;
}
private static void handleCommandCompletion(@NotNull SvnCommand command,
@NotNull File file,
@NotNull SVNEventAction success,
@NotNull SVNEventAction failure,
@Nullable ISVNEventHandler handler) throws VcsException {
// just warning appears in output when can not lock/unlock file for some reason (like, that file is already locked)
SVNErrorMessage error = SvnUtil.parseWarning(command.getErrorOutput());
try {
invokeHandler(file, error == null ? success : failure, handler, error);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
private static void invokeHandler(@NotNull File file,
@NotNull SVNEventAction action,
@Nullable ISVNEventHandler handler,
@Nullable SVNErrorMessage error)
throws SVNException {
if (handler != null) {
handler.handleEvent(createEvent(file, action, error), 1);
}
}
private static SVNEvent createEvent(@NotNull File file, @NotNull SVNEventAction action, @Nullable SVNErrorMessage error) {
return new SVNEvent(file, file.isDirectory() ? SVNNodeKind.DIR : SVNNodeKind.FILE, null, -1, null, null, null, null, action, action,
error, null, null, null, null);
}
}
@@ -0,0 +1,24 @@
package org.jetbrains.idea.svn.lock;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.SvnClient;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface LockClient extends SvnClient {
void lock(@NotNull File file,
boolean force,
@NotNull String message,
@Nullable ISVNEventHandler handler) throws VcsException;
void unlock(@NotNull File file,
boolean force,
@Nullable ISVNEventHandler handler) throws VcsException;
}
@@ -0,0 +1,47 @@
package org.jetbrains.idea.svn.lock;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.BaseSvnClient;
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.SVNWCClient;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitLockClient extends BaseSvnClient implements LockClient {
@Override
public void lock(@NotNull File file, boolean force, @NotNull String message, @Nullable ISVNEventHandler handler) throws VcsException {
try {
getClient(handler).doLock(new File[]{file}, force, message);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
@Override
public void unlock(@NotNull File file, boolean force, @Nullable ISVNEventHandler handler) throws VcsException {
try {
getClient(handler).doUnlock(new File[]{file}, force);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
@NotNull
private SVNWCClient getClient(@Nullable ISVNEventHandler handler) {
SVNWCClient client = myVcs.createWCClient();
client.setEventHandler(handler);
return client;
}
}
@@ -88,6 +88,27 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient {
parseOutput(target, command.getOutput(), handler);
}
@Override
public void setProperty(@NotNull File file,
@NotNull String property,
@Nullable SVNPropertyValue value,
@Nullable SVNDepth depth,
boolean force) throws VcsException {
List<String> parameters = new ArrayList<String>();
boolean isDelete = value == null;
parameters.add(property);
if (!isDelete) {
parameters.add(SVNPropertyValue.getPropertyAsString(value));
// --force could only be used in "propset" command, but not in "propdel" command
CommandUtil.put(parameters, force, "--force");
}
CommandUtil.put(parameters, file);
CommandUtil.put(parameters, depth);
CommandUtil.execute(myVcs, isDelete ? SvnCommandName.propdel : SvnCommandName.propset, parameters, null);
}
private void fillListParameters(@NotNull SvnTarget target,
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
@@ -5,11 +5,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.SvnClient;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.wc.ISVNPropertyHandler;
import org.tmatesoft.svn.core.wc.SVNPropertyData;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
@@ -30,4 +33,10 @@ public interface PropertyClient extends SvnClient {
@Nullable SVNRevision revision,
@Nullable SVNDepth depth,
@Nullable ISVNPropertyHandler handler) throws VcsException;
void setProperty(@NotNull File file,
@NotNull String property,
@Nullable SVNPropertyValue value,
@Nullable SVNDepth depth,
boolean force) throws VcsException;
}
@@ -4,8 +4,10 @@ import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.ISVNPropertyHandler;
import org.tmatesoft.svn.core.wc.SVNPropertyData;
@@ -59,6 +61,20 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien
runGetProperty(target, null, revision, depth, handler);
}
@Override
public void setProperty(@NotNull File file,
@NotNull String property,
@Nullable SVNPropertyValue value,
@Nullable SVNDepth depth,
boolean force) throws VcsException {
try {
myVcs.createWCClient().doSetProperty(file, property, value, force, depth, null, null);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
private void runGetProperty(@NotNull SvnTarget target,
@Nullable String property,
@Nullable SVNRevision revision,