|
|
|
@ -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")); |
|
|
|
|