forked from Qortal/qortal
Apply the unified-diff patch when combining layers.
This commit is contained in:
parent
cb6fc466d1
commit
9a88c0d579
@ -23,6 +23,7 @@ public class ArbitraryDataCombiner {
|
||||
private Path pathAfter;
|
||||
private byte[] signatureBefore;
|
||||
private Path finalPath;
|
||||
ArbitraryDataMetadataPatch metadata;
|
||||
|
||||
public ArbitraryDataCombiner(Path pathBefore, Path pathAfter, byte[] signatureBefore) {
|
||||
this.pathBefore = pathBefore;
|
||||
@ -33,6 +34,7 @@ public class ArbitraryDataCombiner {
|
||||
public void combine() throws IOException {
|
||||
try {
|
||||
this.preExecute();
|
||||
this.readMetadata();
|
||||
this.validatePreviousSignature();
|
||||
this.validatePreviousHash();
|
||||
this.process();
|
||||
@ -86,14 +88,17 @@ public class ArbitraryDataCombiner {
|
||||
|
||||
}
|
||||
|
||||
private void validatePreviousSignature() throws IOException {
|
||||
private void readMetadata() throws IOException {
|
||||
this.metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
||||
this.metadata.read();
|
||||
}
|
||||
|
||||
private void validatePreviousSignature() {
|
||||
if (this.signatureBefore == null) {
|
||||
throw new IllegalStateException("No previous signature passed to the combiner");
|
||||
}
|
||||
|
||||
ArbitraryDataMetadataPatch metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
||||
metadata.read();
|
||||
byte[] previousSignature = metadata.getPreviousSignature();
|
||||
byte[] previousSignature = this.metadata.getPreviousSignature();
|
||||
if (previousSignature == null) {
|
||||
throw new IllegalStateException("Unable to extract previous signature from patch metadata");
|
||||
}
|
||||
@ -105,9 +110,7 @@ public class ArbitraryDataCombiner {
|
||||
}
|
||||
|
||||
private void validatePreviousHash() throws IOException {
|
||||
ArbitraryDataMetadataPatch metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
||||
metadata.read();
|
||||
byte[] previousHash = metadata.getPreviousHash();
|
||||
byte[] previousHash = this.metadata.getPreviousHash();
|
||||
if (previousHash == null) {
|
||||
throw new IllegalStateException("Unable to extract previous hash from patch metadata");
|
||||
}
|
||||
@ -123,7 +126,8 @@ public class ArbitraryDataCombiner {
|
||||
}
|
||||
|
||||
private void process() throws IOException {
|
||||
ArbitraryDataMerge merge = new ArbitraryDataMerge(this.pathBefore, this.pathAfter);
|
||||
String patchType = metadata.getPatchType();
|
||||
ArbitraryDataMerge merge = new ArbitraryDataMerge(this.pathBefore, this.pathAfter, metadata.getPatchType());
|
||||
merge.compute();
|
||||
this.finalPath = merge.getMergePath();
|
||||
}
|
||||
|
@ -1,16 +1,25 @@
|
||||
package org.qortal.arbitrary;
|
||||
|
||||
import com.github.difflib.DiffUtils;
|
||||
import com.github.difflib.UnifiedDiffUtils;
|
||||
import com.github.difflib.patch.Patch;
|
||||
import com.github.difflib.patch.PatchFailedException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.qortal.arbitrary.metadata.ArbitraryDataMetadataPatch;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.FilesystemUtils;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ArbitraryDataMerge {
|
||||
@ -19,13 +28,15 @@ public class ArbitraryDataMerge {
|
||||
|
||||
private Path pathBefore;
|
||||
private Path pathAfter;
|
||||
private String patchType;
|
||||
private Path mergePath;
|
||||
private String identifier;
|
||||
private ArbitraryDataMetadataPatch metadata;
|
||||
|
||||
public ArbitraryDataMerge(Path pathBefore, Path pathAfter) {
|
||||
public ArbitraryDataMerge(Path pathBefore, Path pathAfter, String patchType) {
|
||||
this.pathBefore = pathBefore;
|
||||
this.pathAfter = pathAfter;
|
||||
this.patchType = patchType;
|
||||
}
|
||||
|
||||
public void compute() throws IOException {
|
||||
@ -87,8 +98,7 @@ public class ArbitraryDataMerge {
|
||||
List<Path> modifiedPaths = this.metadata.getModifiedPaths();
|
||||
for (Path path : modifiedPaths) {
|
||||
LOGGER.info("File was modified: {}", path.toString());
|
||||
Path filePath = Paths.get(this.pathAfter.toString(), path.toString());
|
||||
ArbitraryDataMerge.copyPathToBaseDir(filePath, this.mergePath, path);
|
||||
this.applyPatch(path);
|
||||
}
|
||||
|
||||
List<Path> removedPaths = this.metadata.getRemovedPaths();
|
||||
@ -98,6 +108,60 @@ public class ArbitraryDataMerge {
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPatch(Path path) throws IOException {
|
||||
if (Objects.equals(this.patchType, "unified-diff")) {
|
||||
// Create destination file from patch
|
||||
this.applyUnifiedDiffPatch(path);
|
||||
}
|
||||
else {
|
||||
// Copy complete file
|
||||
Path filePath = Paths.get(this.pathAfter.toString(), path.toString());
|
||||
ArbitraryDataMerge.copyPathToBaseDir(filePath, this.mergePath, path);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyUnifiedDiffPatch(Path path) throws IOException {
|
||||
Path originalPath = Paths.get(this.pathBefore.toString(), path.toString());
|
||||
Path patchPath = Paths.get(this.pathAfter.toString(), path.toString());
|
||||
Path mergePath = Paths.get(this.mergePath.toString(), path.toString());
|
||||
|
||||
if (!patchPath.toFile().exists()) {
|
||||
// Patch file doesn't exist, but its path was included in modifiedPaths
|
||||
// TODO: We ought to throw an exception here, but skipping for now
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete an existing file, as we are starting from a duplicate of pathBefore
|
||||
File destFile = mergePath.toFile();
|
||||
if (destFile.exists() && destFile.isFile()) {
|
||||
Files.delete(mergePath);
|
||||
}
|
||||
|
||||
List<String> originalContents = FileUtils.readLines(originalPath.toFile(), StandardCharsets.UTF_8);
|
||||
List<String> patchContents = FileUtils.readLines(patchPath.toFile(), StandardCharsets.UTF_8);
|
||||
|
||||
// At first, parse the unified diff file and get the patch
|
||||
Patch<String> patch = UnifiedDiffUtils.parseUnifiedDiff(patchContents);
|
||||
|
||||
// Then apply the computed patch to the given text
|
||||
try {
|
||||
List<String> patchedContents = DiffUtils.patch(originalContents, patch);
|
||||
|
||||
// Write the patched file to the merge directory
|
||||
FileWriter fileWriter = new FileWriter(mergePath.toString(), true);
|
||||
BufferedWriter writer = new BufferedWriter(fileWriter);
|
||||
for (String line : patchedContents) {
|
||||
writer.append(line);
|
||||
writer.newLine();
|
||||
}
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
} catch (PatchFailedException e) {
|
||||
throw new IllegalStateException(String.format("Failed to apply patch for path %s: %s", path, e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void copyMetadata() throws IOException {
|
||||
Path filePath = Paths.get(this.pathAfter.toString(), ".qortal");
|
||||
ArbitraryDataMerge.copyPathToBaseDir(filePath, this.mergePath, Paths.get(".qortal"));
|
||||
|
Loading…
Reference in New Issue
Block a user