2023-08-26 18:30:49 +02:00
|
|
|
package stirling.software.SPDF.config;
|
2023-09-05 21:58:18 +02:00
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
2023-08-26 18:30:49 +02:00
|
|
|
import java.io.FileNotFoundException;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
2023-09-05 21:58:18 +02:00
|
|
|
import java.io.InputStreamReader;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
2023-08-26 18:30:49 +02:00
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Path;
|
|
|
|
import java.nio.file.Paths;
|
2023-09-05 21:58:18 +02:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Optional;
|
2023-09-24 22:09:34 +02:00
|
|
|
import java.util.Set;
|
|
|
|
import java.util.function.Function;
|
2023-09-05 21:58:18 +02:00
|
|
|
import java.util.stream.Collectors;
|
2023-08-26 18:30:49 +02:00
|
|
|
|
|
|
|
import org.springframework.context.ApplicationContextInitializer;
|
|
|
|
import org.springframework.context.ConfigurableApplicationContext;
|
|
|
|
|
|
|
|
public class ConfigInitializer
|
|
|
|
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
@Override
|
|
|
|
public void initialize(ConfigurableApplicationContext applicationContext) {
|
|
|
|
try {
|
|
|
|
ensureConfigExists();
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new RuntimeException("Failed to initialize application configuration", e);
|
|
|
|
}
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
public void ensureConfigExists() throws IOException {
|
|
|
|
// Define the path to the external config directory
|
|
|
|
Path destPath = Paths.get("configs", "settings.yml");
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
// Check if the file already exists
|
|
|
|
if (Files.notExists(destPath)) {
|
|
|
|
// Ensure the destination directory exists
|
|
|
|
Files.createDirectories(destPath.getParent());
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
// 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<String> templateLines;
|
|
|
|
try (InputStream in =
|
|
|
|
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
|
|
|
templateLines =
|
|
|
|
new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))
|
|
|
|
.lines()
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
mergeYamlFiles(templateLines, destPath, destPath);
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
}
|
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
public void mergeYamlFiles(List<String> templateLines, Path userFilePath, Path outputPath)
|
|
|
|
throws IOException {
|
|
|
|
List<String> userLines = Files.readAllLines(userFilePath);
|
|
|
|
List<String> mergedLines = new ArrayList<>();
|
|
|
|
boolean insideAutoGenerated = false;
|
|
|
|
boolean beforeFirstKey = true;
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
Function<String, Boolean> isCommented = line -> line.trim().startsWith("#");
|
|
|
|
Function<String, String> extractKey =
|
|
|
|
line -> {
|
|
|
|
String[] parts = line.split(":");
|
|
|
|
return parts.length > 0 ? parts[0].trim().replace("#", "").trim() : "";
|
|
|
|
};
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2024-02-17 14:10:00 +01:00
|
|
|
Function<String, Integer> getIndentationLevel =
|
|
|
|
line -> {
|
|
|
|
int count = 0;
|
|
|
|
for (char ch : line.toCharArray()) {
|
|
|
|
if (ch == ' ') count++;
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
Set<String> userKeys = userLines.stream().map(extractKey).collect(Collectors.toSet());
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
for (String line : templateLines) {
|
|
|
|
String key = extractKey.apply(line);
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2024-02-02 01:29:18 +01:00
|
|
|
if ("AutomaticallyGenerated:".equalsIgnoreCase(line.trim())) {
|
2023-09-24 22:09:34 +02:00
|
|
|
insideAutoGenerated = true;
|
|
|
|
mergedLines.add(line);
|
|
|
|
continue;
|
|
|
|
} else if (insideAutoGenerated && line.trim().isEmpty()) {
|
|
|
|
insideAutoGenerated = false;
|
|
|
|
mergedLines.add(line);
|
|
|
|
continue;
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
if (beforeFirstKey && (isCommented.apply(line) || line.trim().isEmpty())) {
|
|
|
|
// Handle top comments and empty lines before the first key.
|
|
|
|
mergedLines.add(line);
|
|
|
|
continue;
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
if (!key.isEmpty()) beforeFirstKey = false;
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
if (userKeys.contains(key)) {
|
|
|
|
// If user has any version (commented or uncommented) of this key, skip the
|
|
|
|
// template line
|
|
|
|
Optional<String> userValue =
|
|
|
|
userLines.stream()
|
|
|
|
.filter(
|
|
|
|
l ->
|
|
|
|
extractKey.apply(l).equalsIgnoreCase(key)
|
|
|
|
&& !isCommented.apply(l))
|
|
|
|
.findFirst();
|
|
|
|
if (userValue.isPresent()) mergedLines.add(userValue.get());
|
|
|
|
continue;
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
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;
|
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
}
|
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
// 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)) {
|
2024-02-17 14:10:00 +01:00
|
|
|
if (!childOfTemplateEntry(
|
|
|
|
isCommented,
|
|
|
|
extractKey,
|
|
|
|
getIndentationLevel,
|
|
|
|
userLines,
|
|
|
|
userLine,
|
|
|
|
templateLines)) {
|
|
|
|
// check if userLine is a child of a entry within templateLines or not, if child
|
|
|
|
// of parent in templateLines then dont add to mergedLines, if anything else
|
|
|
|
// then add
|
|
|
|
mergedLines.add(userLine);
|
|
|
|
}
|
2023-09-24 22:09:34 +02:00
|
|
|
}
|
2023-12-30 20:11:27 +01:00
|
|
|
}
|
|
|
|
|
2023-09-24 22:09:34 +02:00
|
|
|
Files.write(outputPath, mergedLines, StandardCharsets.UTF_8);
|
|
|
|
}
|
2024-02-17 14:10:00 +01:00
|
|
|
|
|
|
|
// New method to check if a userLine is a child of an entry in templateLines
|
|
|
|
boolean childOfTemplateEntry(
|
|
|
|
Function<String, Boolean> isCommented,
|
|
|
|
Function<String, String> extractKey,
|
|
|
|
Function<String, Integer> getIndentationLevel,
|
|
|
|
List<String> userLines,
|
|
|
|
String userLine,
|
|
|
|
List<String> templateLines) {
|
|
|
|
String userKey = extractKey.apply(userLine).trim();
|
|
|
|
int userIndentation = getIndentationLevel.apply(userLine);
|
|
|
|
|
|
|
|
// Start by assuming the line is not a child of an entry in templateLines
|
|
|
|
boolean isChild = false;
|
|
|
|
|
|
|
|
// Iterate backwards through userLines from the current line to find any parent
|
|
|
|
for (int i = userLines.indexOf(userLine) - 1; i >= 0; i--) {
|
|
|
|
String potentialParentLine = userLines.get(i);
|
|
|
|
int parentIndentation = getIndentationLevel.apply(potentialParentLine);
|
|
|
|
|
|
|
|
// Check if we've reached a potential parent based on indentation
|
|
|
|
if (parentIndentation < userIndentation) {
|
|
|
|
String parentKey = extractKey.apply(potentialParentLine).trim();
|
|
|
|
|
|
|
|
// Now, check if this potential parent or any of its parents exist in templateLines
|
|
|
|
boolean parentExistsInTemplate =
|
|
|
|
templateLines.stream()
|
|
|
|
.filter(line -> !isCommented.apply(line)) // Skip commented lines
|
|
|
|
.anyMatch(
|
|
|
|
templateLine -> {
|
|
|
|
String templateKey =
|
|
|
|
extractKey.apply(templateLine).trim();
|
|
|
|
return parentKey.equalsIgnoreCase(templateKey);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!parentExistsInTemplate) {
|
|
|
|
// If the parent does not exist in template, check the next level parent
|
|
|
|
userIndentation =
|
|
|
|
parentIndentation; // Update userIndentation to the parent's indentation
|
|
|
|
// for next iteration
|
|
|
|
if (parentIndentation == 0) {
|
|
|
|
// If we've reached the top-level parent and it's not in template, the
|
|
|
|
// original line is considered not a child
|
|
|
|
isChild = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// If any parent exists in template, the original line is considered a child
|
|
|
|
isChild = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return isChild; // Return true if the line is not a child of any entry in templateLines
|
|
|
|
}
|
2023-09-05 21:58:18 +02:00
|
|
|
}
|