From 8e5f1f5154d93e60422407a5387d8b9967fc5952 Mon Sep 17 00:00:00 2001 From: Matthias Andreas Benkard Date: Sat, 2 Mar 2024 14:54:34 +0100 Subject: jgvariant-tool: Add 'ostree summary add-static-delta' command. Change-Id: I3b318269c4c85b581d6639fe5ec6a14bf2604ad4 --- .../src/main/java/eu/mulk/jgvariant/tool/Main.java | 19 +++++- .../java/eu/mulk/jgvariant/tool/MainCommand.java | 75 +++++++++++++++++++++- jgvariant-tool/src/main/java/module-info.java | 19 +++++- 3 files changed, 108 insertions(+), 5 deletions(-) (limited to 'jgvariant-tool/src') diff --git a/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/Main.java b/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/Main.java index fbf5b71..744d902 100644 --- a/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/Main.java +++ b/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/Main.java @@ -17,7 +17,9 @@ import picocli.CommandLine; * *

Also provides ways to manipulate OSTree repositories. * - *

Usage example (dumping the contents of an OSTree summary file): + *

Usage Examples

+ * + *

Dumping the contents of an OSTree summary file

* * {@snippet lang="sh" : * $ jgvariant ostree summary read ./jgvariant-ostree/src/test/resources/ostree/summary @@ -56,6 +58,21 @@ import picocli.CommandLine; * } * } * } + * + *

Adding a static delta to an OSTree summary file

+ * + *

Static delta 3... (in hex), between commits 1... and 2... + * : + * + * {@snippet lang="sh" : + * $ jgvariant ostree summary add-static-delta ./jgvariant-ostree/src/test/resources/ostree/summary 3333333333333333333333333333333333333333333333333333333333333333 2222222222222222222222222222222222222222222222222222222222222222 1111111111111111111111111111111111111111111111111111111111111111 + * } + * + *

