diff --git a/build.gradle b/build.gradle index e803b512..06db8ab3 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'stirling.software' -version = '0.14.2' +version = '0.14.3' sourceCompatibility = '17' repositories { diff --git a/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java b/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java index 9760662a..862f5718 100644 --- a/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java +++ b/src/main/java/stirling/software/SPDF/config/ConfigInitializer.java @@ -12,6 +12,8 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import org.springframework.context.ApplicationContextInitializer; @@ -19,83 +21,109 @@ import org.springframework.context.ConfigurableApplicationContext; public class ConfigInitializer implements ApplicationContextInitializer { - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - try { - ensureConfigExists(); - } catch (IOException e) { - throw new RuntimeException("Failed to initialize application configuration", e); - } - } + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + try { + ensureConfigExists(); + } catch (IOException e) { + throw new RuntimeException("Failed to initialize application configuration", e); + } + } - public void ensureConfigExists() throws IOException { - // Define the path to the external config directory - Path destPath = Paths.get("configs", "settings.yml"); + public void ensureConfigExists() throws IOException { + // Define the path to the external config directory + Path destPath = Paths.get("configs", "settings.yml"); - // Check if the file already exists - if (Files.notExists(destPath)) { - // Ensure the destination directory exists - Files.createDirectories(destPath.getParent()); + // Check if the file already exists + if (Files.notExists(destPath)) { + // Ensure the destination directory exists + Files.createDirectories(destPath.getParent()); - // Copy the resource from classpath to the external directory - try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) { - if (in != null) { - Files.copy(in, destPath); - } else { - throw new FileNotFoundException("Resource file not found: settings.yml.template"); - } - } - } else { - // If user file exists, we need to merge it with the template from the classpath - List templateLines; - try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) { - templateLines = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines().collect(Collectors.toList()); - } + // Copy the resource from classpath to the external directory + try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) { + if (in != null) { + Files.copy(in, destPath); + } else { + throw new FileNotFoundException("Resource file not found: settings.yml.template"); + } + } + } else { + // If user file exists, we need to merge it with the template from the classpath + List templateLines; + try (InputStream in = getClass().getClassLoader().getResourceAsStream("settings.yml.template")) { + templateLines = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)).lines() + .collect(Collectors.toList()); + } - mergeYamlFiles(templateLines, destPath, destPath); - } - } + mergeYamlFiles(templateLines, destPath, destPath); + } + } - public void mergeYamlFiles(List templateLines, Path userFilePath, Path outputPath) throws IOException { - List userLines = Files.readAllLines(userFilePath); + public void mergeYamlFiles(List templateLines, Path userFilePath, Path outputPath) throws IOException { + List userLines = Files.readAllLines(userFilePath); + List mergedLines = new ArrayList<>(); + boolean insideAutoGenerated = false; + boolean beforeFirstKey = true; - List mergedLines = new ArrayList<>(); - boolean insideAutoGenerated = false; + Function isCommented = line -> line.trim().startsWith("#"); + Function extractKey = line -> { + String[] parts = line.split(":"); + return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : ""; + }; - for (String line : templateLines) { - // Check if we've entered or left the AutomaticallyGenerated section - if (line.trim().equalsIgnoreCase("AutomaticallyGenerated:")) { - insideAutoGenerated = true; - mergedLines.add(line); - continue; - } else if (insideAutoGenerated && line.trim().isEmpty()) { - // We have reached the end of the AutomaticallyGenerated section - insideAutoGenerated = false; - mergedLines.add(line); - continue; - } + Set userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet()); - if (insideAutoGenerated) { - // Add lines from user's settings if we are inside AutomaticallyGenerated - Optional userAutoGenValue = userLines.stream().filter(l -> l.trim().startsWith(line.split(":")[0].trim())).findFirst(); - if (userAutoGenValue.isPresent()) { - mergedLines.add(userAutoGenValue.get()); - continue; - } - } else { - // Outside of AutomaticallyGenerated, continue as before - if (line.contains(": ")) { - String key = line.split(": ")[0].trim(); - Optional userValue = userLines.stream().filter(l -> l.trim().startsWith(key)).findFirst(); - if (userValue.isPresent()) { - mergedLines.add(userValue.get()); - continue; - } - } - mergedLines.add(line); - } - } + for (String line : templateLines) { + String key = extractKey.apply(line); + + if (line.trim().equalsIgnoreCase("AutomaticallyGenerated:")) { + insideAutoGenerated = true; + mergedLines.add(line); + continue; + } else if (insideAutoGenerated && line.trim().isEmpty()) { + insideAutoGenerated = false; + mergedLines.add(line); + continue; + } + + if (beforeFirstKey && (isCommented.apply(line) || line.trim().isEmpty())) { + // Handle top comments and empty lines before the first key. + mergedLines.add(line); + continue; + } + + if (!key.isEmpty()) + beforeFirstKey = false; + + if (userKeys.contains(key)) { + // If user has any version (commented or uncommented) of this key, skip the + // template line + Optional userValue = userLines.stream() + .filter(l -> extractKey.apply(l).equalsIgnoreCase(key) && !isCommented.apply(l)).findFirst(); + if (userValue.isPresent()) + mergedLines.add(userValue.get()); + continue; + } + + if (isCommented.apply(line) || line.trim().isEmpty() || !userKeys.contains(key)) { + mergedLines.add(line); // If line is commented, empty or key not present in user's file, retain the + // template line + continue; + } + } + + // Add any additional uncommented user lines that are not present in the + // template + for (String userLine : userLines) { + String userKey = extractKey.apply(userLine); + boolean isPresentInTemplate = templateLines.stream().map(extractKey) + .anyMatch(templateKey -> templateKey.equalsIgnoreCase(userKey)); + if (!isPresentInTemplate && !isCommented.apply(userLine)) { + mergedLines.add(userLine); + } + } + + Files.write(outputPath, mergedLines, StandardCharsets.UTF_8); + } - Files.write(outputPath, mergedLines, StandardCharsets.UTF_8); - } } \ No newline at end of file