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 Path pathAfter;
|
||||||
private byte[] signatureBefore;
|
private byte[] signatureBefore;
|
||||||
private Path finalPath;
|
private Path finalPath;
|
||||||
|
ArbitraryDataMetadataPatch metadata;
|
||||||
|
|
||||||
public ArbitraryDataCombiner(Path pathBefore, Path pathAfter, byte[] signatureBefore) {
|
public ArbitraryDataCombiner(Path pathBefore, Path pathAfter, byte[] signatureBefore) {
|
||||||
this.pathBefore = pathBefore;
|
this.pathBefore = pathBefore;
|
||||||
@ -33,6 +34,7 @@ public class ArbitraryDataCombiner {
|
|||||||
public void combine() throws IOException {
|
public void combine() throws IOException {
|
||||||
try {
|
try {
|
||||||
this.preExecute();
|
this.preExecute();
|
||||||
|
this.readMetadata();
|
||||||
this.validatePreviousSignature();
|
this.validatePreviousSignature();
|
||||||
this.validatePreviousHash();
|
this.validatePreviousHash();
|
||||||
this.process();
|
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) {
|
if (this.signatureBefore == null) {
|
||||||
throw new IllegalStateException("No previous signature passed to the combiner");
|
throw new IllegalStateException("No previous signature passed to the combiner");
|
||||||
}
|
}
|
||||||
|
|
||||||
ArbitraryDataMetadataPatch metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
byte[] previousSignature = this.metadata.getPreviousSignature();
|
||||||
metadata.read();
|
|
||||||
byte[] previousSignature = metadata.getPreviousSignature();
|
|
||||||
if (previousSignature == null) {
|
if (previousSignature == null) {
|
||||||
throw new IllegalStateException("Unable to extract previous signature from patch metadata");
|
throw new IllegalStateException("Unable to extract previous signature from patch metadata");
|
||||||
}
|
}
|
||||||
@ -105,9 +110,7 @@ public class ArbitraryDataCombiner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validatePreviousHash() throws IOException {
|
private void validatePreviousHash() throws IOException {
|
||||||
ArbitraryDataMetadataPatch metadata = new ArbitraryDataMetadataPatch(this.pathAfter);
|
byte[] previousHash = this.metadata.getPreviousHash();
|
||||||
metadata.read();
|
|
||||||
byte[] previousHash = metadata.getPreviousHash();
|
|
||||||
if (previousHash == null) {
|
if (previousHash == null) {
|
||||||
throw new IllegalStateException("Unable to extract previous hash from patch metadata");
|
throw new IllegalStateException("Unable to extract previous hash from patch metadata");
|
||||||
}
|
}
|
||||||
@ -123,7 +126,8 @@ public class ArbitraryDataCombiner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void process() throws IOException {
|
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();
|
merge.compute();
|
||||||
this.finalPath = merge.getMergePath();
|
this.finalPath = merge.getMergePath();
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
package org.qortal.arbitrary;
|
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.commons.io.FileUtils;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.qortal.arbitrary.metadata.ArbitraryDataMetadataPatch;
|
import org.qortal.arbitrary.metadata.ArbitraryDataMetadataPatch;
|
||||||
import org.qortal.settings.Settings;
|
import org.qortal.settings.Settings;
|
||||||
import org.qortal.utils.FilesystemUtils;
|
import org.qortal.utils.FilesystemUtils;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ArbitraryDataMerge {
|
public class ArbitraryDataMerge {
|
||||||
@ -19,13 +28,15 @@ public class ArbitraryDataMerge {
|
|||||||
|
|
||||||
private Path pathBefore;
|
private Path pathBefore;
|
||||||
private Path pathAfter;
|
private Path pathAfter;
|
||||||
|
private String patchType;
|
||||||
private Path mergePath;
|
private Path mergePath;
|
||||||
private String identifier;
|
private String identifier;
|
||||||
private ArbitraryDataMetadataPatch metadata;
|
private ArbitraryDataMetadataPatch metadata;
|
||||||
|
|
||||||
public ArbitraryDataMerge(Path pathBefore, Path pathAfter) {
|
public ArbitraryDataMerge(Path pathBefore, Path pathAfter, String patchType) {
|
||||||
this.pathBefore = pathBefore;
|
this.pathBefore = pathBefore;
|
||||||
this.pathAfter = pathAfter;
|
this.pathAfter = pathAfter;
|
||||||
|
this.patchType = patchType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void compute() throws IOException {
|
public void compute() throws IOException {
|
||||||
@ -87,8 +98,7 @@ public class ArbitraryDataMerge {
|
|||||||
List<Path> modifiedPaths = this.metadata.getModifiedPaths();
|
List<Path> modifiedPaths = this.metadata.getModifiedPaths();
|
||||||
for (Path path : modifiedPaths) {
|
for (Path path : modifiedPaths) {
|
||||||
LOGGER.info("File was modified: {}", path.toString());
|
LOGGER.info("File was modified: {}", path.toString());
|
||||||
Path filePath = Paths.get(this.pathAfter.toString(), path.toString());
|
this.applyPatch(path);
|
||||||
ArbitraryDataMerge.copyPathToBaseDir(filePath, this.mergePath, path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Path> removedPaths = this.metadata.getRemovedPaths();
|
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 {
|
private void copyMetadata() throws IOException {
|
||||||
Path filePath = Paths.get(this.pathAfter.toString(), ".qortal");
|
Path filePath = Paths.get(this.pathAfter.toString(), ".qortal");
|
||||||
ArbitraryDataMerge.copyPathToBaseDir(filePath, this.mergePath, Paths.get(".qortal"));
|
ArbitraryDataMerge.copyPathToBaseDir(filePath, this.mergePath, Paths.get(".qortal"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user