From dc074746b21a6aec05738a16d290f6094fdf0ef0 Mon Sep 17 00:00:00 2001 From: Chuckame Date: Sat, 21 Nov 2020 15:49:35 +0100 Subject: [PATCH] Added generate-profile with '--diff-from' param (not tested) --- .../configurator/command/ApplyCommand.java | 37 +++++++++++-------- .../configurator/command/DiffCommand.java | 17 ++------- .../command/GenerateProfileCommand.java | 29 +++++++++++---- ...ChangeAdapter.java => ProfileAdapter.java} | 2 +- .../configurator/profile/ConstantHelper.java | 14 +++++++ .../profile/ProfilePropertiesParser.java | 7 ++++ ...apterTest.java => ProfileAdapterTest.java} | 8 ++-- 7 files changed, 71 insertions(+), 43 deletions(-) rename src/main/java/fr/chuckame/marlinfw/configurator/constant/{ProfilePropertiesChangeAdapter.java => ProfileAdapter.java} (93%) rename src/test/java/fr/chuckame/marlinfw/configurator/constant/{ProfilePropertiesChangeAdapterTest.java => ProfileAdapterTest.java} (82%) diff --git a/src/main/java/fr/chuckame/marlinfw/configurator/command/ApplyCommand.java b/src/main/java/fr/chuckame/marlinfw/configurator/command/ApplyCommand.java index 9f3e418..f0bf967 100644 --- a/src/main/java/fr/chuckame/marlinfw/configurator/command/ApplyCommand.java +++ b/src/main/java/fr/chuckame/marlinfw/configurator/command/ApplyCommand.java @@ -6,8 +6,7 @@ import fr.chuckame.marlinfw.configurator.change.LineChangeFormatter; import fr.chuckame.marlinfw.configurator.change.LineChangeManager; import fr.chuckame.marlinfw.configurator.constant.Constant; -import fr.chuckame.marlinfw.configurator.constant.ProfilePropertiesChangeAdapter; -import fr.chuckame.marlinfw.configurator.profile.ProfileProperties; +import fr.chuckame.marlinfw.configurator.constant.ProfileAdapter; import fr.chuckame.marlinfw.configurator.profile.ProfilePropertiesParser; import fr.chuckame.marlinfw.configurator.util.ConsoleHelper; import fr.chuckame.marlinfw.configurator.util.FileHelper; @@ -38,7 +37,7 @@ public class ApplyCommand implements Command { @Parameter(names = {"--yes", "-y"}, description = "when present, the changes will be saved without prompting the user") private boolean applyWithoutPrompt; - private final ProfilePropertiesChangeAdapter changeAdapter; + private final ProfileAdapter profileAdapter; private final LineChangeManager lineChangeManager; private final LineChangeFormatter lineChangeFormatter; private final ProfilePropertiesParser profilePropertiesParser; @@ -47,19 +46,18 @@ public class ApplyCommand implements Command { @Override public Mono run() { - return fileHelper.listFiles(profilePaths) - .flatMap(profilePropertiesParser::parseFromFile) - .reduceWith(ProfileProperties::new, ProfileProperties::merge) - .map(changeAdapter::profileToConstants) - .flatMap(wantedConstants -> - prepareChanges(wantedConstants) - .flatMap(changes -> printChanges(changes) - .then(printUnusedConstants(changes, wantedConstants)) - .then(doSave ? checkIfUserAgree().then(applyAndSaveChanges(changes)) : Mono.empty())) - ); + return profilePropertiesParser + .parseFromFiles(profilePaths) + .map(profileAdapter::profileToConstants) + .flatMap(wantedConstants -> + prepareChanges(wantedConstants) + .flatMap(changes -> printChanges(changes) + .then(printUnusedConstants(changes, wantedConstants)) + .then(applyAndSaveChangesIfNeeded(changes))) + ); } - public Mono>> prepareChanges(final Map wantedConstants) { + private Mono>> prepareChanges(final Map wantedConstants) { return fileHelper.listFiles(filesPath) .flatMap(filePath -> fileHelper.lines(filePath) .index() @@ -117,6 +115,13 @@ private Mono printUnusedConstants(final Map> change .then(); } + private Mono applyAndSaveChangesIfNeeded(final Map> changes) { + if (!doSave) { + return Mono.empty(); + } + return checkIfUserAgree().then(applyAndSaveChanges(changes)); + } + private Mono checkIfUserAgree() { if (applyWithoutPrompt) { return Mono.empty(); @@ -128,7 +133,7 @@ private Mono checkIfUserAgree() { .then(); } - public Mono applyAndSaveChanges(final Map> changes) { + private Mono applyAndSaveChanges(final Map> changes) { return Flux.fromIterable(changes.entrySet()) .filter(e -> onlyChangedFile(e.getValue())) .groupBy(Map.Entry::getKey, Map.Entry::getValue) @@ -144,7 +149,7 @@ private boolean isModifyingChange(final LineChange change) { return !LineChange.DiffEnum.DO_NOTHING.equals(change.getDiff()); } - public Flux applyChanges(final Collection changes) { + private Flux applyChanges(final Collection changes) { return Flux.fromIterable(changes).flatMap(lineChangeManager::applyChange); } } diff --git a/src/main/java/fr/chuckame/marlinfw/configurator/command/DiffCommand.java b/src/main/java/fr/chuckame/marlinfw/configurator/command/DiffCommand.java index 25ae46f..e907418 100644 --- a/src/main/java/fr/chuckame/marlinfw/configurator/command/DiffCommand.java +++ b/src/main/java/fr/chuckame/marlinfw/configurator/command/DiffCommand.java @@ -7,9 +7,8 @@ import fr.chuckame.marlinfw.configurator.change.LineChangeFormatter; import fr.chuckame.marlinfw.configurator.change.LineChangeManager; import fr.chuckame.marlinfw.configurator.constant.Constant; -import fr.chuckame.marlinfw.configurator.constant.ConstantLineInterpreter; +import fr.chuckame.marlinfw.configurator.profile.ConstantHelper; import fr.chuckame.marlinfw.configurator.util.ConsoleHelper; -import fr.chuckame.marlinfw.configurator.util.FileHelper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; @@ -17,7 +16,6 @@ import java.nio.file.Path; import java.util.List; -import java.util.Map; @Component @Parameters(commandNames = "diff", commandDescription = "Display differences between marlin configuration files") @@ -30,26 +28,17 @@ public class DiffCommand implements Command { private final LineChangeManager lineChangeManager; private final LineChangeFormatter lineChangeFormatter; - private final FileHelper fileHelper; + private final ConstantHelper constantHelper; private final ConsoleHelper consoleHelper; - private final ConstantLineInterpreter constantLineInterpreter; @Override public Mono run() { - return Mono.zip(getConstants(leftFiles), getConstants(rightFiles)) + return Mono.zip(constantHelper.getConstants(leftFiles).collectMap(Constant::getName), constantHelper.getConstants(rightFiles).collectMap(Constant::getName)) .map(t -> Maps.difference(t.getT1(), t.getT2())) .flatMap(this::printDiff) .then(); } - private Mono> getConstants(final List files) { - return fileHelper.listFiles(files) - .flatMap(fileHelper::lines) - .flatMap(constantLineInterpreter::parseLine) - .map(ConstantLineInterpreter.ParsedConstant::getConstant) - .collectMap(Constant::getName); - } - private Mono printDiff(final MapDifference diff) { final var added = Flux.fromIterable(diff.entriesOnlyOnRight().values()) .map(addedConstant -> { diff --git a/src/main/java/fr/chuckame/marlinfw/configurator/command/GenerateProfileCommand.java b/src/main/java/fr/chuckame/marlinfw/configurator/command/GenerateProfileCommand.java index 5b377cc..131b407 100644 --- a/src/main/java/fr/chuckame/marlinfw/configurator/command/GenerateProfileCommand.java +++ b/src/main/java/fr/chuckame/marlinfw/configurator/command/GenerateProfileCommand.java @@ -2,13 +2,16 @@ import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; -import fr.chuckame.marlinfw.configurator.constant.ConstantLineInterpreter; +import com.google.common.collect.MapDifference; +import com.google.common.collect.Maps; +import fr.chuckame.marlinfw.configurator.constant.Constant; import fr.chuckame.marlinfw.configurator.profile.ConstantHelper; import fr.chuckame.marlinfw.configurator.profile.ProfilePropertiesParser; import fr.chuckame.marlinfw.configurator.util.ConsoleHelper; -import fr.chuckame.marlinfw.configurator.util.FileHelper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.file.Path; @@ -20,25 +23,35 @@ public class GenerateProfileCommand implements Command { @Parameter(required = true, description = "/path1 /path2 ...\tThe marlin constants folder or files paths") private List filesPath; + @Parameter(names = {"--diff-from"}, description = "The marlin constants folder or files paths from where you want to make a diff. If gathered, the generated profile will contains only the diff between those files and the command files") + private List filesPathBase; @Parameter(names = {"--output", "-o"}, required = true, description = "The output profile path, will be overwritten if already existing file. If 'console' is specified, the profile will just be printed to the console") private Path profilePath; private static final Path CONSOLE_OUTPUT = Path.of("console"); private final ProfilePropertiesParser profilePropertiesParser; - private final FileHelper fileHelper; private final ConstantHelper constantHelper; - private final ConstantLineInterpreter constantLineInterpreter; private final ConsoleHelper consoleHelper; @Override public Mono run() { - return constantHelper.constantsToProfile(fileHelper.listFiles(filesPath) - .flatMap(fileHelper::lines) - .flatMap(constantLineInterpreter::parseLine) - .map(ConstantLineInterpreter.ParsedConstant::getConstant)) + final Flux constants = CollectionUtils.isEmpty(filesPathBase) ? constantHelper.getConstants(filesPath) : getConstantsFromDiff(); + return constantHelper.constantsToProfile(constants) .flatMap(profile -> profilePath.equals(CONSOLE_OUTPUT) ? profilePropertiesParser.writeToString(profile).doOnNext(consoleHelper::writeLine).then() : profilePropertiesParser.writeToFile(profile, profilePath)); } + + /** + * @return only constants that are not present from {@link #filesPathBase}, and only modified constants present on both sides + */ + private Flux getConstantsFromDiff() { + return Mono.zip(constantHelper.getConstants(filesPathBase).collectMap(Constant::getName), + constantHelper.getConstants(filesPath).collectMap(Constant::getName)) + .map(t -> Maps.difference(t.getT1(), t.getT2())) + .flatMapMany(diff -> Flux.fromIterable(diff.entriesDiffering().values()) + .map(MapDifference.ValueDifference::leftValue) + .mergeWith(Flux.fromIterable(diff.entriesOnlyOnRight().values()))); + } } diff --git a/src/main/java/fr/chuckame/marlinfw/configurator/constant/ProfilePropertiesChangeAdapter.java b/src/main/java/fr/chuckame/marlinfw/configurator/constant/ProfileAdapter.java similarity index 93% rename from src/main/java/fr/chuckame/marlinfw/configurator/constant/ProfilePropertiesChangeAdapter.java rename to src/main/java/fr/chuckame/marlinfw/configurator/constant/ProfileAdapter.java index e728513..ee77290 100644 --- a/src/main/java/fr/chuckame/marlinfw/configurator/constant/ProfilePropertiesChangeAdapter.java +++ b/src/main/java/fr/chuckame/marlinfw/configurator/constant/ProfileAdapter.java @@ -7,7 +7,7 @@ import java.util.Map; @Component -public class ProfilePropertiesChangeAdapter { +public class ProfileAdapter { public Map profileToConstants(final ProfileProperties profileProperties) { final var wantedChanges = new HashMap(); profileProperties.getDisabled().forEach(constantName -> wantedChanges.put(constantName, disabledConstant(constantName))); diff --git a/src/main/java/fr/chuckame/marlinfw/configurator/profile/ConstantHelper.java b/src/main/java/fr/chuckame/marlinfw/configurator/profile/ConstantHelper.java index b07802d..2af8ff0 100644 --- a/src/main/java/fr/chuckame/marlinfw/configurator/profile/ConstantHelper.java +++ b/src/main/java/fr/chuckame/marlinfw/configurator/profile/ConstantHelper.java @@ -1,17 +1,24 @@ package fr.chuckame.marlinfw.configurator.profile; import fr.chuckame.marlinfw.configurator.constant.Constant; +import fr.chuckame.marlinfw.configurator.constant.ConstantLineInterpreter; +import fr.chuckame.marlinfw.configurator.util.FileHelper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.nio.file.Path; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; @Component @RequiredArgsConstructor public class ConstantHelper { + private final FileHelper fileHelper; + private final ConstantLineInterpreter constantLineInterpreter; + public Mono constantsToProfile(final Flux constants) { return constants.reduceWith(this::initEmptyProfile, this::addConstantToProfile); } @@ -28,4 +35,11 @@ private ProfileProperties addConstantToProfile(final ProfileProperties profile, } return profile; } + + public Flux getConstants(final List files) { + return fileHelper.listFiles(files) + .flatMap(fileHelper::lines) + .flatMap(constantLineInterpreter::parseLine) + .map(ConstantLineInterpreter.ParsedConstant::getConstant); + } } diff --git a/src/main/java/fr/chuckame/marlinfw/configurator/profile/ProfilePropertiesParser.java b/src/main/java/fr/chuckame/marlinfw/configurator/profile/ProfilePropertiesParser.java index cbce940..d798457 100644 --- a/src/main/java/fr/chuckame/marlinfw/configurator/profile/ProfilePropertiesParser.java +++ b/src/main/java/fr/chuckame/marlinfw/configurator/profile/ProfilePropertiesParser.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.io.Writer; import java.nio.file.Path; +import java.util.List; import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.INDENT_ARRAYS; import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.MINIMIZE_QUOTES; @@ -26,6 +27,12 @@ public class ProfilePropertiesParser { private final ObjectMapper yamlParser = prepareYamlMapper(); private final FileHelper fileHelper; + public Mono parseFromFiles(final List profileFilePaths) { + return fileHelper.listFiles(profileFilePaths) + .flatMap(this::parseFromFile) + .reduceWith(ProfileProperties::new, ProfileProperties::merge); + } + public Mono parseFromFile(final Path profileFilePath) { return fileHelper.read(profileFilePath) .map(ExceptionUtils.wrap(bytes -> yamlParser.readValue(bytes, ProfileProperties.class))); diff --git a/src/test/java/fr/chuckame/marlinfw/configurator/constant/ProfilePropertiesChangeAdapterTest.java b/src/test/java/fr/chuckame/marlinfw/configurator/constant/ProfileAdapterTest.java similarity index 82% rename from src/test/java/fr/chuckame/marlinfw/configurator/constant/ProfilePropertiesChangeAdapterTest.java rename to src/test/java/fr/chuckame/marlinfw/configurator/constant/ProfileAdapterTest.java index 8344dd9..895c933 100644 --- a/src/test/java/fr/chuckame/marlinfw/configurator/constant/ProfilePropertiesChangeAdapterTest.java +++ b/src/test/java/fr/chuckame/marlinfw/configurator/constant/ProfileAdapterTest.java @@ -9,8 +9,8 @@ import static org.assertj.core.api.Assertions.assertThat; -class ProfilePropertiesChangeAdapterTest { - private final ProfilePropertiesChangeAdapter changeAdapter = new ProfilePropertiesChangeAdapter(); +class ProfileAdapterTest { + private final ProfileAdapter profileAdapter = new ProfileAdapter(); @Test void getWantedConstantsShouldReturnEmptyMapWhenEmptyEnabledAndEmptyDisabled() { @@ -19,7 +19,7 @@ void getWantedConstantsShouldReturnEmptyMapWhenEmptyEnabledAndEmptyDisabled() { .disabled(List.of()) .build(); - final var wantedConstants = changeAdapter.profileToConstants(profile); + final var wantedConstants = profileAdapter.profileToConstants(profile); assertThat(wantedConstants).isEmpty(); } @@ -31,7 +31,7 @@ void getWantedConstantsShouldReturnExpectedConstants() { .disabled(List.of("c3", "c4")) .build(); - final var wantedConstants = changeAdapter.profileToConstants(profile); + final var wantedConstants = profileAdapter.profileToConstants(profile); assertThat(wantedConstants) .containsEntry("c1", Constant.builder().enabled(true).name("c1").value(null).build())