diff --git a/README.md b/README.md index 94727447..ade4bbf9 100644 --- a/README.md +++ b/README.md @@ -935,7 +935,8 @@ Provides simple operations to list network interface names and check existence ### patch ``` -Usage: mc-image-helper patch [-h] [--patch-env-prefix=] FILE_OR_DIR +Usage: mc-image-helper patch [-h] [--json-allow-comments] + [--patch-env-prefix=] FILE_OR_DIR Patches one or more existing files using JSON path based operations Supports the file formats: - JSON @@ -945,6 +946,9 @@ Supports the file formats: FILE_OR_DIR Path to a PatchSet json file or directory containing PatchDefinition json files -h, --help Show this usage and exit + --json-allow-comments + Whether to allow comments in JSON files. Env: PATCH_JSON_ALLOW_COMMENTS + Default: true --patch-env-prefix= Only placeholder variables with this prefix will be processed diff --git a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java index 2a78bd00..a67924ef 100644 --- a/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java +++ b/src/main/java/me/itzg/helpers/curseforge/CurseForgeInstaller.java @@ -230,7 +230,7 @@ void install(String slug, InstallationEntryPoint entryPoint) { ); } catch (IOException e) { - throw new GenericException("Failed to setup API caching", e); + throw new GenericException("File system issue during installation", e); } } diff --git a/src/main/java/me/itzg/helpers/patch/JsonFileFormat.java b/src/main/java/me/itzg/helpers/patch/JsonFileFormat.java index 68b74172..2a023c52 100644 --- a/src/main/java/me/itzg/helpers/patch/JsonFileFormat.java +++ b/src/main/java/me/itzg/helpers/patch/JsonFileFormat.java @@ -1,5 +1,6 @@ package me.itzg.helpers.patch; +import com.fasterxml.jackson.core.JsonParser.Feature; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.core.util.Separators; @@ -19,8 +20,9 @@ public class JsonFileFormat implements FileFormat { private final ObjectMapper objectMapper; private final ObjectWriter objectWriter; - public JsonFileFormat() { - objectMapper = new ObjectMapper(); + public JsonFileFormat(boolean allowComments) { + objectMapper = new ObjectMapper() + .configure(Feature.ALLOW_COMMENTS, allowComments); objectWriter = objectMapper.writer( new DefaultPrettyPrinter() .withSeparators( diff --git a/src/main/java/me/itzg/helpers/patch/PatchCommand.java b/src/main/java/me/itzg/helpers/patch/PatchCommand.java index bbb270ad..1ceae993 100644 --- a/src/main/java/me/itzg/helpers/patch/PatchCommand.java +++ b/src/main/java/me/itzg/helpers/patch/PatchCommand.java @@ -13,28 +13,39 @@ import me.itzg.helpers.patch.model.PatchDefinition; import me.itzg.helpers.patch.model.PatchSet; import picocli.CommandLine; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; +import picocli.CommandLine.Parameters; -@CommandLine.Command(name = "patch", +@Command(name = "patch", description = "Patches one or more existing files using JSON path based operations%n" + "Supports the file formats:%n" + "- JSON%n" + "- JSON5%n" + "- Yaml%n" - + "- TOML, but processed output is not pretty" + + "- TOML, but processed output is not pretty", + showDefaultValues = true ) @Slf4j public class PatchCommand implements Callable { - @CommandLine.Option(names = {"-h", "--help"}, usageHelp = true, description = "Show this usage and exit") + + private static final String ENV_JSON_ALLOW_COMMENTS = "PATCH_JSON_ALLOW_COMMENTS"; + @Option(names = {"-h", "--help"}, usageHelp = true, description = "Show this usage and exit") boolean showHelp; - @CommandLine.Option(names = "--patch-env-prefix", + @Option(names = "--patch-env-prefix", defaultValue = "CFG_", - showDefaultValue = CommandLine.Help.Visibility.ALWAYS, description = "Only placeholder variables with this prefix will be processed" ) String envPrefix; - @CommandLine.Parameters(description = "Path to a PatchSet json file or directory containing PatchDefinition json files", + @Option(names = "--json-allow-comments", defaultValue = "${env:" + ENV_JSON_ALLOW_COMMENTS + ":-true}", + description = "Whether to allow comments in JSON files. Env: " + ENV_JSON_ALLOW_COMMENTS, + showDefaultValue = CommandLine.Help.Visibility.ALWAYS + ) + boolean jsonAllowComments; + + @Parameters(description = "Path to a PatchSet json file or directory containing PatchDefinition json files", paramLabel = "FILE_OR_DIR" ) Path patches; diff --git a/src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java b/src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java index 54613f92..2cc906c9 100644 --- a/src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java +++ b/src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java @@ -29,15 +29,20 @@ public class PatchSetProcessor { private final Interpolator interpolator; public PatchSetProcessor(Interpolator interpolator) { + this(interpolator, false); + } + + public PatchSetProcessor(Interpolator interpolator, boolean jsonAllowComments) { this.interpolator = interpolator; + fileFormats = new FileFormat[]{ + new JsonFileFormat(jsonAllowComments), + new Json5FileFormat(), + new YamlFileFormat(), + new TomlFileFormat() + }; } - private final FileFormat[] fileFormats = new FileFormat[]{ - new JsonFileFormat(), - new Json5FileFormat(), - new YamlFileFormat(), - new TomlFileFormat() - }; + private final FileFormat[] fileFormats; public void process(PatchSet patchSet) { log.debug("patchSet={}", patchSet); diff --git a/src/test/java/me/itzg/helpers/patch/PatchSetProcessorTest.java b/src/test/java/me/itzg/helpers/patch/PatchSetProcessorTest.java index b6543831..063652d2 100644 --- a/src/test/java/me/itzg/helpers/patch/PatchSetProcessorTest.java +++ b/src/test/java/me/itzg/helpers/patch/PatchSetProcessorTest.java @@ -16,6 +16,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.stream.Stream; import me.itzg.helpers.env.EnvironmentVariablesProvider; import me.itzg.helpers.env.Interpolator; import me.itzg.helpers.patch.model.PatchDefinition; @@ -25,6 +26,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -34,29 +38,39 @@ class PatchSetProcessorTest { @Mock EnvironmentVariablesProvider environmentVariablesProvider; - @Test - void setInJson(@TempDir Path tempDir) throws IOException { + public static Stream setInJson_args() { + return Stream.of( + Arguments.arguments("testing.json", false), + Arguments.arguments("testing.json", true), + Arguments.arguments("testing-with-comment.json", true) + ); + } + + @ParameterizedTest + @MethodSource("setInJson_args") + void setInJson(String file, boolean allowComments, @TempDir Path tempDir) throws IOException { final Path src = tempDir.resolve("testing.json"); - Files.copy(Paths.get("src/test/resources/patch/testing.json"), src); + Files.copy(Paths.get("src/test/resources/patch/" + file), src); final PatchSetProcessor processor = new PatchSetProcessor( - new Interpolator(environmentVariablesProvider, "CFG_") + new Interpolator(environmentVariablesProvider, "CFG_"), + allowComments ); processor.process(new PatchSet() - .setPatches(singletonList( - new PatchDefinition() - .setFile(src.toString()) - .setOps(singletonList( - new PatchSetOperation() - .setPath("$.outer.field1") - .setValue(new TextNode("new value")) - )) - )) + .setPatches(singletonList( + new PatchDefinition() + .setFile(src.toString()) + .setOps(singletonList( + new PatchSetOperation() + .setPath("$.outer.field1") + .setValue(new TextNode("new value")) + )) + )) ); assertThat(src).hasSameTextualContentAs( - Paths.get("src/test/resources/patch/expected-setInJson.json") + Paths.get("src/test/resources/patch/expected-setInJson.json") ); } diff --git a/src/test/resources/patch/testing-with-comment.json b/src/test/resources/patch/testing-with-comment.json new file mode 100644 index 00000000..59c9e3b8 --- /dev/null +++ b/src/test/resources/patch/testing-with-comment.json @@ -0,0 +1,6 @@ +{ + "outer": { + // some comment + "field1": "old" + } +} \ No newline at end of file