mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-23 16:05:09 +00:00

# Description of Changes Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details. --------- Co-authored-by: Dario Ghunney Ware <dariogware@gmail.com> Co-authored-by: Connor Yoh <con.yoh13@gmail.com> Co-authored-by: a <a> Co-authored-by: Reece <reecebrowne1995@gmail.com>
159 lines
6.4 KiB
Java
159 lines
6.4 KiB
Java
package stirling.software.SPDF.config;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.stream.Collectors;
|
|
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
|
import jakarta.annotation.PostConstruct;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import stirling.software.common.configuration.RuntimePathConfig;
|
|
|
|
@Configuration
|
|
@Slf4j
|
|
public class ExternalAppDepConfig {
|
|
|
|
private final EndpointConfiguration endpointConfiguration;
|
|
|
|
private final String weasyprintPath;
|
|
private final String unoconvPath;
|
|
private final Map<String, List<String>> commandToGroupMapping;
|
|
|
|
public ExternalAppDepConfig(
|
|
EndpointConfiguration endpointConfiguration, RuntimePathConfig runtimePathConfig) {
|
|
this.endpointConfiguration = endpointConfiguration;
|
|
weasyprintPath = runtimePathConfig.getWeasyPrintPath();
|
|
unoconvPath = runtimePathConfig.getUnoConvertPath();
|
|
|
|
commandToGroupMapping =
|
|
new HashMap<>() {
|
|
|
|
{
|
|
put("soffice", List.of("LibreOffice"));
|
|
put(weasyprintPath, List.of("Weasyprint"));
|
|
put("pdftohtml", List.of("Pdftohtml"));
|
|
put(unoconvPath, List.of("Unoconvert"));
|
|
put("qpdf", List.of("qpdf"));
|
|
put("tesseract", List.of("tesseract"));
|
|
}
|
|
};
|
|
}
|
|
|
|
private boolean isCommandAvailable(String command) {
|
|
try {
|
|
ProcessBuilder processBuilder = new ProcessBuilder();
|
|
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
|
processBuilder.command("where", command);
|
|
} else {
|
|
processBuilder.command("which", command);
|
|
}
|
|
Process process = processBuilder.start();
|
|
int exitCode = process.waitFor();
|
|
return exitCode == 0;
|
|
} catch (Exception e) {
|
|
log.debug("Error checking for command {}: {}", command, e.getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private List<String> getAffectedFeatures(String group) {
|
|
return endpointConfiguration.getEndpointsForGroup(group).stream()
|
|
.map(endpoint -> formatEndpointAsFeature(endpoint))
|
|
.toList();
|
|
}
|
|
|
|
private String formatEndpointAsFeature(String endpoint) {
|
|
// First replace common terms
|
|
String feature = endpoint.replace("-", " ").replace("pdf", "PDF").replace("img", "image");
|
|
// Split into words and capitalize each word
|
|
return Arrays.stream(feature.split("\\s+"))
|
|
.map(word -> capitalizeWord(word))
|
|
.collect(Collectors.joining(" "));
|
|
}
|
|
|
|
private String capitalizeWord(String word) {
|
|
if (word.isEmpty()) {
|
|
return word;
|
|
}
|
|
if ("pdf".equalsIgnoreCase(word)) {
|
|
return "PDF";
|
|
}
|
|
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
|
|
}
|
|
|
|
private void checkDependencyAndDisableGroup(String command) {
|
|
boolean isAvailable = isCommandAvailable(command);
|
|
if (!isAvailable) {
|
|
List<String> affectedGroups = commandToGroupMapping.get(command);
|
|
if (affectedGroups != null) {
|
|
for (String group : affectedGroups) {
|
|
List<String> affectedFeatures = getAffectedFeatures(group);
|
|
endpointConfiguration.disableGroup(group);
|
|
log.warn(
|
|
"Missing dependency: {} - Disabling group: {} (Affected features: {})",
|
|
command,
|
|
group,
|
|
affectedFeatures != null && !affectedFeatures.isEmpty()
|
|
? String.join(", ", affectedFeatures)
|
|
: "unknown");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@PostConstruct
|
|
public void checkDependencies() {
|
|
// Check core dependencies
|
|
checkDependencyAndDisableGroup("tesseract");
|
|
checkDependencyAndDisableGroup("soffice");
|
|
checkDependencyAndDisableGroup("qpdf");
|
|
checkDependencyAndDisableGroup(weasyprintPath);
|
|
checkDependencyAndDisableGroup("pdftohtml");
|
|
checkDependencyAndDisableGroup(unoconvPath);
|
|
// Special handling for Python/OpenCV dependencies
|
|
boolean pythonAvailable = isCommandAvailable("python3") || isCommandAvailable("python");
|
|
if (!pythonAvailable) {
|
|
List<String> pythonFeatures = getAffectedFeatures("Python");
|
|
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
|
|
endpointConfiguration.disableGroup("Python");
|
|
endpointConfiguration.disableGroup("OpenCV");
|
|
log.warn(
|
|
"Missing dependency: Python - Disabling Python features: {} and OpenCV features: {}",
|
|
String.join(", ", pythonFeatures),
|
|
String.join(", ", openCVFeatures));
|
|
} else {
|
|
// If Python is available, check for OpenCV
|
|
try {
|
|
ProcessBuilder processBuilder = new ProcessBuilder();
|
|
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
|
processBuilder.command("python", "-c", "import cv2");
|
|
} else {
|
|
processBuilder.command("python3", "-c", "import cv2");
|
|
}
|
|
Process process = processBuilder.start();
|
|
int exitCode = process.waitFor();
|
|
if (exitCode != 0) {
|
|
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
|
|
endpointConfiguration.disableGroup("OpenCV");
|
|
log.warn(
|
|
"OpenCV not available in Python - Disabling OpenCV features: {}",
|
|
String.join(", ", openCVFeatures));
|
|
}
|
|
} catch (Exception e) {
|
|
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
|
|
endpointConfiguration.disableGroup("OpenCV");
|
|
log.warn(
|
|
"Error checking OpenCV: {} - Disabling OpenCV features: {}",
|
|
e.getMessage(),
|
|
String.join(", ", openCVFeatures));
|
|
}
|
|
}
|
|
endpointConfiguration.logDisabledEndpointsSummary();
|
|
}
|
|
}
|