io.bdeploy.bhive.objects.view.scanner.TreeDiff Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of api Show documentation
Show all versions of api Show documentation
Public API including dependencies, ready to be used for integrations and plugins.
The newest version!
package io.bdeploy.bhive.objects.view.scanner;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import io.bdeploy.bhive.model.ObjectId;
import io.bdeploy.bhive.model.Tree;
import io.bdeploy.bhive.model.Tree.EntryType;
import io.bdeploy.bhive.objects.view.BlobView;
import io.bdeploy.bhive.objects.view.ElementView;
import io.bdeploy.bhive.objects.view.ManifestRefView;
import io.bdeploy.bhive.objects.view.TreeView;
/**
* Used to calculate the differences of two {@link TreeView}s.
*/
public class TreeDiff {
private final TreeView left;
private final TreeView right;
public TreeDiff(TreeView left, TreeView right) {
this.left = left;
this.right = right;
}
/**
* @return the actual differences of the two {@link TreeView}s.
*/
public List diff() {
FlattenedTree flatLeft = new FlattenedTree(left);
FlattenedTree flatRight = new FlattenedTree(right);
Map itemsLeft = flatLeft.flatten();
Map itemsRight = flatRight.flatten();
Set keysOnlyLeft = new TreeSet<>(itemsLeft.keySet());
Set keysOnlyRight = new TreeSet<>(itemsRight.keySet());
keysOnlyLeft.removeAll(itemsRight.keySet());
keysOnlyRight.removeAll(itemsLeft.keySet());
List diffs = new ArrayList<>();
keysOnlyLeft.forEach(k -> diffs.add(TreeElementDiff.onlyLeft(itemsLeft.get(k).element, itemsLeft.get(k).type)));
keysOnlyRight.forEach(k -> diffs.add(TreeElementDiff.onlyRight(itemsRight.get(k).element, itemsRight.get(k).type)));
Set keysOnBoth = new TreeSet<>(itemsLeft.keySet());
keysOnBoth.retainAll(itemsRight.keySet());
for (String k : keysOnBoth) {
FlattenedTreeEntry entryLeft = itemsLeft.get(k);
FlattenedTreeEntry entryRight = itemsRight.get(k);
ObjectId leftMfRef = null;
ObjectId rightMfRef = null;
if (entryLeft.element instanceof ManifestRefView) {
leftMfRef = ((ManifestRefView) entryLeft.element).getReferenceId();
}
if (entryRight.element instanceof ManifestRefView) {
rightMfRef = ((ManifestRefView) entryRight.element).getReferenceId();
}
if (Objects.equals(leftMfRef, rightMfRef)
&& entryLeft.element.getElementId().equals(entryRight.element.getElementId())) {
continue;
}
diffs.add(TreeElementDiff.content(entryLeft.element, entryRight.element, entryLeft.type, entryRight.type));
}
return diffs;
}
/**
* A flat representation of a {@link TreeView}. Paths within a {@link TreeView} are guaranteed to be unique, this this
* {@link FlattenedTree} can safely use them as key.
*/
private static class FlattenedTree {
private final Map result = new TreeMap<>();
private final TreeView snapshot;
public FlattenedTree(TreeView snapshot) {
this.snapshot = snapshot;
}
/**
* Recursively visits the {@link TreeView} and indexes all elements to a flat {@link Map}.
*/
synchronized Map flatten() {
if (!result.isEmpty()) {
return result;
}
snapshot.visit(new TreeVisitor.Builder().onMissing(TreeDiff.FlattenedTree::invalid)
.onSkipped(TreeDiff.FlattenedTree::invalid).onBlob(this::blob).onManifestRef(this::manifest)
.onTree(this::tree).build());
return result;
}
private void add(ElementView s, Tree.EntryType t) {
result.put(s.getPathString(), new FlattenedTreeEntry(s, t));
}
private void blob(BlobView b) {
add(b, EntryType.BLOB);
}
private void manifest(ManifestRefView m) {
add(m, EntryType.MANIFEST);
}
private Boolean tree(TreeView t) {
if (t instanceof ManifestRefView) {
return true; // handled by #manifest(ManifestRefSnapshot)
}
add(t, EntryType.TREE);
return true;
}
private static void invalid(ElementView sn) {
throw new IllegalStateException(
"Diff on damaged trees not supported, missing " + sn.getPath() + " [" + sn.getElementId() + "]");
}
}
private static class FlattenedTreeEntry {
private final ElementView element;
private final Tree.EntryType type;
FlattenedTreeEntry(ElementView element, Tree.EntryType type) {
this.element = element;
this.type = type;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy