Skip to content

Commit

Permalink
Allow flexibly-ordered inputs/values
Browse files Browse the repository at this point in the history
  • Loading branch information
lukebemish committed Nov 7, 2024
1 parent ad5aed1 commit 61dd129
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.lukebemish.taskgraphrunner.model.ListContentsHashStrategy;
import dev.lukebemish.taskgraphrunner.model.Input;
import dev.lukebemish.taskgraphrunner.model.InputValue;
import dev.lukebemish.taskgraphrunner.model.PathSensitivity;
Expand All @@ -12,6 +13,7 @@
import dev.lukebemish.taskgraphrunner.runtime.util.JsonUtils;
import org.jspecify.annotations.Nullable;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
Expand All @@ -20,6 +22,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -249,7 +252,7 @@ public JsonElement recordedValue(Context context) {
}
}

record SimpleFileListInput(String name, List<HasFileInput> inputs) implements FileListInput {
record SimpleFileListInput(String name, List<HasFileInput> inputs, ListContentsHashStrategy listContentsHashStrategy) implements FileListInput {
@Override
public void hashReference(ByteConsumer digest, Context context) {
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
Expand All @@ -265,8 +268,24 @@ public void hashContents(ByteConsumer digest, Context context) {
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.putInt(inputs.size());
digest.update(buffer);
for (HasFileInput input : inputs) {
input.hashContents(digest, context);
switch (listContentsHashStrategy) {
case ORIGINAL -> {
for (HasFileInput input : inputs) {
input.hashContents(digest, context);
}
}
case CONTENTS -> {
ArrayList<byte[]> bytes = new ArrayList<>(inputs.size());
for (HasFileInput input : inputs) {
var output = new ByteArrayOutputStream();
input.hashContents(ByteConsumer.of(output), context);
bytes.add(output.toByteArray());
}
bytes.sort(Arrays::compare);
for (byte[] b : bytes) {
digest.update(b);
}
}
}
}

Expand Down Expand Up @@ -360,7 +379,7 @@ static FileListInput files(String name, Input modelInput, WorkItem workItem, Con
for (int i = 0; i < listInput.inputs().size(); i++) {
fileInputs.add(file(name + "_" + i, listInput.inputs().get(i), workItem, context, pathSensitivity));
}
yield new SimpleFileListInput(name, fileInputs);
yield new SimpleFileListInput(name, fileInputs, listInput.listContentsHashStrategy());
}
};
}
Expand All @@ -381,7 +400,7 @@ private static FileListInput fileListFromValue(String name, Context context, Pat
throw new IllegalArgumentException("Array parameter `"+ parameterInput.parameter()+"` contains non-string value at index "+i);
}
}
return new SimpleFileListInput(name, inputs);
return new SimpleFileListInput(name, inputs, listValue.listContentsHashStrategy());
} else if (value != null) {
if (parameterInput == null) {
throw new IllegalArgumentException("Value is not a string or list of strings");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ record ParameterInput(String parameter) implements Input {}
record DirectInput(Value value) implements Input {}

@JsonAdapter(InputAdapter.class)
record ListInput(List<Input> inputs) implements Input {}
record ListInput(List<Input> inputs, ListContentsHashStrategy listContentsHashStrategy) implements Input {
public ListInput(List<Input> inputs) {
this(inputs, ListContentsHashStrategy.ORIGINAL);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,26 @@ public void write(JsonWriter out, Input value) throws IOException {
case Input.TaskInput taskInput ->
out.value("task." + taskInput.output().taskName() + "." + taskInput.output().name());
case Input.ListInput listInput -> {
out.beginArray();
for (var i : listInput.inputs()) {
write(out, i);
if (listInput.listContentsHashStrategy() == ListContentsHashStrategy.ORIGINAL) {
out.beginArray();
for (var i : listInput.inputs()) {
write(out, i);
}
out.endArray();
} else {
out.beginObject();
out.name("type");
out.value("list");
out.name("value");
out.beginArray();
for (var i : listInput.inputs()) {
write(out, i);
}
out.endArray();
out.name("listContentsHashStrategy");
GSON.getAdapter(ListContentsHashStrategy.class).write(out, listInput.listContentsHashStrategy());
out.endObject();
}
out.endArray();
}
}
}
Expand Down Expand Up @@ -86,7 +101,11 @@ public Input read(JsonReader in) throws IOException {
for (var element : value.getAsJsonArray()) {
inputs.add(GSON.fromJson(element, Input.class));
}
yield new Input.ListInput(inputs);
if (!object.has("listContentsHashStrategy")) {
yield new Input.ListInput(inputs);
}
var listContentsHashStrategy = GSON.fromJson(object.get("listContentsHashStrategy"), ListContentsHashStrategy.class);
yield new Input.ListInput(inputs, listContentsHashStrategy);
}
default -> throw new IllegalArgumentException("Invalid input type: " + type);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.lukebemish.taskgraphrunner.model;

public enum ListContentsHashStrategy {
ORIGINAL,
CONTENTS
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ record StringValue(String value) implements Value {}
record BooleanValue(Boolean value) implements Value {}

@JsonAdapter(ValueAdapter.class)
record ListValue(List<Value> value) implements Value {}
record ListValue(List<Value> value, ListContentsHashStrategy listContentsHashStrategy) implements Value {
public ListValue(List<Value> value) {
this(value, ListContentsHashStrategy.ORIGINAL);
}
}

@JsonAdapter(ValueAdapter.class)
record MapValue(Map<String, Value> value) implements Value {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.util.Map;

final class ValueAdapter extends GsonAdapter<Value> {
private static final String ORDER_BY_CONTENTS = "__taskgraphrunner.listContentsHashStrategy."+ ListContentsHashStrategy.CONTENTS.name()+"__";

@Override
public void write(JsonWriter out, Value value) throws IOException {
switch (value) {
Expand All @@ -19,6 +21,9 @@ public void write(JsonWriter out, Value value) throws IOException {
case Value.StringValue stringValue -> out.value(stringValue.value());
case Value.ListValue listValue -> {
out.beginArray();
if (listValue.listContentsHashStrategy() == ListContentsHashStrategy.CONTENTS) {
out.value(ORDER_BY_CONTENTS +listValue.listContentsHashStrategy().name());
}
for (var v : listValue.value()) {
write(out, v);
}
Expand All @@ -44,11 +49,20 @@ public Value read(JsonReader in) throws IOException {
case BEGIN_ARRAY -> {
in.beginArray();
List<Value> list = new ArrayList<>();
ListContentsHashStrategy listContentsHashStrategy = ListContentsHashStrategy.ORIGINAL;
if (in.hasNext()) {
var value = read(in);
if (value instanceof Value.StringValue stringValue && stringValue.value().equals(ORDER_BY_CONTENTS)) {
listContentsHashStrategy = ListContentsHashStrategy.CONTENTS;
} else {
list.add(value);
}
}
while (in.hasNext()) {
list.add(read(in));
}
in.endArray();
yield new Value.ListValue(list);
yield new Value.ListValue(list, listContentsHashStrategy);
}
case BEGIN_OBJECT -> {
in.beginObject();
Expand Down

0 comments on commit 61dd129

Please sign in to comment.