You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kw...@apache.org on 2024/11/18 15:48:55 UTC
(maven-doxia-converter) branch master updated: [DOXIATOOLS-90] Optionally first rename input to output, commit and then (#87)
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-doxia-converter.git
The following commit(s) were added to refs/heads/master by this push:
new 307c428 [DOXIATOOLS-90] Optionally first rename input to output, commit and then (#87)
307c428 is described below
commit 307c428382e16177809622f25b9eaa9a62beca03
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Mon Nov 18 16:48:50 2024 +0100
[DOXIATOOLS-90] Optionally first rename input to output, commit and then (#87)
replace with converted markup
This allows to keep the git history of converted input files (in case
those are part of a git repository)
---
.../java/org/apache/maven/doxia/Converter.java | 8 ++
.../org/apache/maven/doxia/DefaultConverter.java | 103 +++++++++++++++++++--
.../org/apache/maven/doxia/cli/CLIManager.java | 6 ++
.../org/apache/maven/doxia/cli/ConverterCli.java | 17 +++-
.../maven/doxia/wrapper/InputFileWrapper.java | 38 +-------
.../apache/maven/doxia/DefaultConverterTest.java | 40 ++++++++
6 files changed, 169 insertions(+), 43 deletions(-)
diff --git a/src/main/java/org/apache/maven/doxia/Converter.java b/src/main/java/org/apache/maven/doxia/Converter.java
index 360632a..63dae08 100644
--- a/src/main/java/org/apache/maven/doxia/Converter.java
+++ b/src/main/java/org/apache/maven/doxia/Converter.java
@@ -29,6 +29,12 @@ import org.apache.maven.doxia.wrapper.OutputStreamWrapper;
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
*/
public interface Converter {
+ enum PostProcess {
+ NONE,
+ REMOVE_AFTER_CONVERSION,
+ GIT_MV_INPUT_TO_OUTPUT,
+ }
+
/**
* @param input an input file wrapper, not null.
* @param output an output file wrapper, not null.
@@ -55,4 +61,6 @@ public interface Converter {
* @param formatOutput <code>true</code> to format the generated files, <code>false</code> otherwise.
*/
void setFormatOutput(boolean formatOutput);
+
+ void setPostProcess(PostProcess postProcess);
}
diff --git a/src/main/java/org/apache/maven/doxia/DefaultConverter.java b/src/main/java/org/apache/maven/doxia/DefaultConverter.java
index 250d968..b68617a 100644
--- a/src/main/java/org/apache/maven/doxia/DefaultConverter.java
+++ b/src/main/java/org/apache/maven/doxia/DefaultConverter.java
@@ -30,12 +30,16 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.Scanner;
import com.ibm.icu.text.CharsetDetector;
import com.ibm.icu.text.CharsetMatch;
@@ -204,6 +208,8 @@ public class DefaultConverter implements Converter {
}
}
+ private PostProcess postProcess = PostProcess.NONE;
+
/** Flag to format the generated files, actually only for XML based sinks. */
private boolean formatOutput;
@@ -213,6 +219,9 @@ public class DefaultConverter implements Converter {
/** SLF4J logger */
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultConverter.class);
+ /** Map of temporary output files to their final output files */
+ private Map<Path, Path> outputRenameMap = new HashMap<>();
+
/** {@inheritDoc} */
@Override
public void convert(InputFileWrapper input, OutputFileWrapper output)
@@ -225,11 +234,10 @@ public class DefaultConverter implements Converter {
} catch (PlexusContainerException e) {
throw new ConverterException("PlexusContainerException: " + e.getMessage(), e);
}
-
+ outputRenameMap.clear();
try {
if (input.getFile().isFile()) {
convert(input.getFile(), input.getEncoding(), input.getFormat(), output);
- cleanUp(input, input.getFile());
} else {
List<File> files;
try {
@@ -250,20 +258,86 @@ public class DefaultConverter implements Converter {
File relativeOutputDirectory = new File(
PathTool.getRelativeFilePath(input.getFile().getAbsolutePath(), f.getParent()));
convert(f, input.getEncoding(), input.getFormat(), output, relativeOutputDirectory);
- cleanUp(input, f);
}
}
+ try {
+ postProcessAllFiles(output.getFormat());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new ConverterException("Error post processing all files: " + e.getMessage(), e);
+ } catch (IOException e) {
+ throw new ConverterException("Error post processing all files: " + e.getMessage(), e);
+ }
} finally {
stopPlexusContainer();
}
}
- private void cleanUp(InputFileWrapper input, File f) {
- if (input.cleanUp(f)) {
- LOGGER.info("Removed input file \"{}\" after successful conversion", f);
+ private void postProcessFile(File inputFile, File outputFile) throws IOException, InterruptedException {
+ switch (postProcess) {
+ case REMOVE_AFTER_CONVERSION:
+ Files.delete(inputFile.toPath());
+ LOGGER.info("Removed input file \"{}\" after successful conversion", inputFile);
+ break;
+ case GIT_MV_INPUT_TO_OUTPUT:
+ // first move rename output file to tmp file name
+ Path tmpOutputFile = outputFile.toPath().resolveSibling(outputFile.getName() + ".tmp");
+ Files.move(outputFile.toPath(), tmpOutputFile);
+ LOGGER.info(
+ "Renamed output file \"{}\" to temp name \"{}\"",
+ outputFile.getCanonicalPath(),
+ tmpOutputFile.getFileName());
+ // rename all input files to have the proper extension (must be individually committed)
+ executeCommand("git", "mv", inputFile.getCanonicalPath(), outputFile.getCanonicalPath());
+ LOGGER.info(
+ "Moved input file \"{}\" to output file \"{}\" (keeping the old content)",
+ inputFile.getCanonicalPath(),
+ outputFile.getCanonicalPath());
+ outputRenameMap.put(tmpOutputFile, outputFile.getCanonicalFile().toPath());
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void postProcessAllFiles(DoxiaFormat outputFormat) throws IOException, InterruptedException {
+ if (postProcess == PostProcess.GIT_MV_INPUT_TO_OUTPUT) {
+ // first commit the move operation with original contents
+ executeCommand(
+ "git",
+ "commit",
+ "-m",
+ String.format("Move to match target converter format %s with doxia-converter", outputFormat));
+ for (Map.Entry<Path, Path> entry : outputRenameMap.entrySet()) {
+ // move back the converted file to the original output name (i.e. overwrite its old content)
+ Files.move(entry.getKey(), entry.getValue(), StandardCopyOption.REPLACE_EXISTING);
+ LOGGER.info("Replaced output file \"{}\" with converted file \"{}\"", entry.getValue(), entry.getKey());
+ }
+ }
+ }
+
+ static void executeCommand(String... commandAndArgs) throws IOException, InterruptedException {
+ Process process = Runtime.getRuntime().exec(commandAndArgs);
+ int exitCode = process.waitFor();
+ if (exitCode != 0) {
+ logOutput(process.getInputStream(), "");
+ logOutput(process.getErrorStream(), "Error: ");
+ throw new IOException("Command " + String.join(" ", commandAndArgs) + " failed with exit code " + exitCode);
}
}
+ static void logOutput(InputStream inputStream, String prefix) throws InterruptedException {
+ Thread t = new Thread(() -> {
+ Scanner scanner = new Scanner(inputStream, "UTF-8");
+ while (scanner.hasNextLine()) {
+ LOGGER.error("{}{}", prefix, scanner.nextLine());
+ }
+ scanner.close();
+ });
+ t.start();
+ t.join();
+ }
+
/** {@inheritDoc} */
@Override
public void convert(InputReaderWrapper input, OutputStreamWrapper output)
@@ -313,6 +387,11 @@ public class DefaultConverter implements Converter {
this.formatOutput = formatOutput;
}
+ @Override
+ public void setPostProcess(PostProcess postProcess) {
+ this.postProcess = postProcess;
+ }
+
// ----------------------------------------------------------------------
// Private methods
// ----------------------------------------------------------------------
@@ -336,10 +415,11 @@ public class DefaultConverter implements Converter {
* @param parserFormat a not null supported format
* @param output not null OutputFileWrapper object
* @param relativeOutputDirectory the relative output directory (may be null, created if it does not exist yet)
+ * @return the output file
* @throws ConverterException if any
* @throws UnsupportedFormatException if any
*/
- private void convert(
+ private File convert(
File inputFile,
String inputEncoding,
DoxiaFormat parserFormat,
@@ -438,6 +518,15 @@ public class DefaultConverter implements Converter {
"Successfully converted file \"{}\" to \"{}\"",
inputFile.getAbsolutePath(),
outputFile.getAbsolutePath());
+ try {
+ postProcessFile(inputFile, outputFile);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new ConverterException("Error post processing files: " + e.getMessage(), e);
+ } catch (IOException e) {
+ throw new ConverterException("Error post processing files: " + e.getMessage(), e);
+ }
+ return outputFile;
}
/**
diff --git a/src/main/java/org/apache/maven/doxia/cli/CLIManager.java b/src/main/java/org/apache/maven/doxia/cli/CLIManager.java
index e8a0759..603a3c6 100644
--- a/src/main/java/org/apache/maven/doxia/cli/CLIManager.java
+++ b/src/main/java/org/apache/maven/doxia/cli/CLIManager.java
@@ -49,6 +49,8 @@ class CLIManager {
static final String REMOVE_IN = "removeIn";
+ static final String GIT_MV_INPUT_TO_OUTPUT = "gitMvInputToOutput";
+
/** out String */
static final String OUT = "out";
@@ -99,6 +101,10 @@ class CLIManager {
.longOpt("removeInputAfterConversion")
.desc("Whether to remove the input file(s) after successful conversion")
.build());
+ OPTIONS.addOption(Option.builder(GIT_MV_INPUT_TO_OUTPUT)
+ .desc(
+ "When this flag is set the input file(s) are first moved to the output file(s), then committed and afterwards replaced with conversion result to keep the Git history")
+ .build());
OPTIONS.addOption(Option.builder(OUT)
.longOpt("output")
.desc("Output file or directory.")
diff --git a/src/main/java/org/apache/maven/doxia/cli/ConverterCli.java b/src/main/java/org/apache/maven/doxia/cli/ConverterCli.java
index 3ad605b..0cebc1b 100644
--- a/src/main/java/org/apache/maven/doxia/cli/ConverterCli.java
+++ b/src/main/java/org/apache/maven/doxia/cli/ConverterCli.java
@@ -31,6 +31,7 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.maven.doxia.Converter;
+import org.apache.maven.doxia.Converter.PostProcess;
import org.apache.maven.doxia.ConverterException;
import org.apache.maven.doxia.DefaultConverter;
import org.apache.maven.doxia.UnsupportedFormatException;
@@ -114,6 +115,7 @@ public class ConverterCli {
InputFileWrapper input;
OutputFileWrapper output;
+ final PostProcess postProcess;
try {
String sourceFormat = commandLine.getOptionValue(CLIManager.FROM, CLIManager.AUTO_FORMAT);
final DefaultConverter.DoxiaFormat parserFormat;
@@ -127,13 +129,23 @@ public class ConverterCli {
parserFormat = DefaultConverter.DoxiaFormat.valueOf(sourceFormat.toUpperCase());
}
String targetFormat = commandLine.getOptionValue(CLIManager.TO);
+ if (commandLine.hasOption(CLIManager.REMOVE_IN)
+ && commandLine.hasOption(CLIManager.GIT_MV_INPUT_TO_OUTPUT)) {
+ throw new IllegalArgumentException(
+ "Options 'removeIn' and 'gitMvInputToOutput' are mutually exclusive.");
+ } else if (commandLine.hasOption(CLIManager.REMOVE_IN)) {
+ postProcess = PostProcess.REMOVE_AFTER_CONVERSION;
+ } else if (commandLine.hasOption(CLIManager.GIT_MV_INPUT_TO_OUTPUT)) {
+ postProcess = PostProcess.GIT_MV_INPUT_TO_OUTPUT;
+ } else {
+ postProcess = PostProcess.NONE;
+ }
final DefaultConverter.DoxiaFormat sinkFormat =
DefaultConverter.DoxiaFormat.valueOf(targetFormat.toUpperCase());
input = InputFileWrapper.valueOf(
commandLine.getOptionValue(CLIManager.IN),
parserFormat,
- commandLine.getOptionValue(CLIManager.INENCODING),
- commandLine.hasOption(CLIManager.REMOVE_IN));
+ commandLine.getOptionValue(CLIManager.INENCODING));
output = OutputFileWrapper.valueOf(
commandLine.getOptionValue(CLIManager.OUT),
sinkFormat,
@@ -152,6 +164,7 @@ public class ConverterCli {
boolean format = commandLine.hasOption(CLIManager.FORMAT);
converter.setFormatOutput(format);
+ converter.setPostProcess(postProcess);
try {
converter.convert(input, output);
diff --git a/src/main/java/org/apache/maven/doxia/wrapper/InputFileWrapper.java b/src/main/java/org/apache/maven/doxia/wrapper/InputFileWrapper.java
index 2b20c1c..a0dab50 100644
--- a/src/main/java/org/apache/maven/doxia/wrapper/InputFileWrapper.java
+++ b/src/main/java/org/apache/maven/doxia/wrapper/InputFileWrapper.java
@@ -18,7 +18,6 @@
*/
package org.apache.maven.doxia.wrapper;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
@@ -36,11 +35,6 @@ public class InputFileWrapper extends AbstractFileWrapper {
private final DefaultConverter.DoxiaFormat format;
- /**
- * If true, the related input file(s) will be removed after the conversion.
- */
- private final boolean removeAfterConversion;
-
/**
* Private constructor.
*
@@ -50,13 +44,11 @@ public class InputFileWrapper extends AbstractFileWrapper {
* @throws UnsupportedEncodingException if the encoding is unsupported.
* @throws FileNotFoundException if the file for absolutePath is not found.
*/
- private InputFileWrapper(
- String absolutePath, DefaultConverter.DoxiaFormat format, String charsetName, boolean removeAfterConversion)
+ private InputFileWrapper(String absolutePath, DefaultConverter.DoxiaFormat format, String charsetName)
throws UnsupportedEncodingException, FileNotFoundException {
super(absolutePath, charsetName);
this.format = format;
- this.removeAfterConversion = removeAfterConversion;
if (!getFile().exists()) {
throw new FileNotFoundException("The file '" + getFile().getAbsolutePath() + "' doesn't exist.");
}
@@ -72,42 +64,20 @@ public class InputFileWrapper extends AbstractFileWrapper {
*/
public static InputFileWrapper valueOf(String absolutePath, DefaultConverter.DoxiaFormat format)
throws UnsupportedEncodingException, FileNotFoundException {
- return valueOf(absolutePath, format, WriterFactory.UTF_8, false);
+ return valueOf(absolutePath, format, WriterFactory.UTF_8);
}
- /**
- * Performs potential clean up operations on the given file
- * @param file the file to clean up, not null.
- * @return {@code true} if the file was removed.
- */
- public boolean cleanUp(File file) {
- if (!file.toString().startsWith(getFile().toString())) {
- throw new IllegalStateException(
- "The given file " + file + " is not related to the input file: " + getFile());
- }
- if (removeAfterConversion) {
- return file.delete();
- }
- return false;
- }
-
- public static InputFileWrapper valueOf(String absolutePath, DefaultConverter.DoxiaFormat format, String charsetName)
- throws UnsupportedEncodingException, FileNotFoundException {
- return valueOf(absolutePath, format, charsetName, false);
- }
/**
* @param absolutePath for a wanted file or a wanted directory, not null.
* @param format not null
* @param charsetName could be null
- * @param removeAfterConversion if true, the file will be removed after the conversion
* @return a type safe input reader
* @throws UnsupportedEncodingException if the encoding is unsupported.
* @throws FileNotFoundException if the file for absolutePath is not found.
*/
- public static InputFileWrapper valueOf(
- String absolutePath, DefaultConverter.DoxiaFormat format, String charsetName, boolean removeAfterConversion)
+ public static InputFileWrapper valueOf(String absolutePath, DefaultConverter.DoxiaFormat format, String charsetName)
throws UnsupportedEncodingException, FileNotFoundException {
- return new InputFileWrapper(absolutePath, format, charsetName, removeAfterConversion);
+ return new InputFileWrapper(absolutePath, format, charsetName);
}
public DefaultConverter.DoxiaFormat getFormat() {
diff --git a/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java b/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java
new file mode 100644
index 0000000..8b785fd
--- /dev/null
+++ b/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.maven.doxia;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class DefaultConverterTest {
+
+ @Test
+ void testExecuteCommand() throws IOException, InterruptedException {
+ DefaultConverter.executeCommand("git", "version");
+ }
+
+ @Test
+ void testExecuteInvalidCommand() throws IOException, InterruptedException {
+ assertThrows(IOException.class, () -> {
+ DefaultConverter.executeCommand("invalid command");
+ });
+ }
+}