Merge branch 'svn1_8_new'

This commit is contained in:
Konstantin Kolosovsky
2013-08-27 13:56:56 +04:00
123 changed files with 3368 additions and 2170 deletions
-1
View File
@@ -16,7 +16,6 @@
<module fileurl="file://$PROJECT_DIR$/plugins/ant/jps-plugin/ant-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/ant/jps-plugin/ant-jps-plugin.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/jps/antLayout/antlayout.iml" filepath="$PROJECT_DIR$/jps/antLayout/antlayout.iml" group="jps" />
<module fileurl="file://$PROJECT_DIR$/plugins/google-app-engine/runtime/appEngine-runtime.iml" filepath="$PROJECT_DIR$/plugins/google-app-engine/runtime/appEngine-runtime.iml" group="plugins/GAE" />
<module fileurl="file://$PROJECT_DIR$/plugins/svn4idea/bindSvn/bindSvn.iml" filepath="$PROJECT_DIR$/plugins/svn4idea/bindSvn/bindSvn.iml" group="plugins/VCS" />
<module fileurl="file://$PROJECT_DIR$/platform/boot/boot.iml" filepath="$PROJECT_DIR$/platform/boot/boot.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/bootstrap/bootstrap.iml" filepath="$PROJECT_DIR$/platform/bootstrap/bootstrap.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/build/build.iml" filepath="$PROJECT_DIR$/build/build.iml" />
-3
View File
@@ -323,9 +323,6 @@ public def layoutCommunityPlugins(String home) {
}
layoutPlugin("svn4idea") {
jar("bindSvn.jar") {
module("bindSvn")
}
fileset(dir: "$home/plugins/svn4idea/lib", excludes: "**/svnkitsrc.zip")
}
@@ -43,6 +43,7 @@ public class StringUtil extends StringUtilRt {
@NonNls private static final String VOWELS = "aeiouy";
@NonNls private static final Pattern EOL_SPLIT_PATTERN = Pattern.compile(" *(\r|\n|\r\n)+ *");
@NonNls private static final Pattern EOL_SPLIT_PATTERN_WITH_EMPTY = Pattern.compile(" *(\r|\n|\r\n) *");
public static final NotNullFunction<String, String> QUOTER = new NotNullFunction<String, String>() {
@Override
@@ -2132,7 +2133,19 @@ public class StringUtil extends StringUtilRt {
*/
@NotNull
public static String[] splitByLines(@NotNull String string) {
return EOL_SPLIT_PATTERN.split(string);
return splitByLines(string, true);
}
/**
* Splits string by lines. If several line separators are in a row corresponding empty lines
* are also added to result if {@code excludeEmptyStrings} is {@code false}.
*
* @param string String to split
* @return array of strings
*/
@NotNull
public static String[] splitByLines(@NotNull String string, boolean excludeEmptyStrings) {
return (excludeEmptyStrings ? EOL_SPLIT_PATTERN : EOL_SPLIT_PATTERN_WITH_EMPTY).split(string);
}
@NotNull
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="platform-api" />
<orderEntry type="module" module-name="vcs-api" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/javahl.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$MODULE_DIR$/lib/javahlsrc.zip!/src" />
</SOURCES>
</library>
</orderEntry>
</component>
</module>
Binary file not shown.
Binary file not shown.
@@ -1,925 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
import org.tigris.subversion.javahl.*;
import java.io.OutputStream;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 2/5/13
* Time: 3:08 PM
*/
public class SvnBindClient implements SVNClientInterface {
private final String myExecutablePath;
private CommitEventHandler myHandler;
private AuthenticationCallback myAuthenticationCallback;
public SvnBindClient(String path) {
myExecutablePath = path;
}
@Override
public void dispose() {
}
@Override
public Version getVersion() {
// todo real version
throw new UnsupportedOperationException();
}
@Override
public String getAdminDirectoryName() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAdminDirectory(String name) {
throw new UnsupportedOperationException();
}
@Override
public String getLastPath() {
throw new UnsupportedOperationException();
}
@Override
public Status singleStatus(String path, boolean onServer) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public Status[] status(String path, boolean descend, boolean onServer, boolean getAll) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public Status[] status(String path, boolean descend, boolean onServer, boolean getAll, boolean noIgnore) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public Status[] status(String path, boolean descend, boolean onServer, boolean getAll, boolean noIgnore, boolean ignoreExternals)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void status(String path,
int depth,
boolean onServer,
boolean getAll,
boolean noIgnore,
boolean ignoreExternals,
String[] changelists,
StatusCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public DirEntry[] list(String url, Revision revision, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public DirEntry[] list(String url, Revision revision, Revision pegRevision, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void list(String url,
Revision revision,
Revision pegRevision,
int depth,
int direntFields,
boolean fetchLocks,
ListCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void username(String username) {
throw new UnsupportedOperationException();
}
@Override
public void password(String password) {
throw new UnsupportedOperationException();
}
@Override
public void setPrompt(PromptUserPassword prompt) {
throw new UnsupportedOperationException();
}
@Override
public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, boolean stopOnCopy) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public LogMessage[] logMessages(String path, Revision revisionStart, Revision revisionEnd, boolean stopOnCopy, boolean discoverPath)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public LogMessage[] logMessages(String path,
Revision revisionStart,
Revision revisionEnd,
boolean stopOnCopy,
boolean discoverPath,
long limit) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void logMessages(String path,
Revision pegRevision,
Revision revisionStart,
Revision revisionEnd,
boolean stopOnCopy,
boolean discoverPath,
boolean includeMergedRevisions,
String[] revProps,
long limit,
LogMessageCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void logMessages(String path,
Revision pegRevision,
RevisionRange[] ranges,
boolean stopOnCopy,
boolean discoverPath,
boolean includeMergedRevisions,
String[] revProps,
long limit,
LogMessageCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long checkout(String moduleName, String destPath, Revision revision, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long checkout(String moduleName,
String destPath,
Revision revision,
Revision pegRevision,
boolean recurse,
boolean ignoreExternals) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long checkout(String moduleName,
String destPath,
Revision revision,
Revision pegRevision,
int depth,
boolean ignoreExternals,
boolean allowUnverObstructions) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void notification(Notify notify) {
throw new UnsupportedOperationException();
}
@Override
public void notification2(Notify2 notify) {
throw new UnsupportedOperationException();
}
@Override
public void setConflictResolver(ConflictResolverCallback listener) {
throw new UnsupportedOperationException();
}
@Override
public void setProgressListener(ProgressListener listener) {
throw new UnsupportedOperationException();
}
@Override
public void commitMessageHandler(CommitMessage messageHandler) {
throw new UnsupportedOperationException();
}
@Override
public void remove(String[] path, String message, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void remove(String[] path, String message, boolean force, boolean keepLocal, Map revpropTable) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void revert(String path, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void revert(String path, int depth, String[] changelists) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void add(String path, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void add(String path, boolean recurse, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void add(String path, int depth, boolean force, boolean noIgnores, boolean addParents) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long update(String path, Revision revision, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long[] update(String[] path, Revision revision, boolean recurse, boolean ignoreExternals) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long update(String path,
Revision revision,
int depth,
boolean depthIsSticky,
boolean ignoreExternals,
boolean allowUnverObstructions) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long[] update(String[] path,
Revision revision,
int depth,
boolean depthIsSticky,
boolean ignoreExternals,
boolean allowUnverObstructions) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long commit(String[] path, String message, boolean recurse) throws ClientException {
return commit(path, message, recurse? 3 : 0, false, false, null, null);
}
@Override
public long commit(String[] path, String message, boolean recurse, boolean noUnlock) throws ClientException {
return commit(path, message, recurse? 3 : 0, noUnlock, false, null, null);
}
@Override
public long commit(String[] path,
String message,
int depth,
boolean noUnlock,
boolean keepChangelist,
String[] changelists,
Map revpropTable) throws ClientException {
final long commit = new SvnCommitRunner(myExecutablePath, myHandler, myAuthenticationCallback).
commit(path, message, depth, noUnlock, keepChangelist, changelists, revpropTable);
if (commit < 0) {
throw new BindClientException("Wrong committed revision number: " + commit, null, -1);
}
return commit;
}
@Override
public void copy(CopySource[] sources,
String destPath,
String message,
boolean copyAsChild,
boolean makeParents,
boolean ignoreExternals,
Map revpropTable) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void copy(CopySource[] sources, String destPath, String message, boolean copyAsChild, boolean makeParents, Map revpropTable)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void copy(String srcPath, String destPath, String message, Revision revision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void move(String[] srcPaths,
String destPath,
String message,
boolean force,
boolean moveAsChild,
boolean makeParents,
Map revpropTable) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void move(String srcPath, String destPath, String message, Revision ignored, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void move(String srcPath, String destPath, String message, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void mkdir(String[] path, String message, boolean makeParents, Map revpropTable) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void mkdir(String[] path, String message) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void cleanup(String path) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void resolve(String path, int depth, int conflictResult) throws SubversionException {
throw new UnsupportedOperationException();
}
@Override
public void resolved(String path, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long doExport(String srcPath, String destPath, Revision revision, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long doExport(String srcPath,
String destPath,
Revision revision,
Revision pegRevision,
boolean force,
boolean ignoreExternals,
boolean recurse,
String nativeEOL) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long doExport(String srcPath,
String destPath,
Revision revision,
Revision pegRevision,
boolean force,
boolean ignoreExternals,
int depth,
String nativeEOL) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long doSwitch(String path, String url, Revision revision, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public long doSwitch(String path,
String url,
Revision revision,
Revision pegRevision,
int depth,
boolean depthIsSticky,
boolean ignoreExternals,
boolean allowUnverObstructions) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void doImport(String path, String url, String message, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void doImport(String path,
String url,
String message,
int depth,
boolean noIgnore,
boolean ignoreUnknownNodeTypes,
Map revpropTable) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public String[] suggestMergeSources(String path, Revision pegRevision) throws SubversionException {
throw new UnsupportedOperationException();
}
@Override
public void merge(String path1, Revision revision1, String path2, Revision revision2, String localPath, boolean force, boolean recurse)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void merge(String path1,
Revision revision1,
String path2,
Revision revision2,
String localPath,
boolean force,
boolean recurse,
boolean ignoreAncestry,
boolean dryRun) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void merge(String path1,
Revision revision1,
String path2,
Revision revision2,
String localPath,
boolean force,
int depth,
boolean ignoreAncestry,
boolean dryRun,
boolean recordOnly) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void merge(String path,
Revision pegRevision,
Revision revision1,
Revision revision2,
String localPath,
boolean force,
boolean recurse,
boolean ignoreAncestry,
boolean dryRun) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void merge(String path,
Revision pegRevision,
RevisionRange[] revisions,
String localPath,
boolean force,
int depth,
boolean ignoreAncestry,
boolean dryRun,
boolean recordOnly) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void mergeReintegrate(String path, Revision pegRevision, String localPath, boolean dryRun) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public Mergeinfo getMergeinfo(String path, Revision pegRevision) throws SubversionException {
throw new UnsupportedOperationException();
}
@Override
public void getMergeinfoLog(int kind,
String pathOrUrl,
Revision pegRevision,
String mergeSourceUrl,
Revision srcPegRevision,
boolean discoverChangedPaths,
int depth,
String[] revProps,
LogMessageCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void getMergeinfoLog(int kind,
String pathOrUrl,
Revision pegRevision,
String mergeSourceUrl,
Revision srcPegRevision,
boolean discoverChangedPaths,
String[] revProps,
LogMessageCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target1, Revision revision1, String target2, Revision revision2, String outFileName, boolean recurse)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target1,
Revision revision1,
String target2,
Revision revision2,
String outFileName,
boolean recurse,
boolean ignoreAncestry,
boolean noDiffDeleted,
boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target1,
Revision revision1,
String target2,
Revision revision2,
String relativeToDir,
String outFileName,
int depth,
String[] changelists,
boolean ignoreAncestry,
boolean noDiffDeleted,
boolean force,
boolean copiesAsAdds) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target1,
Revision revision1,
String target2,
Revision revision2,
String relativeToDir,
String outFileName,
int depth,
String[] changelists,
boolean ignoreAncestry,
boolean noDiffDeleted,
boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target,
Revision pegRevision,
Revision startRevision,
Revision endRevision,
String outFileName,
boolean recurse,
boolean ignoreAncestry,
boolean noDiffDeleted,
boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target,
Revision pegRevision,
Revision startRevision,
Revision endRevision,
String relativeToDir,
String outFileName,
int depth,
String[] changelists,
boolean ignoreAncestry,
boolean noDiffDeleted,
boolean force,
boolean copiesAsAdds) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diff(String target,
Revision pegRevision,
Revision startRevision,
Revision endRevision,
String relativeToDir,
String outFileName,
int depth,
String[] changelists,
boolean ignoreAncestry,
boolean noDiffDeleted,
boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diffSummarize(String target1,
Revision revision1,
String target2,
Revision revision2,
int depth,
String[] changelists,
boolean ignoreAncestry,
DiffSummaryReceiver receiver) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void diffSummarize(String target,
Revision pegRevision,
Revision startRevision,
Revision endRevision,
int depth,
String[] changelists,
boolean ignoreAncestry,
DiffSummaryReceiver receiver) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData[] properties(String path) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData[] properties(String path, Revision revision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData[] properties(String path, Revision revision, Revision pegRevision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void properties(String path, Revision revision, Revision pegRevision, int depth, String[] changelists, ProplistCallback callback)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertySet(String path, String name, String value, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertySet(String path, String name, String value, boolean recurse, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertySet(String path, String name, byte[] value, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertySet(String path, String name, byte[] value, boolean recurse, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertySet(String path, String name, String value, int depth, String[] changelists, boolean force, Map revpropTable)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyRemove(String path, String name, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyRemove(String path, String name, int depth, String[] changelists) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyCreate(String path, String name, String value, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyCreate(String path, String name, String value, boolean recurse, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyCreate(String path, String name, byte[] value, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyCreate(String path, String name, byte[] value, boolean recurse, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void propertyCreate(String path, String name, String value, int depth, String[] changelists, boolean force)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData revProperty(String path, String name, Revision rev) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData[] revProperties(String path, Revision rev) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void setRevProperty(String path, String name, Revision rev, String value, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void setRevProperty(String path, String name, Revision rev, String value, String originalValue, boolean force)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData propertyGet(String path, String name) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData propertyGet(String path, String name, Revision revision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public PropertyData propertyGet(String path, String name, Revision revision, Revision pegRevision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public byte[] fileContent(String path, Revision revision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public byte[] fileContent(String path, Revision revision, Revision pegRevision) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void streamFileContent(String path, Revision revision, Revision pegRevision, int bufferSize, OutputStream stream)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void relocate(String from, String to, String path, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public byte[] blame(String path, Revision revisionStart, Revision revisionEnd) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void blame(String path, Revision revisionStart, Revision revisionEnd, BlameCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void blame(String path, Revision pegRevision, Revision revisionStart, Revision revisionEnd, BlameCallback callback)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void blame(String path,
Revision pegRevision,
Revision revisionStart,
Revision revisionEnd,
boolean ignoreMimeType,
boolean includeMergedRevisions,
BlameCallback2 callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void blame(String path,
Revision pegRevision,
Revision revisionStart,
Revision revisionEnd,
boolean ignoreMimeType,
boolean includeMergedRevisions,
BlameCallback3 callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void setConfigDirectory(String configDir) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public String getConfigDirectory() throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void cancelOperation() throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public Info info(String path) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void addToChangelist(String[] paths, String changelist, int depth, String[] changelists) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void removeFromChangelists(String[] paths, int depth, String[] changelists) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void getChangelists(String rootPath, String[] changelists, int depth, ChangelistCallback callback) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void lock(String[] path, String comment, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void unlock(String[] path, boolean force) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public Info2[] info2(String pathOrUrl, Revision revision, Revision pegRevision, boolean recurse) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void info2(String pathOrUrl, Revision revision, Revision pegRevision, int depth, String[] changelists, InfoCallback callback)
throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public String getVersionInfo(String path, String trailUrl, boolean lastChanged) throws ClientException {
throw new UnsupportedOperationException();
}
@Override
public void upgrade(String path) throws ClientException {
throw new UnsupportedOperationException();
}
public void setHandler(CommitEventHandler handler) {
myHandler = handler;
}
public void setAuthenticationCallback(AuthenticationCallback authenticationCallback) {
myAuthenticationCallback = authenticationCallback;
}
}
@@ -1,121 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.status;
import org.apache.subversion.javahl.types.Lock;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 2/21/12
* Time: 2:33 PM
*/
public class LockWrapper {
private String myPath;
private String myID;
private String myOwner;
private String myComment;
private Date myCreationDate;
private Date myExpirationDate;
public LockWrapper(String path, String ID, String owner, String comment, Date creationDate, Date expirationDate) {
myPath = path;
myID = ID;
myOwner = owner;
myComment = comment;
myCreationDate = creationDate;
myExpirationDate = expirationDate;
}
public LockWrapper() {
}
public String getPath() {
return myPath;
}
public void setPath(String path) {
myPath = path;
}
public String getID() {
return myID;
}
public void setID(String ID) {
myID = ID;
}
public String getOwner() {
return myOwner;
}
public void setOwner(String owner) {
myOwner = owner;
}
public String getComment() {
return myComment;
}
public void setComment(String comment) {
myComment = comment;
}
public Date getCreationDate() {
return myCreationDate;
}
public void setCreationDate(Date creationDate) {
myCreationDate = creationDate;
}
public Date getExpirationDate() {
return myExpirationDate;
}
public void setExpirationDate(Date expirationDate) {
myExpirationDate = expirationDate;
}
public org.tigris.subversion.javahl.Lock create() {
final Date creation = getCreationDate();
final Date expiration = getExpirationDate();
final Lock newLock = new Lock(getOwner(), getPath(), getID(), getComment(), creation == null ? 0 : creation.getTime(),
expiration == null ? 0 : expiration.getTime());
try {
final Constructor<org.tigris.subversion.javahl.Lock> constructor = org.tigris.subversion.javahl.Lock.class.getConstructor(Lock.class);
constructor.setAccessible(true);
return constructor.newInstance(newLock);
}
catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
catch (InstantiationException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
@@ -1,47 +0,0 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tigris.subversion.javahl;
import org.jetbrains.annotations.NotNull;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 2/25/13
* Time: 6:29 PM
*/
public class BindClientException extends ClientException {
private Throwable myCause;
public BindClientException(String message, String source, int aprError) {
super(message, source, aprError);
}
public BindClientException(org.apache.subversion.javahl.ClientException ex) {
super(ex);
}
public static BindClientException create(@NotNull final Throwable t, final int code) {
final BindClientException exception = new BindClientException(t.getMessage(), null, code);
exception.myCause = t;
return exception;
}
@Override
public Throwable getCause() {
return myCause;
}
}
@@ -49,11 +49,9 @@ public class ForNestedRootChecker {
private static class UrlConstructor {
final SvnVcs myVcs;
final SVNWCClient myClient;
private UrlConstructor(final SvnVcs vcs) {
myVcs = vcs;
myClient = myVcs.createWCClient();
}
@Nullable
@@ -123,52 +123,31 @@ public class RootsToWorkingCopies implements VcsListener {
@Nullable
private WorkingCopy calculateRoot(final VirtualFile root) {
File workingCopyRoot = SvnUtil.getWorkingCopyRootNew(new File(root.getPath()));
WorkingCopy workingCopy = null;
final File ioFile = new File(root.getPath());
File workingCopyRoot = null;
try {
workingCopyRoot = SVNWCUtil.getWorkingCopyRoot(ioFile, true);
if (workingCopyRoot != null) {
// ok to use low-level 1.6 API, 1.7 is checked below
SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
try {
wcAccess.probeOpen(workingCopyRoot, false, 0);
SVNEntry entry = wcAccess.getVersionedEntry(workingCopyRoot, false);
final SVNURL url = entry.getSVNURL();
if (url != null) {
workingCopy = new WorkingCopy(workingCopyRoot, url, false);
}
} finally {
wcAccess.close();
}
}
}
catch (SVNException e) {
//
}
if (workingCopy == null) {
workingCopyRoot = SvnUtil.getWcCopyRootIf17(ioFile, null);
if (workingCopyRoot != null) {
final SVNInfo svnInfo;
try {
svnInfo = SvnVcs.getInstance(myProject).createWCClient().doInfo(workingCopyRoot, SVNRevision.UNDEFINED);
workingCopy = new WorkingCopy(workingCopyRoot, svnInfo.getURL(), true);
}
catch (SVNException e) {
//
}
if (workingCopyRoot != null) {
final SVNInfo svnInfo = myVcs.getInfo(workingCopyRoot);
if (svnInfo != null && svnInfo.getURL() != null) {
workingCopy = new WorkingCopy(workingCopyRoot, svnInfo.getURL(), true);
}
}
return registerWorkingCopy(root, workingCopy);
}
private WorkingCopy registerWorkingCopy(@NotNull VirtualFile root, @Nullable WorkingCopy resolvedWorkingCopy) {
synchronized (myLock) {
if (workingCopy == null) {
if (resolvedWorkingCopy == null) {
myRootMapping.remove(root);
myUnversioned.add(root);
} else {
myUnversioned.remove(root);
myRootMapping.put(root, workingCopy);
myRootMapping.put(root, resolvedWorkingCopy);
}
}
return workingCopy;
return resolvedWorkingCopy;
}
public void clear() {
@@ -36,6 +36,7 @@ import java.util.concurrent.locks.ReentrantLock;
* Date: 10/19/12
* Time: 12:09 PM
*/
// TODO: Such locking functionality is not required anymore. Likely to be removed (together with SvnProxies).
public abstract class SvnAbstractWriteOperationLocks {
private final long myTimeout;
private final static Map<String, Lock> myLockMap = new HashMap<String, Lock>();
@@ -350,7 +350,9 @@ public class SvnAuthenticationNotifier extends GenericNotifierImpl<SvnAuthentica
}
SvnInteractiveAuthenticationProvider.clearCallState();
try {
// start svnkit authentication cycle
SvnVcs.getInstance(project).createWCClient(manager).doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD);
//SvnVcs.getInstance(project).getInfo(url, SVNRevision.HEAD, manager);
} catch (SVNAuthenticationException e) {
log(e);
return false;
@@ -537,6 +537,7 @@ dialog.show.svn.map.table.version14.text=1.4
dialog.show.svn.map.table.version15.text=1.5
dialog.show.svn.map.table.version16.text=1.6
dialog.show.svn.map.table.version17.text=1.7
dialog.show.svn.map.table.version18.text=1.8
action.change.wcopy.format.task.title=Convert working copy format
action.change.wcopy.format.task.progress.text=Converting working copy at {0} format from {1} to {2}
action.change.wcopy.format.after.change.settings=Selected working copy format ({0}) is older than upgrade mode selected in Project Settings ({1}).\
@@ -85,7 +85,7 @@ public class SvnChangeProvider implements ChangeProvider {
statusReceiver.addListener(context);
statusReceiver.addListener(nestedCopiesBuilder);
final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs.getProject(), statusReceiver.getMulticaster(), partner);
final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs, statusReceiver.getMulticaster(), partner);
for (FilePath path : zipper.getRecursiveDirs()) {
walker.go(path, SVNDepth.INFINITY);
@@ -180,7 +180,7 @@ public class SvnChangeProvider implements ChangeProvider {
public void getChanges(final FilePath path, final boolean recursive, final ChangelistBuilder builder) throws SVNException {
final SvnChangeProviderContext context = new SvnChangeProviderContext(myVcs, builder, null);
final StatusWalkerPartnerImpl partner = new StatusWalkerPartnerImpl(myVcs, ProgressManager.getInstance().getProgressIndicator());
final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs.getProject(), context, partner);
final SvnRecursiveStatusWalker walker = new SvnRecursiveStatusWalker(myVcs, context, partner);
walker.go(path, recursive ? SVNDepth.INFINITY : SVNDepth.IMMEDIATES);
processCopiedAndDeleted(context, null);
}
@@ -259,23 +259,15 @@ class SvnChangeProviderContext implements StatusReceiver {
public void addModifiedNotSavedChange(final VirtualFile file) throws SVNException {
final FilePath filePath = new FilePathImpl(file);
final SVNInfo svnInfo;
try {
svnInfo = myVcs.createWCClient().doInfo(new File(file.getPath()), SVNRevision.UNDEFINED);
final SVNInfo svnInfo = myVcs.getInfo(file);
if (svnInfo != null) {
final SVNStatus svnStatus = new SVNStatus();
svnStatus.setRevision(svnInfo.getRevision());
myChangelistBuilder.processChangeInList(
createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, svnInfo.getRevision()), CurrentContentRevision.create(filePath),
FileStatus.MODIFIED, svnStatus), (String)null, SvnVcs.getKey());
}
catch (SVNException e) {
final SVNErrorCode errorCode = e.getErrorMessage().getErrorCode();
if (SVNErrorCode.WC_PATH_NOT_FOUND.equals(errorCode) ||
SVNErrorCode.UNVERSIONED_RESOURCE.equals(errorCode) || SVNErrorCode.WC_NOT_WORKING_COPY.equals(errorCode)) {
return;
}
throw e;
}
final SVNStatus svnStatus = new SVNStatus();
svnStatus.setRevision(svnInfo.getRevision());
myChangelistBuilder.processChangeInList(createChange(SvnContentRevision.createBaseRevision(myVcs, filePath, svnInfo.getRevision()),
CurrentContentRevision.create(filePath), FileStatus.MODIFIED, svnStatus), (String) null,
SvnVcs.getKey());
}
private void checkSwitched(final FilePath filePath, final ChangelistBuilder builder, final SVNStatus status,
@@ -176,11 +176,9 @@ public class SvnChangelistListener implements ChangeListListener {
}
@Nullable
public static String getCurrentMapping(final Project project, final File file) {
final SvnVcs vcs = SvnVcs.getInstance(project);
final SVNStatusClient statusClient = vcs.createStatusClient();
public static String getCurrentMapping(final SvnVcs vcs, final File file) {
try {
final SVNStatus status = statusClient.doStatus(file, false);
final SVNStatus status = vcs.getFactory(file).createStatusClient().doStatus(file, false);
return status == null ? null : status.getChangelistName();
}
catch (SVNException e) {
@@ -18,7 +18,7 @@
<properties/>
<border type="none"/>
<children>
<grid id="2ae3a" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="2ae3a" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<tabbedpane title="General"/>
@@ -29,7 +29,7 @@
<grid id="a4729" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="3" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="2" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -87,7 +87,7 @@
</grid>
<component id="df054" class="javax.swing.JCheckBox" binding="myUseDefaultCheckBox">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="1" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="org/jetbrains/idea/svn/SvnBundle" key="checkbox.configure.use.system.default.configuration.directory"/>
@@ -96,7 +96,7 @@
<grid id="137aa" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="5" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -123,36 +123,29 @@
</grid>
<hspacer id="e8f24">
<constraints>
<grid row="5" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
<grid row="4" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<vspacer id="aa6b2">
<constraints>
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="300b5" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Subversion 1.7 Acceleration"/>
</properties>
</component>
<grid id="12735" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="3ecd1" class="com.intellij.ui.components.JBCheckBox" binding="myWithCommandLineClient">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="2" use-parent-layout="false"/>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="with command line client:"/>
<margin top="2" left="3" bottom="2" right="3"/>
<text value="Use command line client:"/>
</properties>
</component>
<component id="44a8" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myCommandLineClient">
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatus;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.File;
import java.io.IOException;
@@ -113,7 +114,8 @@ public class SvnContentRevision implements ContentRevision, MarkerVcsContentRevi
if (lock.exists()) {
throw new VcsException("Can not access file base revision contents: administrative area is locked");
}
return SvnUtil.getFileContents(myVcs, file.getPath(), false, myUseBaseRevision ? SVNRevision.BASE : myRevision, SVNRevision.UNDEFINED);
return SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(file), myUseBaseRevision ? SVNRevision.BASE : myRevision,
SVNRevision.UNDEFINED);
}
@NotNull
@@ -17,6 +17,7 @@ package org.jetbrains.idea.svn;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.actions.VcsContextFactory;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.diff.DiffMixin;
@@ -26,8 +27,10 @@ import com.intellij.openapi.vcs.history.VcsRevisionDescription;
import com.intellij.openapi.vcs.history.VcsRevisionDescriptionImpl;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient;
import org.jetbrains.idea.svn.history.LatestExistentSearcher;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.*;
@@ -43,19 +46,12 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin {
}
public VcsRevisionNumber getCurrentRevision(VirtualFile file) {
final SVNWCClient client = myVcs.createWCClient();
try {
final SVNInfo svnInfo = client.doInfo(new File(file.getPresentableUrl()), SVNRevision.UNDEFINED);
if (svnInfo == null) return null;
if (SVNRevision.UNDEFINED.equals(svnInfo.getCommittedRevision()) && svnInfo.getCopyFromRevision() != null) {
return new SvnRevisionNumber(svnInfo.getCopyFromRevision());
}
return new SvnRevisionNumber(svnInfo.getRevision());
}
catch (SVNException e) {
LOG.debug(e); // most likely the file is unversioned
return null;
final SVNInfo svnInfo = myVcs.getInfo(new File(file.getPresentableUrl()));
if (svnInfo == null) return null;
if (SVNRevision.UNDEFINED.equals(svnInfo.getCommittedRevision()) && svnInfo.getCopyFromRevision() != null) {
return new SvnRevisionNumber(svnInfo.getCopyFromRevision());
}
return new SvnRevisionNumber(svnInfo.getRevision());
}
@Override
@@ -65,53 +61,36 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin {
}
private VcsRevisionDescription getCurrentRevisionDescription(File path) {
final SVNWCClient client = myVcs.createWCClient();
try {
final SVNInfo svnInfo = client.doInfo(path, SVNRevision.UNDEFINED);
if (svnInfo.getCommittedRevision().equals(SVNRevision.UNDEFINED) && ! svnInfo.getCopyFromRevision().equals(SVNRevision.UNDEFINED) &&
final SVNInfo svnInfo = myVcs.getInfo(path);
if (svnInfo == null) {
return null;
}
if (svnInfo.getCommittedRevision().equals(SVNRevision.UNDEFINED) && !svnInfo.getCopyFromRevision().equals(SVNRevision.UNDEFINED) &&
svnInfo.getCopyFromURL() != null) {
SVNURL copyUrl = svnInfo.getCopyFromURL();
String localPath = myVcs.getSvnFileUrlMapping().getLocalPath(copyUrl.toString());
if (localPath != null) {
return getCurrentRevisionDescription(new File(localPath));
}
SVNURL copyUrl = svnInfo.getCopyFromURL();
String localPath = myVcs.getSvnFileUrlMapping().getLocalPath(copyUrl.toString());
if (localPath != null) {
return getCurrentRevisionDescription(new File(localPath));
}
final String message = getProperties(client, path);
}
try {
final String message = getCommitMessage(path);
return new VcsRevisionDescriptionImpl(new SvnRevisionNumber(svnInfo.getCommittedRevision()), svnInfo.getCommittedDate(),
svnInfo.getAuthor(), message);
}
catch (SVNException e) {
catch (VcsException e) {
LOG.debug(e); // most likely the file is unversioned
return null;
}
}
private String getProperties(SVNWCClient client, File path) throws SVNException {
final String[] message = new String[1];
client.doGetRevisionProperty(path, null, SVNRevision.BASE, new ISVNPropertyHandler() {
@Override
public void handleProperty(File path, SVNPropertyData property) throws SVNException {
handle(property);
}
private String getCommitMessage(File path) throws VcsException {
SVNPropertyData property =
myVcs.getFactory(path).createPropertyClient().getProperty(path, COMMIT_MESSAGE, true, null, SVNRevision.BASE);
@Override
public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException {
handle(property);
}
@Override
public void handleProperty(long revision, SVNPropertyData property) throws SVNException {
handle(property);
}
private void handle(SVNPropertyData data) {
if (COMMIT_MESSAGE.equals(data.getName())) {
message[0] = data.getValue().getString();
}
}
});
return message[0];
return property != null ? SVNPropertyValue.getPropertyAsString(property.getValue()) : null;
}
private static ItemLatestState defaultResult() {
@@ -135,18 +114,45 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin {
return SvnContentRevision.createBaseRevision(myVcs, filePath, svnRevision);
}
}
// not clear why we need it, with remote check..
final SVNStatusClient client = myVcs.createStatusClient();
try {
final SVNStatus svnStatus = client.doStatus(new File(selectedFile.getPresentableUrl()), false, false);
if (svnRevision.equals(svnStatus.getRevision())) {
SVNStatus svnStatus = getFileStatus(new File(selectedFile.getPresentableUrl()), false);
if (svnStatus != null && svnRevision.equals(svnStatus.getRevision())) {
return SvnContentRevision.createBaseRevision(myVcs, filePath, svnRevision);
}
}
return SvnContentRevision.createRemote(myVcs, filePath, svnRevision);
}
private SVNStatus getFileStatus(File file, boolean remote) {
WorkingCopyFormat format = myVcs.getWorkingCopyFormat(file);
return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? getStatusCommandLine(file, remote) : getStatusWithSvnKit(file, remote);
}
private SVNStatus getStatusWithSvnKit(File file, boolean remote) {
SVNStatus result = null;
try {
result = myVcs.createStatusClient().doStatus(file, remote, false);
}
catch (SVNException e) {
LOG.debug(e); // most likely the file is unversioned
}
return SvnContentRevision.createRemote(myVcs, filePath, svnRevision);
return result;
}
private SVNStatus getStatusCommandLine(File file, boolean remote) {
SVNStatus result = null;
try {
result = new SvnCommandLineStatusClient(myVcs.getProject()).doStatus(file, remote, false);
}
catch (SVNException e) {
LOG.debug(e);
}
return result;
}
public ItemLatestState getLastRevision(FilePath filePath) {
@@ -159,36 +165,29 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin {
}
private ItemLatestState getLastRevision(final File file) {
final SVNStatusClient client = myVcs.createStatusClient();
try {
final SVNStatus svnStatus = client.doStatus(file, true);
if (svnStatus == null || itemExists(svnStatus) && SVNRevision.UNDEFINED.equals(svnStatus.getRemoteRevision())) {
// IDEADEV-21785 (no idea why this can happen)
final SVNInfo info = myVcs.createWCClient().doInfo(file, SVNRevision.HEAD);
if (info == null || info.getURL() == null) {
LOG.info("No SVN status returned for " + file.getPath());
return defaultResult();
}
return createResult(info.getCommittedRevision(), true, false);
final SVNStatus svnStatus = getFileStatus(file, true);
if (svnStatus == null || itemExists(svnStatus) && SVNRevision.UNDEFINED.equals(svnStatus.getRemoteRevision())) {
// IDEADEV-21785 (no idea why this can happen)
final SVNInfo info = myVcs.getInfo(file, SVNRevision.HEAD);
if (info == null || info.getURL() == null) {
LOG.info("No SVN status returned for " + file.getPath());
return defaultResult();
}
final boolean exists = itemExists(svnStatus);
if (! exists) {
// get really latest revision
final LatestExistentSearcher searcher = new LatestExistentSearcher(myVcs, svnStatus.getURL());
final long revision = searcher.getDeletionRevision();
return createResult(info.getCommittedRevision(), true, false);
}
final boolean exists = itemExists(svnStatus);
if (! exists) {
// get really latest revision
final LatestExistentSearcher searcher = new LatestExistentSearcher(myVcs, svnStatus.getURL());
final long revision = searcher.getDeletionRevision();
return createResult(SVNRevision.create(revision), exists, false);
}
final SVNRevision remoteRevision = svnStatus.getRemoteRevision();
if (remoteRevision != null) {
return createResult(remoteRevision, exists, false);
}
return createResult(svnStatus.getRevision(), exists, false);
return createResult(SVNRevision.create(revision), exists, false);
}
catch (SVNException e) {
LOG.debug(e); // most likely the file is unversioned
return defaultResult();
final SVNRevision remoteRevision = svnStatus.getRemoteRevision();
if (remoteRevision != null) {
return createResult(remoteRevision, exists, false);
}
return createResult(svnStatus.getRevision(), exists, false);
}
private boolean itemExists(SVNStatus svnStatus) {
@@ -44,10 +44,7 @@ import com.intellij.util.containers.MultiMap;
import com.intellij.vcsUtil.ActionWithTempFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.wc.*;
@@ -160,10 +157,10 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
}
private class UUIDHelper {
private final SVNWCClient myWcClient;
private final SvnVcs myVcs;
private UUIDHelper(final SvnVcs vcs) {
myWcClient = vcs.createWCClient();
myVcs = vcs;
}
/**
@@ -175,7 +172,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
final SVNInfo info1 = new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
myT = myWcClient.doInfo(new File(dir.getPath()), SVNRevision.UNDEFINED);
myT = myVcs.getInfo(new File(dir.getPath()));
}
}.compute();
if (info1 == null || info1.getRepositoryUUID() == null) {
@@ -244,10 +241,11 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
long srcTime = src.lastModified();
try {
final boolean isUndo = isUndo(vcs);
final String list = isUndo ? null : SvnChangelistListener.getCurrentMapping(vcs.getProject(), src);
final String list = isUndo ? null : SvnChangelistListener.getCurrentMapping(vcs, src);
final boolean is17 = SvnUtil.is17CopyPart(src);
if (is17) {
WorkingCopyFormat format = vcs.getWorkingCopyFormat(src);
final boolean is17OrLater = WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || WorkingCopyFormat.ONE_DOT_SEVEN.equals(format);
if (is17OrLater) {
SVNStatus srcStatus = getFileStatus(vcs, src);
final File toDir = dst.getParentFile();
SVNStatus dstStatus = getFileStatus(vcs, toDir);
@@ -283,29 +281,18 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
ourStatusesForUndoMove.add(SVNStatusType.STATUS_ADDED);
}
private boolean for17move(SvnVcs vcs, final File src, final File dst, boolean undo, SVNStatus srcStatus) throws SVNException {
private boolean for17move(final SvnVcs vcs, final File src, final File dst, boolean undo, SVNStatus srcStatus) throws SVNException {
if (srcStatus != null && srcStatus.getCopyFromURL() == null) {
undo = false;
}
if (undo) {
myUndoingMove = true;
final SVNWCClient wcClient = vcs.createWCClient();
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doRevert(dst, true);
}
}.execute();
createRevertAction(vcs, dst, true).execute();
copyUnversionedMembersOfDirectory(src, dst);
if (srcStatus == null || SvnVcs.svnStatusIsUnversioned(srcStatus)) {
FileUtil.delete(src);
} else {
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doRevert(src, true);
}
}.execute();
createRevertAction(vcs, src, true).execute();
}
restoreFromUndoStorage(dst);
} else {
@@ -317,15 +304,9 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
copyFileOrDir(src, dst);
}
catch (IOException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
final SVNWCClient wcClient = vcs.createWCClient();
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doDelete(src, true, false);
}
}.execute();
createDeleteAction(vcs, src, true).execute();
return false;
}
moveFileWithSvn(vcs, src, dst);
@@ -333,13 +314,16 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
return false;
}
public static void moveFileWithSvn(SvnVcs vcs, File src, final File dst) throws SVNException {
final SVNCopyClient copyClient = vcs.createCopyClient();
final SVNCopySource svnCopySource = new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.WORKING, src);
public static void moveFileWithSvn(final SvnVcs vcs, final File src, final File dst) throws SVNException {
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
copyClient.doCopy(new SVNCopySource[]{svnCopySource}, dst, true, false, true);
try {
vcs.getFactory(src).createCopyMoveClient().copy(src, dst, false, true);
}
catch (VcsException e) {
wrapAndThrow(e);
}
}
}.execute();
}
@@ -357,7 +341,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
copyFileOrDir(src, dst);
}
catch (IOException e) {
exc[0] = new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
exc[0] = new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
return false;
}
}
@@ -464,7 +448,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
* deleted: do nothing, return true (strange)
*/
public boolean delete(VirtualFile file) throws IOException {
SvnVcs vcs = getVCS(file);
final SvnVcs vcs = getVCS(file);
if (vcs != null && SvnUtil.isAdminDirectory(file)) {
return true;
}
@@ -476,12 +460,8 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioFile.getParentFile())) {
return false;
}
try {
if (SVNWCUtil.isWorkingCopyRoot(ioFile)) {
return false;
}
} catch (SVNException e) {
//
if (SvnUtil.isWorkingCopyRoot(ioFile)) {
return false;
}
SVNStatus status = getFileStatus(vcs, ioFile);
@@ -507,13 +487,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
}
if (SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_ADDED)) {
try {
final SVNWCClient wcClient = vcs.createWCClient();
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doRevert(ioFile, false);
}
}.execute();
createRevertAction(vcs, ioFile, false).execute();
}
catch (SVNException e) {
// ignore
@@ -529,6 +503,41 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
}
}
@NotNull
private RepeatSvnActionThroughBusy createRevertAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean recursive) {
return new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
try {
vcs.getFactory(file).createRevertClient().revert(new File[]{file}, SVNDepth.fromRecurse(recursive), null);
}
catch (VcsException e) {
wrapAndThrow(e);
}
}
};
}
@NotNull
private RepeatSvnActionThroughBusy createDeleteAction(@NotNull final SvnVcs vcs, @NotNull final File file, final boolean force) {
return new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
try {
vcs.getFactory(file).createDeleteClient().delete(file, force);
}
catch (VcsException e) {
wrapAndThrow(e);
}
}
};
}
private static void wrapAndThrow(VcsException e) throws SVNException {
// TODO: probably we should wrap into new exception only if e.getCause is not SVNException
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, e), e);
}
private boolean isAboveSourceOfCopyOrMove(final Project p, File ioFile) {
for (MovedFileInfo file : myMovedFiles) {
if (FileUtil.isAncestor(ioFile, file.mySrc, false)) return true;
@@ -583,7 +592,6 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
if (! SvnUtil.isSvnVersioned(vcs.getProject(), ioDir) && ! pendingAdd) {
return false;
}
final SVNWCClient wcClient = vcs.createWCClient();
final File targetFile = new File(ioDir, name);
SVNStatus status = getFileStatus(vcs, targetFile);
@@ -603,12 +611,7 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
}
try {
if (isUndo(vcs)) {
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doRevert(targetFile, false);
}
}.execute();
createRevertAction(vcs, targetFile, false).execute();
return true;
}
myAddedFiles.putValue(vcs.getProject(), new AddedFileInfo(dir, name, null, recursive));
@@ -759,8 +762,6 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
return new Runnable() {
@Override
public void run() {
final SVNWCClient wcClient = vcs.createWCClient();
final SVNCopyClient copyClient = vcs.createCopyClient();
for(VirtualFile file: filesToProcess) {
final File ioFile = new File(file.getPath());
try {
@@ -771,11 +772,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
protected void executeInternal() throws VcsException {
try {
// not recursive
final SVNCopySource[] copySource = {new SVNCopySource(SVNRevision.WORKING, SVNRevision.WORKING, copyFrom)};
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
copyClient.doCopy(copySource, ioFile, false, true, true);
try {
vcs.getFactory(copyFrom).createCopyMoveClient().copy(copyFrom, ioFile, true, false);
}
catch (VcsException e) {
wrapAndThrow(e);
}
}
}.execute();
}
@@ -793,7 +798,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doAdd(ioFile, true, false, false, true);
try {
vcs.getFactory(ioFile).createAddClient().add(ioFile, null, false, false, true, null);
}
catch (VcsException e) {
wrapAndThrow(e);
}
}
}.execute();
}
@@ -915,17 +925,11 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
final List<VcsException> exceptions) {
return new Runnable() {
public void run() {
final SVNWCClient wcClient = vcs.createWCClient();
for(FilePath file: filesToProcess) {
VirtualFile vFile = file.getVirtualFile(); // for deleted directories
final File ioFile = new File(file.getPath());
try {
new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
wcClient.doDelete(ioFile, true, false);
}
}.execute();
createDeleteAction(vcs, ioFile, true).execute();
if (vFile != null && vFile.isValid() && vFile.isDirectory()) {
vFile.refresh(true, true);
VcsDirtyScopeManager.getInstance(project).dirDirtyRecursively(vFile);
@@ -978,18 +982,15 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
private void fillDeletedFiles(Project project, List<Pair<FilePath, WorkingCopyFormat>> deletedFiles, Collection<FilePath> deleteAnyway)
throws SVNException {
final SvnVcs vcs = SvnVcs.getInstance(project);
final SVNStatusClient sc = vcs.createStatusClient();
final Collection<File> files = myDeletedFiles.remove(project);
for (final File file : files) {
boolean isAdded = false;
final SVNStatus status;
status = new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
myT = sc.doStatus(file, false);
}
}.compute();
isAdded = SVNStatusType.STATUS_ADDED.equals(status.getNodeStatus());
final SVNStatus status = new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
myT = vcs.getFactory(file).createStatusClient().doStatus(file, false);
}
}.compute();
boolean isAdded = SVNStatusType.STATUS_ADDED.equals(status.getNodeStatus());
final FilePath filePath = VcsContextFactory.SERVICE.getInstance().createFilePathOn(file);
if (isAdded) {
deleteAnyway.add(filePath);
@@ -1034,18 +1035,12 @@ public class SvnFileSystemListener extends CommandAdapter implements LocalFileOp
}
@Nullable
private static SVNStatus getFileStatus(SvnVcs vcs, File file) {
SVNStatusClient stClient = vcs.createStatusClient();
return getFileStatus(file, stClient);
}
@Nullable
private static SVNStatus getFileStatus(final File file, final SVNStatusClient stClient) {
private static SVNStatus getFileStatus(@NotNull final SvnVcs vcs, @NotNull final File file) {
try {
return new RepeatSvnActionThroughBusy() {
@Override
protected void executeImpl() throws SVNException {
myT = stClient.doStatus(file, false);
myT = vcs.getFactory(file).createStatusClient().doStatus(file, false);
}
}.compute();
}
@@ -312,8 +312,8 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState
LOG.info("Error: cannot find repository URL for versioned folder: " + foundRoot.getFile().getPath());
} else {
myRepositoryRoots.register(repoRoot);
myTopRoots.add(new RootUrlInfo(repoRoot, foundRoot.getInfo().getURL(),
SvnFormatSelector.getWorkingCopyFormat(new File(foundRoot.getFile().getPath())), foundRoot.getFile(), vcsRoot));
myTopRoots.add(new RootUrlInfo(repoRoot, foundRoot.getInfo().getURL(), SvnFormatSelector.findRootAndGetFormat(
new File(foundRoot.getFile().getPath())), foundRoot.getFile(), vcsRoot));
}
}
}
@@ -541,8 +541,9 @@ public class SvnFileUrlMappingImpl implements SvnFileUrlMapping, PersistentState
final SVNInfo svnInfo = vcs.getInfo(copyRoot);
if ((svnInfo == null) || (svnInfo.getRepositoryRootURL() == null)) continue;
final RootUrlInfo info = new RootUrlInfo(svnInfo.getRepositoryRootURL(), svnInfo.getURL(),
SvnFormatSelector.getWorkingCopyFormat(svnInfo.getFile()), copyRoot, vcsRoot);
final RootUrlInfo info =
new RootUrlInfo(svnInfo.getRepositoryRootURL(), svnInfo.getURL(), SvnFormatSelector.findRootAndGetFormat(svnInfo.getFile()),
copyRoot, vcsRoot);
mapping.add(info);
}
}
@@ -16,6 +16,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;
@@ -37,6 +38,9 @@ import java.util.Collections;
import java.util.Iterator;
public class SvnFormatSelector implements ISVNAdminAreaFactorySelector {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnFormatSelector");
public Collection getEnabledFactories(File path, Collection factories, boolean writeAccess) throws SVNException {
if (ApplicationManager.getApplication().isUnitTestMode()) {
return factories;
@@ -145,7 +149,19 @@ public class SvnFormatSelector implements ISVNAdminAreaFactorySelector {
return newMode[0];
}
public static WorkingCopyFormat findRootAndGetFormat(final File path) {
File root = SvnUtil.getWorkingCopyRootNew(path);
return root != null ? getWorkingCopyFormat(root) : WorkingCopyFormat.UNKNOWN;
}
public static WorkingCopyFormat getWorkingCopyFormat(final File path) {
WorkingCopyFormat format = SvnUtil.getFormat(path);
return WorkingCopyFormat.UNKNOWN.equals(format) ? detectWithSvnKit(path) : format;
}
private static WorkingCopyFormat detectWithSvnKit(File path) {
try {
final SvnWcGeneration svnWcGeneration = SvnOperationFactory.detectWcGeneration(path, true);
if (SvnWcGeneration.V17.equals(svnWcGeneration)) return WorkingCopyFormat.ONE_DOT_SEVEN;
@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference;
* Date: 10/19/12
* Time: 4:22 PM
*/
// TODO: Likely to be removed (together with SvnAbstractWriteOperationLocks).
public class SvnProxies {
private final SvnAbstractWriteOperationLocks myLocks;
private final AtomicReference<LearningProxy<SVNChangelistClientI, SVNException>> myChangelist;
@@ -47,13 +47,15 @@ import java.util.LinkedList;
public class SvnRecursiveStatusWalker {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnRecursiveStatusWalker");
private final StatusWalkerPartner myPartner;
private final SvnVcs myVcs;
private final Project myProject;
private final StatusReceiver myReceiver;
private final LinkedList<MyItem> myQueue;
private final MyHandler myHandler;
public SvnRecursiveStatusWalker(final Project project, final StatusReceiver receiver, final StatusWalkerPartner partner) {
myProject = project;
public SvnRecursiveStatusWalker(final SvnVcs vcs, final StatusReceiver receiver, final StatusWalkerPartner partner) {
myVcs = vcs;
myProject = vcs.getProject();
myReceiver = receiver;
myPartner = partner;
myQueue = new LinkedList<MyItem>();
@@ -61,7 +63,7 @@ public class SvnRecursiveStatusWalker {
}
public void go(final FilePath rootPath, final SVNDepth depth) throws SVNException {
final MyItem root = new MyItem(myProject, rootPath, depth, myPartner.createStatusClient(), false);
final MyItem root = new MyItem(myVcs, rootPath, depth, myPartner.createStatusClient(), false);
myQueue.add(root);
while (! myQueue.isEmpty()) {
@@ -83,7 +85,7 @@ public class SvnRecursiveStatusWalker {
}
} else {
try {
final SVNStatus status = item.getClient().doStatus(ioFile, false, false);
final SVNStatus status = item.getClient(ioFile).doStatus(ioFile, false, false);
myReceiver.process(path, status);
} catch (SVNException e) {
handleStatusException(item, path, e);
@@ -115,18 +117,20 @@ public class SvnRecursiveStatusWalker {
private final Project myProject;
private final FilePath myPath;
private final SVNDepth myDepth;
private final SVNStatusClient myClient;
private final SvnStatusClientI mySvnClient;
private final SvnStatusClientI myCommandLineClient;
private final boolean myIsInnerCopyRoot;
private final SvnConfiguration myConfiguration17;
private final SvnVcs myVcs;
private MyItem(Project project, FilePath path, SVNDepth depth, SVNStatusClient client, boolean isInnerCopyRoot) {
myProject = project;
private MyItem(SvnVcs vcs, FilePath path, SVNDepth depth, SVNStatusClient client, boolean isInnerCopyRoot) {
myVcs = vcs;
myProject = vcs.getProject();
myConfiguration17 = SvnConfiguration.getInstance(myProject);
myPath = path;
myDepth = depth;
myClient = client;
mySvnClient = new SvnkitSvnStatusClient(client);
myCommandLineClient = new SvnCommandLineStatusClient(myProject);
myIsInnerCopyRoot = isInnerCopyRoot;
}
@@ -138,20 +142,20 @@ public class SvnRecursiveStatusWalker {
return myDepth;
}
public SvnStatusClientI getClient() {
return mySvnClient;
}
public SvnStatusClientI getClient(final File file) {
if (! SVNDepth.INFINITY.equals(myDepth)) {
return mySvnClient;
WorkingCopyFormat format = myVcs.getWorkingCopyFormat(file);
if (format == WorkingCopyFormat.ONE_DOT_EIGHT) {
return myCommandLineClient;
}
// check format
if (CheckJavaHL.isPresent() && SvnConfiguration.UseAcceleration.javaHL.equals(myConfiguration17.myUseAcceleration) &&
Svn17Detector.is17(myProject, file)) {
return new JavaHLSvnStatusClient(myProject);
} else if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration17.myUseAcceleration) && Svn17Detector.is17(myProject, file)) {
return new SvnCommandLineStatusClient(myProject);
} else if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration17.myUseAcceleration)) {
// apply command line disregarding working copy format
return myCommandLineClient;
}
return mySvnClient;
}
@@ -186,7 +190,7 @@ public class SvnRecursiveStatusWalker {
return true;
}
if (file.isDirectory() && new File(file, SVNFileUtil.getAdminDirectoryName()).exists()) {
final MyItem childItem = new MyItem(myProject, path, newDepth, myPartner.createStatusClient(), true);
final MyItem childItem = new MyItem(myVcs, path, newDepth, myPartner.createStatusClient(), true);
myQueue.add(childItem);
} else if (vf != null) {
myReceiver.processUnversioned(vf);
@@ -228,12 +232,13 @@ public class SvnRecursiveStatusWalker {
}
public void checkIfCopyRootWasReported(@Nullable final SVNStatus ioFileStatus, final File ioFile) {
if (! myMetCurrentItem && FileUtil.filesEqual(ioFile, myCurrentItem.getPath().getIOFile())) {
File itemFile = myCurrentItem.getPath().getIOFile();
if (! myMetCurrentItem && FileUtil.filesEqual(ioFile, itemFile)) {
myMetCurrentItem = true;
SVNStatus statusInner;
try {
statusInner = ioFileStatus != null ? ioFileStatus :
myCurrentItem.getClient().doStatus(myCurrentItem.getPath().getIOFile(), false);
myCurrentItem.getClient(itemFile).doStatus(itemFile, false);
}
catch (SVNException e) {
LOG.info(e);
@@ -294,7 +299,7 @@ public class SvnRecursiveStatusWalker {
//myReceiver.processUnversioned(vFile);
//processRecursively(vFile, myCurrentItem.getDepth());
} else {
final MyItem childItem = new MyItem(myProject, new FilePathImpl(vFile), SVNDepth.INFINITY,
final MyItem childItem = new MyItem(myVcs, new FilePathImpl(vFile), SVNDepth.INFINITY,
myPartner.createStatusClient(), true);
myQueue.add(childItem);
}
@@ -25,6 +25,7 @@ import java.io.File;
* Date: 10/23/12
* Time: 2:31 PM
*/
// TODO: Used only in SvnLockingTest which is not required anymore. Likely to be removed.
public class SvnTestWriteOperationLocks extends SvnAbstractWriteOperationLocks {
private final WorkingCopy myWorkingCopy;
@@ -30,21 +30,19 @@ 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.vcs.impl.ContentRevisionCache;
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.vfs.*;
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.ClientFactory;
import org.jetbrains.idea.svn.branchConfig.SvnBranchConfigurationNew;
import org.jetbrains.idea.svn.dialogs.LockDialog;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.table.SqlJetDb;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
@@ -53,14 +51,14 @@ import org.tmatesoft.svn.core.io.SVNCapability;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
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
// TODO: Remember this when moving out SVNKit classes.
@NonNls public static final String SVN_ADMIN_DIR_NAME = SVNFileUtil.getAdminDirectoryName();
@NonNls public static final String ENTRIES_FILE_NAME = "entries";
@NonNls public static final String WC_DB_FILE_NAME = "wc.db";
@@ -71,13 +69,9 @@ public class SvnUtil {
private SvnUtil() { }
public static boolean isSvnVersioned(final Project project, File parent) {
try {
final SVNInfo info = SvnVcs.getInstance(project).createWCClient().doInfo(parent, SVNRevision.UNDEFINED);
return info != null;
}
catch (SVNException e) {
return false;
}
final SVNInfo info = SvnVcs.getInstance(project).getInfo(parent);
return info != null;
}
public static Collection<VirtualFile> crawlWCRoots(final Project project, File path, SvnWCRootCrawler callback, ProgressIndicator progress) {
@@ -123,15 +117,8 @@ public class SvnUtil {
@Nullable
public static String getExactLocation(final SvnVcs vcs, File path) {
try {
SVNWCClient wcClient = vcs.createWCClient();
SVNInfo info = wcClient.doInfo(path, SVNRevision.UNDEFINED);
if (info != null && info.getURL() != null) {
return info.getURL().toString();
}
}
catch (SVNException ignored) { }
return null;
SVNInfo info = vcs.getInfo(path);
return info != null && info.getURL() != null ? info.getURL().toString() : null;
}
public static Map<String, File> getLocationInfoForModule(final SvnVcs vcs, File path, ProgressIndicator progress) {
@@ -288,7 +275,9 @@ public class SvnUtil {
}
public static String formatRepresentation(final WorkingCopyFormat format) {
if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) {
if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format)) {
return SvnBundle.message("dialog.show.svn.map.table.version18.text");
} else if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) {
return SvnBundle.message("dialog.show.svn.map.table.version17.text");
} else if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) {
return SvnBundle.message("dialog.show.svn.map.table.version16.text");
@@ -352,6 +341,54 @@ public class SvnUtil {
return result;
}
/**
* Gets working copy internal format. Works for 1.7 and 1.8.
*
* @param path
* @return
*/
public static WorkingCopyFormat getFormat(final File path) {
int format = 0;
File dbFile = resolveDatabase(path);
if (dbFile != null) {
SqlJetDb db = null;
try {
db = SqlJetDb.open(dbFile, false);
format = db.getOptions().getUserVersion();
}
catch (SqlJetException e) {
LOG.error(e);
} finally {
if (db != null) {
try {
db.close();
}
catch (SqlJetException e) {
LOG.error(e);
}
}
}
}
return WorkingCopyFormat.getInstance(format);
}
private static File resolveDatabase(final File path) {
File dbFile = getWcDb(path);
File result = null;
try {
if (dbFile.exists() && dbFile.isFile()) {
result = dbFile;
}
} catch (SecurityException e) {
LOG.error("Failed to access working copy database", e);
}
return result;
}
private static class LocationsCrawler implements SvnWCRootCrawler {
private final SvnVcs myVcs;
private final Map<String, File> myLocations;
@@ -371,15 +408,9 @@ public class SvnUtil {
oldText = progress.getText();
progress.setText(SvnBundle.message("progress.text.discovering.location", root.getAbsolutePath()));
}
try {
SVNWCClient wcClient = myVcs.createWCClient();
SVNInfo info = wcClient.doInfo(root, SVNRevision.UNDEFINED);
if (info != null && info.getURL() != null) {
myLocations.put(info.getURL().toString(), info.getFile());
}
}
catch (SVNException e) {
//
SVNInfo info = myVcs.getInfo(root);
if (info != null && info.getURL() != null) {
myLocations.put(info.getURL().toString(), info.getFile());
}
if (progress != null) {
progress.setText(oldText);
@@ -389,20 +420,15 @@ public class SvnUtil {
@Nullable
public static String getRepositoryUUID(final SvnVcs vcs, final File file) {
final SVNWCClient client = vcs.createWCClient();
try {
final SVNInfo info = client.doInfo(file, SVNRevision.UNDEFINED);
return (info == null) ? null : info.getRepositoryUUID();
} catch (SVNException e) {
return null;
}
final SVNInfo info = vcs.getInfo(file);
return info != null ? info.getRepositoryUUID() : null;
}
@Nullable
public static String getRepositoryUUID(final SvnVcs vcs, final SVNURL url) {
final SVNWCClient client = vcs.createWCClient();
try {
final SVNInfo info = client.doInfo(url, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED);
final SVNInfo info = vcs.getInfo(url, SVNRevision.UNDEFINED);
return (info == null) ? null : info.getRepositoryUUID();
} catch (SVNException e) {
return null;
@@ -411,19 +437,14 @@ public class SvnUtil {
@Nullable
public static SVNURL getRepositoryRoot(final SvnVcs vcs, final File file) {
final SVNWCClient client = vcs.createWCClient();
try {
final SVNInfo info = client.doInfo(file, SVNRevision.UNDEFINED);
return (info == null) ? null : info.getRepositoryRootURL();
} catch (SVNException e) {
return null;
}
final SVNInfo info = vcs.getInfo(file);
return info != null ? info.getRepositoryRootURL() : null;
}
@Nullable
public static SVNURL getRepositoryRoot(final SvnVcs vcs, final String url) {
try {
return getRepositoryRoot(vcs, SVNURL.parseURIEncoded(url), true);
return getRepositoryRoot(vcs, SVNURL.parseURIEncoded(url));
}
catch (SVNException e) {
return null;
@@ -431,18 +452,14 @@ public class SvnUtil {
}
@Nullable
public static SVNURL getRepositoryRoot(final SvnVcs vcs, final SVNURL url, boolean allowRemote) throws SVNException {
final SVNWCClient client = vcs.createWCClient();
SVNInfo info = client.doInfo(url, SVNRevision.UNDEFINED, SVNRevision.HEAD);
public static SVNURL getRepositoryRoot(final SvnVcs vcs, final SVNURL url) throws SVNException {
SVNInfo info = vcs.getInfo(url, SVNRevision.HEAD);
return (info == null) ? null : info.getRepositoryRootURL();
}
public static boolean isWorkingCopyRoot(final File file) {
try {
return SVNWCUtil.isWorkingCopyRoot(file);
} catch (SVNException e) {
return false;
}
return FileUtil.filesEqual(file, getWorkingCopyRootNew(file));
}
@Nullable
@@ -548,17 +565,9 @@ public class SvnUtil {
}
public static SVNDepth getDepth(final SvnVcs vcs, final File file) {
final SVNWCClient client = vcs.createWCClient();
try {
final SVNInfo svnInfo = client.doInfo(file, SVNRevision.UNDEFINED);
if (svnInfo != null) {
return svnInfo.getDepth();
}
}
catch (SVNException e) {
//
}
return SVNDepth.UNKNOWN;
SVNInfo info = vcs.getInfo(file);
return info != null && info.getDepth() != null ? info.getDepth() : SVNDepth.UNKNOWN;
}
public static boolean seemsLikeVersionedDir(final VirtualFile file) {
@@ -590,21 +599,17 @@ public class SvnUtil {
}
public static SVNURL getCommittedURL(final SvnVcs vcs, final File file) {
final File root = getWorkingCopyRoot(file);
if (root == null) return null;
return getUrl(vcs, root);
final File root = getWorkingCopyRootNew(file);
return root == null ? null : getUrl(vcs, root);
}
@Nullable
public static SVNURL getUrl(final SvnVcs vcs, final File file) {
try {
final SVNInfo info = vcs.createWCClient().doInfo(file, SVNRevision.UNDEFINED);
return info == null ? null : info.getURL(); // todo for moved items?
}
catch (SVNException e) {
LOG.debug(e);
return null;
}
// todo for moved items?
final SVNInfo info = vcs.getInfo(file);
return info == null ? null : info.getURL();
}
public static boolean doesRepositorySupportMergeInfo(final SvnVcs vcs, final SVNURL url) {
@@ -648,17 +653,9 @@ public class SvnUtil {
@Nullable
public static File getWcCopyRootIf17(final File file, @Nullable final File upperBound) {
File current = file;
boolean wcDbFound = false;
while (current != null) {
File wcDb;
if ((wcDb = getWcDb(current)).exists() && ! wcDb.isDirectory()) {
wcDbFound = true;
break;
}
current = current.getParentFile();
}
if (! wcDbFound) return null;
File current = getParentWithDb(file);
if (current == null) return null;
while (current != null) {
try {
final SvnWcGeneration svnWcGeneration = SvnOperationFactory.detectWcGeneration(current, false);
@@ -674,6 +671,40 @@ public class SvnUtil {
return null;
}
/**
* Utility method that deals also with 1.8 working copies.
* TODO: Should be renamed when all parts updated for 1.8.
*
* @param file
* @return
*/
@Nullable
public static File getWorkingCopyRootNew(final File file) {
File current = getParentWithDb(file);
if (current == null) return getWorkingCopyRoot(file);
WorkingCopyFormat format = getFormat(current);
return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)
? current
: getWorkingCopyRoot(file);
}
private static File getParentWithDb(File file) {
File current = file;
boolean wcDbFound = false;
while (current != null) {
File wcDb;
if ((wcDb = getWcDb(current)).exists() && ! wcDb.isDirectory()) {
wcDbFound = true;
break;
}
current = current.getParentFile();
}
if (! wcDbFound) return null;
return current;
}
public static boolean is17CopyPart(final File file) {
try {
return SvnWcGeneration.V17.equals(SvnOperationFactory.detectWcGeneration(file, true));
@@ -703,44 +734,24 @@ public class SvnUtil {
return result;
}
public static byte[] getFileContents(final SvnVcs vcs, final String path, final boolean isUrl, final SVNRevision revision,
final SVNRevision pegRevision)
public static byte[] getFileContents(@NotNull final SvnVcs vcs,
@NotNull final SvnTarget target,
@Nullable final SVNRevision revision,
@Nullable final SVNRevision pegRevision)
throws VcsException {
final int maxSize = VcsUtil.getMaxVcsLoadedFileSize();
ByteArrayOutputStream buffer = new ByteArrayOutputStream() {
@Override
public synchronized void write(int b) {
if (size() > maxSize) throw new FileTooBigRuntimeException();
super.write(b);
}
ClientFactory factory = target.isFile() ? vcs.getFactory(target.getFile()) : vcs.getFactory();
@Override
public synchronized void write(byte[] b, int off, int len) {
if (size() > maxSize) throw new FileTooBigRuntimeException();
super.write(b, off, len);
}
@Override
public synchronized void writeTo(OutputStream out) throws IOException {
if (size() > maxSize) throw new FileTooBigRuntimeException();
super.writeTo(out);
}
};
SVNWCClient wcClient = vcs.createWCClient();
try {
if (isUrl) {
wcClient.doGetFileContents(SVNURL.parseURIEncoded(path), pegRevision, revision, true, buffer);
} else {
wcClient.doGetFileContents(new File(path), pegRevision, revision, true, buffer);
}
ContentRevisionCache.checkContentsSize(path, buffer.size());
} catch (FileTooBigRuntimeException e) {
ContentRevisionCache.checkContentsSize(path, buffer.size());
} catch (SVNException e) {
throw new VcsException(e);
}
return buffer.toByteArray();
return factory.createContentClient().getContent(target, revision, pegRevision);
}
private static class FileTooBigRuntimeException extends RuntimeException {}
public static SVNURL parseUrl(@NotNull String url) {
try {
return SVNURL.parseURIEncoded(url);
}
catch (SVNException e) {
IllegalArgumentException runtimeException = new IllegalArgumentException();
runtimeException.initCause(e);
throw runtimeException;
}
}
}
@@ -68,8 +68,12 @@ import org.jetbrains.idea.svn.actions.CleanupWorker;
import org.jetbrains.idea.svn.actions.ShowPropertiesDiffWithLocalAction;
import org.jetbrains.idea.svn.actions.SvnMergeProvider;
import org.jetbrains.idea.svn.annotate.SvnAnnotationProvider;
import org.jetbrains.idea.svn.api.ClientFactory;
import org.jetbrains.idea.svn.api.CmdClientFactory;
import org.jetbrains.idea.svn.api.SvnKitClientFactory;
import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment;
import org.jetbrains.idea.svn.checkout.SvnCheckoutProvider;
import org.jetbrains.idea.svn.commandLine.SvnCommandLineInfoClient;
import org.jetbrains.idea.svn.commandLine.SvnExecutableChecker;
import org.jetbrains.idea.svn.dialogs.SvnBranchPointsCalculator;
import org.jetbrains.idea.svn.dialogs.WCInfo;
@@ -79,6 +83,7 @@ import org.jetbrains.idea.svn.history.SvnCommittedChangesProvider;
import org.jetbrains.idea.svn.history.SvnHistoryProvider;
import org.jetbrains.idea.svn.lowLevel.PrimitivePool;
import org.jetbrains.idea.svn.networking.SSLProtocolExceptionParser;
import org.jetbrains.idea.svn.portable.SvnWcClientI;
import org.jetbrains.idea.svn.rollback.SvnRollbackEnvironment;
import org.jetbrains.idea.svn.update.SvnIntegrateEnvironment;
import org.jetbrains.idea.svn.update.SvnUpdateEnvironment;
@@ -195,6 +200,10 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
};
private SvnCheckoutProvider myCheckoutProvider;
private ClientFactory cmdClientFactory;
private ClientFactory svnKitClientFactory;
public void checkCommandLineVersion() {
myChecker.checkExecutableAndNotifyIfNeeded();
}
@@ -481,6 +490,9 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
myChecker.checkExecutableAndNotifyIfNeeded();
}
cmdClientFactory = new CmdClientFactory(this);
svnKitClientFactory = new SvnKitClientFactory(this);
// do one time after project loaded
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
@Override
@@ -911,24 +923,125 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
return new File(file, pathToDirProps);
}
/**
* Provides info either with command line or SvnKit based on project settings.
* Call this method only if failed to detect working copy format by any other means.
*
* @param file
* @return
*/
private SVNInfo runInfoCommand(@NotNull final File file) {
SVNInfo result = null;
try {
result = SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration)
? getInfoCommandLine(file, SVNRevision.UNDEFINED)
: getInfoSvnKit(file);
}
catch (SVNException e) {
handleInfoException(e);
}
return result;
}
public SVNInfo getInfo(@NotNull SVNURL url,
SVNRevision pegRevision,
SVNRevision revision,
ISVNAuthenticationManager manager) throws SVNException {
if (SvnConfiguration.UseAcceleration.commandLine.equals(myConfiguration.myUseAcceleration)) {
return createInfoClient().doInfo(url, pegRevision, revision);
} else {
return (manager != null ? createWCClient(manager) : createWCClient()).doInfo(url, pegRevision, revision);
}
}
public SVNInfo getInfo(@NotNull SVNURL url, SVNRevision revision) throws SVNException {
return getInfo(url, SVNRevision.UNDEFINED, revision, null);
}
@Nullable
public SVNInfo getInfo(final VirtualFile file) {
public SVNInfo getInfo(@NotNull final VirtualFile file) {
final File ioFile = new File(file.getPath());
return getInfo(ioFile);
}
public SVNInfo getInfo(File ioFile) {
@Nullable
public SVNInfo getInfo(@NotNull String path) {
return getInfo(new File(path));
}
@Nullable
public SVNInfo getInfo(@NotNull File ioFile) {
WorkingCopyFormat format = getWorkingCopyFormat(ioFile);
SVNInfo result = null;
try {
SVNWCClient wcClient = createWCClient();
SVNInfo info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED);
if (info == null || info.getRepositoryRootURL() == null) {
info = wcClient.doInfo(ioFile, SVNRevision.HEAD);
}
return info;
result = format == WorkingCopyFormat.ONE_DOT_EIGHT ? getInfoCommandLine(ioFile, SVNRevision.UNDEFINED) : runInfoCommand(ioFile);
}
catch (SVNException e) {
return null;
handleInfoException(e);
}
return result;
}
@Nullable
public SVNInfo getInfo(@NotNull File ioFile, @NotNull SVNRevision revision) {
WorkingCopyFormat format = getWorkingCopyFormat(ioFile);
SVNInfo result = null;
try {
result = format == WorkingCopyFormat.ONE_DOT_EIGHT ? getInfoCommandLine(ioFile, revision) : getInfoSvnKit(ioFile, revision);
}
catch (SVNException e) {
handleInfoException(e);
}
return result;
}
private void handleInfoException(SVNException e) {
final SVNErrorCode errorCode = e.getErrorMessage().getErrorCode();
if (SVNErrorCode.WC_PATH_NOT_FOUND.equals(errorCode) ||
SVNErrorCode.UNVERSIONED_RESOURCE.equals(errorCode) || SVNErrorCode.WC_NOT_WORKING_COPY.equals(errorCode)) {
LOG.debug(e);
} else {
LOG.error(e);
}
}
private SVNInfo getInfoSvnKit(@NotNull File ioFile) throws SVNException {
SVNInfo info = getInfoSvnKit(ioFile, SVNRevision.UNDEFINED);
if (info == null || info.getRepositoryRootURL() == null) {
info = getInfoSvnKit(ioFile, SVNRevision.HEAD);
}
return info;
}
private SVNInfo getInfoSvnKit(@NotNull File ioFile, SVNRevision revision) throws SVNException {
return createWCClient().doInfo(ioFile, revision);
}
private SVNInfo getInfoCommandLine(@NotNull File ioFile, SVNRevision revision) throws SVNException {
SvnCommandLineInfoClient client = new SvnCommandLineInfoClient(myProject);
return client.doInfo(ioFile, revision);
}
private SvnWcClientI createInfoClient() {
return new SvnCommandLineInfoClient(myProject);
}
public WorkingCopyFormat getWorkingCopyFormat(@NotNull File ioFile) {
RootUrlInfo rootInfo = getSvnFileUrlMapping().getWcRootForFilePath(ioFile);
WorkingCopyFormat format = rootInfo != null ? rootInfo.getFormat() : WorkingCopyFormat.UNKNOWN;
if (WorkingCopyFormat.UNKNOWN.equals(format)) {
format = SvnFormatSelector.findRootAndGetFormat(ioFile);
}
return format;
}
public void refreshSSLProperty() {
@@ -1245,4 +1358,27 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> {
}
return myCheckoutProvider;
}
/**
* 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.
*
* For instance, when working copies of several formats are presented in project
* (though it seems to be rather unlikely case).
*
* @return
*/
public ClientFactory getFactory() {
// check working copy format of project directory
WorkingCopyFormat format = getWorkingCopyFormat(new File(getProject().getBaseDir().getPath()));
return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ||
myConfiguration.myUseAcceleration.equals(SvnConfiguration.UseAcceleration.commandLine) ? cmdClientFactory : svnKitClientFactory;
}
public ClientFactory getFactory(@NotNull File file) {
WorkingCopyFormat format = getWorkingCopyFormat(file);
return WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? cmdClientFactory : getFactory();
}
}
@@ -30,6 +30,7 @@ import java.io.File;
* Date: 10/23/12
* Time: 2:29 PM
*/
// TODO: Such locking functionality is not required anymore. Likely to be removed.
public class SvnWriteOperationLocks extends SvnAbstractWriteOperationLocks {
private final RootsToWorkingCopies myRootsToWorkingCopies;
@@ -15,19 +15,22 @@
*/
package org.jetbrains.idea.svn;
import org.tmatesoft.svn.core.internal.wc17.db.ISVNWCDb;
/**
* since not all constants are available from svnkit & constants are fixed
*/
public enum WorkingCopyFormat {
ONE_DOT_THREE(4, false, false, false, SvnBundle.message("dialog.show.svn.map.table.version13.text")),
ONE_DOT_FOUR(8, false, false, false, SvnBundle.message("dialog.show.svn.map.table.version14.text")),
ONE_DOT_FIVE(9, true, true, false, SvnBundle.message("dialog.show.svn.map.table.version15.text")),
ONE_DOT_SIX(10, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version16.text")),
ONE_DOT_SEVEN(12, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version17.text")),
ONE_DOT_EIGHT(12, true, true, true, SvnBundle.message("dialog.show.svn.map.table.version18.text")),
UNKNOWN(0, false, false, false, "unknown");
public static final int INTERNAL_FORMAT_17 = 29;
public static final int INTERNAL_FORMAT_18 = 31;
private final int myFormat;
private final boolean myChangelistSupport;
private final boolean myMergeInfoSupport;
@@ -60,10 +63,11 @@ public enum WorkingCopyFormat {
public static WorkingCopyFormat getInstance(final int value) {
// somewhy 1.7 wc format can also be 29
if (ISVNWCDb.WC_FORMAT_17 == value) {
if (INTERNAL_FORMAT_17 == value) {
return ONE_DOT_SEVEN;
}
if (ONE_DOT_FIVE.getFormat() == value) {
} else if (INTERNAL_FORMAT_18 == value) {
return ONE_DOT_EIGHT;
} else if (ONE_DOT_FIVE.getFormat() == value) {
return ONE_DOT_FIVE;
} else if (ONE_DOT_FOUR.getFormat() == value) {
return ONE_DOT_FOUR;
@@ -30,8 +30,6 @@ import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnStatusUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.checkin.SvnCheckinEnvironment;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import java.util.*;
@@ -68,8 +66,6 @@ public class AddAction extends BasicAction {
ProjectLevelVcsManager manager = ProjectLevelVcsManager.getInstance(project);
manager.startBackgroundVcsOperation();
try {
SVNWCClient wcClient = activeVcs.createWCClient();
final Set<VirtualFile> additionallyDirty = new HashSet<VirtualFile>();
final FileStatusManager fileStatusManager = FileStatusManager.getInstance(project);
for (VirtualFile item : items) {
@@ -84,13 +80,13 @@ public class AddAction extends BasicAction {
}
}
}
Collection<SVNException> exceptions =
SvnCheckinEnvironment.scheduleUnversionedFilesForAddition(wcClient, Arrays.asList(items), true);
Collection<VcsException> exceptions =
SvnCheckinEnvironment.scheduleUnversionedFilesForAddition(activeVcs, Arrays.asList(items), true);
additionallyDirty.addAll(Arrays.asList(items));
markDirty(project, additionallyDirty);
if (!exceptions.isEmpty()) {
final Collection<String> messages = new ArrayList<String>(exceptions.size());
for (SVNException exception : exceptions) {
for (VcsException exception : exceptions) {
messages.add(exception.getMessage());
}
throw new VcsException(messages);
@@ -19,6 +19,7 @@ package org.jetbrains.idea.svn.actions;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.AbstractVcs;
@@ -32,8 +33,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnStatusUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.conflict.ConflictClient;
import org.jetbrains.idea.svn.dialogs.SelectFilesDialog;
import org.tmatesoft.svn.core.SVNDepth;
import org.jetbrains.idea.svn.portable.SvnStatusClientI;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.*;
@@ -42,6 +44,8 @@ import java.util.Collection;
import java.util.TreeSet;
public class MarkResolvedAction extends BasicAction {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.actions.MarkResolvedAction");
protected String getActionName(AbstractVcs vcs) {
return SvnBundle.message("action.name.mark.resolved");
}
@@ -88,15 +92,13 @@ public class MarkResolvedAction extends BasicAction {
}
pathsArray = dialog.getSelectedPaths();
try {
SVNWCClient wcClient = vcs.createWCClient();
for (String path : pathsArray) {
File ioFile = new File(path);
wcClient.doResolve(ioFile, SVNDepth.EMPTY, SVNConflictChoice.MERGED);
ConflictClient client = vcs.getFactory(ioFile).createConflictClient();
client.resolve(ioFile, true);
}
}
catch (SVNException e) {
throw new VcsException(e);
}
finally {
for (VirtualFile file : files) {
VcsDirtyScopeManager.getInstance(project).fileDirty(file);
@@ -115,10 +117,12 @@ public class MarkResolvedAction extends BasicAction {
private static Collection<String> collectResolvablePaths(final SvnVcs vcs, VirtualFile[] files) {
final Collection<String> target = new TreeSet<String>();
SVNStatusClient stClient = vcs.createStatusClient();
for (VirtualFile file : files) {
try {
stClient.doStatus(new File(file.getPath()), true, false, false, false, new ISVNStatusHandler() {
File path = new File(file.getPath());
SvnStatusClientI client = vcs.getFactory(path).createStatusClient();
client.doStatus(path, true, false, false, false, new ISVNStatusHandler() {
public void handleStatus(SVNStatus status) {
if (status.getContentsStatus() == SVNStatusType.STATUS_CONFLICTED ||
status.getPropertiesStatus() == SVNStatusType.STATUS_CONFLICTED) {
@@ -128,7 +132,7 @@ public class MarkResolvedAction extends BasicAction {
});
}
catch (SVNException e) {
//
LOG.warn(e);
}
}
return target;
@@ -27,12 +27,13 @@ import com.intellij.vcsUtil.VcsRunnable;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnRevisionNumber;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.jetbrains.idea.svn.properties.PropertyClient;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -57,38 +58,34 @@ public class SvnMergeProvider implements MergeProvider {
final MergeData data = new MergeData();
VcsRunnable runnable = new VcsRunnable() {
public void run() throws VcsException {
SvnVcs vcs = SvnVcs.getInstance(myProject);
File oldFile = null;
File newFile = null;
File workingFile = null;
SVNWCClient client;
boolean mergeCase = false;
try {
client = vcs.createWCClient();
SVNInfo info = client.doInfo(new File(file.getPath()), SVNRevision.UNDEFINED);
if (info != null) {
oldFile = info.getConflictOldFile();
newFile = info.getConflictNewFile();
workingFile = info.getConflictWrkFile();
mergeCase = workingFile == null || workingFile.getName().contains("working");
// for debug
if (workingFile == null) {
LOG.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile);
}
if (mergeCase) {
// this is merge case
oldFile = info.getConflictNewFile();
newFile = info.getConflictOldFile();
workingFile = info.getConflictWrkFile();
}
data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
SvnVcs vcs = SvnVcs.getInstance(myProject);
SVNInfo info = vcs.getInfo(file);
if (info != null) {
oldFile = info.getConflictOldFile();
newFile = info.getConflictNewFile();
workingFile = info.getConflictWrkFile();
mergeCase = workingFile == null || workingFile.getName().contains("working");
// for debug
if (workingFile == null) {
LOG.info("Null working file when merging text conflict for " + file.getPath() + " old file: " + oldFile + " new file: " + newFile);
}
}
catch (SVNException e) {
throw new VcsException(e);
if (mergeCase) {
// this is merge case
oldFile = info.getConflictNewFile();
newFile = info.getConflictOldFile();
workingFile = info.getConflictWrkFile();
}
data.LAST_REVISION_NUMBER = new SvnRevisionNumber(info.getRevision());
} else {
throw new VcsException("Could not get info for " + file.getPath());
}
if (oldFile == null || newFile == null || workingFile == null) {
ByteArrayOutputStream bos = getBaseRevisionContents(client, file);
ByteArrayOutputStream bos = getBaseRevisionContents(vcs, file);
data.ORIGINAL = bos.toByteArray();
data.LAST = bos.toByteArray();
data.CURRENT = readFile(new File(file.getPath()));
@@ -99,7 +96,7 @@ public class SvnMergeProvider implements MergeProvider {
data.CURRENT = readFile(workingFile);
}
if (mergeCase) {
final ByteArrayOutputStream contents = getBaseRevisionContents(vcs.createWCClient(), file);
final ByteArrayOutputStream contents = getBaseRevisionContents(vcs, file);
if (! Arrays.equals(contents.toByteArray(), data.ORIGINAL)) {
// swap base and server: another order of merge arguments
byte[] original = data.ORIGINAL;
@@ -114,13 +111,17 @@ public class SvnMergeProvider implements MergeProvider {
return data;
}
private ByteArrayOutputStream getBaseRevisionContents(SVNWCClient client, VirtualFile file) {
private ByteArrayOutputStream getBaseRevisionContents(@NotNull SvnVcs vcs, @NotNull VirtualFile file) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
client.doGetFileContents(new File(file.getPath()), SVNRevision.UNDEFINED, SVNRevision.BASE, true, bos);
byte[] contents = SvnUtil.getFileContents(vcs, SvnTarget.fromFile(new File(file.getPath())), SVNRevision.BASE, SVNRevision.UNDEFINED);
bos.write(contents);
}
catch (SVNException e) {
//
catch (VcsException e) {
LOG.warn(e);
}
catch (IOException e) {
LOG.warn(e);
}
return bos;
}
@@ -135,13 +136,14 @@ public class SvnMergeProvider implements MergeProvider {
}
public void conflictResolvedForFile(VirtualFile file) {
// TODO: Add possibility to resolve content conflicts separately from property conflicts.
SvnVcs vcs = SvnVcs.getInstance(myProject);
File path = new File(file.getPath());
try {
SVNWCClient client = vcs.createWCClient();
client.doResolve(new File(file.getPath()), SVNDepth.EMPTY, true, false, SVNConflictChoice.MERGED);
vcs.getFactory(path).createConflictClient().resolve(path, false);
}
catch (SVNException e) {
//
catch (VcsException e) {
LOG.warn(e);
}
// the .mine/.r## files have been deleted
final VirtualFile parent = file.getParent();
@@ -152,17 +154,20 @@ public class SvnMergeProvider implements MergeProvider {
public boolean isBinary(@NotNull final VirtualFile file) {
SvnVcs vcs = SvnVcs.getInstance(myProject);
try {
SVNWCClient client = vcs.createWCClient();
File ioFile = new File(file.getPath());
SVNPropertyData svnPropertyData = client.doGetProperty(ioFile, SVNProperty.MIME_TYPE, SVNRevision.UNDEFINED, SVNRevision.WORKING);
PropertyClient client = vcs.getFactory(ioFile).createPropertyClient();
SVNPropertyData svnPropertyData = client.getProperty(ioFile, SVNProperty.MIME_TYPE, false, SVNRevision.UNDEFINED, SVNRevision.WORKING);
if (svnPropertyData != null && SVNProperty.isBinaryMimeType(SVNPropertyValue.getPropertyAsString(svnPropertyData.getValue()))) {
return true;
}
}
catch (SVNException e) {
//
catch (VcsException e) {
LOG.warn(e);
}
return false;
}
}
@@ -0,0 +1,23 @@
package org.jetbrains.idea.svn.add;
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.SVNDepth;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface AddClient extends SvnClient {
void add(@NotNull File file,
@Nullable SVNDepth depth,
boolean makeParents,
boolean includeIgnored,
boolean force,
@Nullable ISVNEventHandler handler) throws VcsException;
}
@@ -0,0 +1,69 @@
package org.jetbrains.idea.svn.add;
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.api.BaseSvnClient;
import org.jetbrains.idea.svn.api.FileStatusResultParser;
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.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNStatusType;
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 CmdAddClient extends BaseSvnClient implements AddClient {
private static final String STATUS = "\\s*(\\w)\\s*";
private static final String OPTIONAL_FILE_TYPE = "(\\(.*\\))?";
private static final String PATH = "\\s*(.*?)\\s*";
private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + OPTIONAL_FILE_TYPE + PATH);
@Override
public void add(@NotNull File file,
@Nullable SVNDepth depth,
boolean makeParents,
boolean includeIgnored,
boolean force,
@Nullable ISVNEventHandler handler) throws VcsException {
List<String> parameters = prepareParameters(file, depth, makeParents, includeIgnored, force);
// 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
CommandUtil.execute(myVcs, SvnCommandName.add, parameters, new FileStatusResultParser(CHANGED_PATH, handler, new AddStatusConvertor()));
}
private static List<String> prepareParameters(File file, SVNDepth depth, boolean makeParents, boolean includeIgnored, boolean force) {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, file);
CommandUtil.put(parameters, depth);
CommandUtil.put(parameters, makeParents, "--parents");
CommandUtil.put(parameters, includeIgnored, "--no-ignore");
CommandUtil.put(parameters, force, "--force");
return parameters;
}
private static class AddStatusConvertor implements Convertor<Matcher, SVNEvent> {
@Override
public SVNEvent convert(Matcher o) {
SVNStatusType contentStatus = CommandUtil.getStatusType(o.group(1));
String path = o.group(3);
return new SVNEvent(new File(path), null, null, 0, contentStatus, null, null, null, null, null, null, null,
null, null, null);
}
}
}
@@ -0,0 +1,39 @@
package org.jetbrains.idea.svn.add;
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.tmatesoft.svn.core.SVNDepth;
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 SvnKitAddClient extends BaseSvnClient implements AddClient {
@Override
public void add(@NotNull File file,
@Nullable SVNDepth depth,
boolean makeParents,
boolean includeIgnored,
boolean force,
@Nullable ISVNEventHandler handler) throws VcsException {
try {
SVNWCClient client = myVcs.createWCClient();
client.setEventHandler(handler);
client.doAdd(file, force,
false, // directory should already be created
makeParents, // not used but will be passed as makeParents value
SVNDepth.recurseFromDepth(depth));
}
catch (SVNException e) {
throw new VcsException(e);
}
}
}
@@ -0,0 +1,24 @@
package org.jetbrains.idea.svn.annotate;
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.ISVNAnnotateHandler;
import org.tmatesoft.svn.core.wc.SVNDiffOptions;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
/**
* @author Konstantin Kolosovsky.
*/
public interface AnnotateClient extends SvnClient {
void annotate(@NotNull SvnTarget target,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean includeMergedRevisions,
@Nullable SVNDiffOptions diffOptions,
@Nullable ISVNAnnotateHandler handler) throws VcsException;
}
@@ -0,0 +1,126 @@
package org.jetbrains.idea.svn.annotate;
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.SvnCommand;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler;
import org.tmatesoft.svn.core.wc.SVNDiffOptions;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdAnnotateClient extends BaseSvnClient implements AnnotateClient {
@Override
public void annotate(@NotNull SvnTarget target,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean includeMergedRevisions,
@Nullable SVNDiffOptions diffOptions,
@Nullable final ISVNAnnotateHandler handler) throws VcsException {
// TODO: after merge remove setting includeMergedRevisions to false and update parsing
includeMergedRevisions = false;
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision);
parameters.add("--revision");
parameters.add(startRevision + ":" + endRevision);
CommandUtil.put(parameters, includeMergedRevisions, "--use-merge-history");
CommandUtil.put(parameters, diffOptions);
parameters.add("--xml");
SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.blame, parameters, null);
parseOutput(command.getOutput(), handler);
}
public void parseOutput(@NotNull String output, @Nullable ISVNAnnotateHandler handler) throws VcsException {
try {
JAXBContext context = JAXBContext.newInstance(BlameInfo.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
BlameInfo info = (BlameInfo)unmarshaller.unmarshal(new StringReader(output));
if (handler != null && info != null && info.target != null && info.target.lineEntries != null) {
for (LineEntry entry : info.target.lineEntries) {
invokeHandler(handler, entry);
}
}
}
catch (JAXBException e) {
throw new VcsException(e);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
private static void invokeHandler(ISVNAnnotateHandler handler, LineEntry entry) throws SVNException {
// line numbers in our api start from 0 - not from 1 like in svn output
handler.handleLine(entry.date(), entry.revision(), entry.author(), null, null, 0, null, null, entry.lineNumber - 1);
}
@XmlRootElement(name = "blame")
public static class BlameInfo {
@XmlElement(name = "target")
public TargetEntry target;
}
public static class TargetEntry {
@XmlElement(name = "entry")
List<LineEntry> lineEntries;
}
public static class LineEntry {
@XmlAttribute(name = "line-number")
public int lineNumber;
@XmlElement(name = "commit")
public CommitEntry commit;
public long revision() {
return commit != null ? commit.revision : 0;
}
public String author() {
return commit != null ? commit.author : null;
}
public Date date() {
return commit != null ? commit.date : null;
}
}
public static class CommitEntry {
@XmlAttribute(name = "revision")
public long revision;
@XmlElement(name = "author")
public String author;
@XmlElement(name = "date")
public Date date;
}
}
@@ -32,14 +32,16 @@ import com.intellij.openapi.vcs.history.*;
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.history.HistoryClient;
import org.jetbrains.idea.svn.history.SvnChangeList;
import org.jetbrains.idea.svn.history.SvnFileRevision;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -89,9 +91,8 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final String contents;
if (loadExternally) {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
myVcs.createWCClient().doGetFileContents(ioFile, SVNRevision.UNDEFINED, SVNRevision.BASE, true, buffer);
contents = LoadTextUtil.getTextByBinaryPresentation(buffer.toByteArray(), file, false, false).toString();
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromFile(ioFile), SVNRevision.BASE, SVNRevision.UNDEFINED);
contents = LoadTextUtil.getTextByBinaryPresentation(data, file, false, false).toString();
} else {
final byte[] bytes = VcsHistoryUtil.loadRevisionContent(revision);
contents = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false).toString();
@@ -99,16 +100,13 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final SvnFileAnnotation result = new SvnFileAnnotation(myVcs, file, contents, lastChangedRevision);
SVNWCClient wcClient = myVcs.createWCClient();
info = wcClient.doInfo(ioFile, SVNRevision.UNDEFINED);
info = myVcs.getInfo(ioFile);
if (info == null) {
exception[0] = new VcsException(new SVNException(SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "File ''{0}'' is not under version control", ioFile)));
return;
}
final String url = info.getURL() == null ? null : info.getURL().toString();
SVNLogClient client = myVcs.createLogClient();
setLogClientOptions(client);
SVNRevision endRevision = ((SvnFileRevision) revision).getRevision();
if (SVNRevision.WORKING.equals(endRevision)) {
endRevision = info.getRevision();
@@ -124,12 +122,19 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
SvnUtil.checkRepositoryVersion15(myVcs, url);
final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision();
final MySteppedLogGetter logGetter = new MySteppedLogGetter(myVcs, ioFile, progress, client, endRevision, result, url, calculateMergeinfo, file.getCharset());
final MySteppedLogGetter logGetter = new MySteppedLogGetter(
myVcs, ioFile, progress,
myVcs.getFactory(ioFile).createHistoryClient(), endRevision, result,
url, calculateMergeinfo, file.getCharset());
logGetter.go();
final LinkedList<SVNRevision> rp = logGetter.getRevisionPoints();
// TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair
AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient();
for (int i = 0; i < rp.size() - 1; i++) {
client.doAnnotate(ioFile, svnRevision, rp.get(i + 1), rp.get(i), true, calculateMergeinfo, annotateHandler, null);
annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), svnRevision, calculateMergeinfo,
getLogClientOptions(myVcs), annotateHandler);
}
if (rp.get(1).getNumber() > 0) {
@@ -137,31 +142,15 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
}
annotation[0] = result;
}
catch (SVNException e) {
if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) {
final CommittedChangesProvider<SvnChangeList,ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
try {
final Pair<SvnChangeList, FilePath> pair = provider.getOneList(file, revision.getRevisionNumber());
if (pair != null && info != null && pair.getSecond() != null && ! Comparing.equal(pair.getSecond().getIOFile(), ioFile)) {
annotation[0] = annotateNonExisting(pair, revision, info, file.getCharset(), file);
return;
}
}
catch (VcsException e1) {
exception[0] = e1;
}
catch (SVNException e1) {
exception[0] = new VcsException(e);
}
catch (IOException e1) {
exception[0] = new VcsException(e);
}
}
exception[0] = new VcsException(e);
} catch (IOException e) {
catch (IOException e) {
exception[0] = new VcsException(e);
} catch (VcsException e) {
exception[0] = e;
if (e.getCause() instanceof SVNException) {
handleSvnException(ioFile, info, (SVNException)e.getCause(), file, revision, annotation, exception);
}
else {
exception[0] = e;
}
}
}
};
@@ -177,6 +166,35 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
return annotation[0];
}
private void handleSvnException(File ioFile,
SVNInfo info,
SVNException e,
VirtualFile file,
VcsFileRevision revision,
FileAnnotation[] annotation, VcsException[] exception) {
// TODO: Check how this scenario could be reproduced by user and what changes needs to be done for command line client
if (SVNErrorCode.FS_NOT_FOUND.equals(e.getErrorMessage().getErrorCode())) {
final CommittedChangesProvider<SvnChangeList,ChangeBrowserSettings> provider = myVcs.getCommittedChangesProvider();
try {
final Pair<SvnChangeList, FilePath> pair = provider.getOneList(file, revision.getRevisionNumber());
if (pair != null && info != null && pair.getSecond() != null && ! Comparing.equal(pair.getSecond().getIOFile(), ioFile)) {
annotation[0] = annotateNonExisting(pair, revision, info, file.getCharset(), file);
return;
}
}
catch (VcsException e1) {
exception[0] = e1;
}
catch (SVNException e1) {
exception[0] = new VcsException(e);
}
catch (IOException e1) {
exception[0] = new VcsException(e);
}
}
exception[0] = new VcsException(e);
}
public static File getCommonAncestor(final File file1, final File file2) throws IOException {
if (FileUtil.filesEqual(file1, file2)) return file1;
final File can1 = file1.getCanonicalFile();
@@ -214,8 +232,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
final String relativePath = FileUtil.getRelativePath(root.getPath(), wasFile.getPath(), File.separatorChar);
if (relativePath == null) throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
SVNWCClient wcClient = myVcs.createWCClient();
SVNInfo wcRootInfo = wcClient.doInfo(root, SVNRevision.UNDEFINED);
SVNInfo wcRootInfo = myVcs.getInfo(root);
if (wcRootInfo == null || wcRootInfo.getURL() == null) {
throw new VcsException("Can not find relative path for " + wasFile.getPath() + "@" + revision.getRevisionNumber().asString());
}
@@ -225,21 +242,18 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
wasUrl = wasUrl.appendPath(string, true);
}
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final SVNRevision svnRevision = ((SvnRevisionNumber)revision.getRevisionNumber()).getRevision();
myVcs.createWCClient().doGetFileContents(wasUrl, svnRevision, svnRevision, true, buffer);
final String contents = LoadTextUtil.getTextByBinaryPresentation(buffer.toByteArray(),
charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString();
SVNLogClient client = myVcs.createLogClient();
setLogClientOptions(client);
byte[] data = SvnUtil.getFileContents(myVcs, SvnTarget.fromURL(wasUrl), svnRevision, svnRevision);
final String contents = LoadTextUtil.getTextByBinaryPresentation(data, charset == null ? CharsetToolkit.UTF8_CHARSET : charset).toString();
final SvnRemoteFileAnnotation result = new SvnRemoteFileAnnotation(myVcs, contents, revision.getRevisionNumber(), pair.getFirst(),
pair.getSecond().getPath(), current);
final ISVNAnnotateHandler annotateHandler = createAnnotationHandler(ProgressManager.getInstance().getProgressIndicator(), result);
final boolean calculateMergeinfo = SvnConfiguration.getInstance(myVcs.getProject()).SHOW_MERGE_SOURCES_IN_ANNOTATE &&
SvnUtil.checkRepositoryVersion15(myVcs, wasUrl.toString());
client.doAnnotate(wasUrl, svnRevision, SVNRevision.create(1), svnRevision, true, calculateMergeinfo, annotateHandler, null);
AnnotateClient client = myVcs.getFactory().createAnnotateClient();
client.annotate(SvnTarget.fromURL(wasUrl), SVNRevision.create(1), svnRevision, svnRevision, calculateMergeinfo,
getLogClientOptions(myVcs), annotateHandler);
return result;
}
@@ -370,14 +384,14 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
private final SvnVcs myVcs;
private final File myIoFile;
private final ProgressIndicator myProgress;
private final SVNLogClient myClient;
private final HistoryClient myClient;
private final SVNRevision myEndRevision;
private final boolean myCalculateMergeinfo;
private final SvnFileAnnotation myResult;
private final String myUrl;
private final Charset myCharset;
private MySteppedLogGetter(final SvnVcs vcs, final File ioFile, final ProgressIndicator progress, final SVNLogClient client,
private MySteppedLogGetter(final SvnVcs vcs, final File ioFile, final ProgressIndicator progress, final HistoryClient client,
final SVNRevision endRevision,
final SvnFileAnnotation result,
final String url,
@@ -395,7 +409,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
myRevisionPoints = new LinkedList<SVNRevision>();
}
public void go() throws SVNException {
public void go() throws VcsException {
final int maxAnnotateRevisions = SvnConfiguration.getInstance(myVcs.getProject()).getMaxAnnotateRevisions();
boolean longHistory = true;
if (maxAnnotateRevisions == -1) {
@@ -437,8 +451,8 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
myRevisionPoints.add(SVNRevision.create(0));
}
private void doLog(final boolean includeMerged, final SVNRevision truncateTo, final int max) throws SVNException {
myClient.doLog(new File[]{myIoFile}, myEndRevision, truncateTo == null ? SVNRevision.create(1L) : truncateTo,
private void doLog(final boolean includeMerged, final SVNRevision truncateTo, final int max) throws VcsException {
myClient.doLog(myIoFile, myEndRevision, truncateTo == null ? SVNRevision.create(1L) : truncateTo,
SVNRevision.UNDEFINED, false, false, includeMerged, max, null,
new ISVNLogEntryHandler() {
public void handleLogEntry(SVNLogEntry logEntry) {
@@ -464,9 +478,7 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn
return true;
}
private void setLogClientOptions(final SVNLogClient client) {
if (SvnConfiguration.getInstance(myVcs.getProject()).IGNORE_SPACES_IN_ANNOTATE) {
client.setDiffOptions(new SVNDiffOptions(true, true, true));
}
private static SVNDiffOptions getLogClientOptions(@NotNull SvnVcs vcs) {
return SvnConfiguration.getInstance(vcs.getProject()).IGNORE_SPACES_IN_ANNOTATE ? new SVNDiffOptions(true, true, true) : null;
}
}
@@ -0,0 +1,42 @@
package org.jetbrains.idea.svn.annotate;
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.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.ISVNAnnotateHandler;
import org.tmatesoft.svn.core.wc.SVNDiffOptions;
import org.tmatesoft.svn.core.wc.SVNLogClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitAnnotateClient extends BaseSvnClient implements AnnotateClient {
@Override
public void annotate(@NotNull SvnTarget target,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean includeMergedRevisions,
@Nullable SVNDiffOptions diffOptions,
@Nullable ISVNAnnotateHandler handler) throws VcsException {
try {
SVNLogClient client = myVcs.createLogClient();
client.setDiffOptions(diffOptions);
if (target.isFile()) {
client.doAnnotate(target.getFile(), pegRevision, startRevision, endRevision, true, includeMergedRevisions, handler, null);
}
else {
client.doAnnotate(target.getURL(), pegRevision, startRevision, endRevision, true, includeMergedRevisions, handler, null);
}
}
catch (SVNException e) {
throw new VcsException(e);
}
}
}
@@ -0,0 +1,22 @@
package org.jetbrains.idea.svn.api;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnVcs;
/**
* @author Konstantin Kolosovsky.
*/
public abstract class BaseSvnClient implements SvnClient {
protected SvnVcs myVcs;
@NotNull
@Override
public SvnVcs getVcs() {
return myVcs;
}
@Override
public void setVcs(@NotNull SvnVcs vcs) {
myVcs = vcs;
}
}
@@ -0,0 +1,99 @@
package org.jetbrains.idea.svn.api;
import org.jetbrains.annotations.NotNull;
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.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.portable.SvnStatusClientI;
import org.jetbrains.idea.svn.properties.PropertyClient;
import org.jetbrains.idea.svn.revert.RevertClient;
/**
* @author Konstantin Kolosovsky.
*/
public abstract class ClientFactory {
@NotNull
protected SvnVcs myVcs;
protected AddClient addClient;
protected AnnotateClient annotateClient;
protected ContentClient contentClient;
protected HistoryClient historyClient;
protected RevertClient revertClient;
protected DeleteClient deleteClient;
protected SvnStatusClientI statusClient;
protected CopyMoveClient copyMoveClient;
protected ConflictClient conflictClient;
protected PropertyClient propertyClient;
protected ClientFactory(@NotNull SvnVcs vcs) {
myVcs = vcs;
setup();
}
protected abstract void setup();
@NotNull
public AddClient createAddClient() {
return prepare(addClient);
}
@NotNull
public AnnotateClient createAnnotateClient() {
return prepare(annotateClient);
}
@NotNull
public ContentClient createContentClient() {
return prepare(contentClient);
}
@NotNull
public HistoryClient createHistoryClient() {
return prepare(historyClient);
}
@NotNull
public RevertClient createRevertClient() {
return prepare(revertClient);
}
@NotNull
public SvnStatusClientI createStatusClient() {
// TODO: Update this in same like other clients - move to corresponding package, rename clients
return statusClient;
}
@NotNull
public DeleteClient createDeleteClient() {
return prepare(deleteClient);
}
@NotNull
public CopyMoveClient createCopyMoveClient() {
return prepare(copyMoveClient);
}
@NotNull
public ConflictClient createConflictClient() {
return prepare(conflictClient);
}
@NotNull
public PropertyClient createPropertyClient() {
return prepare(propertyClient);
}
@NotNull
protected <T extends SvnClient> T prepare(@NotNull T client) {
client.setVcs(myVcs);
return client;
}
}
@@ -0,0 +1,38 @@
package org.jetbrains.idea.svn.api;
import org.jetbrains.annotations.NotNull;
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.commandLine.SvnCommandLineStatusClient;
import org.jetbrains.idea.svn.conflict.CmdConflictClient;
import org.jetbrains.idea.svn.content.CmdContentClient;
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.properties.CmdPropertyClient;
import org.jetbrains.idea.svn.revert.CmdRevertClient;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdClientFactory extends ClientFactory {
public CmdClientFactory(@NotNull SvnVcs vcs) {
super(vcs);
}
@Override
protected void setup() {
addClient = new CmdAddClient();
annotateClient = new CmdAnnotateClient();
contentClient = new CmdContentClient();
historyClient = new CmdHistoryClient();
revertClient = new CmdRevertClient();
deleteClient = new CmdDeleteClient();
copyMoveClient = new CmdCopyMoveClient();
conflictClient = new CmdConflictClient();
propertyClient = new CmdPropertyClient();
statusClient = new SvnCommandLineStatusClient(myVcs.getProject());
}
}
@@ -0,0 +1,68 @@
package org.jetbrains.idea.svn.api;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.containers.Convertor;
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.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Konstantin Kolosovsky.
*/
public class FileStatusResultParser {
private static final double DEFAULT_PROGRESS = 0.0;
@NotNull
private Pattern myLinePattern;
@Nullable
private ISVNEventHandler handler;
@NotNull
private Convertor<Matcher, SVNEvent> myConvertor;
public FileStatusResultParser(@NotNull Pattern linePattern,
@Nullable ISVNEventHandler handler,
@NotNull Convertor<Matcher, SVNEvent> convertor) {
myLinePattern = linePattern;
this.handler = handler;
myConvertor = convertor;
}
public void parse(@NotNull String output) throws VcsException {
if (StringUtil.isEmpty(output)) {
return;
}
for (String line : StringUtil.splitByLines(output)) {
onLine(line);
}
}
public void onLine(@NotNull String line) throws VcsException {
Matcher matcher = myLinePattern.matcher(line);
if (matcher.matches()) {
process(matcher);
}
else {
throw new VcsException("unknown state on line " + line);
}
}
public void process(@NotNull Matcher matcher) throws VcsException {
if (handler != null) {
try {
handler.handleEvent(myConvertor.convert(matcher), DEFAULT_PROGRESS);
} catch (SVNException e) {
throw new VcsException(e);
}
}
}
}
@@ -0,0 +1,15 @@
package org.jetbrains.idea.svn.api;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnVcs;
/**
* @author Konstantin Kolosovsky.
*/
public interface SvnClient {
@NotNull
SvnVcs getVcs();
void setVcs(@NotNull SvnVcs vcs);
}
@@ -0,0 +1,38 @@
package org.jetbrains.idea.svn.api;
import org.jetbrains.annotations.NotNull;
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.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.portable.SvnkitSvnStatusClient;
import org.jetbrains.idea.svn.properties.SvnKitPropertyClient;
import org.jetbrains.idea.svn.revert.SvnKitRevertClient;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitClientFactory extends ClientFactory {
public SvnKitClientFactory(@NotNull SvnVcs vcs) {
super(vcs);
}
@Override
protected void setup() {
addClient = new SvnKitAddClient();
annotateClient = new SvnKitAnnotateClient();
contentClient = new SvnKitContentClient();
historyClient = new SvnKitHistoryClient();
revertClient = new SvnKitRevertClient();
deleteClient = new SvnKitDeleteClient();
copyMoveClient = new SvnKitCopyMoveClient();
conflictClient = new SvnKitConflictClient();
propertyClient = new SvnKitPropertyClient();
statusClient = new SvnkitSvnStatusClient(myVcs.createStatusClient());
}
}
@@ -49,7 +49,7 @@ public class DefaultConfigLoader {
final SvnVcs vcs = SvnVcs.getInstance(project);
File rootFile = new File(vcsRoot.getPath());
final SVNInfo info = vcs.createWCClient().doInfo(rootFile, SVNRevision.UNDEFINED);
final SVNInfo info = vcs.getInfo(rootFile);
if (info == null || info.getURL() == null) {
LOG.info("Directory is not a working copy: " + vcsRoot.getPresentableUrl());
return null;
@@ -223,9 +223,8 @@ public class SvnBranchConfigurationNew {
private BranchRootSearcher(final SvnVcs vcs, final VirtualFile root) throws SVNException {
myRoot = root;
myBranchesUnder = new HashMap<String, String>();
final SVNWCClient client = vcs.createWCClient();
final SVNInfo info = client.doInfo(new File(myRoot.getPath()), SVNRevision.UNDEFINED);
myRootUrl = info.getURL();
final SVNInfo info = vcs.getInfo(myRoot.getPath());
myRootUrl = info != null ? info.getURL() : null;
}
public boolean accept(final String url) throws SVNException {
@@ -16,8 +16,8 @@
package org.jetbrains.idea.svn.checkin;
import com.intellij.openapi.progress.ProgressIndicator;
import org.jetbrains.idea.svn.CommitEventHandler;
import org.jetbrains.idea.svn.CommitEventType;
import org.jetbrains.idea.svn.commandLine.CommitEventHandler;
import org.jetbrains.idea.svn.commandLine.CommitEventType;
import org.jetbrains.idea.svn.SvnBundle;
import java.io.File;
@@ -28,6 +28,7 @@ import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.proxy.CommonProxy;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.commandLine.AuthenticationCallback;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.auth.*;
import org.tmatesoft.svn.core.internal.util.SVNBase64;
@@ -77,6 +78,20 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall
return new CredentialsAuthenticator(myVcs).tryAuthenticate(realm, url, file, previousFailed, passwordRequest);
}
@Nullable
@Override
public SVNAuthentication requestCredentials(@Nullable SVNURL url, String type) {
SVNAuthentication authentication =
url != null ? myVcs.getSvnConfiguration().getInteractiveManager(myVcs).getProvider().requestClientAuthentication(
type, url, url.toDecodedString(), null, null, true) : null;
if (authentication == null) {
LOG.warn("Could not get authentication. Type - " + type + ", Url - " + url);
}
return authentication;
}
@Override
public boolean acceptSSLServerCertificate(final File file, final String realm) {
final File base = getExistingParent(file);
@@ -354,7 +369,9 @@ public class IdeaSvnkitBasedAuthenticationCallback implements AuthenticationCall
}, new ThrowableRunnable<SVNException>() {
@Override
public void run() throws SVNException {
// NOTE: DO NOT replace this call - SSL authentication highly tied to SVNKit
myVcs.createWCClient(active).doInfo(myUrl, SVNRevision.UNDEFINED, SVNRevision.HEAD);
//myVcs.getInfo(myUrl, SVNRevision.HEAD, active);
}
}
);
@@ -48,8 +48,8 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.*;
import org.jetbrains.idea.svn.commandLine.SvnBindClient;
import org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient;
import org.tigris.subversion.javahl.ClientException;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.wc.*;
@@ -177,7 +177,7 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
if (committables.isEmpty()) {
return;
}
if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format) &&
if (WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) || WorkingCopyFormat.ONE_DOT_SEVEN.equals(format) &&
SvnConfiguration.UseAcceleration.commandLine.equals(SvnConfiguration.getInstance(mySvnVcs.getProject()).myUseAcceleration) &&
(SvnAuthenticationManager.HTTP.equals(url.getProtocol()) || SvnAuthenticationManager.HTTPS.equals(url.getProtocol()))) {
doWithCommandLine(committables, comment, exception, feedback);
@@ -256,14 +256,25 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
});
final IdeaSvnkitBasedAuthenticationCallback authenticationCallback = new IdeaSvnkitBasedAuthenticationCallback(mySvnVcs);
try {
final SvnBindClient client = new SvnBindClient(SvnApplicationSettings.getInstance().getCommandLinePath());
final SvnBindClient client = new SvnBindClient(SvnApplicationSettings.getInstance().getCommandLinePath(), new Convertor<String[], SVNURL>() {
@Override
public SVNURL convert(String[] o) {
SVNInfo info = o.length > 0 ? mySvnVcs.getInfo(o[0]) : null;
if (info == null || info.getURL() == null) {
LOG.warn("Could not resolve repository url for commit. Paths - " + Arrays.toString(o));
}
return info != null ? info.getURL() : null;
}
});
client.setAuthenticationCallback(authenticationCallback);
client.setHandler(new IdeaCommitHandler(ProgressManager.getInstance().getProgressIndicator()));
final long revision = client.commit(ArrayUtil.toStringArray(paths), comment, false, false);
reportCommittedRevisions(feedback, String.valueOf(revision));
}
catch (ClientException e) {
exception.add(new VcsException(e));
catch (VcsException e) {
exception.add(e);
} finally {
authenticationCallback.reset();
}
@@ -348,25 +359,19 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
private List<File> getCommitables(List<File> paths) {
final Adder adder = new Adder();
SVNStatusClient statusClient = mySvnVcs.createStatusClient();
for (File path : paths) {
File file = path.getAbsoluteFile();
adder.add(file);
if (file.getParentFile() != null) {
addParents(statusClient, file.getParentFile(), adder);
addParents(file.getParentFile(), adder);
}
}
return adder.getResult();
}
private static void addParents(SVNStatusClient statusClient, File file, final Adder adder) {
SVNStatus status;
try {
status = statusClient.doStatus(file, false);
}
catch (SVNException e) {
return;
}
private void addParents(File file, final Adder adder) {
SVNStatus status = getStatus(file);
if (status != null &&
(SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_ADDED) ||
SvnVcs.svnStatusIs(status, SVNStatusType.STATUS_REPLACED))) {
@@ -374,11 +379,33 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
adder.add(file);
file = file.getParentFile();
if (file != null) {
addParents(statusClient, file, adder);
addParents(file, adder);
}
}
}
private SVNStatus getStatus(File file) {
SVNStatus result = null;
WorkingCopyFormat format = mySvnVcs.getWorkingCopyFormat(file);
try {
result = WorkingCopyFormat.ONE_DOT_EIGHT.equals(format) ? getStatusCommandLine(file) : getStatusSvnKit(file);
}
catch (SVNException e) {
// do nothing
}
return result;
}
private SVNStatus getStatusSvnKit(File file) throws SVNException {
return mySvnVcs.createStatusClient().doStatus(file, false);
}
private SVNStatus getStatusCommandLine(File file) throws SVNException {
return new SvnCommandLineStatusClient(mySvnVcs.getProject()).doStatus(file, false);
}
private static List<File> collectPaths(final List<Change> changes) {
// case sensitive..
ArrayList<File> result = new ArrayList<File>();
@@ -418,15 +445,14 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
public List<VcsException> scheduleMissingFileForDeletion(List<FilePath> filePaths) {
List<VcsException> exceptions = new ArrayList<VcsException>();
final SVNWCClient wcClient = mySvnVcs.createWCClient();
List<File> files = ChangesUtil.filePathsToFiles(filePaths);
for (File file : files) {
try {
wcClient.doDelete(file, true, false);
mySvnVcs.getFactory(file).createDeleteClient().delete(file, true);
}
catch (SVNException e) {
exceptions.add(new VcsException(e));
catch (VcsException e) {
exceptions.add(e);
}
}
@@ -434,30 +460,22 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
}
public List<VcsException> scheduleUnversionedFilesForAddition(List<VirtualFile> files) {
final List<VcsException> result = new ArrayList<VcsException>();
final SVNWCClient wcClient = mySvnVcs.createWCClient();
final List<SVNException> exceptionList = scheduleUnversionedFilesForAddition(wcClient, files);
for (SVNException svnException : exceptionList) {
result.add(new VcsException(svnException));
}
return result;
return scheduleUnversionedFilesForAddition(mySvnVcs, files);
}
public static List<SVNException> scheduleUnversionedFilesForAddition(SVNWCClient wcClient, List<VirtualFile> files) {
return scheduleUnversionedFilesForAddition(wcClient, files, false);
public static List<VcsException> scheduleUnversionedFilesForAddition(@NotNull SvnVcs vcs, List<VirtualFile> files) {
return scheduleUnversionedFilesForAddition(vcs, files, false);
}
public static List<SVNException> scheduleUnversionedFilesForAddition(SVNWCClient wcClient, List<VirtualFile> files, final boolean recursive) {
List<SVNException> exceptions = new ArrayList<SVNException>();
public static List<VcsException> scheduleUnversionedFilesForAddition(@NotNull SvnVcs vcs, List<VirtualFile> files, final boolean recursive) {
Collections.sort(files, FilePathComparator.getInstance());
wcClient.setEventHandler(new ISVNEventHandler() {
ISVNEventHandler eventHandler = new ISVNEventHandler() {
@Override
public void handleEvent(SVNEvent event, double progress) throws SVNException {
final ProgressManager pm = ProgressManager.getInstance();
final ProgressIndicator pi = pm.getProgressIndicator();
// TODO: pi is null here when invoking "Add" action
if (pi != null && event.getFile() != null) {
File file = event.getFile();
pi.setText(SvnBundle.message("progress.text2.adding", file.getName() + " (" + file.getParent() + ")"));
@@ -472,12 +490,18 @@ public class SvnCheckinEnvironment implements CheckinEnvironment {
if (pi.isCanceled()) throw new SVNCancelException();
}
}
});
};
List<VcsException> exceptions = new ArrayList<VcsException>();
for (VirtualFile file : files) {
try {
wcClient.doAdd(new File(FileUtil.toSystemDependentName(file.getPath())), true, false, true, recursive);
File convertedFile = new File(FileUtil.toSystemDependentName(file.getPath()));
SVNDepth depth = recursive ? SVNDepth.INFINITY : SVNDepth.EMPTY;
vcs.getFactory(convertedFile).createAddClient().add(convertedFile, depth, true, false, true, eventHandler);
}
catch (SVNException e) {
catch (VcsException e) {
exceptions.add(e);
}
}
@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
package org.jetbrains.idea.svn.commandLine;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import java.io.File;
import java.io.IOException;
@@ -50,6 +52,17 @@ public interface AuthenticationCallback {
*/
boolean authenticateFor(@Nullable String realm, File base, boolean previousFailed, boolean passwordRequest);
/**
* Provides authentication information to access given url by authentication protocol identified by type.
* For instance, username/password for http/svn protocols. SSL client certificate for two way SSL protocol.
*
* @param url url to item in repository
* @param type authentication protocol type with svn specific values, like "svn.simple" for http.
* @return
*/
@Nullable
SVNAuthentication requestCredentials(@Nullable SVNURL url, String type);
/**
* @return config directory if TMP was created
*/
@@ -0,0 +1,218 @@
package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnApplicationSettings;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.api.FileStatusResultParser;
import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.wc.SVNDiffOptions;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CommandUtil {
public static SvnLineCommand runSimple(@NotNull SvnCommandName name,
@NotNull SvnVcs vcs,
@Nullable File base,
@Nullable SVNURL url,
List<String> parameters)
throws SVNException {
String exe = resolveExePath();
base = resolveBaseDirectory(base, exe);
url = resolveRepositoryUrl(vcs, url);
try {
return SvnLineCommand
.runWithAuthenticationAttempt(exe, base, url, name, new SvnCommitRunner.CommandListener(null),
new IdeaSvnkitBasedAuthenticationCallback(vcs), ArrayUtil.toStringArray(parameters));
}
catch (SvnBindException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
}
@Nullable
private static SVNURL resolveRepositoryUrl(@NotNull SvnVcs vcs, @Nullable SVNURL url) {
if (url == null) {
// TODO: or take it from RootUrlInfo
SVNInfo info = vcs.getInfo(vcs.getProject().getBaseDir());
url = info != null ? info.getURL() : null;
}
return url;
}
@NotNull
private static File resolveBaseDirectory(@Nullable File base, @NotNull String defaultBase) {
return base == null ? new File(defaultBase) : base;
}
@NotNull
private static String resolveExePath() {
return SvnApplicationSettings.getInstance().getCommandLinePath();
}
public static SvnLineCommand runSimple(@NotNull SvnSimpleCommand command, @NotNull SvnVcs vcs, @Nullable File base, @Nullable SVNURL url)
throws SVNException {
// empty command name passed, as command name is already in command.getParameters()
return runSimple(SvnCommandName.empty, vcs, base, url, new ArrayList<String>(Arrays.asList(command.getParameters())));
}
/**
* Puts given value to parameters if condition is satisfied
*
* @param parameters
* @param condition
* @param value
*/
public static void put(@NotNull List<String> parameters, boolean condition, @NotNull String value) {
if (condition) {
parameters.add(value);
}
}
public static void put(@NotNull List<String> parameters, @NotNull File path) {
parameters.add(path.getAbsolutePath());
}
public static void put(@NotNull List<String> parameters, @NotNull File path, @Nullable SVNRevision pegRevision) {
put(parameters, path.getAbsolutePath(), pegRevision);
}
public static void put(@NotNull List<String> parameters, @NotNull String path, @Nullable SVNRevision pegRevision) {
StringBuilder builder = new StringBuilder(path);
if (pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision) && !SVNRevision.WORKING.equals(pegRevision) &&
pegRevision.getNumber() > 0) {
builder.append("@");
builder.append(pegRevision);
}
parameters.add(builder.toString());
}
public static void put(@NotNull List<String> parameters, @NotNull File... paths) {
for (File path : paths) {
put(parameters, path);
}
}
public static void put(@NotNull List<String> parameters, @Nullable SVNDepth depth) {
if (depth != null && !SVNDepth.UNKNOWN.equals(depth)) {
parameters.add("--depth");
parameters.add(depth.getName());
}
}
public static void put(@NotNull List<String> parameters, @Nullable SVNRevision revision) {
if (revision != null && !SVNRevision.UNDEFINED.equals(revision) && !SVNRevision.WORKING.equals(revision) && revision.getNumber() >= 0) {
parameters.add("--revision");
parameters.add(revision.toString());
}
}
public static void put(@NotNull List<String> parameters, @Nullable SVNDiffOptions diffOptions) {
if (diffOptions != null) {
StringBuilder builder = new StringBuilder();
if (diffOptions.isIgnoreAllWhitespace()) {
builder.append(" --ignore-space-change");
}
if (diffOptions.isIgnoreAmountOfWhitespace()) {
builder.append(" --ignore-all-space");
}
if (diffOptions.isIgnoreEOLStyle()) {
builder.append(" --ignore-eol-style");
}
String value = builder.toString().trim();
if (!StringUtil.isEmpty(value)) {
parameters.add("--extensions");
parameters.add(value);
}
}
}
/**
* Utility method for running commands changing certain file status information.
* // TODO: Should be replaced with non-static analogue.
*
* @param vcs
* @param name
* @param parameters
* @param parser
* @throws VcsException
*/
public static SvnCommand execute(@NotNull SvnVcs vcs,
@NotNull SvnCommandName name,
@NotNull List<String> parameters,
@Nullable FileStatusResultParser parser)
throws VcsException {
String exe = resolveExePath();
File base = resolveBaseDirectory(null, exe);
SVNURL url = resolveRepositoryUrl(vcs, null);
SvnLineCommand command = SvnLineCommand.runWithAuthenticationAttempt(
exe, base, url, name, new SvnCommitRunner.CommandListener(null),
new IdeaSvnkitBasedAuthenticationCallback(vcs),
ArrayUtil.toStringArray(parameters));
if (parser != null) {
parser.parse(command.getOutput());
}
return command;
}
/**
* Gets svn status represented by single character.
*
* @param type
* @return
*/
public static char getStatusChar(@Nullable String type) {
return !StringUtil.isEmpty(type) ? type.charAt(0) : ' ';
}
@NotNull
public static SVNStatusType getStatusType(@Nullable String type) {
return getStatusType(getStatusChar(type));
}
@NotNull
public static SVNStatusType getStatusType(char first) {
final SVNStatusType contentsStatus;
if ('A' == first) {
contentsStatus = SVNStatusType.STATUS_ADDED;
} else if ('D' == first) {
contentsStatus = SVNStatusType.STATUS_DELETED;
} else if ('U' == first) {
contentsStatus = SVNStatusType.CHANGED;
} else if ('C' == first) {
contentsStatus = SVNStatusType.CONFLICTED;
} else if ('G' == first) {
contentsStatus = SVNStatusType.MERGED;
} else if ('R' == first) {
contentsStatus = SVNStatusType.STATUS_REPLACED;
} else if ('E' == first) {
contentsStatus = SVNStatusType.STATUS_OBSTRUCTED;
} else {
contentsStatus = SVNStatusType.STATUS_NORMAL;
}
return contentsStatus;
}
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
package org.jetbrains.idea.svn.commandLine;
import java.io.File;
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
package org.jetbrains.idea.svn.commandLine;
/**
* Created with IntelliJ IDEA.
@@ -0,0 +1,67 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.containers.Convertor;
import org.tmatesoft.svn.core.SVNURL;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 2/5/13
* Time: 3:08 PM
*/
public class SvnBindClient {
private final String myExecutablePath;
private CommitEventHandler myHandler;
private AuthenticationCallback myAuthenticationCallback;
private Convertor<String[], SVNURL> myUrlProvider;
public SvnBindClient(String path, Convertor<String[], SVNURL> urlProvider) {
myExecutablePath = path;
myUrlProvider = urlProvider;
}
public long commit(String[] path, String message, boolean recurse, boolean noUnlock) throws VcsException {
return commit(path, message, recurse? 3 : 0, noUnlock, false, null, null);
}
public long commit(String[] path,
String message,
int depth,
boolean noUnlock,
boolean keepChangelist,
String[] changelists,
Map revpropTable) throws VcsException {
final long commit = new SvnCommitRunner(myExecutablePath, myHandler, myAuthenticationCallback).
commit(path, message, depth, noUnlock, keepChangelist, changelists, revpropTable, myUrlProvider);
if (commit < 0) {
throw new VcsException("Wrong committed revision number: " + commit);
}
return commit;
}
public void setHandler(CommitEventHandler handler) {
myHandler = handler;
}
public void setAuthenticationCallback(AuthenticationCallback authenticationCallback) {
myAuthenticationCallback = authenticationCallback;
}
}
@@ -13,12 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.config;
package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.vcs.VcsException;
import java.util.Collection;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
@@ -32,23 +30,7 @@ public class SvnBindException extends VcsException {
super(message);
}
public SvnBindException(Throwable throwable, boolean isWarning) {
super(throwable, isWarning);
}
public SvnBindException(Throwable throwable) {
super(throwable);
}
public SvnBindException(String message, Throwable cause) {
super(message, cause);
}
public SvnBindException(String message, boolean isWarning) {
super(message, isWarning);
}
public SvnBindException(Collection<String> messages) {
super(messages);
}
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
package org.jetbrains.idea.svn.commandLine;
import java.io.File;
import java.text.DateFormat;
@@ -31,16 +31,7 @@ import java.util.Locale;
* Time: 4:56 PM
*/
public class SvnBindUtil {
/**
* SVN_ASP_DOT_NET_HACK allows use of an alternate name for Subversion working copy
* administrative directories on Windows (which were formerly always
* named ".svn"), by setting the SVN_ASP_DOT_NET_HACK environment variable.
* When the variable is set (to any value), the administrative directory
* will be "_svn" instead of ".svn".
*
* http://svn.apache.org/repos/asf/subversion/trunk/notes/asp-dot-net-hack.txt
*/
public static final String ADM_NAME = System.getenv("SVN_ASP_DOT_NET_HACK") != null ? "_svn" : ".svn";
private final static List<DateFormat> ourFormats = new ArrayList<DateFormat>();
static {
@@ -88,17 +79,4 @@ public class SvnBindUtil {
}
return null;
}
public static File getWcRoot(File base) {
File current = base;
while (current != null) {
if (getWcDbUnder(current).exists()) return current;
current = current.getParentFile();
}
return null;
}
public static File getWcDbUnder(final File file) {
return new File(file, ADM_NAME + File.separator + "wc.db");
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.CapturingProcessAdapter;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessListener;
@@ -38,6 +39,7 @@ import java.util.List;
*/
public abstract class SvnCommand {
static final Logger LOG = Logger.getInstance(SvnCommand.class.getName());
private final File myConfigDir;
private boolean myIsDestroyed;
private int myExitCode;
@@ -45,13 +47,13 @@ public abstract class SvnCommand {
private final File myWorkingDirectory;
private Process myProcess;
private OSProcessHandler myHandler;
// TODO: Try to implement commands in a way that they manually indicate if they need full output - to prevent situations
// TODO: when large amount of data needs to be stored instead of just sequential processing.
private CapturingProcessAdapter outputAdapter;
private final Object myLock;
private final EventDispatcher<ProcessEventListener> myListeners = EventDispatcher.create(ProcessEventListener.class);
// todo check version
/*c:\Program Files (x86)\CollabNet\Subversion Client17>svn --version --quiet
1.7.2*/
private final SvnCommandName myCommandName;
public SvnCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath) {
this(workingDirectory, commandName, exePath, null);
@@ -59,15 +61,34 @@ public abstract class SvnCommand {
public SvnCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath,
@Nullable File configDir) {
myCommandName = commandName;
myLock = new Object();
myCommandLine = new GeneralCommandLine();
myWorkingDirectory = workingDirectory;
myCommandLine.setExePath(exePath);
myCommandLine.setWorkDirectory(workingDirectory);
myConfigDir = configDir;
if (configDir != null) {
myCommandLine.addParameters("--config-dir", configDir.getPath());
}
myCommandLine.addParameter(commandName.getName());
if (!SvnCommandName.empty.equals(commandName)) {
myCommandLine.addParameter(commandName.getName());
}
}
public String[] getParameters() {
synchronized (myLock) {
return myCommandLine.getParametersList().getArray();
}
}
/**
* Indicates if process was destroyed "manually" by command execution logic.
*
* @return
*/
public boolean isManuallyDestroyed() {
return myIsDestroyed;
}
public void start() {
@@ -112,10 +133,16 @@ public abstract class SvnCommand {
}
};
outputAdapter = new CapturingProcessAdapter();
myHandler.addProcessListener(outputAdapter);
myHandler.addProcessListener(processListener);
myHandler.startNotify();
}
public String getOutput() {
return outputAdapter.getOutput().getStdout();
}
/**
* Wait for process termination
* @param timeout
@@ -186,6 +213,18 @@ public abstract class SvnCommand {
}
}
public String getCommandText() {
synchronized (myLock) {
return myCommandLine.getCommandLineString();
}
}
public String getExePath() {
synchronized (myLock) {
return myCommandLine.getExePath();
}
}
/**
* check that process is not started yet
*
@@ -226,4 +265,8 @@ public abstract class SvnCommand {
protected File getWorkingDirectory() {
return myWorkingDirectory;
}
public SvnCommandName getCommandName() {
return myCommandName;
}
}
@@ -15,12 +15,13 @@
*/
package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.Consumer;
import org.jetbrains.idea.svn.SvnBindUtil;
import org.jetbrains.idea.svn.SvnApplicationSettings;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.portable.SvnExceptionWrapper;
import org.jetbrains.idea.svn.portable.SvnkitSvnWcClient;
@@ -36,7 +37,9 @@ import javax.xml.parsers.SAXParserFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created with IntelliJ IDEA.
@@ -45,9 +48,12 @@ import java.util.Collection;
* Time: 12:59 PM
*/
public class SvnCommandLineInfoClient extends SvnkitSvnWcClient {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.commandLine.SvnCommandLineInfoClient");
private final Project myProject;
public SvnCommandLineInfoClient(final Project project) {
// TODO: Remove svn kit client instantiation
super(SvnVcs.getInstance(project).createWCClient());
myProject = project;
}
@@ -74,22 +80,56 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient {
base = SvnBindUtil.correctUpToExistingParent(base);
if (base == null) {
// very unrealistic
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), new RuntimeException("Can not find existing parent file"));
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, "Can not find existing parent file"));
}
final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.info);
issueCommand(path.getAbsolutePath(), pegRevision, revision, depth, changeLists, handler, base);
}
if (depth != null) {
command.addParameters("--depth", depth.getName());
}
if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) {
command.addParameters("-r", revision.toString());
}
command.addParameters("--xml");
private void issueCommand(String path, SVNRevision pegRevision,
SVNRevision revision,
SVNDepth depth,
Collection changeLists,
final ISVNInfoHandler handler, File base) throws SVNException {
final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.info);
List<String> parameters = new ArrayList<String>();
fillParameters(path, pegRevision, revision, depth, parameters);
command.addParameters(parameters);
SvnCommandLineStatusClient.changelistsToCommand(changeLists, command);
if (pegRevision != null && ! SVNRevision.UNDEFINED.equals(pegRevision) && ! SVNRevision.WORKING.equals(pegRevision)) {
command.addParameters(path.getPath() + "@" + pegRevision.toString());
} else {
command.addParameters(path.getPath());
parseResult(handler, base, execute(command));
}
private String execute(SvnSimpleCommand command) throws SVNException {
try {
return command.run();
}
catch (VcsException e) {
final String text = e.getMessage();
final boolean notEmpty = !StringUtil.isEmptyOrSpaces(text);
if (notEmpty && text.contains("W155010")) {
// just null
return null;
}
// not a working copy exception
// "E155007: '' is not a working copy"
if (notEmpty && text.contains("is not a working copy")) {
if (StringUtil.isNotEmpty(command.getOutput())) {
// workaround: as in subversion 1.8 "svn info" on a working copy root outputs such error for parent folder,
// if there are files with conflicts.
// but the requested info is still in the output except root closing tag
return command.getOutput() + "</info>";
} else {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY, e), e);
}
}
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
}
private void parseResult(final ISVNInfoHandler handler, File base, String result) throws SVNException {
if (StringUtil.isEmpty(result)) {
return;
}
final SvnInfoHandler[] infoHandler = new SvnInfoHandler[1];
@@ -106,38 +146,34 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient {
});
try {
final String result = command.run();
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), infoHandler[0]);
parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), infoHandler[0]);
}
catch (SvnExceptionWrapper e) {
LOG.info("info output " + result);
throw (SVNException) e.getCause();
} catch (IOException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
LOG.info("info output " + result);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
catch (ParserConfigurationException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
LOG.info("info output " + result);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
catch (SAXException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
}
catch (VcsException e) {
final String text = e.getMessage();
final boolean notEmpty = !StringUtil.isEmptyOrSpaces(text);
if (notEmpty && text.contains("W155010")) {
// just null
return;
}
// not a working copy exception
// "E155007: '' is not a working copy"
if (notEmpty && text.contains("is not a working copy")) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_WORKING_COPY), e);
}
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
LOG.info("info output " + result);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
}
private void fillParameters(String path, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, List<String> parameters) {
CommandUtil.put(parameters, depth);
CommandUtil.put(parameters, revision);
CommandUtil.put(parameters, path, pegRevision);
parameters.add("--xml");
}
@Override
public void doInfo(SVNURL url, SVNRevision pegRevision, SVNRevision revision, boolean recursive, ISVNInfoHandler handler)
throws SVNException {
@@ -147,7 +183,14 @@ public class SvnCommandLineInfoClient extends SvnkitSvnWcClient {
@Override
public void doInfo(SVNURL url, SVNRevision pegRevision, SVNRevision revision, SVNDepth depth, ISVNInfoHandler handler)
throws SVNException {
throw new UnsupportedOperationException();
String path = url.toDecodedString();
List<String> parameters = new ArrayList<String>();
fillParameters(path, pegRevision, revision, depth, parameters);
File base = new File(SvnApplicationSettings.getInstance().getCommandLinePath());
String result = CommandUtil.runSimple(SvnCommandName.info, SvnVcs.getInstance(myProject), base, url, parameters).getOutput();
parseResult(handler, base, result);
}
@Override
@@ -15,14 +15,16 @@
*/
package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.containers.Convertor;
import org.jetbrains.idea.svn.SvnBindUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.portable.PortableStatus;
import org.jetbrains.idea.svn.portable.SvnExceptionWrapper;
import org.jetbrains.idea.svn.portable.SvnStatusClientI;
@@ -48,6 +50,8 @@ import java.util.Map;
* Time: 5:21 PM
*/
public class SvnCommandLineStatusClient implements SvnStatusClientI {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.commandLine.SvnCommandLineStatusClient");
private final Project myProject;
private final SvnCommandLineInfoClient myInfoClient;
@@ -102,47 +106,84 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI {
final SVNInfo infoBase = myInfoClient.doInfo(base, revision);
final SvnSimpleCommand command = SvnCommandFactory.createSimpleCommand(myProject, base, SvnCommandName.st);
putParameters(depth, remote, reportAll, includeIgnored, changeLists, command);
putParameters(path, depth, remote, reportAll, includeIgnored, changeLists, command);
final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1];
svnHandl[0] = createStatusHandler(revision, handler, base, infoBase, svnHandl);
parseResult(path, revision, handler, base, infoBase, command, execute(command, base));
return 0;
}
private String execute(SvnSimpleCommand command, File base) throws SVNException {
String result = CommandUtil.runSimple(command, SvnVcs.getInstance(myProject), base, null).getOutput();
if (StringUtil.isEmptyOrSpaces(result)) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, "Status request returned nothing for command: " +
command.myCommandLine.getCommandLineString()));
}
return result;
}
private void parseResult(final File path,
SVNRevision revision,
ISVNStatusHandler handler,
File base,
SVNInfo infoBase,
SvnSimpleCommand command, String result) throws SVNException {
if (StringUtil.isEmpty(result)) {
return;
}
try {
final String result = command.run();
if (StringUtil.isEmptyOrSpaces(result)) {
throw new VcsException("Status request returned nothing for command: " + command.myCommandLine.getCommandLineString());
}
final SvnStatusHandler[] svnHandl = new SvnStatusHandler[1];
svnHandl[0] = createStatusHandler(revision, handler, base, infoBase, svnHandl);
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
parser.parse(new ByteArrayInputStream(result.getBytes(CharsetToolkit.UTF8_CHARSET)), svnHandl[0]);
if (! svnHandl[0].isAnythingReported()) {
if (! SvnUtil.isSvnVersioned(myProject, path)) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY));
if (!svnHandl[0].isAnythingReported()) {
if (!SvnUtil.isSvnVersioned(myProject, path)) {
throw new SVNException(
SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY, "Command - " + command.getCommandText() + ". Result - " + result));
} else {
// return status indicating "NORMAL" state
// typical output would be like
// <status>
// <target path="1.txt"></target>
// </status>
// so it does not contain any <entry> element and current parsing logic returns null
PortableStatus status = new PortableStatus();
status.setPath(path.getAbsolutePath());
status.setContentsStatus(SVNStatusType.STATUS_NORMAL);
status.setInfoGetter(new Getter<SVNInfo>() {
@Override
public SVNInfo get() {
return createInfoGetter(null).convert(path);
}
});
handler.handleStatus(status);
}
}
}
catch (SvnExceptionWrapper e) {
throw (SVNException) e.getCause();
} catch (IOException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
catch (ParserConfigurationException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
catch (SAXException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR, e), e);
}
catch (VcsException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.IO_ERROR), e);
}
return 0;
}
private void putParameters(SVNDepth depth,
private void putParameters(@NotNull File path, SVNDepth depth,
boolean remote,
boolean reportAll,
boolean includeIgnored,
Collection changeLists,
SvnSimpleCommand command) {
command.addParameters(path.getAbsolutePath());
if (depth != null) {
command.addParameters("--depth", depth.getName());
}
@@ -171,7 +212,11 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI {
final SVNInfo infoBase, final SvnStatusHandler[] svnHandl) {
final SvnStatusHandler.ExternalDataCallback callback = createStatusCallback(handler, base, infoBase, svnHandl);
return new SvnStatusHandler(callback, base, new Convertor<File, SVNInfo>() {
return new SvnStatusHandler(callback, base, createInfoGetter(revision));
}
private Convertor<File, SVNInfo> createInfoGetter(final SVNRevision revision) {
return new Convertor<File, SVNInfo>() {
@Override
public SVNInfo convert(File o) {
try {
@@ -181,7 +226,7 @@ public class SvnCommandLineStatusClient implements SvnStatusClientI {
throw new SvnExceptionWrapper(e);
}
}
});
};
}
public static SvnStatusHandler.ExternalDataCallback createStatusCallback(final ISVNStatusHandler handler,
@@ -24,7 +24,6 @@ import com.intellij.util.ArrayUtil;
import org.jetbrains.idea.svn.SvnApplicationSettings;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.checkin.IdeaSvnkitBasedAuthenticationCallback;
import org.jetbrains.idea.svn.config.SvnBindException;
import org.jetbrains.idea.svn.portable.SvnSvnkitUpdateClient;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.wc.*;
@@ -49,9 +48,9 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
private final VirtualFile myCommonAncestor;
private boolean myIgnoreExternals;
public SvnCommandLineUpdateClient(final Project project, VirtualFile commonAncestor) {
super(SvnVcs.getInstance(project).createUpdateClient());
myProject = project;
public SvnCommandLineUpdateClient(final SvnVcs vcs, VirtualFile commonAncestor) {
super(vcs.createUpdateClient());
myProject = vcs.getProject();
myCommonAncestor = commonAncestor;
}
@@ -88,35 +87,7 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath());
base = base.isDirectory() ? base : base.getParentFile();
final List<String> parameters = new ArrayList<String>();
if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) {
parameters.add("-r");
parameters.add(revision.toString());
}
// unknown depth is not used any more for 1.7 -> why?
if (depth != null && ! SVNDepth.UNKNOWN.equals(depth)) {
parameters.add("--depth");
parameters.add(depth.toString());
}
if (allowUnversionedObstructions) {
parameters.add("--force");
}
if (depthIsSticky && depth != null) {// !!! not sure, but not used
parameters.add("--set-depth");
parameters.add(depth.toString());
}
if (makeParents) {
parameters.add("--parents");
}
if (myIgnoreExternals) {
parameters.add("--ignore-externals");
}
parameters.add("--accept");
parameters.add("postpone");
for (File path : paths) {
parameters.add(path.getPath());
}
final List<String> parameters = prepareParameters(paths, revision, depth, allowUnversionedObstructions, depthIsSticky, makeParents);
final AtomicReference<SVNException> excRef = new AtomicReference<SVNException>();
final ISVNEventHandler handler = getEventHandler();
@@ -166,7 +137,7 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
}
};
SvnLineCommand.runWithAuthenticationAttempt(SvnApplicationSettings.getInstance().getCommandLinePath(),
base, SvnCommandName.up, listener,
base, info.getURL(), SvnCommandName.up, listener,
new IdeaSvnkitBasedAuthenticationCallback(SvnVcs.getInstance(myProject)),
ArrayUtil.toStringArray(parameters));
}
@@ -180,6 +151,29 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
return updatedToRevision.get();
}
private List<String> prepareParameters(File[] paths,
SVNRevision revision,
SVNDepth depth,
boolean allowUnversionedObstructions,
boolean depthIsSticky, boolean makeParents) {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, revision);
CommandUtil.put(parameters, depth);
CommandUtil.put(parameters, allowUnversionedObstructions, "--force");
if (depthIsSticky && depth != null) {// !!! not sure, but not used
parameters.add("--set-depth");
parameters.add(depth.toString());
}
CommandUtil.put(parameters, makeParents, "--parents");
CommandUtil.put(parameters, myIgnoreExternals, "--ignore-externals");
parameters.add("--accept");
parameters.add("postpone");
CommandUtil.put(parameters, paths);
return parameters;
}
private void checkForException(final StringBuffer sbError) throws SVNException {
if (sbError.length() == 0) return;
@@ -22,13 +22,25 @@ package org.jetbrains.idea.svn.commandLine;
* Time: 1:49 PM
*/
public enum SvnCommandName {
// TODO: temporary command for "more smooth" converting between simple commands and line commands
empty("", false),
version("--version", false),
info("info", false),
st("st", false),
up("up", true),
ci("commit", true),
cleanup("cleanup", true);
cleanup("cleanup", true),
cat("cat", false),
add("add", true),
log("log", false),
revert("revert", true),
delete("delete", true),
copy("copy", true),
move("move", true),
resolve("resolve", true),
propget("propget", false),
blame("blame", false);
private final String myName;
private final boolean myWriteable;
@@ -13,22 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn;
package org.jetbrains.idea.svn.commandLine;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.Convertor;
import org.apache.subversion.javahl.types.Revision;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.commandLine.LineCommandListener;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.jetbrains.idea.svn.commandLine.SvnLineCommand;
import org.jetbrains.idea.svn.config.SvnBindException;
import org.tigris.subversion.javahl.BindClientException;
import org.tigris.subversion.javahl.ClientException;
import org.tmatesoft.svn.core.SVNURL;
import java.io.File;
import java.util.*;
@@ -42,7 +39,7 @@ import java.util.*;
public class SvnCommitRunner {
private final String myExePath;
@Nullable private final AuthenticationCallback myAuthenticationCallback;
private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.SvnCommitRunner");
private static final Logger LOG = Logger.getInstance("org.jetbrains.idea.svn.commandLine.SvnCommitRunner");
private SvnCommitRunner.CommandListener myCommandListener;
public SvnCommitRunner(@NotNull String path, @Nullable CommitEventHandler handler, @Nullable AuthenticationCallback authenticationCallback) {
@@ -57,7 +54,7 @@ public class SvnCommitRunner {
boolean noUnlock,
boolean keepChangelist,
String[] changelists,
Map revpropTable) throws ClientException {
Map revpropTable, Convertor<String[], SVNURL> urlProvider) throws VcsException {
if (paths.length == 0) return Revision.SVN_INVALID_REVNUM;
final List<String> parameters = new ArrayList<String>();
@@ -84,19 +81,14 @@ public class SvnCommitRunner {
Arrays.sort(paths);
parameters.addAll(Arrays.asList(paths));
try {
SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), SvnCommandName.ci,
myCommandListener, myAuthenticationCallback, ArrayUtil.toStringArray(parameters));
}
catch (SvnBindException e) {
throw BindClientException.create(e, Revision.SVN_INVALID_REVNUM);
}
SvnLineCommand.runWithAuthenticationAttempt(myExePath, new File(paths[0]), urlProvider.convert(paths), SvnCommandName.ci,
myCommandListener, myAuthenticationCallback, ArrayUtil.toStringArray(parameters));
myCommandListener.throwExceptionIfOccurred();
return myCommandListener.getCommittedRevision();
}
private static class CommandListener extends LineCommandListener {
public static class CommandListener extends LineCommandListener {
@Nullable private final CommitEventHandler myHandler;
private SvnBindException myException;
private long myCommittedRevision = Revision.SVN_INVALID_REVNUM;
@@ -106,9 +98,9 @@ public class SvnCommitRunner {
myHandler = handler;
}
public void throwExceptionIfOccurred() throws BindClientException {
public void throwExceptionIfOccurred() throws VcsException {
if (myException != null) {
throw BindClientException.create(myException, Revision.SVN_INVALID_REVNUM);
throw myException;
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.idea.svn.commandLine;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNNodeKind;
@@ -49,7 +50,7 @@ public class SvnInfoHandler extends DefaultHandler {
public SvnInfoHandler(File base, final Consumer<SVNInfo> infoConsumer) {
myBase = base;
myInfoConsumer = infoConsumer;
myPending = new SvnInfoStructure();
myPending = createPending();
myElementsMap = new HashMap<String, Getter<ElementHandlerBase>>();
fillElements();
myParseStack = new ArrayList<ElementHandlerBase>();
@@ -70,7 +71,14 @@ public class SvnInfoHandler extends DefaultHandler {
myInfoConsumer.consume(info);
}
myResultsMap.put(info.getFile(), info);
myPending = new SvnInfoStructure();
myPending = createPending();
}
private SvnInfoStructure createPending() {
SvnInfoStructure pending = new SvnInfoStructure();
pending.myDepth = SVNDepth.INFINITY;
return pending;
}
@Override
@@ -90,16 +98,13 @@ public class SvnInfoHandler extends DefaultHandler {
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
assertSAX(! myParseStack.isEmpty());
ElementHandlerBase current = myParseStack.get(myParseStack.size() - 1);
if (mySb.length() > 0) {
current.characters(mySb.toString().trim(), myPending);
mySb.setLength(0);
}
while (true) {
final boolean createNewChild = current.startElement(uri, localName, qName, attributes);
if (createNewChild) {
assertSAX(myElementsMap.containsKey(qName));
final ElementHandlerBase newChild = myElementsMap.get(qName).get();
newChild.setParent(current);
newChild.updateInfo(attributes, myPending);
myParseStack.add(newChild);
return;
@@ -115,6 +120,18 @@ public class SvnInfoHandler extends DefaultHandler {
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
ElementHandlerBase current = myParseStack.get(myParseStack.size() - 1);
String value = mySb.toString().trim();
if (!StringUtil.isEmpty(value)) {
current.characters(value, myPending);
}
mySb.setLength(0);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
assertSAX(! myParseStack.isEmpty());
@@ -252,6 +269,24 @@ public class SvnInfoHandler extends DefaultHandler {
return new Url();
}
});
myElementsMap.put("relative-url", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new RelativeUrl();
}
});
myElementsMap.put("lock", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new Lock();
}
});
myElementsMap.put("created", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new Date();
}
});
myElementsMap.put("uuid", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
@@ -270,6 +305,18 @@ public class SvnInfoHandler extends DefaultHandler {
return new WcInfo();
}
});
myElementsMap.put("moved-to", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new MovedPath();
}
});
myElementsMap.put("moved-from", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
return new MovedPath();
}
});
myElementsMap.put("wcroot-abspath", new Getter<ElementHandlerBase>() {
@Override
public ElementHandlerBase get() {
@@ -295,6 +342,12 @@ public class SvnInfoHandler extends DefaultHandler {
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
// TODO: Currently information for conflict (not tree-conflict) available in svn 1.8 is not used
// TODO: And it also not suite well for SVNKit api
if (getParent() instanceof Conflict) {
return;
}
final String side = attributes.getValue("side");
if ("source-left".equals(side)) {
final SvnInfoStructure.ConflictVersion conflictVersion = new SvnInfoStructure.ConflictVersion();
@@ -382,7 +435,7 @@ public class SvnInfoHandler extends DefaultHandler {
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.myConflictWorking = s;
structure.myConflictNew = new File(s).getName();
}
}
@@ -397,7 +450,7 @@ public class SvnInfoHandler extends DefaultHandler {
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.myConflictNew = s;
structure.myConflictWorking = new File(s).getName();
}
}
@@ -412,14 +465,13 @@ public class SvnInfoHandler extends DefaultHandler {
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
// todo path? or plus base
structure.myConflictOld = s;
structure.myConflictOld = new File(s).getName();
}
}
private static class Conflict extends ElementHandlerBase {
private Conflict() {
super(new String[]{"prev-base-file","prev-wc-file","cur-base-file","prop-file"}, new String[]{});
super(new String[]{"prev-base-file","prev-wc-file","cur-base-file","prop-file"}, new String[]{"version"});
}
@Override
@@ -498,6 +550,25 @@ public class SvnInfoHandler extends DefaultHandler {
}
}
/**
* "moved-from" and "moved-to" elements are represented by this class.
*/
private static class MovedPath extends ElementHandlerBase {
private MovedPath() {
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 {
// TODO: is there some field to initialize from this value?
}
}
private static class TextUpdated extends ElementHandlerBase {
private TextUpdated() {
super(new String[]{}, new String[]{});
@@ -617,7 +688,7 @@ public class SvnInfoHandler extends DefaultHandler {
private static class WcInfo extends ElementHandlerBase {
private WcInfo() {
super(new String[]{"wcroot-abspath", "schedule", "depth", "text-updated", "checksum", "changelist", "copy-from-url",
"copy-from-rev"}, new String[]{});
"copy-from-rev", "moved-to", "moved-from"}, new String[]{});
}
@Override
@@ -698,11 +769,34 @@ public class SvnInfoHandler extends DefaultHandler {
}
}
private static class RelativeUrl extends Url{
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
structure.relativeUrl = s;
}
}
private static class Lock extends ElementHandlerBase {
private Lock() {
super(new String[]{"created"}, new String[]{});
}
@Override
protected void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException {
// TODO:
}
@Override
public void characters(String s, SvnInfoStructure structure) throws SAXException {
// TODO:
}
}
private static class Entry extends ElementHandlerBase {
private final File myBase;
private Entry(final File base) {
super(new String[]{"url","repository","wc-info","commit","conflict","tree-conflict"}, new String[]{});
super(new String[]{"url", "relative-url", "lock", "repository","wc-info","commit","conflict","tree-conflict"}, new String[]{});
myBase = base;
}
@@ -763,12 +857,22 @@ public class SvnInfoHandler extends DefaultHandler {
private abstract static class ElementHandlerBase {
private final Set<String> myAwaitedChildren;
private final Set<String> myAwaitedChildrenMultiple;
private ElementHandlerBase parent;
ElementHandlerBase(String[] awaitedChildren, String[] awaitedChildrenMultiple) {
myAwaitedChildren = new HashSet<String>(Arrays.asList(awaitedChildren));
myAwaitedChildrenMultiple = new HashSet<String>(Arrays.asList(awaitedChildrenMultiple));
}
@NotNull
public ElementHandlerBase getParent() {
return parent;
}
public void setParent(@NotNull ElementHandlerBase parent) {
this.parent = parent;
}
protected abstract void updateInfo(Attributes attributes, SvnInfoStructure structure) throws SAXException;
public boolean startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
@@ -34,6 +34,7 @@ import java.util.Date;
*/
public class SvnInfoStructure {
public File myFile;
public String relativeUrl;
public SVNURL myUrl;
public SVNURL myRootURL;
public long myRevision;
@@ -23,20 +23,30 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.LineHandlerHelper;
import com.intellij.openapi.vcs.LineProcessEventListener;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ArrayUtil;
import com.intellij.util.EventDispatcher;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.AuthenticationCallback;
import org.jetbrains.idea.svn.SvnBindUtil;
import org.jetbrains.idea.svn.config.SvnBindException;
import org.jetbrains.idea.svn.SvnUtil;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.auth.SVNAuthentication;
import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication;
import org.tmatesoft.svn.core.auth.SVNSSLAuthentication;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created with IntelliJ IDEA.
@@ -47,11 +57,21 @@ import java.util.concurrent.atomic.AtomicReference;
* honestly stolen from GitLineHandler
*/
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 CANNOT_AUTHENTICATE_TO_PROXY = "Could not authenticate to proxy server";
public static final String AUTHENTICATION_FAILED_MESSAGE = "Authentication failed";
private static final String INVALID_CREDENTIALS_FOR_SVN_PROTOCOL = "svn: E170001: Can't get";
private static final String UNTRUSTED_SERVER_CERTIFICATE = "Server SSL certificate untrusted";
private static final String ACCESS_TO_PREFIX = "Access to ";
private static final String FORBIDDEN_STATUS = "forbidden";
private static final String PASSWORD_STRING = "password";
private static final Pattern UNABLE_TO_CONNECT_TO_URL_PATTERN = Pattern.compile("Unable to connect to a repository at URL '(.*)'");
// kept for exact text
//public static final String CLIENT_CERTIFICATE_FILENAME = "Client certificate filename:";
@@ -66,6 +86,7 @@ public class SvnLineCommand extends SvnCommand {
private final EventDispatcher<LineProcessEventListener> myLineListeners;
private final AtomicReference<Integer> myExitCode;
private final StringBuffer myErr;
private final StringBuffer myStdOut;
public SvnLineCommand(File workingDirectory, @NotNull SvnCommandName commandName, @NotNull @NonNls String exePath) {
this(workingDirectory, commandName, exePath, null);
@@ -76,6 +97,7 @@ public class SvnLineCommand extends SvnCommand {
myLineListeners = EventDispatcher.create(LineProcessEventListener.class);
myExitCode = new AtomicReference<Integer>();
myErr = new StringBuffer();
myStdOut = new StringBuffer();
}
@Override
@@ -89,13 +111,14 @@ public class SvnLineCommand extends SvnCommand {
}
}
public static void runWithAuthenticationAttempt(final String exePath,
final File firstFile,
SvnCommandName commandName,
final LineCommandListener listener,
@Nullable AuthenticationCallback authenticationCallback,
final String... parameters) throws SvnBindException {
File base = firstFile.isDirectory() ? firstFile : firstFile.getParentFile();
public static SvnLineCommand runWithAuthenticationAttempt(final String exePath,
final File firstFile,
final SVNURL url,
SvnCommandName commandName,
final LineCommandListener listener,
@Nullable AuthenticationCallback authenticationCallback,
String... parameters) throws SvnBindException {
File base = firstFile != null ? (firstFile.isDirectory() ? firstFile : firstFile.getParentFile()) : null;
base = SvnBindUtil.correctUpToExistingParent(base);
listener.baseDirectory(base);
@@ -114,13 +137,14 @@ public class SvnLineCommand extends SvnCommand {
if (command.myErr.length() > 0) {
final String errText = command.myErr.toString().trim();
if (authenticationCallback != null) {
final AuthCallbackCase callback = createCallback(errText, authenticationCallback, base);
final AuthCallbackCase callback = createCallback(errText, authenticationCallback, base, url);
if (callback != null) {
cleanup(exePath, commandName, base);
cleanup(exePath, command, base);
if (callback.getCredentials(errText)) {
if (authenticationCallback.getSpecialConfigDir() != null) {
configDir = authenticationCallback.getSpecialConfigDir();
}
parameters = updateParameters(callback, parameters);
continue;
}
}
@@ -131,7 +155,7 @@ public class SvnLineCommand extends SvnCommand {
if (exitCode != 0) {
throw new SvnBindException("Svn process exited with error code: " + exitCode);
}
return;
return command;
}
} finally {
if (authenticationCallback != null) {
@@ -140,6 +164,13 @@ public class SvnLineCommand extends SvnCommand {
}
}
private static String[] updateParameters(AuthCallbackCase callback, String[] parameters) {
List<String> p = new ArrayList<String>(Arrays.asList(parameters));
callback.updateParameters(p);
return ArrayUtil.toStringArray(p);
}
private static void writeIdeaConfig2SubversionConfig(@NotNull AuthenticationCallback authenticationCallback, @NotNull File base) throws SvnBindException {
if (authenticationCallback.haveDataForTmpConfig()) {
try {
@@ -158,7 +189,7 @@ public class SvnLineCommand extends SvnCommand {
}
}
private static AuthCallbackCase createCallback(final String errText, final AuthenticationCallback callback, final File base) {
private static AuthCallbackCase createCallback(final String errText, final AuthenticationCallback callback, final File base, final SVNURL url) {
if (errText.startsWith(CERTIFICATE_ERROR)) {
return new CertificateCallbackCase(callback, base);
}
@@ -171,9 +202,85 @@ public class SvnLineCommand extends SvnCommand {
if (errText.startsWith(UNABLE_TO_CONNECT) && errText.contains(CANNOT_AUTHENTICATE_TO_PROXY)) {
return new ProxyCallback(callback, base);
}
// http/https protocol invalid credentials
if (errText.contains(AUTHENTICATION_FAILED_MESSAGE)) {
return new UsernamePasswordCallback(callback, base, url);
}
// messages could be "Can't get password", "Can't get username or password"
if (errText.contains(INVALID_CREDENTIALS_FOR_SVN_PROTOCOL) && errText.contains(PASSWORD_STRING)) {
// svn protocol invalid credentials
return new UsernamePasswordCallback(callback, base, url);
}
// https one-way protocol untrusted server certificate
if (errText.contains(UNTRUSTED_SERVER_CERTIFICATE)) {
return new CertificateCallbackCase(callback, base);
}
// https two-way protocol invalid client certificate
if (errText.contains(ACCESS_TO_PREFIX) && errText.contains(FORBIDDEN_STATUS)) {
return new TwoWaySslCallback(callback, base, url);
}
return null;
}
// Special callback for svn 1.8 credentials request as --non-interactive does not return
// authentication realm (just url) - so we could not create temp cache
private static class UsernamePasswordCallback extends AuthCallbackCase {
protected SVNAuthentication myAuthentication;
protected SVNURL myUrl;
protected UsernamePasswordCallback(AuthenticationCallback callback, File base, SVNURL url) {
super(callback, base);
myUrl = url;
}
@Override
boolean getCredentials(String errText) throws SvnBindException {
myAuthentication = myAuthenticationCallback.requestCredentials(myUrl != null ? myUrl : parseUrlFromError(errText),
getType());
return myAuthentication != null;
}
public String getType() {
return ISVNAuthenticationManager.PASSWORD;
}
@Override
public void updateParameters(List<String> parameters) {
if (myAuthentication instanceof SVNPasswordAuthentication) {
SVNPasswordAuthentication auth = (SVNPasswordAuthentication)myAuthentication;
parameters.add("--username");
parameters.add(auth.getUserName());
parameters.add("--password");
parameters.add(auth.getPassword());
if (!auth.isStorageAllowed()) {
parameters.add("--no-auth-cache");
}
}
}
private SVNURL parseUrlFromError(String errorText) {
Matcher matcher = UNABLE_TO_CONNECT_TO_URL_PATTERN.matcher(errorText);
String urlValue = null;
if (matcher.find()) {
urlValue = matcher.group(1);
}
return urlValue != null ? parseUrl(urlValue) : null;
}
private SVNURL parseUrl(String urlValue) {
try {
return SVNURL.parseURIEncoded(urlValue);
}
catch (SVNException e) {
return null;
}
}
}
private static class ProxyCallback extends AuthCallbackCase {
protected ProxyCallback(AuthenticationCallback callback, File base) {
super(callback, base);
@@ -192,7 +299,8 @@ public class SvnLineCommand extends SvnCommand {
@Override
boolean getCredentials(String errText) throws SvnBindException {
final String realm = cutFirstLine(errText).substring(AUTHENTICATION_REALM.length()).trim();
final String realm =
errText.startsWith(AUTHENTICATION_REALM) ? cutFirstLine(errText).substring(AUTHENTICATION_REALM.length()).trim() : null;
final boolean isPassword = StringUtil.containsIgnoreCase(errText, "password");
if (myTried) {
myAuthenticationCallback.clearPassiveCredentials(realm, myBase, isPassword);
@@ -212,13 +320,16 @@ public class SvnLineCommand extends SvnCommand {
}
private static class CertificateCallbackCase extends AuthCallbackCase {
private boolean accepted;
private CertificateCallbackCase(AuthenticationCallback callback, File base) {
super(callback, base);
}
@Override
public boolean getCredentials(final String errText) throws SvnBindException {
String realm = cutFirstLine(errText).substring(CERTIFICATE_ERROR.length());
// parse realm from error text
String realm = errText;
final int idx1 = realm.indexOf('\'');
if (idx1 == -1) {
throw new SvnBindException("Can not detect authentication realm name: " + errText);
@@ -229,11 +340,48 @@ public class SvnLineCommand extends SvnCommand {
}
realm = realm.substring(idx1 + 1, idx2);
if (! myTried && myAuthenticationCallback.acceptSSLServerCertificate(myBase, realm)) {
accepted = true;
myTried = true;
return true;
}
throw new SvnBindException("Server SSL certificate rejected");
}
@Override
public void updateParameters(List<String> parameters) {
if (accepted) {
parameters.add("--trust-server-cert");
}
}
}
private static class TwoWaySslCallback extends UsernamePasswordCallback {
protected TwoWaySslCallback(AuthenticationCallback callback, File base, SVNURL url) {
super(callback, base, url);
}
@Override
public String getType() {
return ISVNAuthenticationManager.SSL;
}
@Override
public void updateParameters(List<String> parameters) {
if (myAuthentication instanceof SVNSSLAuthentication) {
SVNSSLAuthentication auth = (SVNSSLAuthentication)myAuthentication;
// TODO: Seems that config option should be specified for concrete server and not for global group.
// as in that case it could be overriden by settings in config file
parameters.add("--config-option");
parameters.add("servers:global:ssl-client-cert-file=" + auth.getCertificatePath());
parameters.add("--config-option");
parameters.add("servers:global:ssl-client-cert-password=" + auth.getPassword());
if (!auth.isStorageAllowed()) {
parameters.add("--no-auth-cache");
}
}
}
}
private static abstract class AuthCallbackCase {
@@ -247,17 +395,23 @@ public class SvnLineCommand extends SvnCommand {
}
abstract boolean getCredentials(final String errText) throws SvnBindException;
public void updateParameters(List<String> parameters) {
}
}
private static void cleanup(String exePath, SvnCommandName commandName, File base) throws SvnBindException {
File wcRoot = SvnBindUtil.getWcRoot(base);
if (wcRoot == null) throw new SvnBindException("Can not find working copy root for: " + base.getPath());
private static void cleanup(String exePath, SvnCommand command, File base) throws SvnBindException {
// TODO: could be issues with fake "empty" command as it is not writable - but only read commands currently use "empty" command
// TODO: and "empty" command will be removed shortly
if (command.isManuallyDestroyed() && command.getCommandName().isWriteable()) {
File wcRoot = SvnUtil.getWorkingCopyRootNew(base);
if (wcRoot == null) {
throw new SvnBindException("Can not find working copy root for: " + base.getPath());
}
//cleanup -> check command type
if (commandName.isWriteable()) {
final SvnSimpleCommand command = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath);
final SvnSimpleCommand cleanupCommand = new SvnSimpleCommand(wcRoot, SvnCommandName.cleanup, exePath);
try {
command.run();
cleanupCommand.run();
}
catch (VcsException e) {
throw new SvnBindException(e);
@@ -320,6 +474,10 @@ public class SvnLineCommand extends SvnCommand {
command.addLineListener(new LineProcessEventListener() {
@Override
public void onLineAvailable(String line, Key outputType) {
if (ProcessOutputTypes.STDOUT.equals(outputType)) {
command.myStdOut.append(line);
}
if (SvnCommand.LOG.isDebugEnabled()) {
SvnCommand.LOG.debug("==> " + line);
}
@@ -94,7 +94,11 @@ public class SvnSimpleCommand extends SvnCommand {
if (myException != null) throw myException;
final int code = getExitCode();
if (code == 0) {
return myStdout.toString();
String result = myStdout.toString();
LOG.debug(result);
return result;
} else {
final String msg = new StringBuilder("Svn process exited with error code: ").append(code).append("\n")
.append("stderr: ").append(myStderr.toString()).append("\nstdout: ").append(getStdout().toString())
@@ -62,6 +62,8 @@ public class UpdateOutputLineConverter {
}
public SVNEvent convert(final String line) {
// TODO: Add direct processing of "Summary of conflicts" lines at the end of "svn update" output (if there are conflicts).
// TODO: Now it works ok because parseNormalLine could not determine necessary statuses from that and further lines
if (StringUtil.isEmptyOrSpaces(line)) return null;
if (line.startsWith(UPDATING)) {
@@ -103,9 +105,9 @@ public class UpdateOutputLineConverter {
if (line.length() < 5) return null;
final char first = line.charAt(0);
if (' ' != first && ! ourActions.contains(first)) return null;
final SVNStatusType contentsStatus = getStatusType(first);
final SVNStatusType contentsStatus = CommandUtil.getStatusType(first);
final char second = line.charAt(1);
final SVNStatusType propertiesStatus = getStatusType(second);
final SVNStatusType propertiesStatus = CommandUtil.getStatusType(second);
final char lock = line.charAt(2); // dont know what to do with stolen lock info
if (' ' != lock && 'B' != lock) return null;
final char treeConflict = line.charAt(3);
@@ -140,28 +142,6 @@ public class UpdateOutputLineConverter {
null, action, expectedAction, null, null, null, null, null);
}
private SVNStatusType getStatusType(char first) {
final SVNStatusType contentsStatus;
if ('A' == first) {
contentsStatus = SVNStatusType.STATUS_ADDED;
} else if ('D' == first) {
contentsStatus = SVNStatusType.STATUS_DELETED;
} else if ('U' == first) {
contentsStatus = SVNStatusType.CHANGED;
} else if ('C' == first) {
contentsStatus = SVNStatusType.CONFLICTED;
} else if ('G' == first) {
contentsStatus = SVNStatusType.MERGED;
} else if ('R' == first) {
contentsStatus = SVNStatusType.STATUS_REPLACED;
} else if ('E' == first) {
contentsStatus = SVNStatusType.STATUS_OBSTRUCTED;
} else {
contentsStatus = SVNStatusType.STATUS_NORMAL;
}
return contentsStatus;
}
@Nullable
private long matchAndGetRevision(final Pattern pattern, final String line) {
final Matcher matcher = pattern.matcher(line);
@@ -0,0 +1,33 @@
package org.jetbrains.idea.svn.conflict;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.tmatesoft.svn.core.SVNDepth;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdConflictClient extends BaseSvnClient implements ConflictClient {
// TODO: Add possibility to resolve content conflicts separately from property conflicts.
@Override
public void resolve(@NotNull File path, boolean resolvePropertyConflicts) throws VcsException {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, path);
CommandUtil.put(parameters, SVNDepth.EMPTY);
parameters.add("--accept");
parameters.add("working");
// for now parsing of the output is not required as command is executed only for one file
// and will be either successful or exception will be thrown
CommandUtil.execute(myVcs, SvnCommandName.resolve, parameters, null);
}
}
@@ -0,0 +1,15 @@
package org.jetbrains.idea.svn.conflict;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.SvnClient;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface ConflictClient extends SvnClient {
void resolve(@NotNull File path, boolean resolvePropertyConflicts) throws VcsException;
}
@@ -0,0 +1,25 @@
package org.jetbrains.idea.svn.conflict;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNConflictChoice;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitConflictClient extends BaseSvnClient implements ConflictClient {
@Override
public void resolve(@NotNull File path, boolean resolvePropertyConflicts) throws VcsException {
try {
myVcs.createWCClient().doResolve(path, SVNDepth.EMPTY, true, resolvePropertyConflicts, SVNConflictChoice.MERGED);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
}
@@ -0,0 +1,39 @@
package org.jetbrains.idea.svn.content;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
import com.intellij.openapi.vfs.CharsetToolkit;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.*;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdContentClient extends BaseSvnClient implements ContentClient {
@Override
public byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision)
throws VcsException, FileTooBigRuntimeException {
// TODO: rewrite this to provide output as Stream
// TODO: rewrite without conversion from String to byte[]
// TODO: Also implement max size constraint like in SvnKitContentClient
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision);
CommandUtil.put(parameters, revision);
SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.cat, parameters, null);
byte[] bytes = CharsetToolkit.getUtf8Bytes(command.getOutput());
ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), bytes.length);
return bytes;
}
}
@@ -0,0 +1,17 @@
package org.jetbrains.idea.svn.content;
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.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
/**
* @author Konstantin Kolosovsky.
*/
public interface ContentClient extends SvnClient {
byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision)
throws VcsException, FileTooBigRuntimeException;
}
@@ -0,0 +1,7 @@
package org.jetbrains.idea.svn.content;
/**
* @author Konstantin Kolosovsky.
*/
public class FileTooBigRuntimeException extends RuntimeException {
}
@@ -0,0 +1,61 @@
package org.jetbrains.idea.svn.content;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitContentClient extends BaseSvnClient implements ContentClient {
@Override
public byte[] getContent(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable SVNRevision pegRevision)
throws VcsException, FileTooBigRuntimeException {
final int maxSize = VcsUtil.getMaxVcsLoadedFileSize();
ByteArrayOutputStream buffer = new ByteArrayOutputStream() {
@Override
public synchronized void write(int b) {
if (size() > maxSize) throw new FileTooBigRuntimeException();
super.write(b);
}
@Override
public synchronized void write(byte[] b, int off, int len) {
if (size() > maxSize) throw new FileTooBigRuntimeException();
super.write(b, off, len);
}
@Override
public synchronized void writeTo(OutputStream out) throws IOException {
if (size() > maxSize) throw new FileTooBigRuntimeException();
super.writeTo(out);
}
};
SVNWCClient wcClient = myVcs.createWCClient();
try {
if (target.isURL()) {
wcClient.doGetFileContents(target.getURL(), pegRevision, revision, true, buffer);
} else {
wcClient.doGetFileContents(target.getFile(), pegRevision, revision, true, buffer);
}
ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), buffer.size());
} catch (FileTooBigRuntimeException e) {
ContentRevisionCache.checkContentsSize(target.getPathOrUrlString(), buffer.size());
} catch (SVNException e) {
throw new VcsException(e);
}
return buffer.toByteArray();
}
}
@@ -0,0 +1,30 @@
package org.jetbrains.idea.svn.copy;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdCopyMoveClient extends BaseSvnClient implements CopyMoveClient {
@Override
public void copy(@NotNull File src, @NotNull File dst, boolean makeParents, boolean isMove) throws VcsException {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, src);
CommandUtil.put(parameters, dst);
CommandUtil.put(parameters, makeParents, "--parents");
// for now parsing of the output is not required as command is executed only for one file
// and will be either successful or exception will be thrown
CommandUtil.execute(myVcs, isMove ? SvnCommandName.move : SvnCommandName.copy, parameters, null);
}
}
@@ -0,0 +1,15 @@
package org.jetbrains.idea.svn.copy;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.SvnClient;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface CopyMoveClient extends SvnClient {
void copy(@NotNull File src, @NotNull File dst, boolean makeParents, boolean isMove) throws VcsException;
}
@@ -0,0 +1,28 @@
package org.jetbrains.idea.svn.copy;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNCopySource;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitCopyMoveClient extends BaseSvnClient implements CopyMoveClient {
@Override
public void copy(@NotNull File src, @NotNull File dst, boolean makeParents, boolean isMove) throws VcsException {
final SVNCopySource copySource = new SVNCopySource(isMove ? SVNRevision.UNDEFINED : SVNRevision.WORKING, SVNRevision.WORKING, src);
try {
myVcs.createCopyClient().doCopy(new SVNCopySource[]{copySource}, dst, isMove, makeParents, true);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
}
@@ -0,0 +1,29 @@
package org.jetbrains.idea.svn.delete;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdDeleteClient extends BaseSvnClient implements DeleteClient {
@Override
public void delete(@NotNull File path, boolean force) throws VcsException {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, path);
CommandUtil.put(parameters, force, "--force");
// for now parsing of the output is not required as command is executed only for one file
// and will be either successful or exception will be thrown
CommandUtil.execute(myVcs, SvnCommandName.delete, parameters, null);
}
}
@@ -0,0 +1,15 @@
package org.jetbrains.idea.svn.delete;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.SvnClient;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface DeleteClient extends SvnClient {
void delete(@NotNull File path, boolean force) throws VcsException;
}
@@ -0,0 +1,24 @@
package org.jetbrains.idea.svn.delete;
import com.intellij.openapi.vcs.VcsException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.tmatesoft.svn.core.SVNException;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitDeleteClient extends BaseSvnClient implements DeleteClient {
@Override
public void delete(@NotNull File path, boolean force) throws VcsException {
try {
myVcs.createWCClient().doDelete(path, force, false);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
}
@@ -263,17 +263,11 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
super.init();
SvnVcs vcs = SvnVcs.getInstance(myProject);
String revStr = "";
try {
SVNWCClient client = vcs.createWCClient();
SVNInfo info = client.doInfo(mySrcFile, SVNRevision.UNDEFINED);
if (info != null) {
mySrcURL = info.getURL() == null ? null : info.getURL().toString();
revStr = String.valueOf(info.getRevision());
myURL = mySrcURL;
}
}
catch (SVNException e) {
//
SVNInfo info = vcs.getInfo(mySrcFile);
if (info != null) {
mySrcURL = info.getURL() == null ? null : info.getURL().toString();
revStr = String.valueOf(info.getRevision());
myURL = mySrcURL;
}
if (myURL == null) {
return;
@@ -354,15 +348,8 @@ public class CreateBranchOrTagDialog extends DialogWrapper {
return true;
}
else if (myWorkingCopyRadioButton.isSelected()) {
String srcUrl;
try {
SVNWCClient client = SvnVcs.getInstance(myProject).createWCClient();
SVNInfo info = client.doInfo(mySrcFile, SVNRevision.UNDEFINED);
srcUrl = info != null && info.getURL() != null ? info.getURL().toString() : null;
}
catch (SVNException e) {
srcUrl = null;
}
SVNInfo info = SvnVcs.getInstance(myProject).getInfo(mySrcFile);
String srcUrl = info != null && info.getURL() != null ? info.getURL().toString() : null;
if (srcUrl == null) {
myErrorLabel.setText(SvnBundle.message("create.branch.no.working.copy.error", myWorkingCopyField.getText()));
return false;
@@ -0,0 +1,223 @@
package org.jetbrains.idea.svn.history;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
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.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.CommandUtil;
import org.jetbrains.idea.svn.commandLine.SvnCommandName;
import org.jetbrains.idea.svn.commandLine.SvnLineCommand;
import org.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdHistoryClient extends BaseSvnClient implements HistoryClient {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.CmdHistoryClient");
@Override
public void doLog(@NotNull File path,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean stopOnCopy,
boolean discoverChangedPaths,
boolean includeMergedRevisions,
long limit,
@Nullable String[] revisionProperties,
@Nullable ISVNLogEntryHandler handler) throws VcsException {
// TODO: add revision properties parameter if necessary
// TODO: svn log command supports --xml option - could update parsing to use xml format
// TODO: after merge remove setting includeMergedRevisions to false and update parsing
includeMergedRevisions = false;
List<String> parameters =
prepareCommand(path, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions, limit);
try {
SvnLineCommand command = CommandUtil.runSimple(SvnCommandName.log, myVcs, path, null, parameters);
// 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
parseOutput(handler, command);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
private static void parseOutput(@Nullable ISVNLogEntryHandler handler, @NotNull SvnLineCommand command)
throws VcsException, SVNException {
Parser parser = new Parser(handler);
for (String line : StringUtil.splitByLines(command.getOutput(), false)) {
parser.onLine(line);
}
}
private static List<String> prepareCommand(@NotNull File path,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean stopOnCopy, boolean discoverChangedPaths, boolean includeMergedRevisions, long limit) {
List<String> parameters = new ArrayList<String>();
CommandUtil.put(parameters, path, pegRevision);
parameters.add("--revision");
parameters.add(startRevision + ":" + endRevision);
CommandUtil.put(parameters, stopOnCopy, "--stop-on-copy");
CommandUtil.put(parameters, discoverChangedPaths, "--verbose");
CommandUtil.put(parameters, includeMergedRevisions, "--use-merge-history");
if (limit > 0) {
parameters.add("--limit");
parameters.add(String.valueOf(limit));
}
return parameters;
}
private static class Parser {
private static final String REVISION = "\\s*r(\\d+)\\s*";
private static final String AUTHOR = "\\s*([^|]*)\\s*";
private static final String DATE = "\\s*([^|]*)\\s*";
private static final String MESSAGE_LINES = "\\s*(\\d+).*";
private static final Pattern ENTRY_START = Pattern.compile("-+");
private static final Pattern DETAILS = Pattern.compile(REVISION + "\\|" + AUTHOR + "\\|" + DATE + "\\|" + MESSAGE_LINES);
private static final String STATUS = "\\s*(\\w)";
private static final String PATH = "\\s*(.*?)\\s*";
private static final String COPY_FROM_PATH = "(/[^:]*)";
private static final String COPY_FROM_REVISION = "(\\d+)\\))\\s*";
private static final String COPY_FROM_INFO = "((\\(from " + COPY_FROM_PATH + ":" + COPY_FROM_REVISION + ")?";
private static final Pattern CHANGED_PATH = Pattern.compile(STATUS + PATH + COPY_FROM_INFO);
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
ISVNLogEntryHandler handler;
Entry entry;
boolean waitDetails;
boolean waitChangedPath;
boolean waitMessage;
public Parser(@Nullable ISVNLogEntryHandler handler) {
this.handler = handler;
}
public void onLine(@NotNull String line) throws VcsException, SVNException {
if (ENTRY_START.matcher(line).matches()) {
processEntryStart();
}
else if (waitDetails) {
processDetails(line);
}
else if (waitMessage) {
processMessage(line);
}
else if (StringUtil.isEmpty(line.trim())) {
processChangedPathsFinished();
}
else if (line.startsWith("Changed paths:")) {
processChangedPathsStarted();
}
else if (waitChangedPath) {
processChangedPath(line);
}
else {
throw new VcsException("unknown state on line " + line);
}
}
private void processChangedPath(@NotNull String line) throws VcsException {
Matcher matcher = CHANGED_PATH.matcher(line);
if (!matcher.matches()) {
throw new VcsException("changed path not found in " + line);
}
String path = matcher.group(2);
char type = CommandUtil.getStatusChar(matcher.group(1));
String copyPath = matcher.group(5);
long copyRevision = !StringUtil.isEmpty(matcher.group(6)) ? Long.valueOf(matcher.group(6)) : 0;
entry.changedPaths.put(path, new SVNLogEntryPath(path, type, copyPath, copyRevision));
}
private void processChangedPathsStarted() {
waitChangedPath = true;
}
private void processChangedPathsFinished() {
waitChangedPath = false;
waitMessage = true;
}
private void processMessage(@NotNull String line) {
entry.message.append(line);
entry.message.append(LineSeparator.LF.getSeparatorString());
}
private void processDetails(@NotNull String line) throws VcsException {
Matcher matcher = DETAILS.matcher(line);
if (!matcher.matches()) {
throw new VcsException("details not found in " + line);
}
entry.revision = Long.valueOf(matcher.group(1));
entry.author = matcher.group(2).trim();
entry.date = tryGetDate(matcher.group(3));
waitDetails = false;
}
private void processEntryStart() throws SVNException {
if (entry != null) {
handler.handleLogEntry(entry.toLogEntry());
}
entry = new Entry();
waitDetails = true;
waitMessage = false;
}
private static Date tryGetDate(@NotNull String value) {
Date result = null;
try {
result = DATE_FORMAT.parse(value);
}
catch (ParseException e) {
LOG.debug(e);
}
return result;
}
private static class Entry {
Map<String, SVNLogEntryPath> changedPaths = new HashMap<String, SVNLogEntryPath>();
long revision;
String author;
Date date;
StringBuilder message = new StringBuilder();
private SVNLogEntry toLogEntry() {
return new SVNLogEntry(changedPaths, revision, author, date, message.toString());
}
}
}
}
@@ -0,0 +1,28 @@
package org.jetbrains.idea.svn.history;
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.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface HistoryClient extends SvnClient {
// TODO: Url is also supported as parameter in cmd - use Target class
void doLog(@NotNull File path,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean stopOnCopy,
boolean discoverChangedPaths,
boolean includeMergedRevisions,
long limit,
@Nullable String[] revisionProperties,
@Nullable ISVNLogEntryHandler handler) throws VcsException;
}
@@ -518,9 +518,8 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
revisionBefore = SVNRevision.create(revision);
svnurl = SVNURL.parseURIEncoded(url);
final SVNWCClient client = myVcs.createWCClient();
final SVNInfo info = client.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD);
targetInfo = client.doInfo(new File(file.getPath()), SVNRevision.UNDEFINED);
final SVNInfo info = myVcs.getInfo(svnurl, SVNRevision.HEAD);
targetInfo = myVcs.getInfo(new File(file.getPath()));
if (info == null) {
throw new VcsException("Can not get repository URL");
}
@@ -137,7 +137,7 @@ public class SvnEditCommitMessageAction extends AnAction {
final String url = myLocation.getURL();
final SVNURL root;
try {
root = SvnUtil.getRepositoryRoot(myVcs, SVNURL.parseURIEncoded(url), true);
root = SvnUtil.getRepositoryRoot(myVcs, SVNURL.parseURIEncoded(url));
if (root == null) {
myException = new VcsException("Can not determine repository root for URL: " + url);
return;
@@ -33,6 +33,7 @@ import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -211,7 +212,7 @@ public class SvnFileRevision implements VcsFileRevision {
}
try {
myContents = SvnUtil.getFileContents(myVCS, myURL, true, myRevision, myPegRevision);
myContents = SvnUtil.getFileContents(myVCS, SvnTarget.fromURL(SvnUtil.parseUrl(myURL)), myRevision, myPegRevision);
}
catch (VcsException e) {
myException = e;
@@ -42,7 +42,6 @@ import org.jetbrains.idea.svn.*;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.*;
import org.tmatesoft.svn.util.SVNLogType;
@@ -50,7 +49,6 @@ import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.File;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Date;
@@ -285,18 +283,9 @@ public class SvnHistoryProvider
@Override
protected void preliminary() throws SVNException {
SVNWCClient wcClient = myVcs.createWCClient();
myInfo = wcClient.doInfo(new File(myFile.getIOFile().getAbsolutePath()), SVNRevision.UNDEFINED);
wcClient.setEventHandler(new ISVNEventHandler() {
public void handleEvent(SVNEvent event, double progress) throws SVNException {
}
public void checkCancelled() throws SVNCancelException {
myPI.checkCanceled();
}
});
myInfo = myVcs.getInfo(myFile.getIOFile());
if (myInfo == null || myInfo.getRepositoryRootURL() == null) {
myException = new VcsException("File ''{0}'' is not under version control" + myFile.getIOFile());
myException = new VcsException("File " + myFile.getPath() + " is not under version control");
return;
}
if (myInfo.getURL() == null) {
@@ -319,14 +308,15 @@ public class SvnHistoryProvider
myPI.setText2(SvnBundle.message("progress.text2.changes.establishing.connection", myUrl));
}
final SVNRevision pegRevision = myInfo.getRevision();
SVNLogClient client = myVcs.createLogClient();
try {
// a bug noticed when testing: we should pass "limit + 1" to get "limit" rows
client
.doLog(new File[]{new File(myFile.getIOFile().getAbsolutePath())},
myFrom == null ? SVNRevision.HEAD : myFrom, myTo == null ? SVNRevision.create(1) : myTo, myPeg,
false, true, myShowMergeSources && mySupport15, myLimit + 1, null,
new MyLogEntryHandler(myVcs, myUrl, pegRevision, relativeUrl, createConsumerAdapter(myConsumer), repoRootURL, myFile.getCharset()));
myVcs.getFactory(myFile.getIOFile()).createHistoryClient().doLog(
myFile.getIOFile(),
myFrom == null ? SVNRevision.HEAD : myFrom,
myTo == null ? SVNRevision.create(1) : myTo, myPeg,
false, true, myShowMergeSources && mySupport15, myLimit + 1, null,
new MyLogEntryHandler(myVcs, myUrl, pegRevision, relativeUrl,
createConsumerAdapter(myConsumer),
repoRootURL, myFile.getCharset()));
}
catch (SVNCancelException e) {
//
@@ -383,7 +373,6 @@ public class SvnHistoryProvider
}
}
SVNWCClient wcClient = myVcs.createWCClient();
final SVNURL svnurl = SVNURL.parseURIEncoded(myUrl);
SVNRevision operationalFrom = myFrom == null ? SVNRevision.HEAD : myFrom;
final SVNURL rootURL = getRepositoryRoot(svnurl, myFrom);
@@ -395,6 +384,7 @@ public class SvnHistoryProvider
if (myUrl.startsWith(root)) {
relativeUrl = myUrl.substring(root.length());
}
// TODO: Update this call to myVcs.getFactory.createHistoryClient
SVNLogClient client = myVcs.createLogClient();
// a bug noticed when testing: we should pass "limit + 1" to get "limit" rows
client.doLog(svnurl, new String[]{}, myPeg == null ? myFrom : myPeg,
@@ -420,6 +410,7 @@ public class SvnHistoryProvider
relativeUrl = myUrl.substring(root.length());
}
// TODO: Update this call to myVcs.getFactory.createHistoryClient
SVNLogClient client = myVcs.createLogClient();
final RepositoryLogEntryHandler repositoryLogEntryHandler =
@@ -437,36 +428,15 @@ public class SvnHistoryProvider
}
private SVNURL getRepositoryRoot(SVNURL svnurl, SVNRevision operationalFrom) throws SVNException {
final SVNRepository repository = myVcs.createRepository(svnurl);
final SVNURL root = repository.getRepositoryRoot(false);
if (root == null) {
return repository.getRepositoryRoot(true);
}
return root;
/*final SVNWCClient wcClient = myVcs.createWCClient();
try {
final SVNInfo info;
info = wcClient.doInfo(svnurl, myPeg, operationalFrom);
return info.getRepositoryRootURL();
}
catch (SVNException e) {
try {
final SVNInfo info;
info = wcClient.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.UNDEFINED);
return info.getRepositoryRootURL();
} catch (SVNException e1) {
final SVNInfo info;
info = wcClient.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD);
return info.getRepositoryRootURL();
}
}*/
SVNInfo info = myVcs.getInfo(svnurl, SVNRevision.HEAD);
return info != null ? info.getRepositoryRootURL() : null;
}
private boolean existsNow(SVNURL svnurl) {
final SVNWCClient wcClient = myVcs.createWCClient();
final SVNInfo info;
try {
info = wcClient.doInfo(svnurl, SVNRevision.HEAD, SVNRevision.HEAD);
info = myVcs.getInfo(svnurl, SVNRevision.HEAD, SVNRevision.HEAD, null);
}
catch (SVNException e) {
return false;
@@ -20,21 +20,19 @@ import com.intellij.openapi.vcs.history.*;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnRevisionNumber;
import org.jetbrains.idea.svn.SvnVcs;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNWCClient;
import java.io.File;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 4/27/12
* Time: 12:24 PM
* To change this template use File | Settings | File Templates.
*/
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 4/27/12
* Time: 12:24 PM
* To change this template use File | Settings | File Templates.
*/
public class SvnHistorySession extends VcsAbstractHistorySession {
private final SvnVcs myVcs;
private final FilePath myCommittedPath;
@@ -71,19 +69,8 @@ public class SvnHistorySession extends VcsAbstractHistorySession {
}
public static VcsRevisionNumber getCurrentCommittedRevision(final SvnVcs vcs, final File file) {
try {
SVNWCClient wcClient = vcs.createWCClient();
SVNInfo info = wcClient.doInfo(file, SVNRevision.UNDEFINED);
if (info != null) {
return new SvnRevisionNumber(info.getCommittedRevision());
}
else {
return null;
}
}
catch (SVNException e) {
return null;
}
SVNInfo info = vcs.getInfo(file);
return info != null ? new SvnRevisionNumber(info.getCommittedRevision()) : null;
}
public FilePath getCommittedPath() {
@@ -101,7 +88,8 @@ public class SvnHistorySession extends VcsAbstractHistorySession {
@Override
public VcsHistorySession copy() {
return new SvnHistorySession(myVcs, getRevisionList(), myCommittedPath, myHaveMergeSources, getCurrentRevisionNumber(), true, myHasLocalSource);
return new SvnHistorySession(myVcs, getRevisionList(), myCommittedPath, myHaveMergeSources, getCurrentRevisionNumber(), true,
myHasLocalSource);
}
@Override
@@ -0,0 +1,40 @@
package org.jetbrains.idea.svn.history;
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.tmatesoft.svn.core.ISVNLogEntryHandler;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNLogClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitHistoryClient extends BaseSvnClient implements HistoryClient {
@Override
public void doLog(@NotNull File path,
@NotNull SVNRevision startRevision,
@NotNull SVNRevision endRevision,
@Nullable SVNRevision pegRevision,
boolean stopOnCopy,
boolean discoverChangedPaths,
boolean includeMergedRevisions,
long limit,
@Nullable String[] revisionProperties,
@Nullable ISVNLogEntryHandler handler) throws VcsException {
try {
// TODO: a bug noticed when testing: we should pass "limit + 1" to get "limit" rows
SVNLogClient client = myVcs.createLogClient();
client.doLog(new File[]{path}, startRevision, endRevision, pegRevision, stopOnCopy, discoverChangedPaths, includeMergedRevisions,
limit, revisionProperties, handler);
}
catch (SVNException e) {
throw new VcsException(e);
}
}
}
@@ -38,13 +38,10 @@ import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnBundle;
import org.jetbrains.idea.svn.SvnRevisionNumber;
import org.jetbrains.idea.svn.SvnUtil;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.*;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -108,7 +105,7 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC
else {
loader.run();
}
final SVNException exception = loader.getException();
final Exception exception = loader.getException();
if (exception != null) {
throw new VcsException(exception);
}
@@ -148,7 +145,7 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC
private final String myPath;
private final long myRevision;
private final OutputStream myDst;
private SVNException myException;
private Exception myException;
public ContentLoader(String path, OutputStream dst, long revision) {
myPath = path;
@@ -156,7 +153,7 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC
myRevision = revision;
}
public SVNException getException() {
public Exception getException() {
return myException;
}
@@ -166,16 +163,16 @@ public class SvnRepositoryContentRevision implements ContentRevision, MarkerVcsC
progress.setText(SvnBundle.message("progress.text.loading.contents", myPath));
progress.setText2(SvnBundle.message("progress.text2.revision.information", myRevision));
}
try {
SVNRepository repository = myVcs.createRepository(getFullPath());
try {
repository.getFile("", myRevision, null, myDst);
}
finally {
repository.closeSession();
}
byte[] contents = SvnUtil.getFileContents(myVcs, SvnTarget.fromURL(SvnUtil.parseUrl(getFullPath())), SVNRevision.create(myRevision),
SVNRevision.UNDEFINED);
myDst.write(contents);
}
catch (SVNException e) {
catch (VcsException e) {
myException = e;
}
catch (IOException e) {
myException = e;
}
}
@@ -251,19 +251,10 @@ public class IntegratedSelectedOptionsDialog extends DialogWrapper {
@Nullable
private static SVNURL realTargetUrl(final SvnVcs vcs, final WorkingCopyInfo info, final String targetBranchUrl) {
final SVNWCClient client = vcs.createWCClient();
try {
final SVNInfo svnInfo = client.doInfo(new File(info.getLocalPath()), SVNRevision.UNDEFINED);
final SVNURL svnurl = svnInfo.getURL();
final SVNInfo svnInfo = vcs.getInfo(info.getLocalPath());
final SVNURL svnurl = svnInfo != null ? svnInfo.getURL() : null;
if ((svnurl != null) && (svnurl.toString().startsWith(targetBranchUrl))) {
return svnurl;
}
}
catch (SVNException e) {
// tracked by return value
}
return null;
return (svnurl != null) && (svnurl.toString().startsWith(targetBranchUrl)) ? svnurl : null;
}
@Nullable
@@ -238,12 +238,7 @@ public class BranchInfo {
}
private SVNInfo getInfo(final File pathFile) {
try {
return myClient.doInfo(pathFile, SVNRevision.UNDEFINED);
} catch (SVNException e) {
//
}
return null;
return myVcs.getInfo(pathFile);
}
private SvnMergeInfoCache.MergeCheckResult checkPathGoingUp(final long revisionAsked, final long targetRevision, final String branchRootPath,
@@ -117,6 +117,7 @@ public class PortableStatus extends SVNStatus {
return null;
}
};
// TODO: Update working copy format detection
setWorkingCopyFormat(WorkingCopyFormat.ONE_DOT_SEVEN.getFormat());
}
@@ -241,6 +242,30 @@ public class PortableStatus extends SVNStatus {
return url == null ? null : url.toString();
}
@Override
public SVNURL getURL() {
SVNURL url = super.getURL();
if (url == null) {
SVNInfo info = initInfo();
url = info != null ? info.getURL() : url;
}
return url;
}
@Override
public File getFile() {
File file = super.getFile();
if (file == null) {
SVNInfo info = initInfo();
file = info != null ? info.getFile() : file;
}
return file;
}
@Override
public SVNRevision getRevision() {
final SVNRevision revision = super.getRevision();
@@ -0,0 +1,65 @@
package org.jetbrains.idea.svn.properties;
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.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.SVNPropertyValue;
import org.tmatesoft.svn.core.wc.SVNInfo;
import org.tmatesoft.svn.core.wc.SVNPropertyData;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class CmdPropertyClient extends BaseSvnClient implements PropertyClient {
@Nullable
@Override
public SVNPropertyData getProperty(@NotNull File path,
@NotNull String property,
boolean revisionProperty,
@Nullable SVNRevision pegRevision,
@Nullable SVNRevision revision)
throws VcsException {
List<String> parameters = new ArrayList<String>();
parameters.add(property);
CommandUtil.put(parameters, path, pegRevision);
if (!revisionProperty) {
CommandUtil.put(parameters, revision);
} else {
parameters.add("--revprop");
CommandUtil.put(parameters, resolveRevisionNumber(path, revision));
}
SvnCommand command = CommandUtil.execute(myVcs, SvnCommandName.propget, parameters, null);
return new SVNPropertyData(property, SVNPropertyValue.create(StringUtil.nullize(command.getOutput())), null);
}
private SVNRevision resolveRevisionNumber(@NotNull File path, @Nullable SVNRevision revision) throws VcsException {
long result = revision != null ? revision.getNumber() : -1;
// base should be resolved manually - could not set revision to BASE to get revision property
if (SVNRevision.BASE.equals(revision)) {
SVNInfo info = myVcs.getInfo(path, SVNRevision.BASE);
result = info != null ? info.getRevision().getNumber() : -1;
}
if (result == -1) {
throw new VcsException("Could not determine revision number for file " + path + " and revision " + revision);
}
return SVNRevision.create(result);
}
}
@@ -0,0 +1,23 @@
package org.jetbrains.idea.svn.properties;
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.SVNPropertyData;
import org.tmatesoft.svn.core.wc.SVNRevision;
import java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public interface PropertyClient extends SvnClient {
@Nullable
SVNPropertyData getProperty(@NotNull final File path,
@NotNull final String property,
boolean revisionProperty,
@Nullable SVNRevision pegRevision,
@Nullable SVNRevision revision) throws VcsException;
}
@@ -0,0 +1,68 @@
package org.jetbrains.idea.svn.properties;
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.tmatesoft.svn.core.SVNException;
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 java.io.File;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClient {
@Nullable
@Override
public SVNPropertyData getProperty(@NotNull File path,
@NotNull String property,
boolean revisionProperty,
@Nullable SVNRevision pegRevision,
@Nullable SVNRevision revision) throws VcsException {
try {
if (!revisionProperty) {
return myVcs.createWCClient().doGetProperty(path, property, pegRevision, revision);
} else {
return getRevisionProperty(path, property, revision);
}
}
catch (SVNException e) {
throw new VcsException(e);
}
}
private SVNPropertyData getRevisionProperty(@NotNull File path, @NotNull final String property, @Nullable SVNRevision revision) throws SVNException{
final SVNWCClient client = myVcs.createWCClient();
final SVNPropertyData[] result = new SVNPropertyData[1];
client.doGetRevisionProperty(path, null, revision, new ISVNPropertyHandler() {
@Override
public void handleProperty(File path, SVNPropertyData property) throws SVNException {
handle(property);
}
@Override
public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException {
handle(property);
}
@Override
public void handleProperty(long revision, SVNPropertyData property) throws SVNException {
handle(property);
}
private void handle(@NotNull SVNPropertyData data) {
if (property.equals(data.getName())) {
result[0] = data;
}
}
});
return result[0];
}
}
@@ -1,25 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.properties;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 2/12/12
* Time: 8:40 PM
*/
public class SvnPropDetailsProvider {
}

Some files were not shown because too many files have changed in this diff Show More