[patch]: refactoring

* make ApplyPatchForBaseRevisionTexts.java immutable;
* remove Warning list from ApplyPatchForBaseRevisionTexts, use LOG.warn;
* extract applying onto baseContent, found base, local as methods;
* do not apply patch onto wrong base someHow: if base is presented then
patch has to be applied exactly otherwise -> warn;
This commit is contained in:
Nadya Zabrodina
2017-05-17 17:23:12 +03:00
parent 263ce7232a
commit 96dd1c74ad
5 changed files with 104 additions and 90 deletions
@@ -19,12 +19,9 @@ import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.Processor;
import java.util.List;
public interface VcsBaseRevisionAdviser {
/**
* @return true if base revision was found by this provider
*/
boolean getBaseVersionContent(final FilePath filePath, Processor<String> processor, String beforeVersionId, List<String> warnings)
throws VcsException;
boolean getBaseVersionContent(final FilePath filePath, Processor<String> processor, String beforeVersionId) throws VcsException;
}
@@ -24,6 +24,7 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
@@ -32,90 +33,120 @@ import org.jetbrains.annotations.CalledInAny;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.util.ObjectUtils.chooseNotNull;
public class ApplyPatchForBaseRevisionTexts {
private static final Logger LOG = Logger.getInstance(ApplyPatchForBaseRevisionTexts.class);
@NotNull private final String myLocal;
@Nullable private String myBase;
private String myPatched;
private boolean myIsAppliedSomehow;
private final List<String> myWarnings;
private boolean myBaseRevisionLoaded;
@Nullable private final String myBase;
@NotNull private final String myPatched;
private final boolean myIsAppliedSomehow;
public ApplyPatchForBaseRevisionTexts(@NotNull String patched, @NotNull String local, @Nullable String base, boolean isAppliedSomehow) {
myLocal = local;
myBase = base;
myPatched = patched;
myIsAppliedSomehow = isAppliedSomehow;
}
@NotNull
@CalledInAny
public static ApplyPatchForBaseRevisionTexts create(final Project project, @NotNull final VirtualFile file, final FilePath pathBeforeRename,
final TextFilePatch patch, @Nullable final CharSequence baseContents) {
public static ApplyPatchForBaseRevisionTexts create(@NotNull Project project,
@NotNull VirtualFile file,
@NotNull FilePath pathBeforeRename,
@NotNull TextFilePatch patch,
@Nullable CharSequence baseContents) {
assert !patch.isNewFile();
final String beforeVersionId = patch.getBeforeVersionId();
DefaultPatchBaseVersionProvider provider = null;
if (beforeVersionId != null) {
provider = new DefaultPatchBaseVersionProvider(project, file, beforeVersionId);
String localContent = getLocalFileContent(file);
if (baseContents != null) {
ApplyPatchForBaseRevisionTexts result = createFromStoredBase(localContent, patch, baseContents);
if (result != null) return result;
}
if (provider != null && provider.canProvideContent()) {
return new ApplyPatchForBaseRevisionTexts(provider, pathBeforeRename, patch, file, baseContents);
} else {
return new ApplyPatchForBaseRevisionTexts(null, pathBeforeRename, patch, file, baseContents);
String beforeVersionId = patch.getBeforeVersionId();
if (beforeVersionId != null) {
ApplyPatchForBaseRevisionTexts result =
createFromBaseVersionProvider(project, localContent, patch, beforeVersionId, file, pathBeforeRename);
if (result != null) return result;
}
return createFromLocal(localContent, patch);
}
@NotNull
private static ApplyPatchForBaseRevisionTexts createFromLocal(@NotNull String localContent, @NotNull TextFilePatch patch) {
final GenericPatchApplier applier = new GenericPatchApplier(localContent, patch.getHunks());
boolean exactlyApplied = applier.execute();
if (!exactlyApplied) {
applier.trySolveSomehow();
}
String patched = StringUtil.convertLineSeparators(applier.getAfter());
return new ApplyPatchForBaseRevisionTexts(patched, localContent, null, !exactlyApplied);
}
@Nullable
private static ApplyPatchForBaseRevisionTexts createFromBaseVersionProvider(@NotNull Project project,
@NotNull String localContent,
@NotNull TextFilePatch patch,
@NotNull String beforeVersionId,
@NotNull VirtualFile file,
@NotNull FilePath pathBeforeRename) {
DefaultPatchBaseVersionProvider baseVersionProvider = new DefaultPatchBaseVersionProvider(project, file, beforeVersionId);
if (!baseVersionProvider.canProvideContent()) return null;
try {
List<PatchHunk> hunks = patch.getHunks();
Ref<String> baseRef = new Ref<>();
Ref<String> patchedRef = new Ref<>();
baseVersionProvider.getBaseVersionContent(pathBeforeRename, base -> {
final GenericPatchApplier applier = new GenericPatchApplier(base, hunks);
if (!applier.execute()) return true;
baseRef.set(base);
patchedRef.set(StringUtil.convertLineSeparators(applier.getAfter()));
return false;
});
String base = baseRef.get();
String patched = patchedRef.get();
if (base == null || patched == null) return null;
return new ApplyPatchForBaseRevisionTexts(patched, localContent, base, false);
}
catch (VcsException e) {
LOG.warn(e);
return null;
}
}
@CalledInAny
private ApplyPatchForBaseRevisionTexts(final DefaultPatchBaseVersionProvider provider,
final FilePath pathBeforeRename,
final TextFilePatch patch,
@NotNull final VirtualFile file,
@Nullable CharSequence baseContents) {
myWarnings = new ArrayList<>();
myLocal = getLocalFileContent(file);
@Nullable
private static ApplyPatchForBaseRevisionTexts createFromStoredBase(@NotNull String localContent,
@NotNull TextFilePatch patch,
@NotNull CharSequence baseContents) {
final List<PatchHunk> hunks = patch.getHunks();
if (baseContents != null) {
myBase = StringUtil.convertLineSeparators(baseContents.toString());
myBaseRevisionLoaded = true;
final GenericPatchApplier applier = new GenericPatchApplier(myBase, hunks);
if (!applier.execute()) {
myIsAppliedSomehow = true;
LOG.warn(
String.format("Patch for %s has wrong base and can't be applied properly",
chooseNotNull(patch.getBeforeName(), patch.getAfterName())));
applier.trySolveSomehow();
}
setPatched(applier.getAfter());
return;
String base = StringUtil.convertLineSeparators(baseContents.toString());
final GenericPatchApplier applier = new GenericPatchApplier(base, hunks);
boolean exactlyApplied = applier.execute();
if (!exactlyApplied) {
LOG.warn(String.format("Patch for %s has wrong base and can't be applied properly",
chooseNotNull(patch.getBeforeName(), patch.getAfterName())));
return null;
}
if (provider != null) {
try {
provider.getBaseVersionContent(pathBeforeRename, text -> {
final GenericPatchApplier applier = new GenericPatchApplier(text, hunks);
if (!applier.execute()) {
return true;
}
myBase = text;
myBaseRevisionLoaded = true;
setPatched(applier.getAfter());
return false;
}, myWarnings);
}
catch (VcsException e) {
myWarnings.add(e.getMessage());
}
if (myPatched != null) return;
}
String patched = StringUtil.convertLineSeparators(applier.getAfter());
final GenericPatchApplier applier = new GenericPatchApplier(myLocal, hunks);
if (!applier.execute()) {
myIsAppliedSomehow = true;
applier.trySolveSomehow();
}
setPatched(applier.getAfter());
return new ApplyPatchForBaseRevisionTexts(patched, localContent, base, false);
}
@NotNull
@@ -139,14 +170,7 @@ public class ApplyPatchForBaseRevisionTexts {
return myBase;
}
public void clearBase() {
myBase = null;
}
private void setPatched(final String text) {
myPatched = StringUtil.convertLineSeparators(text);
}
@NotNull
public String getPatched() {
return myPatched;
}
@@ -156,6 +180,6 @@ public class ApplyPatchForBaseRevisionTexts {
}
public boolean isBaseRevisionLoaded() {
return myBaseRevisionLoaded;
return myBase != null;
}
}
@@ -74,8 +74,7 @@ public class DefaultPatchBaseVersionProvider {
@CalledInAny
public void getBaseVersionContent(final FilePath filePath,
final Processor<String> processor,
final List<String> warnings) throws VcsException {
final Processor<String> processor) throws VcsException {
if (myVcs == null) {
return;
}
@@ -94,7 +93,7 @@ public class DefaultPatchBaseVersionProvider {
computeInBackgroundTask(myProject, message("progress.text2.loading.revision", finalRevision.asString()), true, () -> {
if (historyProvider instanceof VcsBaseRevisionAdviser) {
VcsBaseRevisionAdviser revisionAdviser = (VcsBaseRevisionAdviser)historyProvider;
return revisionAdviser.getBaseVersionContent(filePath, processor, finalRevision.asString(), warnings);
return revisionAdviser.getBaseVersionContent(filePath, processor, finalRevision.asString());
}
else {
DiffProvider diffProvider = myVcs.getDiffProvider();
@@ -261,20 +261,18 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware {
ApplyPatchForBaseRevisionTexts texts =
ApplyPatchForBaseRevisionTexts.create(project, file, patchContext.getPathBeforeRename(file), patch, baseContents);
//found base
if (texts.isBaseRevisionLoaded() && !texts.isAppliedSomehow()) {
if (texts.isBaseRevisionLoaded()) {
assert !texts.isAppliedSomehow();
//normal diff
DiffContentFactory contentFactory = DiffContentFactory.getInstance();
DiffContent leftContent = withLocal
? contentFactory.create(project, file)
: contentFactory.create(project, texts.getBase().toString());
: contentFactory.create(project, assertNotNull(texts.getBase()));
return new SimpleDiffRequest(getName(), leftContent, contentFactory.create(project, texts.getPatched()),
withLocal ? CURRENT_VERSION : BASE_VERSION, SHELVED_VERSION);
}
else {
//try applying on local
if (texts.isAppliedSomehow()) {
texts.clearBase(); // wrong base should not be used even it exists
}
DiffRequest diffRequest = shelvedChange.isConflictingChange(project)
? createConflictDiffRequest(project, file, patch, SHELVED_VERSION, texts, getName())
: createDiffRequest(project, shelvedChange.getChange(project), getName(), context, indicator);
@@ -149,11 +149,7 @@ public class GitHistoryProvider implements VcsHistoryProviderEx,
}
@Override
public boolean getBaseVersionContent(FilePath filePath,
Processor<String> processor,
String beforeVersionId,
List<String> warnings)
throws VcsException {
public boolean getBaseVersionContent(FilePath filePath, Processor<String> processor, String beforeVersionId) throws VcsException {
if (StringUtil.isEmptyOrSpaces(beforeVersionId) || filePath.getVirtualFile() == null) return false;
// apply if base revision id matches revision
final VirtualFile root = GitUtil.getGitRoot(filePath);