From 05bb3d8f19714cedda7d47d6a295ce28d736a8ea Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Thu, 5 Dec 2024 16:00:05 +0100 Subject: [PATCH 1/3] Adds a `log4j-transform-cli` tool This PR adds a simple `picocli`-based tool to access the Configuration Converter API from the command line. Currently, two commands are available: - `configFile listFormats` lists the available configuration file formats. - `configFile convert` converts configuration files from one format to another (e.g., a Log4j 1 Properties file to a Log4j 2 Core XML file). Part of apache/logging-log4j2#3220 --- antora-playbook.yaml | 1 + .../config/ConfigurationConverter.java | 9 + .../DefaultConfigurationConverter.java | 10 + .../v1/PropertiesV1ConfigurationParser.java | 5 + .../internal/v1/XmlV1ConfigurationParser.java | 5 + .../internal/v2/JsonConfigurationMapper.java | 5 + .../v2/PropertiesV2ConfigurationParser.java | 5 + .../internal/v2/XmlConfigurationMapper.java | 5 + .../internal/v2/YamlConfigurationMapper.java | 5 + .../v3/PropertiesV3ConfigurationMapper.java | 5 + .../config/spi/ConfigurationMapper.java | 15 ++ .../config/spi/ConfigurationParser.java | 5 + .../config/spi/ConfigurationWriter.java | 5 + .../.picocli-application-activator | 17 ++ log4j-transform-cli/pom.xml | 131 ++++++++++++ log4j-transform-cli/src/antora/antora.yml | 24 +++ .../ROOT/partials/configFile-convert.adoc | 21 ++ .../ROOT/partials/configFile-listFormats.adoc | 21 ++ .../cli/ConfigurationFileCommands.java | 198 ++++++++++++++++++ .../logging/log4j/transform/cli/Main.java | 33 +++ .../logging/log4j/transform/cli/Strings.java | 29 +++ .../log4j/transform/cli/package-info.java | 20 ++ log4j-transform-parent/pom.xml | 3 +- pom.xml | 7 + src/changelog/.0.x.x/add-transform-cli.xml | 12 ++ src/site/antora/modules/ROOT/pages/cli.adoc | 21 +- 26 files changed, 614 insertions(+), 3 deletions(-) create mode 100644 log4j-transform-cli/.picocli-application-activator create mode 100644 log4j-transform-cli/pom.xml create mode 100644 log4j-transform-cli/src/antora/antora.yml create mode 100644 log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc create mode 100644 log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc create mode 100644 log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java create mode 100644 log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java create mode 100644 log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Strings.java create mode 100644 log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/package-info.java create mode 100644 src/changelog/.0.x.x/add-transform-cli.xml diff --git a/antora-playbook.yaml b/antora-playbook.yaml index eb34ee62..de8462a4 100644 --- a/antora-playbook.yaml +++ b/antora-playbook.yaml @@ -25,6 +25,7 @@ content: - url: . branches: HEAD start_paths: + - log4j-transform-cli/target/generated-site/antora - target/generated-site/antora edit_url: diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/ConfigurationConverter.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/ConfigurationConverter.java index 90602105..69a7637b 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/ConfigurationConverter.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/ConfigurationConverter.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.io.OutputStream; +import java.util.Map; import java.util.Set; import org.apache.logging.converter.config.internal.DefaultConfigurationConverter; @@ -55,4 +56,12 @@ void convert(InputStream inputStream, String inputFormat, OutputStream outputStr * Returns the list of supported output formats. */ Set getSupportedOutputFormats(); + + /** + * Associates each supported format symbol with a description. + *

+ * For self-documentation purposes. + *

