Skip to content

Commit

Permalink
feat: dont delete output when equal to input, add ignorePrefixes opti…
Browse files Browse the repository at this point in the history
…ons to PatchOperation (#7)

* feat: add emptyOutput and ignorePrefixes options to PatchOperation

* make emptyOutput implicit, add tests

* actually make sure basePath is a path
  • Loading branch information
MiniDigger authored Apr 2, 2024
1 parent 9f9eeda commit 07808bf
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 21 deletions.
17 changes: 1 addition & 16 deletions src/main/java/codechicken/diffpatch/cli/DiffOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Consumer;

import static codechicken.diffpatch.util.LogLevel.*;
import static codechicken.diffpatch.util.Utils.filterPrefixed;
import static codechicken.diffpatch.util.Utils.indexChildren;

/**
Expand Down Expand Up @@ -307,21 +307,6 @@ public List<String> doDiff(DiffSummary summary, String aName, String bName, List
return patchFile.toLines(autoHeader);
}

private static Set<String> filterPrefixed(Set<String> toFilter, String[] filters) {
if (filters.length == 0) return toFilter;

return FastStream.of(toFilter)
.filterNot(e -> {
for (String s : filters) {
if (e.startsWith(s)) {
return true;
}
}
return false;
})
.toSet();
}

public static class DiffSummary {

public int unchangedFiles;
Expand Down
24 changes: 19 additions & 5 deletions src/main/java/codechicken/diffpatch/cli/PatchOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.function.Function;

import static codechicken.diffpatch.util.LogLevel.*;
import static codechicken.diffpatch.util.Utils.filterPrefixed;
import static codechicken.diffpatch.util.Utils.indexChildren;
import static net.covers1624.quack.io.IOUtils.makeParents;
import static net.covers1624.quack.util.SneakyUtils.sneak;
Expand All @@ -45,8 +46,9 @@ public class PatchOperation extends CliOperation<PatchOperation.PatchesSummary>
private final PatchMode mode;
private final String patchesPrefix;
private final String lineEnding;
private final String[] ignorePrefixes;

private PatchOperation(PrintStream logger, LogLevel level, Consumer<PrintStream> helpCallback, boolean summary, InputPath basePath, InputPath patchesPath, String aPrefix, String bPrefix, OutputPath outputPath, OutputPath rejectsPath, float minFuzz, int maxOffset, PatchMode mode, String patchesPrefix, String lineEnding) {
private PatchOperation(PrintStream logger, LogLevel level, Consumer<PrintStream> helpCallback, boolean summary, InputPath basePath, InputPath patchesPath, String aPrefix, String bPrefix, OutputPath outputPath, OutputPath rejectsPath, float minFuzz, int maxOffset, PatchMode mode, String patchesPrefix, String lineEnding, String[] ignorePrefixes) {
super(logger, level, helpCallback);
this.summary = summary;
this.basePath = basePath;
Expand All @@ -60,6 +62,7 @@ private PatchOperation(PrintStream logger, LogLevel level, Consumer<PrintStream>
this.mode = mode;
this.patchesPrefix = patchesPrefix;
this.lineEnding = lineEnding;
this.ignorePrefixes = ignorePrefixes;
}

public static Builder builder() {
Expand Down Expand Up @@ -172,11 +175,12 @@ public Result<PatchesSummary> operate() throws IOException {

try (ArchiveReader baseReader = basePath.getFormat().createReader(basePath.open())) {
try (ArchiveReader patchesReader = patchesPath.getFormat().createReader(patchesPath.open(), patchesPrefix)) {
Set<String> filteredBaseIndex = filterPrefixed(baseReader.getEntries(), ignorePrefixes);
patchSuccess = doPatch(
outputCollector,
rejectCollector,
summary,
baseReader.getEntries(),
filteredBaseIndex,
patchesReader.getEntries(),
sneak(baseReader::getBytes),
sneak(patchesReader::getBytes),
Expand All @@ -191,11 +195,12 @@ public Result<PatchesSummary> operate() throws IOException {
if (!basePath.isFile() && !patchesPath.isFile()) {
Map<String, Path> baseIndex = indexChildren(basePath.toPath());
Map<String, Path> patchIndex = indexChildren(patchesPath.toPath(), patchesPrefix);
Set<String> filteredBaseIndex = filterPrefixed( baseIndex.keySet(), ignorePrefixes);
patchSuccess = doPatch(
outputCollector,
rejectCollector,
summary,
baseIndex.keySet(),
filteredBaseIndex,
patchIndex.keySet(),
SneakyUtils.<String, byte[]>sneak(e -> Files.readAllBytes(baseIndex.get(e))),
SneakyUtils.<String, byte[]>sneak(e -> Files.readAllBytes(patchIndex.get(e))),
Expand Down Expand Up @@ -238,6 +243,7 @@ public Result<PatchesSummary> operate() throws IOException {
baseFunc = sneak(reader::getBytes);
}
}
baseIndex = filterPrefixed(baseIndex, ignorePrefixes);
patchSuccess = doPatch(outputCollector, rejectCollector, summary, baseIndex, patchIndex, baseFunc, patchFunc, minFuzz, maxOffset, mode);
}
}
Expand All @@ -249,7 +255,8 @@ public Result<PatchesSummary> operate() throws IOException {
}
}
} else {
if (Files.exists(outputPath.toPath())) {
boolean isInPlaceOperation = basePath.getType().isPath() && basePath.toPath().equals(outputPath.toPath());
if (!isInPlaceOperation && Files.exists(outputPath.toPath())) {
Utils.deleteFolder(outputPath.toPath());
}
for (Map.Entry<String, CollectedEntry> entry : outputCollector.get().entrySet()) {
Expand Down Expand Up @@ -533,6 +540,8 @@ public static class Builder {
private String bPrefix = "b/";
private String lineEnding = System.lineSeparator();

private final List<String> ignorePrefixes = new LinkedList<>();

private Builder() {
}

Expand Down Expand Up @@ -665,6 +674,11 @@ public Builder lineEnding(String lineEnding) {
return this;
}

public Builder ignorePrefix(String prefix) {
ignorePrefixes.add(prefix);
return this;
}

public PatchOperation build() {
if (basePath == null) {
throw new IllegalStateException("basePath not set.");
Expand All @@ -675,7 +689,7 @@ public PatchOperation build() {
if (outputPath == null) {
throw new IllegalStateException("output not set.");
}
return new PatchOperation(logger, level, helpCallback, summary, basePath, patchesPath, aPrefix, bPrefix, outputPath, rejectsPath, minFuzz, maxOffset, mode, patchesPrefix, lineEnding);
return new PatchOperation(logger, level, helpCallback, summary, basePath, patchesPath, aPrefix, bPrefix, outputPath, rejectsPath, minFuzz, maxOffset, mode, patchesPrefix, lineEnding, ignorePrefixes.toArray(new String[0]));
}

}
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/codechicken/diffpatch/util/Utils.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package codechicken.diffpatch.util;

import net.covers1624.quack.collection.FastStream;
import net.covers1624.quack.util.SneakyUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -43,4 +45,19 @@ public static Map<String, Path> indexChildren(Path toIndex, String prefix) throw
.collect(Collectors.toMap(e -> stripStart('/', finalToIndex.relativize(e).toString().replace("\\", "/")), Function.identity()));
}
}

public static Set<String> filterPrefixed(Set<String> toFilter, String[] filters) {
if (filters.length == 0) return toFilter;

return FastStream.of(toFilter)
.filterNot(e -> {
for (String s : filters) {
if (e.startsWith(s)) {
return true;
}
}
return false;
})
.toSet();
}
}
31 changes: 31 additions & 0 deletions src/test/java/codechicken/diffpatch/test/PatchOperationTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void testFolderToFolder() throws Throwable {
Path src = tempDir.resolve("src");
Path patches = tempDir.resolve("patches");
copyResource("/data/orig/PatchFile.java", orig.resolve("PatchFile.java"));
copyResource("/data/orig/A.txt", orig.resolve("A.txt"));
copyResource("/data/src/PatchFile.java", cmp.resolve("PatchFile.java"));
copyResource("/data/patches/PatchFile.java.patch", patches.resolve("PatchFile.java.patch"));
CliOperation.Result<PatchOperation.PatchesSummary> result = PatchOperation.builder()
Expand All @@ -40,15 +41,45 @@ public void testFolderToFolder() throws Throwable {
.basePath(orig)
.outputPath(src)
.patchesPath(patches)
.ignorePrefix("A")
.build()
.operate();
assertEquals(0, result.exit);
assertTrue(Files.exists(src.resolve("PatchFile.java")));
assertFalse(Files.exists(src.resolve("A.txt")), "A is ignored, A.txt should not have been copied");
List<String> output = Files.readAllLines(src.resolve("PatchFile.java"));
List<String> original = Files.readAllLines(cmp.resolve("PatchFile.java"));
assertEquals(output, original);
}

@Test
public void testFolderInplace() throws Throwable {
Path tempDir = Files.createTempDirectory("dir_test");
tempDir.toFile().deleteOnExit();
Path orig = tempDir.resolve("orig");
Path cmp = tempDir.resolve("cmp");
Path patches = tempDir.resolve("patches");
copyResource("/data/orig/PatchFile.java", orig.resolve("PatchFile.java"));
copyResource("/data/orig/A.txt", orig.resolve("A.txt"));
copyResource("/data/src/PatchFile.java", cmp.resolve("PatchFile.java"));
copyResource("/data/patches/PatchFile.java.patch", patches.resolve("PatchFile.java.patch"));
CliOperation.Result<PatchOperation.PatchesSummary> result = PatchOperation.builder()
.logTo(System.out)
.level(LogLevel.ALL)
.basePath(orig)
.outputPath(orig)
.patchesPath(patches)
.ignorePrefix("A")
.build()
.operate();
assertEquals(0, result.exit);
assertTrue(Files.exists(orig.resolve("PatchFile.java")));
assertTrue(Files.exists(orig.resolve("A.txt")), "A is ignored, A.txt should not have been deleted");
List<String> output = Files.readAllLines(orig.resolve("PatchFile.java"));
List<String> original = Files.readAllLines(cmp.resolve("PatchFile.java"));
assertEquals(output, original);
}

@Test
public void testFolderToZip() throws Throwable {
Path tempDir = Files.createTempDirectory("dir_test");
Expand Down

0 comments on commit 07808bf

Please sign in to comment.