001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2023-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.cli; 019 020import dev.enola.common.canonicalize.Canonicalizer; 021import dev.enola.common.context.TLC; 022import dev.enola.common.function.MoreStreams; 023import dev.enola.common.io.iri.URIs; 024import dev.enola.common.io.resource.DelegatingResource; 025import dev.enola.common.io.resource.ReadableResource; 026import dev.enola.common.io.resource.stream.GlobResolvers; 027import dev.enola.common.io.resource.stream.WritableResourcesProvider; 028 029import picocli.CommandLine; 030 031import java.io.IOException; 032import java.nio.file.Paths; 033 034@CommandLine.Command( 035 name = "canonicalize", 036 description = { 037 "Canonicalize (AKA normalize) resources", 038 "using e.g. RFC 8785 JSON Canonicalization Scheme (JCS) inspired approach", 039 "(but this implementation is currently not yet fully compliant with that RFC)" 040 }) 041public class CanonicalizeCommand extends CommandWithResourceProvider { 042 043 // TODO Merge this completely with RosettaCommand ?! 044 045 @CommandLine.ArgGroup(multiplicity = "1") 046 CommandWithModel.LoadableModelURIs resources; 047 048 @CommandLine.ArgGroup CommandWithModel.Output output; 049 050 @CommandLine.Option( 051 names = {"--pretty"}, 052 negatable = true, 053 required = true, 054 defaultValue = "false", 055 fallbackValue = "true", 056 showDefaultValue = CommandLine.Help.Visibility.ALWAYS, 057 description = "Whether to 'pretty print' (format) output") 058 boolean pretty; 059 060 private WritableResourcesProvider wrp; 061 private Canonicalizer canonicalizer; 062 063 @Override 064 public void run() throws Exception { 065 super.run(); 066 try (var ctx = TLC.open().push(URIs.ContextKeys.BASE, Paths.get("").toUri())) { 067 wrp = new WritableResourcesProvider(rp); 068 canonicalizer = new Canonicalizer(rp); 069 070 var fgrp = new GlobResolvers(); 071 for (var globIRI : resources.load) { 072 try (var stream = fgrp.get(globIRI)) { 073 MoreStreams.forEach(stream, uri -> canonicalize(rp.getResource(uri))); 074 } 075 } 076 } 077 } 078 079 private void canonicalize(ReadableResource r) throws IOException { 080 var out = wrp.getWritableResource(CommandWithModel.Output.get(output), r.uri()); 081 out = new DelegatingResource(out, r.mediaType().withoutParameters()); 082 canonicalizer.canonicalize(r, out, pretty); 083 } 084}