+ */ + Map getFormatDescriptions(); } diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/DefaultConfigurationConverter.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/DefaultConfigurationConverter.java index cd90dd93..1edd43f7 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/DefaultConfigurationConverter.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/DefaultConfigurationConverter.java @@ -54,6 +54,7 @@ public final class DefaultConfigurationConverter implements ConfigurationConvert private final Map parsers = new HashMap<>(); private final Map writers = new HashMap<>(); + private final Map descriptions = new HashMap<>(); private DefaultConfigurationConverter() { ServiceLoader.load(ConfigurationParser.class).forEach(parser -> parsers.put(parser.getInputFormat(), parser)); @@ -62,6 +63,10 @@ private DefaultConfigurationConverter() { parsers.put(mapper.getInputFormat(), mapper); writers.put(mapper.getOutputFormat(), mapper); }); + parsers.values() + .forEach(parser -> descriptions.put(parser.getInputFormat(), parser.getInputFormatDescription())); + writers.values() + .forEach(writer -> descriptions.put(writer.getOutputFormat(), writer.getOutputFormatDescription())); } @Override @@ -98,4 +103,9 @@ public Set getSupportedInputFormats() { public Set getSupportedOutputFormats() { return Collections.unmodifiableSet(writers.keySet()); } + + @Override + public Map getFormatDescriptions() { + return Collections.unmodifiableMap(descriptions); + } } diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/PropertiesV1ConfigurationParser.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/PropertiesV1ConfigurationParser.java index 1c174c98..75ee8130 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/PropertiesV1ConfigurationParser.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/PropertiesV1ConfigurationParser.java @@ -56,6 +56,11 @@ public String getInputFormat() { return LOG4J_V1_PROPERTIES_FORMAT; } + @Override + public String getInputFormatDescription() { + return "Log4j 1 Properties configuration file format."; + } + @Override public ConfigurationNode parse(InputStream inputStream) throws IOException { Properties properties = new Properties(); diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/XmlV1ConfigurationParser.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/XmlV1ConfigurationParser.java index 84250143..877a4ce7 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/XmlV1ConfigurationParser.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v1/XmlV1ConfigurationParser.java @@ -61,6 +61,11 @@ public String getInputFormat() { return LOG4J_V1_XML_FORMAT; } + @Override + public String getInputFormatDescription() { + return "Log4j 1 XML configuration file format."; + } + @Override public ConfigurationNode parse(InputStream inputStream) throws IOException { DocumentBuilder documentBuilder = XmlUtils.createDocumentBuilderV1(); diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/JsonConfigurationMapper.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/JsonConfigurationMapper.java index d97e9266..8eed7c05 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/JsonConfigurationMapper.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/JsonConfigurationMapper.java @@ -34,4 +34,9 @@ public JsonConfigurationMapper() { public String getFormat() { return LOG4J_V2_JSON_FORMAT; } + + @Override + public String getFormatDescription() { + return "Log4j Core 2 JSON configuration format."; + } } diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/PropertiesV2ConfigurationParser.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/PropertiesV2ConfigurationParser.java index e1ef6724..85fc653b 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/PropertiesV2ConfigurationParser.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/PropertiesV2ConfigurationParser.java @@ -70,6 +70,11 @@ public String getInputFormat() { return LOG4J_V2_PROPERTIES_FORMAT; } + @Override + public String getInputFormatDescription() { + return "Log4j Core 2 Properties configuration format."; + } + @Override public ConfigurationNode parse(InputStream inputStream) throws IOException { Properties rootProperties = new Properties(); diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/XmlConfigurationMapper.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/XmlConfigurationMapper.java index 8f87c860..077c944a 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/XmlConfigurationMapper.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/XmlConfigurationMapper.java @@ -108,6 +108,11 @@ public String getFormat() { return LOG4J_V2_XML_FORMAT; } + @Override + public String getFormatDescription() { + return "Log4j Core 2 XML configuration format."; + } + private static XMLStreamWriter createStreamWriter(OutputStream outputStream) throws IOException { XMLOutputFactory outputFactory = XMLOutputFactory.newFactory(); try { diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/YamlConfigurationMapper.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/YamlConfigurationMapper.java index 6e2385b9..bd2d6da5 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/YamlConfigurationMapper.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v2/YamlConfigurationMapper.java @@ -40,4 +40,9 @@ public YamlConfigurationMapper() { public String getFormat() { return LOG4J_V2_YAML_FORMAT; } + + @Override + public String getFormatDescription() { + return "Log4j Core 2 YAML configuration format."; + } } diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v3/PropertiesV3ConfigurationMapper.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v3/PropertiesV3ConfigurationMapper.java index 090baf46..c1f10c8d 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v3/PropertiesV3ConfigurationMapper.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/internal/v3/PropertiesV3ConfigurationMapper.java @@ -44,6 +44,11 @@ public String getFormat() { return LOG4J_V3_PROPERTIES_FORMAT; } + @Override + public String getFormatDescription() { + return "Log4j Core 3 Properties configuration format."; + } + @Override public ConfigurationNode parse(InputStream inputStream) throws IOException { return super.parse(inputStream); diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationMapper.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationMapper.java index a143e99a..c46b8f43 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationMapper.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationMapper.java @@ -35,13 +35,28 @@ public interface ConfigurationMapper extends ConfigurationParser, ConfigurationW */ String getFormat(); + /** + * A description of the supported format for self-documentation purposes. + */ + String getFormatDescription(); + @Override default String getInputFormat() { return getFormat(); } + @Override + default String getInputFormatDescription() { + return getFormatDescription(); + } + @Override default String getOutputFormat() { return getFormat(); } + + @Override + default String getOutputFormatDescription() { + return getFormatDescription(); + } } diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationParser.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationParser.java index d0a943fc..a7516e93 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationParser.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationParser.java @@ -37,6 +37,11 @@ public interface ConfigurationParser { */ String getInputFormat(); + /** + * A description of the supported format for self-documentation purposes. + */ + String getInputFormatDescription(); + /** * Parses a configuration file into a tree of configuration nodes. *

diff --git a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationWriter.java b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationWriter.java index 9f2fa009..30a77c3c 100644 --- a/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationWriter.java +++ b/log4j-converter-config/src/main/java/org/apache/logging/converter/config/spi/ConfigurationWriter.java @@ -37,6 +37,11 @@ public interface ConfigurationWriter { */ String getOutputFormat(); + /** + * A description of the supported format for self-documentation purposes. + */ + String getOutputFormatDescription(); + /** * Write a tree of configuration nodes to a configuration file. *

diff --git a/log4j-transform-cli/.picocli-application-activator b/log4j-transform-cli/.picocli-application-activator new file mode 100644 index 00000000..15cc6df6 --- /dev/null +++ b/log4j-transform-cli/.picocli-application-activator @@ -0,0 +1,17 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +This file activates the `picocli` profile \ No newline at end of file diff --git a/log4j-transform-cli/pom.xml b/log4j-transform-cli/pom.xml new file mode 100644 index 00000000..cfdb179c --- /dev/null +++ b/log4j-transform-cli/pom.xml @@ -0,0 +1,131 @@ + + + + 4.0.0 + + org.apache.logging.log4j + log4j-transform-parent + ${revision} + ../log4j-transform-parent + + + log4j-transform-cli + Apache Log4j Transform CLI + The Apache Log4j Transform CLI tool provides access to other Log4j Transform modules such as conversion + between + configuration formats and plugin descriptors. + + + + false + + + 1.9.0 + + + org.apache.logging.log4j.transform.cli.Main + + + + + + commons-cli + commons-cli + ${commons-cli.version} + + + + info.picocli + picocli + + + + org.apache.logging.log4j + log4j-converter-config + + + + + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + + + copy-antora + + copy-resources + + process-resources + + target/generated-site/antora + + + src/antora + + + + + + + + + org.codehaus.mojo + exec-maven-plugin + + + info.picocli + picocli-codegen + ${picocli.version} + + + + + generate-man-pages + + java + + process-classes + + true + picocli.codegen.docgen.manpage.ManPageGenerator + + -d + ${project.build.directory}/generated-site/antora/modules/ROOT/partials + org.apache.logging.log4j.transform.cli.ConfigurationFileCommands + + + + + + + + + diff --git a/log4j-transform-cli/src/antora/antora.yml b/log4j-transform-cli/src/antora/antora.yml new file mode 100644 index 00000000..569d0def --- /dev/null +++ b/log4j-transform-cli/src/antora/antora.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# This Antora module is only used as a container for automatically generated `partials` +# + +name: cli +title: Log4j Transform CLI Tools +version: ~ diff --git a/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc b/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc new file mode 100644 index 00000000..4c104b91 --- /dev/null +++ b/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc @@ -0,0 +1,21 @@ +//// +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +//// + += configFile-convert(1) + +This is a dummy file to help validation in an IDE. +Its content will be generated by `picocli-codegen`. \ No newline at end of file diff --git a/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc b/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc new file mode 100644 index 00000000..e61399a7 --- /dev/null +++ b/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc @@ -0,0 +1,21 @@ +//// +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +//// + += configFile-listFormats(1) + +This is a dummy file to help validation in an IDE. +Its content will be generated by `picocli-codegen`. \ No newline at end of file diff --git a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java new file mode 100644 index 00000000..19a3982a --- /dev/null +++ b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.transform.cli; + +import static java.util.Objects.requireNonNull; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Callable; +import org.apache.logging.converter.config.ConfigurationConverter; +import org.jspecify.annotations.Nullable; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.Parameters; + +@Command( + name = "configFile", + description = "Handles the transformation of logging configuration files.", + subcommands = {ConfigurationFileCommands.Convert.class, ConfigurationFileCommands.ListFormats.class}) +class ConfigurationFileCommands { + + private static final int PADDING_SIZE = 2; + + @Command(name = "listFormats", description = "Lists the supported configuration file formats.") + static class ListFormats implements Callable { + + private final ConfigurationConverter converter = ConfigurationConverter.getInstance(); + + @Override + public Integer call() { + Map supportedFormatMap = new TreeMap<>(); + converter + .getSupportedInputFormats() + .forEach(formatName -> supportedFormatMap.compute(formatName, SupportedFormat::enableInput)); + converter + .getSupportedOutputFormats() + .forEach(formatName -> supportedFormatMap.compute(formatName, SupportedFormat::enableOutput)); + converter + .getFormatDescriptions() + .forEach((formatName, description) -> supportedFormatMap.compute( + formatName, (f, old) -> SupportedFormat.updateDescription(f, description, old))); + System.out.println("Supported formats:"); + System.out.println(); + formatRows(supportedFormatMap.values()).forEach(System.out::println); + return 0; + } + + private static List formatRows(Collection supportedFormats) { + List rows = new ArrayList<>(supportedFormats.size()); + // Print first column + int maxLength = 0; + for (SupportedFormat format : supportedFormats) { + StringBuilder row = new StringBuilder(); + Strings.appendPadding(row, PADDING_SIZE).append(format.formatName); + maxLength = Math.max(maxLength, row.length()); + rows.add(row); + } + // Print second column + int i = 0; + for (SupportedFormat format : supportedFormats) { + StringBuilder row = rows.get(i++); + Strings.appendPadding(row, PADDING_SIZE + maxLength - row.length()); + if (format.description != null) { + row.append(format.description); + } + if (!format.input) { + if (format.output) { + row.append(" (write-only)"); + } else { + rows.remove(--i); + } + } else if (!format.output) { + row.append(" (read-only)"); + } + } + return rows; + } + } + + @Command(name = "convert", description = "Converts a logging configuration file to a different format.") + static class Convert implements Callable { + + private final ConfigurationConverter converter = ConfigurationConverter.getInstance(); + + private @Nullable String inputFormat; + private @Nullable String outputFormat; + private @Nullable File inputFile; + private @Nullable File outputFile; + + @Option( + names = {"-i", "--input-format"}, + description = "The format of the input file.", + required = true) + public void setInputFormat(String inputFormat) { + if (!converter.getSupportedInputFormats().contains(inputFormat)) { + throw new IllegalArgumentException("Unsupported input format: `" + inputFormat + + "`.\nRun `listFormats` for a list of supported formats."); + } + this.inputFormat = inputFormat; + } + + @Option( + names = {"-o", "--output-format"}, + description = "The format of the output file.", + required = true) + public void setOutputFormat(String outputFormat) { + if (!converter.getSupportedOutputFormats().contains(outputFormat)) { + throw new IllegalArgumentException("Unsupported output format: `" + outputFormat + + "`.\nRun `listFormats` for a list of supported formats."); + } + this.outputFormat = outputFormat; + } + + @Parameters(index = "0", description = "The input logging configuration file.") + public void setInputFile(File inputFile) { + if (!Files.exists(inputFile.toPath())) { + throw new IllegalArgumentException("Input file does not exist: `" + inputFile + "`."); + } + this.inputFile = inputFile; + } + + @Parameters(index = "1", description = "The output logging configuration file.") + public void setOutputFile(File outputFile) { + if (Files.exists(outputFile.toPath())) { + throw new IllegalArgumentException("Output file already exists: `" + outputFile + "`."); + } + this.outputFile = outputFile; + } + + @Override + public Integer call() throws IOException { + String inputFormat = requireNonNull(this.inputFormat); + Path inputPath = requireNonNull(this.inputFile).toPath(); + String outputFormat = requireNonNull(this.outputFormat); + Path outputPath = requireNonNull(this.outputFile).toPath(); + try (InputStream inputStream = Files.newInputStream(inputPath); + OutputStream outputStream = Files.newOutputStream(outputPath)) { + converter.convert(inputStream, inputFormat, outputStream, outputFormat); + } + return 0; + } + } + + private static final class SupportedFormat { + private final String formatName; + private final @Nullable String description; + private final boolean input; + private final boolean output; + + private static SupportedFormat enableInput(String formatName, @Nullable SupportedFormat old) { + return new SupportedFormat( + formatName, old != null ? old.formatName : null, true, old != null && old.output); + } + + private static SupportedFormat enableOutput(String formatName, @Nullable SupportedFormat old) { + return new SupportedFormat(formatName, old != null ? old.formatName : null, old != null && old.input, true); + } + + private static SupportedFormat updateDescription( + String formatName, String description, @Nullable SupportedFormat old) { + return new SupportedFormat(formatName, description, old != null && old.input, old != null && old.output); + } + + private SupportedFormat( + final String formatName, + @Nullable final String description, + final boolean input, + final boolean output) { + this.formatName = formatName; + this.description = description; + this.input = input; + this.output = output; + } + } +} diff --git a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java new file mode 100644 index 00000000..1ca5e03a --- /dev/null +++ b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.transform.cli; + +import picocli.CommandLine; +import picocli.CommandLine.Command; + +@Command( + name = "log4j-transform-cli", + description = "Provides several utilities that transform Log4j-related files.", + subcommands = {ConfigurationFileCommands.class}) +public final class Main { + + public static void main(final String[] args) { + System.exit(new CommandLine(Main.class).execute(args)); + } + + private Main() {} +} diff --git a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Strings.java b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Strings.java new file mode 100644 index 00000000..714d80e6 --- /dev/null +++ b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Strings.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.logging.log4j.transform.cli; + +final class Strings { + + static StringBuilder appendPadding(StringBuilder appendable, int count) { + for (int i = 0; i < count; i++) { + appendable.append(' '); + } + return appendable; + } + + private Strings() {} +} diff --git a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/package-info.java b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/package-info.java new file mode 100644 index 00000000..fffab2d6 --- /dev/null +++ b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/package-info.java @@ -0,0 +1,20 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +package org.apache.logging.log4j.transform.cli; + +import org.jspecify.annotations.NullMarked; diff --git a/log4j-transform-parent/pom.xml b/log4j-transform-parent/pom.xml index d7c69dc7..f4f641c5 100644 --- a/log4j-transform-parent/pom.xml +++ b/log4j-transform-parent/pom.xml @@ -211,7 +211,7 @@ - + picocli @@ -259,6 +259,7 @@ + true true shaded diff --git a/pom.xml b/pom.xml index 400dcf73..528fc889 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,7 @@ log4j-codegen log4j-converter-config log4j-converter-plugin-descriptor + log4j-transform-cli log4j-transform-maven-plugin log4j-transform-maven-shade-plugin-extensions log4j-weaver @@ -149,6 +150,12 @@ ${project.version} + + org.apache.logging.log4j + log4j-transform-cli + ${project.version} + + org.apache.logging.log4j log4j-transform-maven-plugin diff --git a/src/changelog/.0.x.x/add-transform-cli.xml b/src/changelog/.0.x.x/add-transform-cli.xml new file mode 100644 index 00000000..3ec4bf7e --- /dev/null +++ b/src/changelog/.0.x.x/add-transform-cli.xml @@ -0,0 +1,12 @@ + + + + + Adds a + xref:cli.adoc#log4j-transform-cli[`log4j-transform-cli` tool] + to access the functionalities of Log4j Transform from the command line. + + diff --git a/src/site/antora/modules/ROOT/pages/cli.adoc b/src/site/antora/modules/ROOT/pages/cli.adoc index 5ae4da84..dcf696c4 100644 --- a/src/site/antora/modules/ROOT/pages/cli.adoc +++ b/src/site/antora/modules/ROOT/pages/cli.adoc @@ -257,5 +257,22 @@ A list of file paths to the runtime dependencies of your application, separated The command will filter and output each `reflect-config.json` in its original path under the `META-INF/native-image` subfolder of the output directory. -[#log4j-converter-plugin-descriptor-example] -=== Examples \ No newline at end of file +[#log4j-transform-cli] +== `log4j-transform-cli` + +The `log4j-transform-cli` tool provides CLI access to some of the functionalities offered by +xref:ROOT::index.adoc[]. + +Currently, you can use it to: + +* Convert between different formats of logging configuration files. +See <> for the syntax. + +* List the support configuration file formats. +See <> for the syntax. + +[#log4j-transform-cli-configFile-convert] +include::cli::partial$configFile-convert.adoc[leveloffset=2] + +[#log4j-transform-cli-configFile-listFormats] +include::cli::partial$configFile-listFormats.adoc[leveloffset=2] From a024f710d82ee32280001aded03652c38d2b655a Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Sun, 15 Dec 2024 08:01:47 +0100 Subject: [PATCH 2/3] Normalize commands and add help/version --- .../cli/ConfigurationFileCommands.java | 27 +++++++++++++++---- .../logging/log4j/transform/cli/Main.java | 14 +++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java index 19a3982a..2b04e17e 100644 --- a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java +++ b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/ConfigurationFileCommands.java @@ -32,19 +32,32 @@ import java.util.concurrent.Callable; import org.apache.logging.converter.config.ConfigurationConverter; import org.jspecify.annotations.Nullable; +import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; @Command( - name = "configFile", + name = "config-file", description = "Handles the transformation of logging configuration files.", - subcommands = {ConfigurationFileCommands.Convert.class, ConfigurationFileCommands.ListFormats.class}) -class ConfigurationFileCommands { + mixinStandardHelpOptions = true, + subcommands = {ConfigurationFileCommands.Convert.class, ConfigurationFileCommands.ListFormats.class}, + versionProvider = Main.VersionProvider.class) +public final class ConfigurationFileCommands { private static final int PADDING_SIZE = 2; - @Command(name = "listFormats", description = "Lists the supported configuration file formats.") + public static void main(final String[] args) { + System.exit(new CommandLine(ConfigurationFileCommands.class).execute(args)); + } + + private ConfigurationFileCommands() {} + + @Command( + name = "list-formats", + description = "Lists the supported configuration file formats.", + mixinStandardHelpOptions = true, + versionProvider = Main.VersionProvider.class) static class ListFormats implements Callable { private final ConfigurationConverter converter = ConfigurationConverter.getInstance(); @@ -100,7 +113,11 @@ private static List formatRows(Collection { private final ConfigurationConverter converter = ConfigurationConverter.getInstance(); diff --git a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java index 1ca5e03a..61f911f2 100644 --- a/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java +++ b/log4j-transform-cli/src/main/java/org/apache/logging/log4j/transform/cli/Main.java @@ -22,7 +22,9 @@ @Command( name = "log4j-transform-cli", description = "Provides several utilities that transform Log4j-related files.", - subcommands = {ConfigurationFileCommands.class}) + mixinStandardHelpOptions = true, + subcommands = ConfigurationFileCommands.class, + versionProvider = Main.VersionProvider.class) public final class Main { public static void main(final String[] args) { @@ -30,4 +32,14 @@ public static void main(final String[] args) { } private Main() {} + + static class VersionProvider implements CommandLine.IVersionProvider { + + @Override + public String[] getVersion() { + return new String[] { + "log4j-transform-cli " + Main.class.getPackage().getImplementationVersion() + }; + } + } } From c368e48cf3b86cd17993da94c85f710159a09511 Mon Sep 17 00:00:00 2001 From: "Piotr P. Karwasz" Date: Sun, 15 Dec 2024 08:41:05 +0100 Subject: [PATCH 3/3] Fix configuration links --- .../{configFile-convert.adoc => config-file-convert.adoc} | 2 +- ...figFile-listFormats.adoc => config-file-list-formats.adoc} | 2 +- src/site/antora/modules/ROOT/pages/cli.adoc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename log4j-transform-cli/src/antora/modules/ROOT/partials/{configFile-convert.adoc => config-file-convert.adoc} (97%) rename log4j-transform-cli/src/antora/modules/ROOT/partials/{configFile-listFormats.adoc => config-file-list-formats.adoc} (96%) diff --git a/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc b/log4j-transform-cli/src/antora/modules/ROOT/partials/config-file-convert.adoc similarity index 97% rename from log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc rename to log4j-transform-cli/src/antora/modules/ROOT/partials/config-file-convert.adoc index 4c104b91..39019c0c 100644 --- a/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-convert.adoc +++ b/log4j-transform-cli/src/antora/modules/ROOT/partials/config-file-convert.adoc @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. //// -= configFile-convert(1) += config-file-convert(1) This is a dummy file to help validation in an IDE. Its content will be generated by `picocli-codegen`. \ No newline at end of file diff --git a/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc b/log4j-transform-cli/src/antora/modules/ROOT/partials/config-file-list-formats.adoc similarity index 96% rename from log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc rename to log4j-transform-cli/src/antora/modules/ROOT/partials/config-file-list-formats.adoc index e61399a7..b56bcfc1 100644 --- a/log4j-transform-cli/src/antora/modules/ROOT/partials/configFile-listFormats.adoc +++ b/log4j-transform-cli/src/antora/modules/ROOT/partials/config-file-list-formats.adoc @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. //// -= configFile-listFormats(1) += config-file-list-formats(1) This is a dummy file to help validation in an IDE. Its content will be generated by `picocli-codegen`. \ No newline at end of file diff --git a/src/site/antora/modules/ROOT/pages/cli.adoc b/src/site/antora/modules/ROOT/pages/cli.adoc index dcf696c4..53ac0874 100644 --- a/src/site/antora/modules/ROOT/pages/cli.adoc +++ b/src/site/antora/modules/ROOT/pages/cli.adoc @@ -272,7 +272,7 @@ See <> for the syntax. See <> for the syntax. [#log4j-transform-cli-configFile-convert] -include::cli::partial$configFile-convert.adoc[leveloffset=2] +include::cli::partial$config-file-convert.adoc[leveloffset=2] [#log4j-transform-cli-configFile-listFormats] -include::cli::partial$configFile-listFormats.adoc[leveloffset=2] +include::cli::partial$config-file-list-formats.adoc[leveloffset=2]