summaryrefslogtreecommitdiff
path: root/platform/vcs-api/vcs-api-core
diff options
context:
space:
mode:
Diffstat (limited to 'platform/vcs-api/vcs-api-core')
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java93
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/FilePath.java108
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsException.java91
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsKey.java50
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java282
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/ContentRevision.java54
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/MergeTexts.java46
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/LongRevisionNumber.java26
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/VcsRevisionNumber.java129
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/impl/VcsPathPresenter.java42
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java34
-rw-r--r--platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/VcsFilePathUtil.java32
-rw-r--r--platform/vcs-api/vcs-api-core/vcs-api-core.iml15
13 files changed, 1002 insertions, 0 deletions
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java b/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java
new file mode 100644
index 000000000000..3b6a7ff2a5c6
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/lifecycle/PeriodicalTasksCloser.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lifecycle;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ApplicationComponent;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.project.Project;
+import com.intellij.vcsUtil.Rethrow;
+import org.jetbrains.annotations.NotNull;
+
+public class PeriodicalTasksCloser implements ApplicationComponent {
+ private static final Logger LOG = Logger.getInstance("#com.intellij.lifecycle.PeriodicalTasksCloser");
+ private final Object myLock = new Object();
+
+ public static PeriodicalTasksCloser getInstance() {
+ return ApplicationManager.getApplication().getComponent(PeriodicalTasksCloser.class);
+ }
+
+ @Override
+ public void disposeComponent() {
+ }
+
+ @NotNull
+ @Override
+ public String getComponentName() {
+ return PeriodicalTasksCloser.class.getName();
+ }
+
+ @Override
+ public void initComponent() {
+ }
+
+ public <T> T safeGetComponent(@NotNull final Project project, final Class<T> componentClass) throws ProcessCanceledException {
+ T component = null;
+ try {
+ component = project.getComponent(componentClass);
+ }
+ catch (NullPointerException e) {
+ throwCanceledException(project, e);
+ } catch (AssertionError e) {
+ throwCanceledException(project, e);
+ }
+ if (component == null) {
+ if (project.isDefault()) {
+ LOG.info("no component in default project: " + componentClass.getName());
+ }
+ throwCanceledException(project, new NullPointerException());
+ }
+ return component;
+ }
+
+ public <T> T safeGetService(@NotNull final Project project, final Class<T> componentClass) throws ProcessCanceledException {
+ try {
+ T service = ServiceManager.getService(project, componentClass);
+ if (service == null && project.isDefault()) {
+ LOG.info("no service in default project: " + componentClass.getName());
+ }
+ return service;
+ }
+ catch (NullPointerException e) {
+ throwCanceledException(project, e);
+ } catch (AssertionError e) {
+ throwCanceledException(project, e);
+ }
+ return null;
+ }
+
+ private void throwCanceledException(final Project project, final Throwable t) {
+ synchronized (myLock) {
+ // allow NPE & assertion _catch_ only if project is closed and being disposed
+ if (project.isOpen()) {
+ Rethrow.reThrowRuntime(t);
+ }
+ }
+ throw new ProcessCanceledException();
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/FilePath.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/FilePath.java
new file mode 100644
index 000000000000..1ca489c0d128
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/FilePath.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+/**
+ * Represents a path to a (possibly non-existing) file on disk or in a VCS repository.
+ */
+public interface FilePath {
+ /**
+ * @return a virtual file that corresponds to this path, or null if the virtual file is no more valid.
+ */
+ @Nullable
+ VirtualFile getVirtualFile();
+
+ /**
+ * @return the virtual file that corresponds to the parent file path, or null if the virtual file is no more valid.
+ */
+ @Nullable
+ VirtualFile getVirtualFileParent();
+
+ /**
+ * @return the {@link java.io.File} that corresponds to the path. The path might be non-existent or not local.
+ * @see #isNonLocal()
+ */
+ @NotNull
+ File getIOFile();
+
+ /**
+ * @return the file name (without directory component)
+ */
+ @NotNull
+ String getName();
+
+ String getPresentableUrl();
+
+ @Nullable
+ Document getDocument();
+
+ Charset getCharset();
+
+ /**
+ * Get character set, considering the project defaults and a virtual file
+ *
+ * @param project the project which settings will be consulted
+ * @return the character set of the file
+ */
+ Charset getCharset(Project project);
+
+ /**
+ * @return the type of the file
+ */
+ FileType getFileType();
+
+ void refresh();
+
+ void hardRefresh();
+
+ @NotNull
+ String getPath();
+
+ /**
+ * @return true if the path represents the directory
+ */
+ boolean isDirectory();
+
+ /**
+ * Check if the provided file is an ancestor of the current file.
+ *
+ * @param parent a possible parent
+ * @param strict if false, the method also returns true if files are equal
+ * @return true if {@code this} file is ancestor of the {@code parent}.
+ */
+ boolean isUnder(@NotNull FilePath parent, boolean strict);
+
+ /**
+ * @return the parent path or null if there are no parent
+ */
+ @Nullable
+ FilePath getParentPath();
+
+ /**
+ * @return true if the path does not represents a file in the local file system
+ */
+ boolean isNonLocal();
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsException.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsException.java
new file mode 100644
index 000000000000..dacf4e654f5f
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs;
+
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ArrayUtil;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class VcsException extends Exception {
+ public static final VcsException[] EMPTY_ARRAY = new VcsException[0];
+
+ private VirtualFile myVirtualFile;
+ private Collection<String> myMessages;
+ private boolean isWarning = false;
+
+ public VcsException(String message) {
+ super(message);
+ initMessage(message);
+ }
+
+ private void initMessage(final String message) {
+ String shownMessage = message == null ? VcsBundle.message("exception.text.unknown.error") : message;
+ myMessages = Collections.singleton(shownMessage);
+ }
+
+ public VcsException(Throwable throwable, final boolean isWarning) {
+ this(throwable.getMessage() != null ? throwable.getMessage() : throwable.getLocalizedMessage(), throwable);
+ this.isWarning = isWarning;
+ }
+
+ public VcsException(Throwable throwable) {
+ this(throwable, false);
+ }
+
+ public VcsException(final String message, final Throwable cause) {
+ super(message, cause);
+ initMessage(message);
+ }
+
+ public VcsException(final String message, final boolean isWarning) {
+ this(message);
+ this.isWarning = isWarning;
+ }
+
+ public VcsException(Collection<String> messages) {
+ myMessages = messages;
+ }
+
+ //todo: should be in constructor?
+ public void setVirtualFile(VirtualFile virtualFile) {
+ myVirtualFile = virtualFile;
+ }
+
+ public VirtualFile getVirtualFile() {
+ return myVirtualFile;
+ }
+
+ public String[] getMessages() {
+ return ArrayUtil.toStringArray(myMessages);
+ }
+
+ public VcsException setIsWarning(boolean warning) {
+ isWarning = warning;
+ return this;
+ }
+
+ public boolean isWarning() {
+ return isWarning;
+ }
+
+ @Override
+ public String getMessage() {
+ return StringUtil.join(myMessages, ", ");
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsKey.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsKey.java
new file mode 100644
index 000000000000..4e2871b3f539
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/VcsKey.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs;
+
+import org.jetbrains.annotations.NotNull;
+
+public final class VcsKey {
+ @NotNull
+ private final String myName;
+
+ // to forbid creation outside AbstractVcs
+ VcsKey(@NotNull final String name) {
+ myName = name;
+ }
+
+ @NotNull
+ public String getName() {
+ return myName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ VcsKey vcsKey = (VcsKey)o;
+
+ if (!myName.equals(vcsKey.myName)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return myName.hashCode();
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java
new file mode 100644
index 000000000000..b1d8978eea68
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/Change.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intellij.openapi.vcs.changes;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Getter;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.FileStatus;
+import com.intellij.openapi.vcs.VcsBundle;
+import com.intellij.openapi.vcs.impl.VcsPathPresenter;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.vcsUtil.VcsFilePathUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author max
+ */
+public class Change {
+ private int myHash;
+
+ public enum Type {
+ MODIFICATION,
+ NEW,
+ DELETED,
+ MOVED
+ }
+
+ private final ContentRevision myBeforeRevision;
+ private final ContentRevision myAfterRevision;
+ private final FileStatus myFileStatus;
+ protected String myMoveRelativePath;
+ protected boolean myRenamed;
+ protected boolean myMoved;
+ protected boolean myRenameOrMoveCached = false;
+ private boolean myIsReplaced;
+ private Type myType;
+ private final Map<String, Change> myOtherLayers;
+ // if null, vcs's is used. intended: for property conflict case
+ private Getter<MergeTexts> myMergeProvider;
+
+ public Change(@Nullable final ContentRevision beforeRevision, @Nullable final ContentRevision afterRevision) {
+ this(beforeRevision, afterRevision, convertStatus(beforeRevision, afterRevision));
+ }
+
+ public Change(@Nullable final ContentRevision beforeRevision, @Nullable final ContentRevision afterRevision, @Nullable FileStatus fileStatus) {
+ assert beforeRevision != null || afterRevision != null;
+ myBeforeRevision = beforeRevision;
+ myAfterRevision = afterRevision;
+ myFileStatus = fileStatus == null ? convertStatus(beforeRevision, afterRevision) : fileStatus;
+ myHash = -1;
+ myOtherLayers = new HashMap<String, Change>(0);
+ }
+
+ private static FileStatus convertStatus(@Nullable ContentRevision beforeRevision, @Nullable ContentRevision afterRevision) {
+ if (beforeRevision == null) return FileStatus.ADDED;
+ if (afterRevision == null) return FileStatus.DELETED;
+ return FileStatus.MODIFIED;
+ }
+
+ public Getter<MergeTexts> getMergeProvider() {
+ return myMergeProvider;
+ }
+
+ public void setMergeProvider(Getter<MergeTexts> mergeProvider) {
+ myMergeProvider = mergeProvider;
+ }
+
+ public void addAdditionalLayerElement(final String name, final Change change) {
+ myOtherLayers.put(name, change);
+ }
+
+ public Map<String, Change> getOtherLayers() {
+ return myOtherLayers;
+ }
+
+ public boolean isTreeConflict() {
+ return false;
+ }
+
+ public boolean isPhantom() {
+ return false;
+ }
+
+ public boolean hasOtherLayers() {
+ return ! myOtherLayers.isEmpty();
+ }
+
+ public Type getType() {
+ if (myType == null) {
+ if (myBeforeRevision == null) {
+ myType = Type.NEW;
+ return myType;
+ }
+
+ if (myAfterRevision == null) {
+ myType = Type.DELETED;
+ return myType;
+ }
+
+ if ((! Comparing.equal(myBeforeRevision.getFile(), myAfterRevision.getFile())) ||
+ ((! SystemInfo.isFileSystemCaseSensitive) && VcsFilePathUtil
+ .caseDiffers(myBeforeRevision.getFile().getPath(), myAfterRevision.getFile().getPath()))) {
+ myType = Type.MOVED;
+ return myType;
+ }
+
+ myType = Type.MODIFICATION;
+ }
+ return myType;
+ }
+
+ @Nullable
+ public ContentRevision getBeforeRevision() {
+ return myBeforeRevision;
+ }
+
+ @Nullable
+ public ContentRevision getAfterRevision() {
+ return myAfterRevision;
+ }
+
+ public FileStatus getFileStatus() {
+ return myFileStatus;
+ }
+
+ @Nullable
+ public VirtualFile getVirtualFile() {
+ return myAfterRevision == null ? null : myAfterRevision.getFile().getVirtualFile();
+ }
+
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || (! (o instanceof Change))) return false;
+ final Change otherChange = ((Change)o);
+
+ final ContentRevision br1 = getBeforeRevision();
+ final ContentRevision br2 = otherChange.getBeforeRevision();
+ final ContentRevision ar1 = getAfterRevision();
+ final ContentRevision ar2 = otherChange.getAfterRevision();
+
+ FilePath fbr1 = br1 != null ? br1.getFile() : null;
+ FilePath fbr2 = br2 != null ? br2.getFile() : null;
+
+ FilePath far1 = ar1 != null ? ar1.getFile() : null;
+ FilePath far2 = ar2 != null ? ar2.getFile() : null;
+
+ return Comparing.equal(fbr1, fbr2) && Comparing.equal(far1, far2);
+ }
+
+ public int hashCode() {
+ if (myHash == -1) {
+ myHash = calculateHash();
+ }
+ return myHash;
+ }
+
+ private int calculateHash() {
+ return revisionHashCode(getBeforeRevision()) * 27 + revisionHashCode(getAfterRevision());
+ }
+
+ private static int revisionHashCode(ContentRevision rev) {
+ if (rev == null) return 0;
+ return rev.getFile().getIOFile().getPath().hashCode();
+ }
+
+ public boolean affectsFile(File ioFile) {
+ if (myBeforeRevision != null && myBeforeRevision.getFile().getIOFile().equals(ioFile)) return true;
+ if (myAfterRevision != null && myAfterRevision.getFile().getIOFile().equals(ioFile)) return true;
+ return false;
+ }
+
+ public boolean isRenamed() {
+ cacheRenameOrMove(null);
+ return myRenamed;
+ }
+
+ public boolean isMoved() {
+ cacheRenameOrMove(null);
+ return myMoved;
+ }
+
+ public String getMoveRelativePath(Project project) {
+ cacheRenameOrMove(project);
+ return myMoveRelativePath;
+ }
+
+ private void cacheRenameOrMove(final Project project) {
+ if (myBeforeRevision != null && myAfterRevision != null && (! revisionPathsSame())) {
+ if (!myRenameOrMoveCached) {
+ myRenameOrMoveCached = true;
+ if (Comparing.equal(myBeforeRevision.getFile().getParentPath(), myAfterRevision.getFile().getParentPath())) {
+ myRenamed = true;
+ }
+ else {
+ myMoved = true;
+ }
+ }
+ if (myMoved && myMoveRelativePath == null && project != null) {
+ myMoveRelativePath = VcsPathPresenter.getInstance(project).getPresentableRelativePath(myBeforeRevision, myAfterRevision);
+ }
+ }
+ }
+
+ private boolean revisionPathsSame() {
+ final String path1 = myBeforeRevision.getFile().getIOFile().getAbsolutePath();
+ final String path2 = myAfterRevision.getFile().getIOFile().getAbsolutePath();
+ return path1.equals(path2);
+ }
+
+ @NonNls
+ public String toString() {
+ final Type type = getType();
+ //noinspection EnumSwitchStatementWhichMissesCases
+ switch (type) {
+ case NEW: return "A: " + myAfterRevision;
+ case DELETED: return "D: " + myBeforeRevision;
+ case MOVED: return "M: " + myBeforeRevision + " -> " + myAfterRevision;
+ default: return "M: " + myAfterRevision;
+ }
+ }
+
+ @Nullable
+ public String getOriginText(final Project project) {
+ cacheRenameOrMove(project);
+ if (isMoved()) {
+ return getMovedText(project);
+ } else if (isRenamed()) {
+ return getRenamedText();
+ }
+ return myIsReplaced ? VcsBundle.message("change.file.replaced.text") : null;
+ }
+
+ @Nullable
+ protected String getRenamedText() {
+ return VcsBundle.message("change.file.renamed.from.text", myBeforeRevision.getFile().getName());
+ }
+
+ @Nullable
+ protected String getMovedText(final Project project) {
+ return VcsBundle.message("change.file.moved.from.text", getMoveRelativePath(project));
+ }
+
+ public boolean isIsReplaced() {
+ return myIsReplaced;
+ }
+
+ public void setIsReplaced(final boolean isReplaced) {
+ myIsReplaced = isReplaced;
+ }
+
+ @Nullable
+ public Icon getAdditionalIcon() {
+ return null;
+ }
+
+ @Nullable
+ public String getDescription() {
+ return null;
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/ContentRevision.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/ContentRevision.java
new file mode 100644
index 000000000000..de5944ac9b3c
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/ContentRevision.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intellij.openapi.vcs.changes;
+
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author max
+ */
+public interface ContentRevision {
+ /**
+ * Content of the revision. Implementers are encouraged to lazy implement this especially when it requires connection to the
+ * version control server or something.
+ * Might return null in case if file path denotes a directory or content is impossible to retreive.
+ *
+ * @return content of the revision
+ * @throws com.intellij.openapi.vcs.VcsException in case when content retrieval fails
+ */
+ @Nullable
+ String getContent() throws VcsException;
+
+ /**
+ * @return file path of the revision
+ */
+ @NotNull
+ FilePath getFile();
+
+ /**
+ * Revision ID. Content revisions with same file path and revision number are considered to be equal and must have same content unless
+ * {@link VcsRevisionNumber#NULL} is returned. Use {@link VcsRevisionNumber#NULL} when revision number is not applicable like for
+ * the currently uncommited revision.
+ * @return revision ID in terms of version control
+ */
+ @NotNull
+ VcsRevisionNumber getRevisionNumber();
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/MergeTexts.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/MergeTexts.java
new file mode 100644
index 000000000000..16ed06a00b41
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/changes/MergeTexts.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.changes;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Irina.Chernushina
+ * Date: 2/14/12
+ * Time: 4:31 PM
+ */
+public class MergeTexts {
+ private final String myLeft;
+ private final String myRight;
+ private final String myBase;
+
+ public MergeTexts(String left, String right, String base) {
+ myLeft = left;
+ myRight = right;
+ myBase = base;
+ }
+
+ public String getLeft() {
+ return myLeft;
+ }
+
+ public String getRight() {
+ return myRight;
+ }
+
+ public String getBase() {
+ return myBase;
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/LongRevisionNumber.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/LongRevisionNumber.java
new file mode 100644
index 000000000000..52bae307b01e
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/LongRevisionNumber.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.history;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Irina.Chernushina
+ * Date: 10/12/12
+ * Time: 12:06 PM
+ */
+public interface LongRevisionNumber {
+ long getLongRevisionNumber();
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/VcsRevisionNumber.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/VcsRevisionNumber.java
new file mode 100644
index 000000000000..9d5851da6889
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/history/VcsRevisionNumber.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.history;
+
+public interface VcsRevisionNumber extends Comparable<VcsRevisionNumber>{
+ VcsRevisionNumber NULL = new VcsRevisionNumber() {
+ @Override public String asString() {
+ return "";
+ }
+
+ @Override public int compareTo(VcsRevisionNumber vcsRevisionNumber) {
+ return 0;
+ }
+
+ @Override public String toString() {
+ return "NULL";
+ }
+ };
+
+ class Int implements VcsRevisionNumber, LongRevisionNumber {
+ private final int myValue;
+
+ public Int(int value) {
+ myValue = value;
+ }
+
+ @Override
+ public long getLongRevisionNumber() {
+ return myValue;
+ }
+
+ public String asString() {
+ return String.valueOf(myValue);
+ }
+
+ public int compareTo(VcsRevisionNumber vcsRevisionNumber) {
+ if (vcsRevisionNumber instanceof VcsRevisionNumber.Int){
+ return myValue - ((Int)vcsRevisionNumber).myValue;
+ }
+ return 0;
+ }
+
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final Int anInt = (Int)o;
+
+ if (myValue != anInt.myValue) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return myValue;
+ }
+
+ public int getValue() {
+ return myValue;
+ }
+
+ @Override
+ public String toString() {
+ return asString();
+ }
+ }
+
+ class Long implements VcsRevisionNumber, LongRevisionNumber {
+ private final long myValue;
+
+ public Long(long value) {
+ myValue = value;
+ }
+
+ @Override
+ public long getLongRevisionNumber() {
+ return myValue;
+ }
+
+ public String asString() {
+ return String.valueOf(myValue);
+ }
+
+ public int compareTo(VcsRevisionNumber vcsRevisionNumber) {
+ if (vcsRevisionNumber instanceof VcsRevisionNumber.Long){
+ return java.lang.Long.signum(myValue - ((Long)vcsRevisionNumber).myValue);
+ }
+ return 0;
+ }
+
+ public long getLongValue() {
+ return myValue;
+ }
+
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final Long aLong = (Long)o;
+
+ if (myValue != aLong.myValue) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (int)(myValue ^ (myValue >>> 32));
+ }
+
+ public String toString() {
+ return asString();
+ }
+ }
+
+ String asString();
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/impl/VcsPathPresenter.java b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/impl/VcsPathPresenter.java
new file mode 100644
index 000000000000..9985cf77518f
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/openapi/vcs/impl/VcsPathPresenter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.impl;
+
+import com.intellij.lifecycle.PeriodicalTasksCloser;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.changes.ContentRevision;
+import com.intellij.openapi.vfs.VirtualFile;
+
+/**
+ * @author yole
+ */
+public abstract class VcsPathPresenter {
+ public static VcsPathPresenter getInstance(Project project) {
+ return PeriodicalTasksCloser.getInstance().safeGetService(project, VcsPathPresenter.class);
+ }
+
+ /**
+ * Returns the user-visible relative path from the content root under which the
+ * specified file is located to the file itself, prefixed by the module name in
+ * angle brackets.
+ *
+ * @param file the file for which the path is requested.
+ * @return the relative path.
+ */
+ public abstract String getPresentableRelativePathFor(VirtualFile file);
+
+ public abstract String getPresentableRelativePath(ContentRevision fromRevision, ContentRevision toRevision);
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java b/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java
new file mode 100644
index 000000000000..6c42caaa3126
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/Rethrow.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.vcsUtil;
+
+/**
+ * @author irengrig
+ */
+public class Rethrow {
+ private Rethrow() {
+ }
+
+ public static void reThrowRuntime(final Throwable t) {
+ if (t instanceof Error) {
+ throw (Error) t;
+ }
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
+ }
+ throw new RuntimeException(t);
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/VcsFilePathUtil.java b/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/VcsFilePathUtil.java
new file mode 100644
index 000000000000..b6992f53ab0c
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/src/com/intellij/vcsUtil/VcsFilePathUtil.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.vcsUtil;
+
+import java.io.File;
+
+public class VcsFilePathUtil {
+ public static boolean caseDiffers(final String s1, final String s2) {
+ String s1Trimmed = s1.trim();
+ String s2Trimmed = s2.trim();
+
+ if (File.separatorChar != '/') {
+ s1Trimmed = s1Trimmed.replace(File.separatorChar, '/');
+ s2Trimmed = s2Trimmed.replace(File.separatorChar, '/');
+ }
+
+ return (! s1Trimmed.equals(s2Trimmed)) && s1Trimmed.equalsIgnoreCase(s2Trimmed);
+ }
+}
diff --git a/platform/vcs-api/vcs-api-core/vcs-api-core.iml b/platform/vcs-api/vcs-api-core/vcs-api-core.iml
new file mode 100644
index 000000000000..434160533f3b
--- /dev/null
+++ b/platform/vcs-api/vcs-api-core/vcs-api-core.iml
@@ -0,0 +1,15 @@
+<?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="annotations" />
+ <orderEntry type="module" module-name="core-api" />
+ <orderEntry type="module" module-name="editor-ui-api" />
+ </component>
+</module>
+