Static delta 3... (in hex), between the empty commit and 2...: + * + * {@snippet lang="sh" : + * $ jgvariant ostree summary add-static-delta ./jgvariant-ostree/src/test/resources/ostree/summary 4444444444444444444444444444444444444444444444444444444444444444 2222222222222222222222222222222222222222222222222222222222222222 + * } */ public final class Main { static { diff --git a/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/MainCommand.java b/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/MainCommand.java index fe8211e..2bea23c 100644 --- a/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/MainCommand.java +++ b/jgvariant-tool/src/main/java/eu/mulk/jgvariant/tool/MainCommand.java @@ -7,6 +7,10 @@ package eu.mulk.jgvariant.tool; import static java.util.logging.Level.*; import eu.mulk.jgvariant.core.Decoder; +import eu.mulk.jgvariant.core.Signature; +import eu.mulk.jgvariant.core.Variant; +import eu.mulk.jgvariant.ostree.ByteString; +import eu.mulk.jgvariant.ostree.Metadata; import eu.mulk.jgvariant.ostree.Summary; import eu.mulk.jgvariant.tool.jsonb.*; import jakarta.json.bind.Jsonb; @@ -16,10 +20,15 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.text.ParseException; +import java.util.*; import java.util.logging.Logger; +import java.util.stream.IntStream; import org.jetbrains.annotations.VisibleForTesting; import picocli.AutoComplete; import picocli.CommandLine; @@ -76,10 +85,56 @@ final class MainCommand { static final class SummaryCommand extends BaseDecoderCommand

{ @Command(mixinStandardHelpOptions = true) - void read(@Parameters(paramLabel = "") File file) throws IOException { + void read(@Parameters(paramLabel = "", description = "Summary file to read") File file) + throws IOException { read(file, Summary.decoder()); } + @Command(name = "add-static-delta", mixinStandardHelpOptions = true) + void addStaticDelta( + @Parameters(paramLabel = "", description = "Summary file to manipulate.") + File summaryFile, + @Parameters(paramLabel = "", description = "Checksum of the static delta (hex).") + String delta, + @Parameters(paramLabel = "", description = "Commit checksum the delta ends at (hex).") + String toCommit, + @Parameters( + paramLabel = "", + arity = "0..1", + description = "Commit checksum the delta starts from (hex).") + String fromCommit) + throws IOException, ParseException { + var summaryDecoder = Summary.decoder(); + + var summary = decodeFile(summaryFile, summaryDecoder); + + var staticDeltaMapSignature = Signature.parse("a{sv}"); + var checksumSignature = Signature.parse("ay"); + + var metadata = summary.metadata(); + var metadataFields = new LinkedHashMap<>(metadata.fields()); + metadataFields.compute( + "ostree.static-deltas", + (k, v) -> { + Map staticDeltas = + v != null + ? new LinkedHashMap<>((Map) v.value()) + : new LinkedHashMap<>(); + staticDeltas.put( + fromCommit != null ? fromCommit + "-" + toCommit : toCommit, + new Variant(checksumSignature, toByteList(ByteString.ofHex(delta).bytes()))); + return new Variant(staticDeltaMapSignature, staticDeltas); + }); + metadata = new Metadata(metadataFields); + summary = new Summary(summary.entries(), metadata); + + encodeFile(summaryFile, summaryDecoder, summary); + } + + private List toByteList(byte[] bytes) { + return IntStream.range(0, bytes.length).mapToObj(i -> bytes[i]).toList(); + } + SummaryCommand() {} } @@ -111,10 +166,24 @@ final class MainCommand { abstract static class BaseDecoderCommand extends BaseCommand { protected final void read(File file, Decoder decoder) throws IOException { + var thing = decodeFile(file, decoder); + out().println(jsonb.toJson(thing)); + } + + protected final T decodeFile(File file, Decoder decoder) throws IOException { LOG.fine(() -> "Reading file %s".formatted(file)); var fileBytes = ByteBuffer.wrap(Files.readAllBytes(fs().getPath(file.getPath()))); - var thing = decoder.decode(fileBytes); - out().println(jsonb.toJson(thing)); + return decoder.decode(fileBytes); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + protected final void encodeFile(File file, Decoder decoder, T thing) throws IOException { + var thingBytes = decoder.encode(thing); + + LOG.fine(() -> "Writing file %s".formatted(file)); + try (var out = FileChannel.open(fs().getPath(file.getPath()), StandardOpenOption.WRITE)) { + out.write(thingBytes); + } } } diff --git a/jgvariant-tool/src/main/java/module-info.java b/jgvariant-tool/src/main/java/module-info.java index e62808e..6faa226 100644 --- a/jgvariant-tool/src/main/java/module-info.java +++ b/jgvariant-tool/src/main/java/module-info.java @@ -11,7 +11,9 @@ * *

The {@link eu.mulk.jgvariant.tool.Main} class defines the entry point of the tool. * - *

Usage example (dumping the contents of an OSTree summary file): + *

Usage Examples

+ * + *

Dumping the contents of an OSTree summary file

* * {@snippet lang="sh" : * $ jgvariant ostree summary read ./jgvariant-ostree/src/test/resources/ostree/summary @@ -50,6 +52,21 @@ * } * } * } + * + *

Adding a static delta to an OSTree summary file

+ * + *

Static delta 3... (in hex), between commits 1... and 2... + * : + * + * {@snippet lang="sh" : + * $ jgvariant ostree summary add-static-delta ./jgvariant-ostree/src/test/resources/ostree/summary 3333333333333333333333333333333333333333333333333333333333333333 2222222222222222222222222222222222222222222222222222222222222222 1111111111111111111111111111111111111111111111111111111111111111 + * } + * + *

Static delta 3... (in hex), between the empty commit and 2...: + * + * {@snippet lang="sh" : + * $ jgvariant ostree summary add-static-delta ./jgvariant-ostree/src/test/resources/ostree/summary 4444444444444444444444444444444444444444444444444444444444444444 2222222222222222222222222222222222222222222222222222222222222222 + * } */ module eu.mulk.jgvariant.tool { requires transitive eu.mulk.jgvariant.ostree; -- cgit v1.2.3