use of org.locationtech.geogig.api.RevObject in project GeoGig by boundlessgeo.
the class VerifyPatchOp method _call.
/**
* Executes the verify command
*
* @return the result of checking if the patch can be applied
*/
protected VerifyPatchResults _call() throws RuntimeException {
Preconditions.checkArgument(patch != null, "No patch file provided");
Patch patch = reverse ? this.patch.reversed() : this.patch;
Patch toApply = new Patch();
Patch toReject = new Patch();
for (RevFeatureType ft : patch.getFeatureTypes()) {
toApply.addFeatureType(ft);
toReject.addFeatureType(ft);
}
String path;
Optional<RevObject> obj;
List<FeatureDiff> diffs = patch.getModifiedFeatures();
for (FeatureDiff diff : diffs) {
path = diff.getPath();
String refSpec = Ref.WORK_HEAD + ":" + path;
obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
if (!obj.isPresent()) {
toReject.addModifiedFeature(diff);
break;
}
RevFeature feature = (RevFeature) obj.get();
DepthSearch depthSearch = new DepthSearch(stagingDatabase());
Optional<NodeRef> noderef = depthSearch.find(workingTree().getTree(), path);
RevFeatureType featureType = command(RevObjectParse.class).setObjectId(noderef.get().getMetadataId()).call(RevFeatureType.class).get();
ImmutableList<PropertyDescriptor> descriptors = featureType.sortedDescriptors();
Set<Entry<PropertyDescriptor, AttributeDiff>> attrDiffs = diff.getDiffs().entrySet();
boolean ok = true;
for (Iterator<Entry<PropertyDescriptor, AttributeDiff>> iterator = attrDiffs.iterator(); iterator.hasNext(); ) {
Entry<PropertyDescriptor, AttributeDiff> entry = iterator.next();
AttributeDiff attrDiff = entry.getValue();
PropertyDescriptor descriptor = entry.getKey();
switch(attrDiff.getType()) {
case ADDED:
if (descriptors.contains(descriptor)) {
ok = false;
}
break;
case REMOVED:
case MODIFIED:
if (!descriptors.contains(descriptor)) {
ok = false;
break;
}
for (int i = 0; i < descriptors.size(); i++) {
if (descriptors.get(i).equals(descriptor)) {
Optional<Object> value = feature.getValues().get(i);
if (!attrDiff.canBeAppliedOn(value)) {
ok = false;
}
break;
}
}
}
}
if (!ok) {
toReject.addModifiedFeature(diff);
} else {
toApply.addModifiedFeature(diff);
}
}
List<FeatureInfo> added = patch.getAddedFeatures();
for (FeatureInfo feature : added) {
String refSpec = Ref.WORK_HEAD + ":" + feature.getPath();
obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
if (obj.isPresent()) {
toReject.addAddedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
} else {
toApply.addAddedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
}
}
List<FeatureInfo> removed = patch.getRemovedFeatures();
for (FeatureInfo feature : removed) {
String refSpec = Ref.WORK_HEAD + ":" + feature.getPath();
obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
if (!obj.isPresent()) {
toReject.addRemovedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
} else {
RevFeature revFeature = (RevFeature) obj.get();
DepthSearch depthSearch = new DepthSearch(stagingDatabase());
Optional<NodeRef> noderef = depthSearch.find(workingTree().getTree(), feature.getPath());
RevFeatureType revFeatureType = command(RevObjectParse.class).setObjectId(noderef.get().getMetadataId()).call(RevFeatureType.class).get();
RevFeature patchRevFeature = RevFeatureBuilder.build(feature.getFeature());
if (revFeature.equals(patchRevFeature) && revFeatureType.equals(feature.getFeatureType())) {
toApply.addRemovedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
} else {
toReject.addRemovedFeature(feature.getPath(), feature.getFeature(), feature.getFeatureType());
}
}
}
ImmutableList<FeatureTypeDiff> alteredTrees = patch.getAlteredTrees();
for (FeatureTypeDiff diff : alteredTrees) {
DepthSearch depthSearch = new DepthSearch(stagingDatabase());
Optional<NodeRef> noderef = depthSearch.find(workingTree().getTree(), diff.getPath());
ObjectId metadataId = noderef.isPresent() ? noderef.get().getMetadataId() : ObjectId.NULL;
if (Objects.equal(metadataId, diff.getOldFeatureType())) {
toApply.addAlteredTree(diff);
} else {
toReject.addAlteredTree(diff);
}
}
return new VerifyPatchResults(toApply, toReject);
}
use of org.locationtech.geogig.api.RevObject in project GeoGig by boundlessgeo.
the class ReportCommitConflictsOp method _call.
@Override
protected MergeScenarioReport _call() {
MergeScenarioReport report = new MergeScenarioReport();
ObjectId parentCommitId = ObjectId.NULL;
if (commit.getParentIds().size() > 0) {
parentCommitId = commit.getParentIds().get(0);
}
ObjectId parentTreeId = ObjectId.NULL;
Repository repository = repository();
if (repository.commitExists(parentCommitId)) {
parentTreeId = repository.getCommit(parentCommitId).getTreeId();
}
// get changes
Iterator<DiffEntry> diffs = command(DiffTree.class).setOldTree(parentTreeId).setNewTree(commit.getTreeId()).setReportTrees(true).call();
while (diffs.hasNext()) {
DiffEntry diff = diffs.next();
String path = diff.oldPath() == null ? diff.newPath() : diff.oldPath();
Optional<RevObject> obj = command(RevObjectParse.class).setRefSpec(Ref.HEAD + ":" + path).call();
switch(diff.changeType()) {
case ADDED:
if (obj.isPresent()) {
TYPE type = command(ResolveObjectType.class).setObjectId(diff.getNewObject().objectId()).call();
if (TYPE.TREE.equals(type)) {
NodeRef headVersion = command(FindTreeChild.class).setChildPath(path).setParent(repository.getOrCreateHeadTree()).call().get();
if (!headVersion.getMetadataId().equals(diff.getNewObject().getMetadataId())) {
report.addConflict(new Conflict(path, ObjectId.NULL, diff.getNewObject().getMetadataId(), headVersion.getMetadataId()));
}
} else {
if (!obj.get().getId().equals(diff.newObjectId())) {
report.addConflict(new Conflict(path, ObjectId.NULL, diff.newObjectId(), obj.get().getId()));
}
}
} else {
report.addUnconflicted(diff);
}
break;
case REMOVED:
if (obj.isPresent()) {
if (obj.get().getId().equals(diff.oldObjectId())) {
report.addUnconflicted(diff);
} else {
report.addConflict(new Conflict(path, diff.oldObjectId(), ObjectId.NULL, obj.get().getId()));
}
}
break;
case MODIFIED:
TYPE type = command(ResolveObjectType.class).setObjectId(diff.getNewObject().objectId()).call();
if (TYPE.TREE.equals(type)) {
// one
if (!diff.isChange()) {
report.addUnconflicted(diff);
}
} else {
String refSpec = Ref.HEAD + ":" + path;
obj = command(RevObjectParse.class).setRefSpec(refSpec).call();
if (!obj.isPresent()) {
// git reports this as a conflict but does not mark as conflicted, just adds
// the missing file.
// We add it and consider it unconflicted
report.addUnconflicted(diff);
break;
}
RevFeature feature = (RevFeature) obj.get();
DepthSearch depthSearch = new DepthSearch(repository.objectDatabase());
Optional<NodeRef> noderef = depthSearch.find(this.workingTree().getTree(), path);
RevFeatureType featureType = command(RevObjectParse.class).setObjectId(noderef.get().getMetadataId()).call(RevFeatureType.class).get();
ImmutableList<PropertyDescriptor> descriptors = featureType.sortedDescriptors();
FeatureDiff featureDiff = command(DiffFeature.class).setOldVersion(Suppliers.ofInstance(diff.getOldObject())).setNewVersion(Suppliers.ofInstance(diff.getNewObject())).call();
Set<Entry<PropertyDescriptor, AttributeDiff>> attrDiffs = featureDiff.getDiffs().entrySet();
RevFeature newFeature = command(RevObjectParse.class).setObjectId(diff.newObjectId()).call(RevFeature.class).get();
boolean ok = true;
for (Iterator<Entry<PropertyDescriptor, AttributeDiff>> iterator = attrDiffs.iterator(); iterator.hasNext() && ok; ) {
Entry<PropertyDescriptor, AttributeDiff> entry = iterator.next();
AttributeDiff attrDiff = entry.getValue();
PropertyDescriptor descriptor = entry.getKey();
switch(attrDiff.getType()) {
case ADDED:
if (descriptors.contains(descriptor)) {
ok = false;
}
break;
case REMOVED:
case MODIFIED:
if (!descriptors.contains(descriptor)) {
ok = false;
break;
}
for (int i = 0; i < descriptors.size(); i++) {
if (descriptors.get(i).equals(descriptor)) {
Optional<Object> value = feature.getValues().get(i);
Optional<Object> newValue = newFeature.getValues().get(i);
if (!newValue.equals(value)) {
// check
if (!attrDiff.canBeAppliedOn(value)) {
ok = false;
}
break;
}
}
}
}
}
if (ok) {
report.addUnconflicted(diff);
} else {
report.addConflict(new Conflict(path, diff.oldObjectId(), diff.newObjectId(), obj.get().getId()));
}
}
break;
}
}
return report;
}
use of org.locationtech.geogig.api.RevObject in project GeoGig by boundlessgeo.
the class PreOrderDiffWalk method traverseLeafBucket.
/**
* Compares a bucket tree (i.e. its size is greater than {@link RevTree#NORMALIZED_SIZE_LIMIT}
* and hence has been split into buckets) at the right side of the comparison, and a the
* {@link RevTree#children() children} nodes of a leaf tree at the left side of the comparison.
* <p>
* This happens when the right tree is much larger than the left tree
* <p>
* This traversal is symmetric to {@link #traverseBucketLeaf} so be careful that any change made
* to this method shall have a matching change at {@link #traverseBucketLeaf}
*
* @precondition {@code right.buckets().isPresent()}
*/
private void traverseLeafBucket(final Consumer consumer, final Iterator<Node> left, final RevTree right, final int bucketDepth) {
checkState(right.buckets().isPresent());
final SortedMap<Integer, Bucket> rightBuckets = right.buckets().get();
final ListMultimap<Integer, Node> nodesByBucket = splitNodesToBucketsAtDepth(left, bucketDepth);
final SortedSet<Integer> bucketIndexes = Sets.newTreeSet(Sets.union(rightBuckets.keySet(), nodesByBucket.keySet()));
// get all buckets at once, to leverage ObjectDatabase optimizations
final Map<ObjectId, RevObject> bucketTrees;
bucketTrees = uniqueIndex(rightSource.getAll(transform(rightBuckets.values(), BUCKET_ID)), OBJECT_ID);
for (Integer bucketIndex : bucketIndexes) {
Bucket rightBucket = rightBuckets.get(bucketIndex);
// never returns null, but empty
List<Node> leftNodes = nodesByBucket.get(bucketIndex);
if (null == rightBucket) {
traverseLeafLeaf(consumer, leftNodes.iterator(), Iterators.<Node>emptyIterator());
} else if (leftNodes.isEmpty()) {
if (consumer.bucket(bucketIndex, bucketDepth, null, rightBucket)) {
RevTree rightTree = (RevTree) bucketTrees.get(rightBucket.id());
// traverseBucketBucket(consumer, RevTree.EMPTY, rightTree, bucketDepth);
traverseTree(consumer, RevTree.EMPTY, rightTree, bucketDepth + 1);
}
consumer.endBucket(bucketIndex, bucketDepth, null, rightBucket);
} else {
RevTree rightTree = (RevTree) bucketTrees.get(rightBucket.id());
if (rightTree.buckets().isPresent()) {
traverseLeafBucket(consumer, leftNodes.iterator(), rightTree, bucketDepth + 1);
} else {
traverseLeafLeaf(consumer, leftNodes.iterator(), rightTree.children());
}
}
}
}
use of org.locationtech.geogig.api.RevObject in project GeoGig by boundlessgeo.
the class PreOrderDiffWalk method traverseBucketLeaf.
/**
* Compares a bucket tree (i.e. its size is greater than {@link RevTree#NORMALIZED_SIZE_LIMIT}
* and hence has been split into buckets) at the left side of the comparison, and a the
* {@link RevTree#children() children} nodes of a leaf tree at the right side of the comparison.
* <p>
* This happens when the left tree is much larger than the right tree
* <p>
* This traversal is symmetric to {@link #traverseLeafBucket} so be careful that any change made
* to this method shall have a matching change at {@link #traverseLeafBucket}
*
* @precondition {@code left.buckets().isPresent()}
*/
private void traverseBucketLeaf(final Consumer consumer, final RevTree left, final Iterator<Node> right, final int bucketDepth) {
checkState(left.buckets().isPresent());
final SortedMap<Integer, Bucket> leftBuckets = left.buckets().get();
final ListMultimap<Integer, Node> nodesByBucket = splitNodesToBucketsAtDepth(right, bucketDepth);
final SortedSet<Integer> bucketIndexes = Sets.newTreeSet(Sets.union(leftBuckets.keySet(), nodesByBucket.keySet()));
// get all buckets at once, to leverage ObjectDatabase optimizations
final Map<ObjectId, RevObject> bucketTrees;
bucketTrees = uniqueIndex(leftSource.getAll(transform(leftBuckets.values(), BUCKET_ID)), OBJECT_ID);
for (Integer bucketIndex : bucketIndexes) {
Bucket leftBucket = leftBuckets.get(bucketIndex);
// never returns null, but empty
List<Node> rightNodes = nodesByBucket.get(bucketIndex);
if (null == leftBucket) {
traverseLeafLeaf(consumer, Iterators.<Node>emptyIterator(), rightNodes.iterator());
} else if (rightNodes.isEmpty()) {
if (consumer.bucket(bucketIndex, bucketDepth, leftBucket, null)) {
RevTree leftTree = (RevTree) bucketTrees.get(leftBucket.id());
// traverseBucketBucket(consumer, leftTree, RevTree.EMPTY, bucketDepth);
traverseTree(consumer, leftTree, RevTree.EMPTY, bucketDepth + 1);
}
consumer.endBucket(bucketIndex, bucketDepth, leftBucket, null);
} else {
RevTree leftTree = (RevTree) bucketTrees.get(leftBucket.id());
if (leftTree.buckets().isPresent()) {
traverseBucketLeaf(consumer, leftTree, rightNodes.iterator(), bucketDepth + 1);
} else {
traverseLeafLeaf(consumer, leftTree.children(), rightNodes.iterator());
}
}
}
}
use of org.locationtech.geogig.api.RevObject in project GeoGig by boundlessgeo.
the class Patch method toString.
/**
* This method is not intended to serialize the patch, as it misses some needed information. To
* serialize the patch, use the {@link PatchSerializer} class instead. Use this method to show
* patch content in a human-readable format
*/
@Override
public String toString() {
TextSerializationFactory factory = new TextSerializationFactory();
StringBuilder sb = new StringBuilder();
for (FeatureInfo feature : addedFeatures) {
String path = feature.getPath();
sb.append("A\t" + path + "\t" + feature.getFeatureType().getId() + "\n");
ObjectWriter<RevObject> writer = factory.createObjectWriter(TYPE.FEATURE);
ByteArrayOutputStream output = new ByteArrayOutputStream();
RevFeature revFeature = RevFeatureBuilder.build(feature.getFeature());
try {
writer.write(revFeature, output);
} catch (IOException e) {
}
sb.append(output.toString());
sb.append('\n');
}
for (FeatureInfo feature : removedFeatures) {
String path = feature.getPath();
sb.append("R\t" + path + "\t" + feature.getFeatureType().getId() + "\n");
ObjectWriter<RevObject> writer = factory.createObjectWriter(TYPE.FEATURE);
ByteArrayOutputStream output = new ByteArrayOutputStream();
RevFeature revFeature = RevFeatureBuilder.build(feature.getFeature());
try {
writer.write(revFeature, output);
} catch (IOException e) {
}
sb.append(output.toString());
sb.append('\n');
}
for (FeatureDiff diff : modifiedFeatures) {
sb.append("M\t" + diff.getPath() + /*
* + "\t" + diff.getOldFeatureType().getId().toString()
* + "\t" + diff.getNewFeatureType().getId().toString()
*/
"\n");
sb.append(diff.toString() + "\n");
}
for (FeatureTypeDiff diff : alteredTrees) {
sb.append(featureTypeDiffAsString(diff) + "\n");
}
return sb.toString();
}
Aggregations