VCS: extension point PatchEP added to allow read/write custom information for each file in patch

This commit is contained in:
irengrig
2011-07-12 16:21:43 +04:00
parent d6b7a7b8d4
commit 216c3bbb46
17 changed files with 727 additions and 305 deletions
@@ -41,7 +41,7 @@ public class PatchCreator {
Writer writer = new OutputStreamWriter(new FileOutputStream(filePath));
try {
String lineSeparator = CodeStyleSettingsManager.getInstance(p).getCurrentSettings().getLineSeparator();
UnifiedDiffWriter.write(patches, writer, lineSeparator);
UnifiedDiffWriter.write(p, patches, writer, lineSeparator);
}
finally {
writer.close();
@@ -16,18 +16,15 @@
package com.intellij.history.integration;
import com.intellij.openapi.diff.impl.patch.BinaryFilePatch;
import com.intellij.openapi.diff.impl.patch.FilePatch;
import com.intellij.openapi.diff.impl.patch.PatchReader;
import com.intellij.openapi.diff.impl.patch.PatchVirtualFileReader;
import com.intellij.openapi.diff.impl.patch.*;
import com.intellij.openapi.diff.impl.patch.formove.PatchApplier;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public abstract class PatchingTestCase extends IntegrationTestCase {
@@ -47,14 +44,9 @@ public abstract class PatchingTestCase extends IntegrationTestCase {
}
protected void applyPatch() throws Exception {
List<FilePatch> patches = new ArrayList<FilePatch>();
PatchReader reader = PatchVirtualFileReader.create(LocalFileSystem.getInstance().refreshAndFindFileByPath(patchFilePath));
while (true) {
FilePatch p = reader.readNextPatch();
if (p == null) break;
patches.add(p);
}
List<FilePatch> patches = ObjectsConvertor.<FilePatch, TextFilePatch>downcast(reader.readAllPatches());
new PatchApplier<BinaryFilePatch>(myProject, myRoot, patches, (LocalChangeList) null, null).execute();
}
@@ -39,5 +39,6 @@
<extensionPoint name="vcsPopupProvider"
interface="com.intellij.openapi.vcs.actions.VcsQuickListContentProvider"/>
<extensionPoint name="patch.extension" interface="com.intellij.openapi.diff.impl.patch.PatchEP" area="IDEA_PROJECT"/>
</extensionPoints>
@@ -19,6 +19,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.text.CharArrayCharSequence;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -36,8 +37,17 @@ public class LineTokenizer {
}
private static String[] tokenize(final CharSequence chars, final boolean includeSeparators, final boolean skipLastEmptyLine) {
final List<String> strings = tokenizeIntoList(chars, includeSeparators, skipLastEmptyLine);
return strings.isEmpty() ? ArrayUtil.EMPTY_STRING_ARRAY : ArrayUtil.toStringArray(strings);
}
public static List<String> tokenizeIntoList(final CharSequence chars, final boolean includeSeparators) {
return tokenizeIntoList(chars, includeSeparators, true);
}
public static List<String> tokenizeIntoList(final CharSequence chars, final boolean includeSeparators, final boolean skipLastEmptyLine) {
if (chars == null || chars.length() == 0){
return ArrayUtil.EMPTY_STRING_ARRAY;
return Collections.emptyList();
}
LineTokenizer tokenizer = new LineTokenizer(chars);
@@ -57,7 +67,7 @@ public class LineTokenizer {
if (!skipLastEmptyLine && stringEndsWithSeparator(tokenizer)) lines.add("");
return ArrayUtil.toStringArray(lines);
return lines;
}
public static int calcLineCount(final CharSequence chars, final boolean skipLastEmptyLine) {
@@ -911,6 +911,10 @@ public class StringUtil {
return s == null || s.length() == 0;
}
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
@NotNull
public static String notNullize(final String s) {
return notNullize(s, "");
@@ -0,0 +1,40 @@
/*
* Copyright 2000-2011 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;
import com.intellij.openapi.extensions.ExtensionPointName;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author irengrig
* Date: 7/11/11
* Time: 11:43 AM
*/
public interface PatchEP {
ExtensionPointName<PatchEP> EP_NAME = ExtensionPointName.create("com.intellij.patch.extension");
@NotNull
String getName();
/**
* @param path - before path, if exist, otherwise after path
*/
@Nullable
CharSequence provideContent(@NotNull final String path);
/**
* @param path - before path, if exist, otherwise after path
*/
void consumeContent(@NotNull final String path, @NotNull final CharSequence content);
}
@@ -23,22 +23,25 @@
package com.intellij.openapi.diff.impl.patch;
import com.intellij.openapi.util.text.LineTokenizer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatchReader {
@NonNls public static final String NO_NEWLINE_SIGNATURE = "\\ No newline at end of file";
private final List<String> myLines;
private final PatchReader.PatchContentParser myPatchContentParser;
private final AdditionalInfoParser myAdditionalInfoParser;
private List<TextFilePatch> myPatches;
private enum DiffFormat { CONTEXT, UNIFIED }
private final String[] myLines;
private int myLineIndex = 0;
private DiffFormat myDiffFormat = null;
@NonNls private static final String CONTEXT_HUNK_PREFIX = "***************";
@NonNls private static final String CONTEXT_FILE_PREFIX = "*** ";
@NonNls private static final Pattern ourUnifiedHunkStartPattern = Pattern.compile("@@ -(\\d+)(,(\\d+))? \\+(\\d+)(,(\\d+))? @@.*");
@@ -46,279 +49,455 @@ public class PatchReader {
@NonNls private static final Pattern ourContextAfterHunkStartPattern = Pattern.compile("--- (\\d+),(\\d+) ----");
public PatchReader(CharSequence patchContent) {
myLines = LineTokenizer.tokenize(patchContent, false);
myLines = LineTokenizer.tokenizeIntoList(patchContent, false);
myAdditionalInfoParser = new AdditionalInfoParser();
myPatchContentParser = new PatchContentParser();
}
public List<TextFilePatch> readAllPatches() throws PatchSyntaxException {
List<TextFilePatch> result = new ArrayList<TextFilePatch>();
while(true) {
TextFilePatch patch = readNextPatch();
if (patch == null) break;
result.add(patch);
}
return result;
parseAllPatches();
return myPatches;
}
@Nullable
public TextFilePatch readNextPatch() throws PatchSyntaxException {
while (myLineIndex < myLines.length) {
String curLine = myLines [myLineIndex];
if (curLine.startsWith("--- ") && (myDiffFormat == null || myDiffFormat == DiffFormat.UNIFIED)) {
public List<TextFilePatch> getPatches() {
return myPatches;
}
public void parseAllPatches() throws PatchSyntaxException {
final ListIterator<String> iterator = myLines.listIterator();
if (! iterator.hasNext()) {
myPatches = Collections.emptyList();
return;
}
String next;
boolean containsAdditional = false;
while (iterator.hasNext()) {
next = iterator.next();
final boolean containsAdditionalNow = myAdditionalInfoParser.testIsStart(next);
if (containsAdditionalNow && containsAdditional) {
myAdditionalInfoParser.acceptError(new PatchSyntaxException(iterator.previousIndex(), "Contains additional information without patch itself"));
}
if (containsAdditionalNow) {
containsAdditional = containsAdditionalNow;
myAdditionalInfoParser.parse(next, iterator);
if (! iterator.hasNext()) {
myAdditionalInfoParser.acceptError(new PatchSyntaxException(iterator.previousIndex(), "Contains additional information without patch itself"));
break;
}
next = iterator.next();
}
if (myPatchContentParser.testIsStart(next)) {
myPatchContentParser.parse(next, iterator);
//iterator.previous(); // to correctly initialize next
if (containsAdditional) {
final String lastName = myPatchContentParser.getLastName();
if (lastName == null) {
myAdditionalInfoParser.acceptError(new PatchSyntaxException(iterator.previousIndex(), "Contains additional information without patch itself"));
} else {
myAdditionalInfoParser.copyToResult(lastName);
}
}
containsAdditional = false;
}
}
myPatches = myPatchContentParser.getResult();
}
public TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> getAdditionalInfo(final Set<String> filterByPaths) {
final TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException>
value = new TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException>();
final Map<String, Map<String, CharSequence>> map = myAdditionalInfoParser.getResultMap();
final Map<String, Map<String, CharSequence>>newMap = new HashMap<String, Map<String, CharSequence>>();
for (Map.Entry<String, Map<String, CharSequence>> entry : map.entrySet()) {
final Map<String, CharSequence> innerMap = entry.getValue();
if (filterByPaths == null || filterByPaths.contains(entry.getKey())) {
newMap.put(entry.getKey(), innerMap);
}
}
value.set(newMap);
final PatchSyntaxException e = myAdditionalInfoParser.getSyntaxException();
if (e != null) {
value.fail(e);
}
return value;
}
private static class AdditionalInfoParser implements Parser {
// first is path!
private final Map<String,Map<String, CharSequence>> myResultMap;
private Map<String, CharSequence> myAddMap;
private PatchSyntaxException mySyntaxException;
private AdditionalInfoParser() {
myAddMap = new HashMap<String, CharSequence>();
myResultMap = new HashMap<String, Map<String, CharSequence>>();
}
public PatchSyntaxException getSyntaxException() {
return mySyntaxException;
}
public Map<String, Map<String, CharSequence>> getResultMap() {
return myResultMap;
}
public void copyToResult(final String filePath) {
if (myAddMap != null && ! myAddMap.isEmpty()) {
myResultMap.put(filePath, myAddMap);
myAddMap = new HashMap<String, CharSequence>();
}
}
@Override
public boolean testIsStart(String start) {
if (mySyntaxException != null) return false; // stop on first error
return start != null && start.contains(UnifiedDiffWriter.ADDITIONAL_PREFIX);
}
@Override
public void parse(String start, ListIterator<String> iterator) {
if (! iterator.hasNext()) {
mySyntaxException = new PatchSyntaxException(iterator.previousIndex(), "Empty additional info header");
return;
}
while (true) {
final String header = iterator.next();
final int idxHead = header.indexOf(UnifiedDiffWriter.ADD_INFO_HEADER);
if (idxHead == -1) {
if (myAddMap.isEmpty()) {
mySyntaxException = new PatchSyntaxException(iterator.previousIndex(), "Empty additional info header");
}
iterator.previous();
return;
}
final String subsystem = header.substring(idxHead + UnifiedDiffWriter.ADD_INFO_HEADER.length()).trim();
if (! iterator.hasNext()) {
mySyntaxException = new PatchSyntaxException(iterator.previousIndex(), "Empty '" + subsystem + "' data section");
return;
}
final StringBuilder sb = new StringBuilder();
myAddMap.put(subsystem, sb);
while (iterator.hasNext()) {
final String line = iterator.next();
if (! line.startsWith(UnifiedDiffWriter.ADD_INFO_LINE_START)) {
iterator.previous();
break;
}
if (sb.length() > 0) {
sb.append("\n");
}
sb.append(StringUtil.unescapeStringCharacters(line.substring(UnifiedDiffWriter.ADD_INFO_LINE_START.length())));
}
}
}
public void acceptError(PatchSyntaxException e) {
mySyntaxException = e;
}
}
private static class PatchContentParser implements Parser {
private DiffFormat myDiffFormat = null;
private final List<TextFilePatch> myPatches;
private PatchContentParser() {
myPatches = new SmartList<TextFilePatch>();
}
@Override
public boolean testIsStart(String start) {
if (start.startsWith("--- ") && (myDiffFormat == null || myDiffFormat == DiffFormat.UNIFIED)) {
myDiffFormat = DiffFormat.UNIFIED;
return readPatch(curLine);
return true;
}
else if (curLine.startsWith(CONTEXT_FILE_PREFIX) && (myDiffFormat == null || myDiffFormat == DiffFormat.CONTEXT)) {
else if (start.startsWith(CONTEXT_FILE_PREFIX) && (myDiffFormat == null || myDiffFormat == DiffFormat.CONTEXT)) {
myDiffFormat = DiffFormat.CONTEXT;
return readPatch(curLine);
return true;
}
myLineIndex++;
return false;
}
return null;
}
private TextFilePatch readPatch(String curLine) throws PatchSyntaxException {
final TextFilePatch curPatch;
curPatch = new TextFilePatch();
extractFileName(curLine, curPatch, true);
myLineIndex++;
curLine = myLines [myLineIndex];
String secondNamePrefix = myDiffFormat == DiffFormat.UNIFIED ? "+++ " : "--- ";
if (!curLine.startsWith(secondNamePrefix)) {
throw new PatchSyntaxException(myLineIndex, "Second file name expected");
@Override
public void parse(String start, ListIterator<String> iterator) throws PatchSyntaxException {
final TextFilePatch patch = readPatch(start, iterator);
if (patch != null) {
myPatches.add(patch);
}
}
extractFileName(curLine, curPatch, false);
myLineIndex++;
while(myLineIndex < myLines.length) {
PatchHunk hunk;
if (myDiffFormat == DiffFormat.UNIFIED) {
hunk = readNextHunkUnified();
public List<TextFilePatch> getResult() throws PatchSyntaxException {
return myPatches;
}
private TextFilePatch readPatch(String curLine, ListIterator<String> iterator) throws PatchSyntaxException {
final TextFilePatch curPatch = new TextFilePatch();
extractFileName(curLine, curPatch, true);
if (! iterator.hasNext()) throw new PatchSyntaxException(iterator.previousIndex(), "Second file name expected");
curLine = iterator.next();
String secondNamePrefix = myDiffFormat == DiffFormat.UNIFIED ? "+++ " : "--- ";
if (! curLine.startsWith(secondNamePrefix)) {
throw new PatchSyntaxException(iterator.previousIndex(), "Second file name expected");
}
extractFileName(curLine, curPatch, false);
while (iterator.hasNext()) {
PatchHunk hunk;
if (myDiffFormat == DiffFormat.UNIFIED) {
hunk = readNextHunkUnified(iterator);
}
else {
hunk = readNextHunkContext(iterator);
}
if (hunk == null) break;
curPatch.addHunk(hunk);
}
return curPatch;
}
@Nullable
private PatchHunk readNextHunkUnified(ListIterator<String> iterator) throws PatchSyntaxException {
String curLine = null;
int numIncrements = 0;
while (iterator.hasNext()) {
curLine = iterator.next();
++ numIncrements;
if (curLine.startsWith("--- ")) {
for (int i = 0; i < numIncrements; i++) {
iterator.previous();
}
return null;
}
if (curLine.startsWith("@@ ")) {
break;
}
}
if (! iterator.hasNext()) return null;
Matcher m = ourUnifiedHunkStartPattern.matcher(curLine);
if (!m.matches()) {
throw new PatchSyntaxException(iterator.previousIndex(), "Unknown hunk start syntax");
}
int startLineBefore = Integer.parseInt(m.group(1));
final String linesBeforeText = m.group(3);
int linesBefore = linesBeforeText == null ? 1 : Integer.parseInt(linesBeforeText);
int startLineAfter = Integer.parseInt(m.group(4));
final String linesAfterText = m.group(6);
int linesAfter = linesAfterText == null ? 1 : Integer.parseInt(linesAfterText);
PatchHunk hunk = new PatchHunk(startLineBefore-1, startLineBefore+linesBefore-1, startLineAfter-1, startLineAfter+linesAfter-1);
PatchLine lastLine = null;
while (iterator.hasNext()) {
String hunkCurLine = iterator.next();
if (lastLine != null && hunkCurLine.startsWith(NO_NEWLINE_SIGNATURE)) {
lastLine.setSuppressNewLine(true);
continue;
}
if (hunkCurLine.startsWith("--- ")) {
iterator.previous();
break;
}
lastLine = parsePatchLine(hunkCurLine, 1);
if (lastLine == null) {
iterator.previous();
break;
}
hunk.addLine(lastLine);
}
return hunk;
}
@Nullable
public String getLastName() {
if (myPatches.isEmpty()) {
return null;
}
else {
hunk = readNextHunkContext();
final TextFilePatch patch = myPatches.get(myPatches.size() - 1);
return patch.getBeforeName() == null ? patch.getAfterName() : patch.getBeforeName();
}
if (hunk == null) break;
curPatch.addHunk(hunk);
}
return curPatch;
}
@Nullable
private PatchHunk readNextHunkUnified() throws PatchSyntaxException {
while(myLineIndex < myLines.length) {
String curLine = myLines [myLineIndex];
if (curLine.startsWith("--- ") && myLineIndex < myLines.length-1 && myLines [myLineIndex+1].startsWith("+++ ")) {
@Nullable
private static PatchLine parsePatchLine(final String line, final int prefixLength) {
PatchLine.Type type;
if (line.startsWith("+")) {
type = PatchLine.Type.ADD;
}
else if (line.startsWith("-")) {
type = PatchLine.Type.REMOVE;
}
else if (line.startsWith(" ")) {
type = PatchLine.Type.CONTEXT;
}
else {
return null;
}
if (curLine.startsWith("@@ ")) {
break;
String lineText;
if (line.length() < prefixLength) {
lineText = "";
}
myLineIndex++;
}
if (myLineIndex == myLines.length) {
return null;
else {
lineText = line.substring(prefixLength);
}
return new PatchLine(type, lineText);
}
Matcher m = ourUnifiedHunkStartPattern.matcher(myLines [myLineIndex]);
if (!m.matches()) {
throw new PatchSyntaxException(myLineIndex, "Unknown hunk start syntax");
}
int startLineBefore = Integer.parseInt(m.group(1));
final String linesBeforeText = m.group(3);
int linesBefore = linesBeforeText == null ? 1 : Integer.parseInt(linesBeforeText);
int startLineAfter = Integer.parseInt(m.group(4));
final String linesAfterText = m.group(6);
int linesAfter = linesAfterText == null ? 1 : Integer.parseInt(linesAfterText);
PatchHunk hunk = new PatchHunk(startLineBefore-1, startLineBefore+linesBefore-1, startLineAfter-1, startLineAfter+linesAfter-1);
myLineIndex++;
PatchLine lastLine = null;
while(myLineIndex < myLines.length) {
String curLine = myLines [myLineIndex];
if (lastLine != null && curLine.startsWith(NO_NEWLINE_SIGNATURE)) {
lastLine.setSuppressNewLine(true);
myLineIndex++;
continue;
@Nullable
private PatchHunk readNextHunkContext(ListIterator<String> iterator) throws PatchSyntaxException {
while (iterator.hasNext()) {
String curLine = iterator.next();
if (curLine.startsWith(CONTEXT_FILE_PREFIX)) {
return null;
}
if (curLine.startsWith(CONTEXT_HUNK_PREFIX)) {
break;
}
}
if (curLine.startsWith("--- ")) {
break;
}
lastLine = parsePatchLine(curLine, 1);
if (lastLine == null) {
break;
}
hunk.addLine(lastLine);
myLineIndex++;
}
return hunk;
}
@Nullable
private static PatchLine parsePatchLine(final String line, final int prefixLength) {
PatchLine.Type type;
if (line.startsWith("+")) {
type = PatchLine.Type.ADD;
}
else if (line.startsWith("-")) {
type = PatchLine.Type.REMOVE;
}
else if (line.startsWith(" ")) {
type = PatchLine.Type.CONTEXT;
}
else {
return null;
}
String lineText;
if (line.length() < prefixLength) {
lineText = "";
}
else {
lineText = line.substring(prefixLength);
}
return new PatchLine(type, lineText);
}
@Nullable
private PatchHunk readNextHunkContext() throws PatchSyntaxException {
while(myLineIndex < myLines.length) {
String curLine = myLines [myLineIndex];
if (curLine.startsWith(CONTEXT_FILE_PREFIX)) {
if (! iterator.hasNext()) {
return null;
}
if (curLine.startsWith(CONTEXT_HUNK_PREFIX)) {
break;
Matcher beforeMatcher = ourContextBeforeHunkStartPattern.matcher(iterator.next());
if (! beforeMatcher.matches()) {
throw new PatchSyntaxException(iterator.previousIndex(), "Unknown before hunk start syntax");
}
myLineIndex++;
}
if (myLineIndex == myLines.length) {
return null;
}
myLineIndex++;
Matcher beforeMatcher = ourContextBeforeHunkStartPattern.matcher(myLines [myLineIndex]);
if (!beforeMatcher.matches()) {
throw new PatchSyntaxException(myLineIndex, "Unknown before hunk start syntax");
}
myLineIndex++;
List<String> beforeLines = readContextDiffLines();
if (myLineIndex == myLines.length) {
throw new PatchSyntaxException(myLineIndex, "Missing after hunk");
}
Matcher afterMatcher = ourContextAfterHunkStartPattern.matcher(myLines [myLineIndex]);
if (!afterMatcher.matches()) {
throw new PatchSyntaxException(myLineIndex, "Unknown after hunk start syntax");
}
myLineIndex++;
List<String> afterLines = readContextDiffLines();
int startLineBefore = Integer.parseInt(beforeMatcher.group(1));
int endLineBefore = Integer.parseInt(beforeMatcher.group(2));
int startLineAfter = Integer.parseInt(afterMatcher.group(1));
int endLineAfter = Integer.parseInt(afterMatcher.group(2));
PatchHunk hunk = new PatchHunk(startLineBefore-1, endLineBefore-1, startLineAfter-1, endLineAfter-1);
List<String> beforeLines = readContextDiffLines(iterator);
if (! iterator.hasNext()) {
throw new PatchSyntaxException(iterator.previousIndex(), "Missing after hunk");
}
Matcher afterMatcher = ourContextAfterHunkStartPattern.matcher(iterator.next());
if (! afterMatcher.matches()) {
throw new PatchSyntaxException(iterator.previousIndex(), "Unknown after hunk start syntax");
}
//if (! iterator.hasNext()) {
//throw new PatchSyntaxException(iterator.previousIndex(), "Unexpected patch end");
//}
List<String> afterLines = readContextDiffLines(iterator);
int startLineBefore = Integer.parseInt(beforeMatcher.group(1));
int endLineBefore = Integer.parseInt(beforeMatcher.group(2));
int startLineAfter = Integer.parseInt(afterMatcher.group(1));
int endLineAfter = Integer.parseInt(afterMatcher.group(2));
PatchHunk hunk = new PatchHunk(startLineBefore-1, endLineBefore-1, startLineAfter-1, endLineAfter-1);
int beforeLineIndex = 0;
int afterLineIndex = 0;
PatchLine lastBeforePatchLine = null;
PatchLine lastAfterPatchLine = null;
if (beforeLines.size() == 0) {
for(String line: afterLines) {
hunk.addLine(parsePatchLine(line, 2));
int beforeLineIndex = 0;
int afterLineIndex = 0;
PatchLine lastBeforePatchLine = null;
PatchLine lastAfterPatchLine = null;
if (beforeLines.size() == 0) {
for(String line: afterLines) {
hunk.addLine(parsePatchLine(line, 2));
}
}
}
else if (afterLines.size() == 0) {
for(String line: beforeLines) {
hunk.addLine(parsePatchLine(line, 2));
else if (afterLines.size() == 0) {
for(String line: beforeLines) {
hunk.addLine(parsePatchLine(line, 2));
}
}
}
else {
while(beforeLineIndex < beforeLines.size() || afterLineIndex < afterLines.size()) {
String beforeLine = beforeLineIndex >= beforeLines.size() ? null : beforeLines.get(beforeLineIndex);
String afterLine = afterLineIndex >= afterLines.size() ? null : afterLines.get(afterLineIndex);
if (startsWith(beforeLine, NO_NEWLINE_SIGNATURE) && lastBeforePatchLine != null) {
lastBeforePatchLine.setSuppressNewLine(true);
beforeLineIndex++;
}
else if (startsWith(afterLine, NO_NEWLINE_SIGNATURE) && lastAfterPatchLine != null) {
lastAfterPatchLine.setSuppressNewLine(true);
afterLineIndex++;
}
else if (startsWith(beforeLine, " ") &&
(startsWith(afterLine, " ") || afterLine == null /* handle some weird cases with line breaks truncated at EOF */ )) {
addContextDiffLine(hunk, beforeLine, PatchLine.Type.CONTEXT);
beforeLineIndex++;
afterLineIndex++;
}
else if (startsWith(beforeLine, "-")) {
lastBeforePatchLine = addContextDiffLine(hunk, beforeLine, PatchLine.Type.REMOVE);
beforeLineIndex++;
}
else if (startsWith(afterLine, "+")) {
lastAfterPatchLine = addContextDiffLine(hunk, afterLine, PatchLine.Type.ADD);
afterLineIndex++;
}
else if (startsWith(beforeLine, "!") && startsWith(afterLine, "!")) {
while(beforeLineIndex < beforeLines.size() && beforeLines.get(beforeLineIndex).startsWith("! ")) {
lastBeforePatchLine = addContextDiffLine(hunk, beforeLines.get(beforeLineIndex), PatchLine.Type.REMOVE);
else {
while(beforeLineIndex < beforeLines.size() || afterLineIndex < afterLines.size()) {
String beforeLine = beforeLineIndex >= beforeLines.size() ? null : beforeLines.get(beforeLineIndex);
String afterLine = afterLineIndex >= afterLines.size() ? null : afterLines.get(afterLineIndex);
if (startsWith(beforeLine, NO_NEWLINE_SIGNATURE) && lastBeforePatchLine != null) {
lastBeforePatchLine.setSuppressNewLine(true);
beforeLineIndex++;
}
while(afterLineIndex < afterLines.size() && afterLines.get(afterLineIndex).startsWith("! ")) {
lastAfterPatchLine = addContextDiffLine(hunk, afterLines.get(afterLineIndex), PatchLine.Type.ADD);
else if (startsWith(afterLine, NO_NEWLINE_SIGNATURE) && lastAfterPatchLine != null) {
lastAfterPatchLine.setSuppressNewLine(true);
afterLineIndex++;
}
}
else {
throw new PatchSyntaxException(-1, "Unknown line prefix");
else if (startsWith(beforeLine, " ") &&
(startsWith(afterLine, " ") || afterLine == null /* handle some weird cases with line breaks truncated at EOF */ )) {
addContextDiffLine(hunk, beforeLine, PatchLine.Type.CONTEXT);
beforeLineIndex++;
afterLineIndex++;
}
else if (startsWith(beforeLine, "-")) {
lastBeforePatchLine = addContextDiffLine(hunk, beforeLine, PatchLine.Type.REMOVE);
beforeLineIndex++;
}
else if (startsWith(afterLine, "+")) {
lastAfterPatchLine = addContextDiffLine(hunk, afterLine, PatchLine.Type.ADD);
afterLineIndex++;
}
else if (startsWith(beforeLine, "!") && startsWith(afterLine, "!")) {
while(beforeLineIndex < beforeLines.size() && beforeLines.get(beforeLineIndex).startsWith("! ")) {
lastBeforePatchLine = addContextDiffLine(hunk, beforeLines.get(beforeLineIndex), PatchLine.Type.REMOVE);
beforeLineIndex++;
}
while(afterLineIndex < afterLines.size() && afterLines.get(afterLineIndex).startsWith("! ")) {
lastAfterPatchLine = addContextDiffLine(hunk, afterLines.get(afterLineIndex), PatchLine.Type.ADD);
afterLineIndex++;
}
}
else {
throw new PatchSyntaxException(-1, "Unknown line prefix");
}
}
}
return hunk;
}
return hunk;
}
private static boolean startsWith(@Nullable final String line, final String prefix) {
return line != null && line.startsWith(prefix);
}
private static PatchLine addContextDiffLine(final PatchHunk hunk, final String line, final PatchLine.Type type) {
final PatchLine patchLine = new PatchLine(type, line.length() < 2 ? "" : line.substring(2));
hunk.addLine(patchLine);
return patchLine;
}
private List<String> readContextDiffLines() {
ArrayList<String> result = new ArrayList<String>();
while(myLineIndex < myLines.length) {
final String line = myLines[myLineIndex];
if (!line.startsWith(" ") && !line.startsWith("+ ") && !line.startsWith("- ") && !line.startsWith("! ") &&
!line.startsWith(NO_NEWLINE_SIGNATURE)) {
break;
}
result.add(line);
myLineIndex++;
private static boolean startsWith(@Nullable final String line, final String prefix) {
return line != null && line.startsWith(prefix);
}
return result;
}
private static void extractFileName(final String curLine, final FilePatch patch, final boolean before) {
String fileName = curLine.substring(4);
int pos = fileName.indexOf('\t');
if (pos < 0) {
pos = fileName.indexOf(' ');
private static PatchLine addContextDiffLine(final PatchHunk hunk, final String line, final PatchLine.Type type) {
final PatchLine patchLine = new PatchLine(type, line.length() < 2 ? "" : line.substring(2));
hunk.addLine(patchLine);
return patchLine;
}
if (pos >= 0) {
String versionId = fileName.substring(pos).trim();
fileName = fileName.substring(0, pos);
if (versionId.length() > 0) {
if (before) {
patch.setBeforeVersionId(versionId);
private List<String> readContextDiffLines(ListIterator<String> iterator) {
ArrayList<String> result = new ArrayList<String>();
while (iterator.hasNext()) {
final String line = iterator.next();
if (!line.startsWith(" ") && !line.startsWith("+ ") && !line.startsWith("- ") && !line.startsWith("! ") &&
!line.startsWith(NO_NEWLINE_SIGNATURE)) {
iterator.previous();
break;
}
else {
patch.setAfterVersionId(versionId);
result.add(line);
}
return result;
}
private static void extractFileName(final String curLine, final FilePatch patch, final boolean before) {
String fileName = curLine.substring(4);
int pos = fileName.indexOf('\t');
if (pos < 0) {
pos = fileName.indexOf(' ');
}
if (pos >= 0) {
String versionId = fileName.substring(pos).trim();
fileName = fileName.substring(0, pos);
if (versionId.length() > 0) {
if (before) {
patch.setBeforeVersionId(versionId);
}
else {
patch.setAfterVersionId(versionId);
}
}
}
if (before) {
patch.setBeforeName(fileName);
}
else {
patch.setAfterName(fileName);
}
}
if (before) {
patch.setBeforeName(fileName);
}
else {
patch.setAfterName(fileName);
}
}
private interface Parser {
boolean testIsStart(final String start);
void parse(final String start, final ListIterator<String> iterator) throws PatchSyntaxException;
}
}
@@ -22,25 +22,48 @@
*/
package com.intellij.openapi.diff.impl.patch;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import java.io.IOException;
import java.io.Writer;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class UnifiedDiffWriter {
@NonNls private static final String INDEX_SIGNATURE = "Index: {0}{1}";
@NonNls public static final String ADDITIONAL_PREFIX = "IDEA additional info:";
@NonNls public static final String ADD_INFO_HEADER = "Subsystem: ";
@NonNls public static final String ADD_INFO_LINE_START = "<+>";
private static final String HEADER_SEPARATOR = "===================================================================";
private UnifiedDiffWriter() {
}
public static void write(Collection<FilePatch> patches, Writer writer, final String lineSeparator) throws IOException {
public static void write(Project project, Collection<FilePatch> patches, Writer writer, final String lineSeparator) throws IOException {
final PatchEP[] extensions = project == null ? new PatchEP[0] : Extensions.getExtensions(PatchEP.EP_NAME, project);
write(patches, writer, lineSeparator, extensions);
}
public static void write(Collection<FilePatch> patches, Writer writer, final String lineSeparator,
final PatchEP[] extensions) throws IOException {
for(FilePatch filePatch: patches) {
if (!(filePatch instanceof TextFilePatch)) continue;
TextFilePatch patch = (TextFilePatch) filePatch;
writeFileHeading(patch, writer, lineSeparator);
final String path = patch.getBeforeName() == null ? patch.getAfterName() : patch.getBeforeName();
final Map<String , CharSequence> additionalMap = new HashMap<String, CharSequence>();
for (PatchEP extension : extensions) {
final CharSequence charSequence = extension.provideContent(path);
if (! StringUtil.isEmpty(charSequence)) {
additionalMap.put(extension.getName(), charSequence);
}
}
writeFileHeading(patch, writer, lineSeparator, additionalMap);
for(PatchHunk hunk: patch.getHunks()) {
writeHunkStart(writer, hunk.getStartLineBefore(), hunk.getEndLineBefore(), hunk.getStartLineAfter(), hunk.getEndLineAfter(),
lineSeparator);
@@ -67,8 +90,26 @@ public class UnifiedDiffWriter {
}
}
private static void writeFileHeading(final FilePatch patch, final Writer writer, final String lineSeparator) throws IOException {
private static void writeFileHeading(final FilePatch patch,
final Writer writer,
final String lineSeparator,
Map<String, CharSequence> additionalMap) throws IOException {
writer.write(MessageFormat.format(INDEX_SIGNATURE, patch.getBeforeName(), lineSeparator));
if (additionalMap != null && ! additionalMap.isEmpty()) {
writer.write(ADDITIONAL_PREFIX);
writer.write(lineSeparator);
for (Map.Entry<String, CharSequence> entry : additionalMap.entrySet()) {
writer.write(ADD_INFO_HEADER + entry.getKey());
writer.write(lineSeparator);
final String value = StringUtil.escapeStringCharacters(entry.getValue().toString());
final List<String> lines = StringUtil.split(value, "\n");
for (String line : lines) {
writer.write(ADD_INFO_LINE_START);
writer.write(line);
writer.write(lineSeparator);
}
}
}
writer.write(HEADER_SEPARATOR + lineSeparator);
writeRevisionHeading(writer, "---", patch.getBeforeName(), patch.getBeforeVersionId(), lineSeparator);
writeRevisionHeading(writer, "+++", patch.getAfterName(), patch.getAfterVersionId(), lineSeparator);
@@ -98,4 +139,4 @@ public class UnifiedDiffWriter {
writer.write(prefix);
writer.write(line);
}
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2000-2011 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.formove;
import com.intellij.openapi.diff.impl.patch.PatchEP;
import org.jetbrains.annotations.NotNull;
/**
* @author irengrig
* Date: 7/12/11
* Time: 1:15 PM
*/
public class TestPatchEP implements PatchEP {
private final static String ourName = "com.intellij.openapi.diff.impl.patch.formove.TestPatchEP";
private final static String ourContent = "ourContent\nseveral\nlines\twith\u0142\u0001 different symbols";
@NotNull
@Override
public String getName() {
return ourName;
}
@Override
public CharSequence provideContent(@NotNull String path) {
return ourContent + path;
}
@Override
public void consumeContent(@NotNull String path, @NotNull CharSequence content) {
assert (ourContent + path).equals(content.toString());
}
}
@@ -36,4 +36,9 @@ public class TransparentlyFailedValue<T, E extends Exception> {
if (this.e != null) throw this.e;
return this.t;
}
public void take(final TransparentlyFailedValue<T,E> value) {
this.t = value.t;
this.e = value.e;
}
}
@@ -27,6 +27,19 @@ import java.util.Collection;
import java.util.List;
public class ObjectsConvertor {
private final static DownCast DOWN_CAST = new DownCast();
public static class DownCast<Sup, Sub extends Sup> implements Convertor<Sub, Sup> {
@Override
public Sup convert(Sub o) {
return o;
}
}
public static <Sup, Sub extends Sup> List<Sup> downcast(List<Sub> list) {
return convert(list, (Convertor<Sub, Sup>) DOWN_CAST);
}
public static final Convertor<FilePath, VirtualFile> FILEPATH_TO_VIRTUAL = new Convertor<FilePath, VirtualFile>() {
public VirtualFile convert(FilePath fp) {
return fp.getVirtualFile();
@@ -17,16 +17,25 @@ package com.intellij.openapi.vcs.changes.patch;
import com.intellij.openapi.diff.impl.patch.BinaryFilePatch;
import com.intellij.openapi.diff.impl.patch.FilePatch;
import com.intellij.openapi.diff.impl.patch.PatchEP;
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
import com.intellij.openapi.diff.impl.patch.formove.PatchApplier;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MultiMap;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
* @author irengrig
@@ -47,7 +56,10 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor {
}
@Override
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups, LocalChangeList localList, String fileName) {
public void apply(MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
LocalChangeList localList,
String fileName,
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
final Collection<PatchApplier> appliers = new LinkedList<PatchApplier>();
for (VirtualFile base : patchGroups.keySet()) {
final PatchApplier patchApplier =
@@ -60,5 +72,43 @@ public class ApplyPatchDefaultExecutor implements ApplyPatchExecutor {
appliers.add(patchApplier);
}
PatchApplier.executePatchGroup(appliers);
applyAdditionalInfo(myProject, additionalInfo);
}
public static void applyAdditionalInfo(final Project project,
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
final PatchEP[] extensions = Extensions.getExtensions(PatchEP.EP_NAME, project);
if (extensions == null && extensions.length == 0) return;
if (additionalInfo != null) {
try {
final Map<String, Map<String, CharSequence>> map = additionalInfo.get();
for (Map.Entry<String, Map<String, CharSequence>> entry : map.entrySet()) {
final String path = entry.getKey();
final Map<String, CharSequence> innerMap = entry.getValue();
for (PatchEP extension : extensions) {
final CharSequence charSequence = innerMap.get(extension.getName());
if (charSequence != null) {
extension.consumeContent(path, charSequence);
}
}
}
}
catch (PatchSyntaxException e) {
VcsBalloonProblemNotifier
.showOverChangesView(project, "Can not apply additional patch info: " + e.getMessage(), MessageType.ERROR);
}
}
}
public static Set<String> pathsFromGroups(MultiMap<VirtualFile, FilePatchInProgress> patchGroups) {
final Set<String> selectedPaths = new HashSet<String>();
final Collection<? extends FilePatchInProgress> values = patchGroups.values();
for (FilePatchInProgress value : values) {
final String path = value.getPatch().getBeforeName() == null ? value.getPatch().getAfterName() : value.getPatch().getBeforeName();
selectedPaths.add(path);
}
return selectedPaths;
}
}
@@ -17,7 +17,10 @@ package com.intellij.openapi.vcs.changes.patch;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diff.impl.patch.*;
import com.intellij.openapi.diff.impl.patch.PatchReader;
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
import com.intellij.openapi.diff.impl.patch.PatchVirtualFileReader;
import com.intellij.openapi.diff.impl.patch.TextFilePatch;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileTypes.FileTypes;
@@ -86,6 +89,7 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
private boolean myContainBasedChanges;
private JLabel myPatchFileLabel;
private PatchReader myReader;
public ApplyPatchDifferentiatedDialog(final Project project, final ApplyPatchExecutor callback, final List<ApplyPatchExecutor> executors,
@NotNull final ApplyPatchMode applyPatchMode, @NotNull final VirtualFile patchFile) {
@@ -196,7 +200,9 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
for (FilePatchInProgress patchInProgress : included) {
patchGroups.putValue(patchInProgress.getBase(), patchInProgress);
}
executor.apply(patchGroups, getSelectedChangeList(), myRecentPathFileChange.get().getVf().getName());
final LocalChangeList selected = getSelectedChangeList();
executor.apply(patchGroups, selected, myRecentPathFileChange.get().getVf().getName(),
myReader == null ? null : myReader.getAdditionalInfo(ApplyPatchDefaultExecutor.pathsFromGroups(patchGroups)));
}
@Override
@@ -229,64 +235,42 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper {
}
final VirtualFile file = filePresentation.getVf();
final List<TextFilePatch> patches = loadPatches(file);
final AutoMatchIterator autoMatchIterator = new AutoMatchIterator(myProject);
final List<FilePatchInProgress> matchedPathes = autoMatchIterator.execute(patches);
final PatchReader patchReader = loadPatches(file);
final List<FilePatchInProgress> matchedPathes = patchReader == null ? Collections.<FilePatchInProgress>emptyList() :
new AutoMatchIterator(myProject).execute(patchReader.getPatches());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myChangeListChooser.setDefaultName(file.getNameWithoutExtension().replace('_', ' ').trim());
myPatches.clear();
myPatches.addAll(matchedPathes);
myReader = patchReader;
updateTree(true);
}
});
}
}
private List<TextFilePatch> loadPatches(final VirtualFile patchFile) {
@Nullable
private PatchReader loadPatches(final VirtualFile patchFile) {
if (! patchFile.isValid()) {
//todo
//queueUpdateStatus("Cannot find patch file");
return Collections.emptyList();
return null;
}
PatchReader reader;
try {
reader = PatchVirtualFileReader.create(patchFile);
}
catch (IOException e) {
//todo
//queueUpdateStatus(VcsBundle.message("patch.apply.open.error", e.getMessage()));
return Collections.emptyList();
return null;
}
try {
reader.parseAllPatches();
}
catch (PatchSyntaxException e) {
return null;
}
final List<TextFilePatch> result = new LinkedList<TextFilePatch>();
while(true) {
FilePatch patch;
try {
patch = reader.readNextPatch();
}
catch (PatchSyntaxException e) {
// todo
if (e.getLine() >= 0) {
//queueUpdateStatus(VcsBundle.message("patch.apply.load.error.line", e.getMessage(), e.getLine()));
}
else {
//queueUpdateStatus(VcsBundle.message("patch.apply.load.error", e.getMessage()));
}
return Collections.emptyList();
}
if (patch == null) {
break;
}
result.add((TextFilePatch) patch);
}
if (myPatches.isEmpty()) {
// todo
//queueUpdateStatus(VcsBundle.message("patch.apply.no.patches.found"));
}
return result;
return reader;
}
private static class FilePresentation {
@@ -15,10 +15,14 @@
*/
package com.intellij.openapi.vcs.changes.patch;
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.MultiMap;
import java.util.Map;
/**
* @author irengrig
* Date: 2/25/11
@@ -26,5 +30,8 @@ import com.intellij.util.containers.MultiMap;
*/
public interface ApplyPatchExecutor {
String getName();
void apply(final MultiMap<VirtualFile, FilePatchInProgress> patchGroups, final LocalChangeList localList, String fileName);
void apply(final MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
final LocalChangeList localList,
String fileName,
TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo);
}
@@ -16,26 +16,33 @@
package com.intellij.openapi.vcs.changes.patch;
import com.intellij.openapi.diff.impl.patch.FilePatch;
import com.intellij.openapi.diff.impl.patch.PatchEP;
import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
import com.intellij.openapi.diff.impl.patch.TextFilePatch;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vcs.AbstractVcsHelper;
import com.intellij.openapi.vcs.ObjectsConvertor;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.changes.TransparentlyFailedValue;
import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager;
import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList;
import com.intellij.openapi.vcs.changes.shelf.ShelvedChangesViewManager;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Convertor;
import com.intellij.util.containers.MultiMap;
import com.intellij.vcsUtil.VcsCatchingRunnable;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author irengrig
@@ -56,7 +63,10 @@ public class ImportToShelfExecutor implements ApplyPatchExecutor {
}
@Override
public void apply(final MultiMap<VirtualFile, FilePatchInProgress> patchGroups, LocalChangeList localList, final String fileName) {
public void apply(final MultiMap<VirtualFile, FilePatchInProgress> patchGroups,
LocalChangeList localList,
final String fileName,
final TransparentlyFailedValue<Map<String, Map<String, CharSequence>>, PatchSyntaxException> additionalInfo) {
final VcsCatchingRunnable vcsCatchingRunnable = new VcsCatchingRunnable() {
@Override
public void runImpl() throws VcsException {
@@ -77,9 +87,24 @@ public class ImportToShelfExecutor implements ApplyPatchExecutor {
}
}));
}
if (!allPatches.isEmpty()) {
if (! allPatches.isEmpty()) {
PatchEP[] patchTransitExtensions = null;
if (additionalInfo != null) {
try {
final List<PatchEP> list = new ArrayList<PatchEP>();
for (Map.Entry<String, Map<String, CharSequence>> entry : additionalInfo.get().entrySet()) {
list.add(new TransitExtension(entry.getKey(), entry.getValue()));
}
patchTransitExtensions = list.toArray(new PatchEP[list.size()]);
}
catch (PatchSyntaxException e) {
VcsBalloonProblemNotifier
.showOverChangesView(myProject, "Can not import additional patch info: " + e.getMessage(), MessageType.ERROR);
}
}
try {
final ShelvedChangeList shelvedChangeList = ShelveChangesManager.getInstance(myProject).importFilePatches(fileName, allPatches);
final ShelvedChangeList shelvedChangeList = ShelveChangesManager.getInstance(myProject).
importFilePatches(fileName, allPatches, patchTransitExtensions);
ShelvedChangesViewManager.getInstance(myProject).activateView(shelvedChangeList);
}
catch (IOException e) {
@@ -93,4 +118,30 @@ public class ImportToShelfExecutor implements ApplyPatchExecutor {
AbstractVcsHelper.getInstance(myProject).showErrors(vcsCatchingRunnable.get(), IMPORT_TO_SHELF);
}
}
private static class TransitExtension implements PatchEP {
private final String myName;
private final Map<String, CharSequence> myMap;
private TransitExtension(String name, Map<String, CharSequence> map) {
myName = name;
myMap = map;
}
@NotNull
@Override
public String getName() {
return myName;
}
@Override
public CharSequence provideContent(@NotNull String path) {
return myMap.get(path);
}
@Override
public void consumeContent(@NotNull String path, @NotNull CharSequence content) {
throw new UnsupportedOperationException();
}
}
}
@@ -39,7 +39,7 @@ public class PatchWriter {
Writer writer = new OutputStreamWriter(new FileOutputStream(fileName));
try {
final String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator();
UnifiedDiffWriter.write(patches, writer, lineSeparator);
UnifiedDiffWriter.write(project, patches, writer, lineSeparator);
}
finally {
writer.close();
@@ -178,7 +178,7 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
myFileProcessor.savePathFile(
new CompoundShelfFileProcessor.ContentProvider(){
public void writeContentTo(final Writer writer) throws IOException {
UnifiedDiffWriter.write(patches, writer, "\n");
UnifiedDiffWriter.write(myProject, patches, writer, "\n");
}
},
patchPath);
@@ -198,13 +198,13 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
return changeList;
}
public ShelvedChangeList importFilePatches(final String fileName, final List<FilePatch> patches) throws IOException {
public ShelvedChangeList importFilePatches(final String fileName, final List<FilePatch> patches, final PatchEP[] patchTransitExtensions) throws IOException {
try {
final File patchPath = getPatchPath(fileName);
myFileProcessor.savePathFile(
new CompoundShelfFileProcessor.ContentProvider(){
public void writeContentTo(final Writer writer) throws IOException {
UnifiedDiffWriter.write(patches, writer, "\n");
UnifiedDiffWriter.write(patches, writer, "\n", patchTransitExtensions);
}
},
patchPath);
@@ -484,12 +484,12 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
return false;
}
private static void writePatchesToFile(final String path, final List<FilePatch> remainingPatches) {
private static void writePatchesToFile(final Project project, final String path, final List<FilePatch> remainingPatches) {
OutputStreamWriter writer;
try {
writer = new OutputStreamWriter(new FileOutputStream(path));
try {
UnifiedDiffWriter.write(remainingPatches, writer, "\n");
UnifiedDiffWriter.write(project, remainingPatches, writer, "\n");
}
finally {
writer.close();
@@ -514,7 +514,7 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
new ArrayList<ShelvedBinaryFile>(changeList.getBinaryFiles()));
listCopy.DATE = (changeList.DATE == null) ? null : new Date(changeList.DATE.getTime());
writePatchesToFile(changeList.PATH, remainingPatches);
writePatchesToFile(myProject, changeList.PATH, remainingPatches);
changeList.getBinaryFiles().retainAll(remainingBinaries);
changeList.clearLoadedChanges();
@@ -569,7 +569,7 @@ public class ShelveChangesManager implements ProjectComponent, JDOMExternalizabl
for (ShelvedChange change : listCopy.getChanges()) {
patches.add(change.loadFilePatch());
}
writePatchesToFile(listCopy.PATH, patches);
writePatchesToFile(myProject, listCopy.PATH, patches);
}
catch (IOException e) {
LOG.info(e);