forked from Qortal/qortal
Added support of patch creation from files without a newline at the end
The simplest solution was to only include a newline at the end of the patch file if the source file ended with a newline. This is used to inform the merge code as to whether to add the newline to the end of the resulting file. Without this, the checksums do not match (and therefore previously the complete file would have been included as a result).
This commit is contained in:
parent
361dc79ede
commit
2d853e5a2f
@ -10,6 +10,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.repository.DataException;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.FilesystemUtils;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
@ -72,6 +73,9 @@ public class UnifiedDiffPatch {
|
||||
List<String> original = FileUtils.readLines(before.toFile(), StandardCharsets.UTF_8);
|
||||
List<String> revised = FileUtils.readLines(after.toFile(), StandardCharsets.UTF_8);
|
||||
|
||||
// Check if the original file ends with a newline
|
||||
boolean endsWithNewline = FilesystemUtils.fileEndsWithNewline(before);
|
||||
|
||||
// Generate diff information
|
||||
Patch<String> diff = DiffUtils.diff(original, revised);
|
||||
|
||||
@ -83,9 +87,13 @@ public class UnifiedDiffPatch {
|
||||
// Write the diff to the destination directory
|
||||
FileWriter fileWriter = new FileWriter(destination.toString(), true);
|
||||
BufferedWriter writer = new BufferedWriter(fileWriter);
|
||||
for (String line : unifiedDiff) {
|
||||
for (int i=0; i<unifiedDiff.size(); i++) {
|
||||
String line = unifiedDiff.get(i);
|
||||
writer.append(line);
|
||||
writer.newLine();
|
||||
// Add a newline if this isn't the last line, or the original ended with a newline
|
||||
if (i < unifiedDiff.size()-1 || endsWithNewline) {
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
@ -173,6 +181,9 @@ public class UnifiedDiffPatch {
|
||||
List<String> originalContents = FileUtils.readLines(originalPath.toFile(), StandardCharsets.UTF_8);
|
||||
List<String> patchContents = FileUtils.readLines(patchPath.toFile(), StandardCharsets.UTF_8);
|
||||
|
||||
// Check if the patch file (and therefore the original file) ends with a newline
|
||||
boolean endsWithNewline = FilesystemUtils.fileEndsWithNewline(patchPath);
|
||||
|
||||
// At first, parse the unified diff file and get the patch
|
||||
Patch<String> patch = UnifiedDiffUtils.parseUnifiedDiff(patchContents);
|
||||
|
||||
@ -183,9 +194,15 @@ public class UnifiedDiffPatch {
|
||||
// Write the patched file to the merge directory
|
||||
FileWriter fileWriter = new FileWriter(mergePath.toString(), true);
|
||||
BufferedWriter writer = new BufferedWriter(fileWriter);
|
||||
for (String line : patchedContents) {
|
||||
for (int i=0; i<patchedContents.size(); i++) {
|
||||
String line = patchedContents.get(i);
|
||||
LOGGER.info("Applying line: %s", line);
|
||||
writer.append(line);
|
||||
writer.newLine();
|
||||
// Add a newline if this isn't the last line, or the original ended with a newline
|
||||
if (i < patchedContents.size()-1 || endsWithNewline) {
|
||||
LOGGER.info("Applying newline");
|
||||
writer.newLine();
|
||||
}
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
@ -6,6 +6,8 @@ import org.qortal.settings.Settings;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
|
||||
public class FilesystemUtils {
|
||||
@ -239,4 +241,23 @@ public class FilesystemUtils {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static byte[] readFromFile(String filePath, long position, int size) throws IOException {
|
||||
RandomAccessFile file = new RandomAccessFile(filePath, "r");
|
||||
file.seek(position);
|
||||
byte[] bytes = new byte[size];
|
||||
file.read(bytes);
|
||||
file.close();
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String readUtf8StringFromFile(String filePath, long position, int size) throws IOException {
|
||||
return new String(FilesystemUtils.readFromFile(filePath, position, size), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static boolean fileEndsWithNewline(Path path) throws IOException {
|
||||
long length = Files.size(path);
|
||||
String lastCharacter = FilesystemUtils.readUtf8StringFromFile(path.toString(), length-1, 1);
|
||||
return (lastCharacter.equals("\n") || lastCharacter.equals("\r"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -349,13 +349,12 @@ public class ArbitraryDataMergeTests extends Common {
|
||||
assertTrue(Files.exists(patchFilePath));
|
||||
byte[] patchDigest = Crypto.digest(patchFilePath.toFile());
|
||||
|
||||
// The patch file should be identical to file2, because we don't currently
|
||||
// support arbitrary diff patches on files without trailing newlines
|
||||
assertArrayEquals(patchDigest, file2Digest);
|
||||
|
||||
// Make sure that the patch file is different from file1
|
||||
assertFalse(Arrays.equals(patchDigest, file1Digest));
|
||||
|
||||
// Make sure that the patch file is different from file2
|
||||
assertFalse(Arrays.equals(patchDigest, file2Digest));
|
||||
|
||||
// Now merge the patch with the original path
|
||||
ArbitraryDataCombiner combiner = new ArbitraryDataCombiner(tempDir1, patchPath, signature);
|
||||
combiner.setShouldValidateHashes(true);
|
||||
|
Loading…
Reference in New Issue
Block a user