Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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=<envPrefix>] FILE_OR_DIR
Usage: mc-image-helper patch [-h] [--json-allow-comments]
[--patch-env-prefix=<envPrefix>] FILE_OR_DIR
Patches one or more existing files using JSON path based operations
Supports the file formats:
- JSON
Expand All @@ -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=<envPrefix>
Only placeholder variables with this prefix will be
processed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/me/itzg/helpers/patch/JsonFileFormat.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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(
Expand Down
23 changes: 17 additions & 6 deletions src/main/java/me/itzg/helpers/patch/PatchCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Integer> {
@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;
Expand Down
17 changes: 11 additions & 6 deletions src/main/java/me/itzg/helpers/patch/PatchSetProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
42 changes: 28 additions & 14 deletions src/test/java/me/itzg/helpers/patch/PatchSetProcessorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand All @@ -34,29 +38,39 @@ class PatchSetProcessorTest {
@Mock
EnvironmentVariablesProvider environmentVariablesProvider;

@Test
void setInJson(@TempDir Path tempDir) throws IOException {
public static Stream<Arguments> 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")
);
}

Expand Down
6 changes: 6 additions & 0 deletions src/test/resources/patch/testing-with-comment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"outer": {
// some comment
"field1": "old"
}
}