blob: 5ce16c9ea1fb986e040c85068a990028176ca066 [file] [log] [blame]
/*
* Copyright 2000-2009 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 git4idea;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.Throwable2Computable;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ContentRevision;
import com.intellij.openapi.vcs.changes.CurrentContentRevision;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsFileUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.util.GitFileUtils;
import git4idea.history.wholeTree.GitBinaryMultipleContentsRevision;
import git4idea.history.wholeTree.GitMultipleContentsRevision;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
/**
* Git content revision
*/
public class GitContentRevision implements ContentRevision {
/**
* the file path
*/
@NotNull protected final FilePath myFile;
/**
* the revision number
*/
@NotNull protected final GitRevisionNumber myRevision;
/**
* the context project
*/
@NotNull protected final Project myProject;
/**
* The charset for the file
*/
@Nullable private Charset myCharset;
protected GitContentRevision(@NotNull FilePath file, @NotNull GitRevisionNumber revision, @NotNull Project project,
@Nullable Charset charset) {
myProject = project;
myFile = file;
myRevision = revision;
myCharset = charset;
}
@Nullable
public String getContent() throws VcsException {
if (myFile.isDirectory()) {
return null;
}
try {
return ContentRevisionCache
.getOrLoadAsString(myProject, myFile, myRevision, GitVcs.getKey(), ContentRevisionCache.UniqueType.REPOSITORY_CONTENT,
new Throwable2Computable<byte[], VcsException, IOException>() {
@Override
public byte[] compute() throws VcsException, IOException {
return loadContent();
}
}, myCharset);
}
catch (IOException e) {
throw new VcsException(e);
}
}
private byte[] loadContent() throws VcsException {
VirtualFile root = GitUtil.getGitRoot(myFile);
return GitFileUtils.getFileContent(myProject, root, myRevision.getRev(), VcsFileUtil.relativePath(root, myFile));
}
@NotNull
public FilePath getFile() {
return myFile;
}
@NotNull
public VcsRevisionNumber getRevisionNumber() {
return myRevision;
}
public boolean equals(Object obj) {
if (this == obj) return true;
if ((obj == null) || (obj.getClass() != getClass())) return false;
GitContentRevision test = (GitContentRevision)obj;
return (myFile.equals(test.myFile) && myRevision.equals(test.myRevision));
}
public int hashCode() {
return myFile.hashCode() + myRevision.hashCode();
}
public static ContentRevision createMultipleParentsRevision(@NotNull Project project, @NotNull final FilePath file,
@NotNull GitRevisionNumber currentRevision,
@NotNull final List<GitRevisionNumber> parentRevisions) throws VcsException {
final GitContentRevision contentRevision = createRevisionImpl(file, currentRevision, project, null);
if (parentRevisions.size() == 1) {
return contentRevision;
} else {
if (contentRevision instanceof GitBinaryContentRevision) {
return new GitBinaryMultipleContentsRevision(file, parentRevisions, (GitBinaryContentRevision) contentRevision);
} else {
return new GitMultipleContentsRevision(file, parentRevisions, contentRevision);
}
}
}
/**
* Create revision
*
*
* @param vcsRoot a vcs root for the repository
* @param path an path inside with possibly escape sequences
* @param revisionNumber a revision number, if null the current revision will be created
* @param project the context project
* @param isDeleted if true, the file is deleted
* @param unescapePath
* @return a created revision
* @throws com.intellij.openapi.vcs.VcsException
* if there is a problem with creating revision
*/
public static ContentRevision createRevision(VirtualFile vcsRoot,
String path,
@Nullable VcsRevisionNumber revisionNumber,
Project project,
boolean isDeleted, final boolean canBeDeleted, boolean unescapePath) throws VcsException {
final FilePath file;
if (project.isDisposed()) {
file = new FilePathImpl(new File(makeAbsolutePath(vcsRoot, path, unescapePath)), false);
} else {
file = createPath(vcsRoot, path, isDeleted, canBeDeleted, unescapePath);
}
return createRevision(file, revisionNumber, project);
}
private static ContentRevision createRevision(@NotNull FilePath filePath, @Nullable VcsRevisionNumber revisionNumber, @NotNull Project project) {
if (revisionNumber != null && revisionNumber != VcsRevisionNumber.NULL) {
return createRevisionImpl(filePath, (GitRevisionNumber)revisionNumber, project, null);
}
else {
return CurrentContentRevision.create(filePath);
}
}
public static ContentRevision createRevisionForTypeChange(@NotNull Project project, @NotNull VirtualFile vcsRoot,
@NotNull String path, @Nullable VcsRevisionNumber revisionNumber,
boolean unescapePath) throws VcsException {
final FilePath filePath;
if (revisionNumber == null) {
File file = new File(makeAbsolutePath(vcsRoot, path, unescapePath));
VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
filePath = virtualFile == null ? new FilePathImpl(file, false) : new FilePathImpl(virtualFile);
} else {
filePath = createPath(vcsRoot, path, false, false, unescapePath);
}
return createRevision(filePath, revisionNumber, project);
}
public static FilePath createPath(@NotNull VirtualFile vcsRoot, @NotNull String path,
boolean isDeleted, boolean canBeDeleted, boolean unescapePath) throws VcsException {
final String absolutePath = makeAbsolutePath(vcsRoot, path, unescapePath);
FilePath file = isDeleted ? VcsUtil.getFilePathForDeletedFile(absolutePath, false) : VcsUtil.getFilePath(absolutePath, false);
if (canBeDeleted && (! SystemInfo.isFileSystemCaseSensitive) && VcsUtil.caseDiffers(file.getPath(), absolutePath)) {
// as for deleted file
file = FilePathImpl.createForDeletedFile(new File(absolutePath), false);
}
return file;
}
private static String makeAbsolutePath(@NotNull VirtualFile vcsRoot, @NotNull String path, boolean unescapePath) throws VcsException {
final String unescapedPath = unescapePath ? GitUtil.unescapePath(path) : path;
return vcsRoot.getPath() + "/" + unescapedPath;
}
public static ContentRevision createRevision(@NotNull final VirtualFile file, @Nullable final VcsRevisionNumber revisionNumber,
@NotNull final Project project) throws VcsException {
return createRevision(file, revisionNumber, project, null);
}
public static ContentRevision createRevision(@NotNull final VirtualFile file, @Nullable final VcsRevisionNumber revisionNumber,
@NotNull final Project project, @Nullable final Charset charset) throws VcsException {
final FilePathImpl filePath = new FilePathImpl(file);
return createRevision(filePath, revisionNumber, project, charset);
}
public static ContentRevision createRevision(@NotNull final FilePath filePath, @Nullable final VcsRevisionNumber revisionNumber,
@NotNull final Project project, @Nullable final Charset charset) {
if (revisionNumber != null && revisionNumber != VcsRevisionNumber.NULL) {
return createRevisionImpl(filePath, (GitRevisionNumber)revisionNumber, project, charset);
}
else {
return CurrentContentRevision.create(filePath);
}
}
private static GitContentRevision createRevisionImpl(@NotNull FilePath path, @NotNull GitRevisionNumber revisionNumber,
@NotNull Project project, @Nullable final Charset charset) {
if (path.getFileType().isBinary()) {
return new GitBinaryContentRevision(path, revisionNumber, project);
} else {
return new GitContentRevision(path, revisionNumber, project, charset);
}
}
@Override
public String toString() {
return myFile.getPath();
}
}