blob: dc9ab5ac99d2e225d79ab983090177ff54073ede [file] [log] [blame]
/*
* Copyright 2000-2010 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.diff.impl.patch.apply;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diff.impl.patch.ApplyPatchContext;
import com.intellij.openapi.diff.impl.patch.FilePatch;
import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.changes.CommitContext;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
public abstract class ApplyFilePatchBase<T extends FilePatch> implements ApplyFilePatch {
private final static Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.patch.apply.ApplyFilePatchBase");
protected final T myPatch;
public ApplyFilePatchBase(T patch) {
myPatch = patch;
}
public T getPatch() {
return myPatch;
}
private FilePath getTarget(final VirtualFile file) {
if (myPatch.isNewFile()) {
return new FilePathImpl(file, myPatch.getBeforeFileName(), false);
}
return new FilePathImpl(file);
}
public Result apply(final VirtualFile fileToPatch,
final ApplyPatchContext context,
final Project project,
FilePath pathBeforeRename,
Getter<CharSequence> baseContents, CommitContext commitContext) throws IOException {
if (LOG.isDebugEnabled()) {
LOG.debug("apply patch called for : " + fileToPatch.getPath());
}
context.addAffectedFile(getTarget(fileToPatch));
if (myPatch.isNewFile()) {
applyCreate(fileToPatch, commitContext);
} else if (myPatch.isDeletedFile()) {
FileEditorManagerImpl.getInstance(project).closeFile(fileToPatch);
fileToPatch.delete(this);
}
else {
return applyChange(project, fileToPatch, pathBeforeRename, baseContents);
}
return SUCCESS;
}
protected abstract void applyCreate(VirtualFile newFile, CommitContext commitContext) throws IOException;
protected abstract Result applyChange(Project project, VirtualFile fileToPatch, FilePath pathBeforeRename, Getter<CharSequence> baseContents) throws IOException;
@Nullable
public static VirtualFile findPatchTarget(final ApplyPatchContext context, final String beforeName, final String afterName,
final boolean isNewFile) throws IOException {
VirtualFile file = null;
if (beforeName != null) {
file = findFileToPatchByName(context, beforeName, isNewFile);
}
if (file == null) {
file = findFileToPatchByName(context, afterName, isNewFile);
}
else if (context.isAllowRename() && afterName != null && !beforeName.equals(afterName)) {
String[] beforeNameComponents = beforeName.split("/");
String[] afterNameComponents = afterName.split("/");
if (!beforeNameComponents [beforeNameComponents.length-1].equals(afterNameComponents [afterNameComponents.length-1])) {
context.registerBeforeRename(file);
file.rename(FilePatch.class, afterNameComponents [afterNameComponents.length-1]);
context.addAffectedFile(file);
}
boolean needMove = (beforeNameComponents.length != afterNameComponents.length);
if (!needMove) {
needMove = checkPackageRename(context, beforeNameComponents, afterNameComponents);
}
if (needMove) {
VirtualFile moveTarget = findFileToPatchByComponents(context, afterNameComponents, afterNameComponents.length-1);
if (moveTarget == null) {
return null;
}
context.registerBeforeRename(file);
file.move(FilePatch.class, moveTarget);
context.addAffectedFile(file);
}
}
return file;
}
private static boolean checkPackageRename(final ApplyPatchContext context,
final String[] beforeNameComponents,
final String[] afterNameComponents) {
int changedIndex = -1;
for(int i=context.getSkipTopDirs(); i<afterNameComponents.length-1; i++) {
if (!beforeNameComponents [i].equals(afterNameComponents [i])) {
if (changedIndex != -1) {
return true;
}
changedIndex = i;
}
}
if (changedIndex == -1) return false;
VirtualFile oldDir = findFileToPatchByComponents(context, beforeNameComponents, changedIndex+1);
VirtualFile newDir = findFileToPatchByComponents(context.getPrepareContext(), afterNameComponents, changedIndex+1);
if (oldDir != null && newDir == null) {
context.addPendingRename(oldDir, afterNameComponents [changedIndex]);
return false;
}
return true;
}
@Nullable
private static VirtualFile findFileToPatchByName(@NotNull ApplyPatchContext context, final String fileName,
boolean isNewFile) {
String[] pathNameComponents = fileName.split("/");
int lastComponentToFind = isNewFile ? pathNameComponents.length-1 : pathNameComponents.length;
return findFileToPatchByComponents(context, pathNameComponents, lastComponentToFind);
}
@Nullable
private static VirtualFile findFileToPatchByComponents(ApplyPatchContext context,
final String[] pathNameComponents,
final int lastComponentToFind) {
VirtualFile patchedDir = context.getBaseDir();
for(int i=context.getSkipTopDirs(); i<lastComponentToFind; i++) {
VirtualFile nextChild;
if (pathNameComponents [i].equals("..")) {
nextChild = patchedDir.getParent();
}
else {
nextChild = patchedDir.findChild(pathNameComponents [i]);
}
if (nextChild == null) {
if (context.isCreateDirectories()) {
try {
nextChild = patchedDir.createChildDirectory(null, pathNameComponents [i]);
}
catch (IOException e) {
return null;
}
}
else {
context.registerMissingDirectory(patchedDir, pathNameComponents, i);
return null;
}
}
patchedDir = nextChild;
}
return patchedDir;
}
/*@Nullable
public static ApplyPatchStatus applyModifications(final TextFilePatch patch, final CharSequence text, final StringBuilder newText) throws
ApplyPatchException {
final List<PatchHunk> hunks = patch.getHunks();
if (hunks.isEmpty()) {
return ApplyPatchStatus.SUCCESS;
}
List<String> lines = new ArrayList<String>();
Collections.addAll(lines, LineTokenizer.tokenize(text, false));
ApplyPatchStatus result = null;
for(PatchHunk hunk: hunks) {
result = ApplyPatchStatus.and(result, new ApplyPatchHunk(hunk).apply(lines));
}
for(int i=0; i<lines.size(); i++) {
newText.append(lines.get(i));
if (i < lines.size()-1 || !hunks.get(hunks.size()-1).isNoNewLineAtEnd()) {
newText.append("\n");
}
}
return result;
}*/
}