Skip to content

Commit

Permalink
Add versioning
Browse files Browse the repository at this point in the history
If a save file cannot be loaded, no changes happen to the pipeline and the user is notified. This will happen for any save file, pre-versioning or otherwise.

When saving a loaded project, the original version string will be changed to the version of GRIP that saved it. Pre-versioning save files will also be upgraded to the versioned format and have the current version of GRIP
  • Loading branch information
SamCarlberg committed Oct 26, 2016
1 parent 54d98ea commit f3a0f53
Show file tree
Hide file tree
Showing 53 changed files with 477 additions and 151 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ project(":core") {
compile group: 'org.bytedeco.javacpp-presets', name: 'videoinput', version: '0.200-1.1', classifier: os
compile group: 'org.python', name: 'jython', version: '2.7.0'
compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.9'
compile group: 'com.github.zafarkhaja', name: 'java-semver', version: '0.9.0'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4'
compile group: 'com.google.guava', name: 'guava', version: '19.0'
compile group: 'com.google.auto.value', name: 'auto-value', version: '1.2'
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/edu/wpi/grip/core/GripCoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import edu.wpi.grip.core.util.ExceptionWitness;
import edu.wpi.grip.core.util.GripMode;

import com.github.zafarkhaja.semver.Version;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;
import com.google.inject.AbstractModule;
Expand Down Expand Up @@ -125,6 +126,9 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
// Allow for just injecting the settings provider, instead of the whole pipeline
bind(SettingsProvider.class).to(Pipeline.class);

// Bind the current GRIP version.
bind(Version.class).toInstance(VersionManager.CURRENT_VERSION);

install(new FactoryModuleBuilder().build(new TypeLiteral<Connection.Factory<Object>>() {
}));

Expand Down
58 changes: 54 additions & 4 deletions core/src/main/java/edu/wpi/grip/core/Palette.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package edu.wpi.grip.core;

import edu.wpi.grip.core.events.OperationAddedEvent;
import edu.wpi.grip.core.sockets.Socket;

import com.google.common.collect.ImmutableList;
import com.google.common.eventbus.Subscribe;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.inject.Singleton;

Expand All @@ -24,10 +29,54 @@ public class Palette {

@Subscribe
public void onOperationAdded(OperationAddedEvent event) {
final OperationMetaData operation = event.getOperation();
map(operation.getDescription().name(), operation);
for (String alias : operation.getDescription().aliases()) {
map(alias, operation);
final OperationMetaData operationData = event.getOperation();
map(operationData.getDescription().name(), operationData);
for (String alias : operationData.getDescription().aliases()) {
map(alias, operationData);
}
// Validate that every input and output socket has a unique name and UID
Operation operation = operationData.getOperationSupplier().get();
try {
final List<? extends Socket> sockets = new ImmutableList.Builder<Socket>()
.addAll(operation.getInputSockets())
.addAll(operation.getOutputSockets())
.build();
checkDuplicates(
operationData,
"input socket names",
operation.getInputSockets(), s -> s.getSocketHint().getIdentifier()
);
checkDuplicates(
operationData,
"output socket names",
operation.getOutputSockets(), s -> s.getSocketHint().getIdentifier()
);
checkDuplicates(operationData, "socket IDs", sockets, Socket::getUid);
} finally {
operation.cleanUp();
}
}

private static <T, U> void checkDuplicates(OperationMetaData operationMetaData,
String type,
List<T> list,
Function<T, U> extractionFunction) {
List<U> duplicates = list.stream()
.map(extractionFunction)
.collect(Collectors.toList());
list.stream()
.map(extractionFunction)
.distinct()
.forEach(duplicates::remove);
if (!duplicates.isEmpty()) {
throw new IllegalArgumentException(
String.format(
"Duplicate %s found in operation %s: %s",
type,
operationMetaData.getDescription().name(),
duplicates
)
);
}
}

Expand All @@ -36,6 +85,7 @@ public void onOperationAdded(OperationAddedEvent event) {
*
* @param key The key the operation should be mapped to
* @param operation The operation to map the key to
*
* @throws IllegalArgumentException if the key is already in the {@link #operations} map.
*/
private void map(String key, OperationMetaData operation) {
Expand Down
38 changes: 38 additions & 0 deletions core/src/main/java/edu/wpi/grip/core/VersionManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package edu.wpi.grip.core;

import edu.wpi.grip.core.exception.IncompatibleVersionException;

import com.github.zafarkhaja.semver.Version;

/**
* Manager for GRIP versions.
*/
public final class VersionManager {

/**
* The final release of GRIP without versioned saves.
*/
public static final Version LAST_UNVERSIONED_RELEASE = Version.valueOf("1.5.0");

/**
* The current version of GRIP.
*/
public static final Version CURRENT_VERSION = Version.valueOf("2.0.0-beta");

/**
* Checks compatibility between two versions of GRIP.
*
* @param current the current version of GRIP
* @param check the version to check
*
* @throws IncompatibleVersionException if the versions are incompatible
*/
public static void checkVersionCompatibility(Version current, Version check)
throws IncompatibleVersionException {
if (check.getMajorVersion() > current.getMajorVersion()
|| check.getMinorVersion() > current.getMinorVersion()) {
throw new IncompatibleVersionException("Incompatible future version: " + check);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package edu.wpi.grip.core.exception;

/**
* An exception thrown when trying to load a saved project created in an incompatible version
* of GRIP.
*/
public class IncompatibleVersionException extends InvalidSaveException {

public IncompatibleVersionException(String message) {
super(message);
}

public IncompatibleVersionException(String message, Throwable cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.wpi.grip.core.exception;

/**
* An exception thrown when trying to load an invalid saved project.
*/
public class InvalidSaveException extends GripException {

public InvalidSaveException(String message) {
super(message);
}

public InvalidSaveException(String message, Throwable cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.wpi.grip.core.http;

import edu.wpi.grip.core.exception.InvalidSaveException;
import edu.wpi.grip.core.serialization.Project;
import edu.wpi.grip.core.util.GripMode;

Expand Down Expand Up @@ -43,9 +44,15 @@ protected void handleIfPassed(String target,
}
switch (mode) {
case HEADLESS:
project.open(new String(IOUtils.toByteArray(request.getInputStream()), "UTF-8"));
response.setStatus(HttpServletResponse.SC_CREATED);
baseRequest.setHandled(true);
try {
project.open(new String(IOUtils.toByteArray(request.getInputStream()), "UTF-8"));
response.setStatus(HttpServletResponse.SC_CREATED);
baseRequest.setHandled(true);
} catch (InvalidSaveException e) {
// 403 - Forbidden if given an invalid save
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
baseRequest.setHandled(true);
}
break;
case GUI:
// Don't run in GUI mode, it doesn't make much sense and can easily deadlock if pipelines
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ public class BlurOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public BlurOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.typeSocket = inputSocketFactory.create(typeHint);
this.radiusSocket = inputSocketFactory.create(radiusHint);
this.inputSocket = inputSocketFactory.create(inputHint, "source-image");
this.typeSocket = inputSocketFactory.create(typeHint, "blur-type");
this.radiusSocket = inputSocketFactory.create(radiusHint, "blur-radius");

this.outputSocket = outputSocketFactory.create(outputHint);
this.outputSocket = outputSocketFactory.create(outputHint, "result");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,21 @@ public class ConvexHullsOperation implements Operation {
.category(OperationDescription.Category.FEATURE_DETECTION)
.build();

private final SocketHint<ContoursReport> contoursHint = new SocketHint.Builder<>(ContoursReport
.class)
.identifier("Contours").initialValueSupplier(ContoursReport::new).build();
private final SocketHint<ContoursReport> contoursHint =
new SocketHint.Builder<>(ContoursReport.class)
.identifier("Contours")
.initialValueSupplier(ContoursReport::new)
.build();

private final InputSocket<ContoursReport> inputSocket;
private final OutputSocket<ContoursReport> outputSocket;

@SuppressWarnings("JavadocMethod")
public ConvexHullsOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(contoursHint);
this.inputSocket = inputSocketFactory.create(contoursHint, "contours");

this.outputSocket = outputSocketFactory.create(contoursHint);
this.outputSocket = outputSocketFactory.create(contoursHint, "hulls");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public class DesaturateOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public DesaturateOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.outputSocket = outputSocketFactory.create(outputHint);
this.inputSocket = inputSocketFactory.create(inputHint, "source-image");
this.outputSocket = outputSocketFactory.create(outputHint, "result");
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ public class DistanceTransformOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public DistanceTransformOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.srcSocket = inputSocketFactory.create(srcHint);
this.typeSocket = inputSocketFactory.create(typeHint);
this.maskSizeSocket = inputSocketFactory.create(maskSizeHint);
this.srcSocket = inputSocketFactory.create(srcHint, "source-image");
this.typeSocket = inputSocketFactory.create(typeHint, "transform-type");
this.maskSizeSocket = inputSocketFactory.create(maskSizeHint, "mask-size");

this.outputSocket = outputSocketFactory.create(outputHint);
this.outputSocket = outputSocketFactory.create(outputHint, "result");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +95,20 @@ public class FilterContoursOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public FilterContoursOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.contoursSocket = inputSocketFactory.create(contoursHint);
this.minAreaSocket = inputSocketFactory.create(minAreaHint);
this.minPerimeterSocket = inputSocketFactory.create(minPerimeterHint);
this.minWidthSocket = inputSocketFactory.create(minWidthHint);
this.maxWidthSocket = inputSocketFactory.create(maxWidthHint);
this.minHeightSocket = inputSocketFactory.create(minHeightHint);
this.maxHeightSocket = inputSocketFactory.create(maxHeightHint);
this.soliditySocket = inputSocketFactory.create(solidityHint);
this.minVertexSocket = inputSocketFactory.create(minVertexHint);
this.maxVertexSocket = inputSocketFactory.create(maxVertexHint);
this.minRatioSocket = inputSocketFactory.create(minRatioHint);
this.maxRatioSocket = inputSocketFactory.create(maxRatioHint);

this.outputSocket = outputSocketFactory.create(contoursHint);
this.contoursSocket = inputSocketFactory.create(contoursHint, "contours");
this.minAreaSocket = inputSocketFactory.create(minAreaHint, "min-area");
this.minPerimeterSocket = inputSocketFactory.create(minPerimeterHint, "min-perimeter");
this.minWidthSocket = inputSocketFactory.create(minWidthHint, "min-width");
this.maxWidthSocket = inputSocketFactory.create(maxWidthHint, "max-width");
this.minHeightSocket = inputSocketFactory.create(minHeightHint, "min-height");
this.maxHeightSocket = inputSocketFactory.create(maxHeightHint, "max-height");
this.soliditySocket = inputSocketFactory.create(solidityHint, "solidity");
this.minVertexSocket = inputSocketFactory.create(minVertexHint, "min-vertices");
this.maxVertexSocket = inputSocketFactory.create(maxVertexHint, "max-vertices");
this.minRatioSocket = inputSocketFactory.create(minRatioHint, "min-ratio");
this.maxRatioSocket = inputSocketFactory.create(maxRatioHint, "max-ratio");

this.outputSocket = outputSocketFactory.create(contoursHint, "filtered-contours");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ public class FilterLinesOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public FilterLinesOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.minLengthSocket = inputSocketFactory.create(minLengthHint);
this.angleSocket = inputSocketFactory.create(angleHint);
this.inputSocket = inputSocketFactory.create(inputHint, "lines");
this.minLengthSocket = inputSocketFactory.create(minLengthHint, "min-length");
this.angleSocket = inputSocketFactory.create(angleHint, "angle");

this.linesOutputSocket = outputSocketFactory.create(outputHint);
this.linesOutputSocket = outputSocketFactory.create(outputHint, "filtered-lines");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ public class FindBlobsOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public FindBlobsOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.minAreaSocket = inputSocketFactory.create(minAreaHint);
this.circularitySocket = inputSocketFactory.create(circularityHint);
this.colorSocket = inputSocketFactory.create(colorHint);
this.inputSocket = inputSocketFactory.create(inputHint, "source-image");
this.minAreaSocket = inputSocketFactory.create(minAreaHint, "min-area");
this.circularitySocket = inputSocketFactory.create(circularityHint, "circularity");
this.colorSocket = inputSocketFactory.create(colorHint, "find-dark-blobs");

this.outputSocket = outputSocketFactory.create(blobsHint);
this.outputSocket = outputSocketFactory.create(blobsHint, "found-blobs");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ public class FindContoursOperation implements Operation {
@SuppressWarnings("JavadocMethod")
public FindContoursOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.externalSocket = inputSocketFactory.create(externalHint);
this.inputSocket = inputSocketFactory.create(inputHint, "source-image");
this.externalSocket = inputSocketFactory.create(externalHint, "find-external-only");

this.contoursSocket = outputSocketFactory.create(contoursHint);
this.contoursSocket = outputSocketFactory.create(contoursHint, "found-contours");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public class FindLinesOperation implements Operation {

public FindLinesOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.linesReportSocket = outputSocketFactory.create(linesHint);
this.inputSocket = inputSocketFactory.create(inputHint, "source-image");
this.linesReportSocket = outputSocketFactory.create(linesHint, "found-lines");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ public class HSLThresholdOperation extends ThresholdOperation {
@SuppressWarnings("JavadocMethod")
public HSLThresholdOperation(InputSocket.Factory inputSocketFactory, OutputSocket.Factory
outputSocketFactory) {
this.inputSocket = inputSocketFactory.create(inputHint);
this.hueSocket = inputSocketFactory.create(hueHint);
this.saturationSocket = inputSocketFactory.create(saturationHint);
this.luminanceSocket = inputSocketFactory.create(luminanceHint);
this.inputSocket = inputSocketFactory.create(inputHint, "source-image");
this.hueSocket = inputSocketFactory.create(hueHint, "hue");
this.saturationSocket = inputSocketFactory.create(saturationHint, "saturation");
this.luminanceSocket = inputSocketFactory.create(luminanceHint, "luminance");

this.outputSocket = outputSocketFactory.create(outputHint);
this.outputSocket = outputSocketFactory.create(outputHint, "result");
}

@Override
Expand Down
Loading

0 comments on commit f3a0f53

Please sign in to comment.