package ch.bfh.lpdg; import ch.bfh.lpdg.datastructure.Dependency; import ch.bfh.lpdg.datastructure.DependencyType; import lombok.NoArgsConstructor; import org.springframework.util.FileSystemUtils; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @NoArgsConstructor public class LatexHelper { private final InteractionHandler interactionHandler = InteractionHandler.getInstance(); private Path tempFile; private Path sourceFile; private Path tempFolder; private Dependency dependencies; public LatexHelper(File file, Dependency dependencies) throws IOException { this.dependencies = dependencies; this.tempFile = createTempFile(file, ".temp"); this.sourceFile = file.toPath(); this.tempFolder = createTempFolder(Paths.get(file.getParent())); interactionHandler.printDebugMessage("Temp-File has been created. " + tempFile); } private static String getFileExtension(String fileName) { int lastDotIndex = fileName.lastIndexOf("."); return (lastDotIndex != -1) ? fileName.substring(lastDotIndex) : ""; } public void findUnnecessaryDependencies(Boolean overwrite, Boolean minimize) throws IOException { this.interactionHandler.printDebugMessage("Finding unnecessary Dependencies."); List unnecessaryDependencies = new ArrayList<>(); for (var dep : dependencies.getDependencyList()) { if(dep.getType() != DependencyType.REQUIRE_PACKAGE && dep.getType() != DependencyType.USE_PACKAGE) continue; this.interactionHandler.printDebugMessage("Trying without " + dep.toString()); this.replaceDependency(tempFile, dep.getSource(), "%" + dep.getSource()); if (this.compileTempDocument(tempFolder.toAbsolutePath().toString(), tempFile.toAbsolutePath().toString())) { unnecessaryDependencies.add(dep); dep.IsUnused = true; } this.replaceDependency(tempFile, "%" + dep.getSource(), dep.getSource()); } this.deleteTempFiles(); if(unnecessaryDependencies.size() > 0) { System.out.println("\nThe following Packages are not needed:"); for (var dep : unnecessaryDependencies) System.out.println("\t" + dep.getName()); } if (minimize || overwrite) { Path fileToMinimize = overwrite ? this.sourceFile : createTempFile(sourceFile.toFile(), ".minimized"); this.writeMinimizedFile(fileToMinimize); } } public boolean compileTempDocument(final String outputDirectory, final String documentToCompile) { try { List cmd = Arrays.asList( "pdflatex", //We use pdflatex to compile the documents. "-output-directory", outputDirectory, //Set the output directory to the created tempFolder directory of the input "-interaction", "nonstopmode", "-halt-on-error", "-file-line-error", documentToCompile); this.interactionHandler.printDebugMessage("Running: " + cmd); ProcessBuilder processBuilder = new ProcessBuilder(cmd); // Redirect the error stream to the output stream processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); InputStream is = process.getInputStream(); int readBytes; byte[] buffer = new byte[1024]; StringBuilder outputBuilder = new StringBuilder(); while ((readBytes = is.read(buffer)) != -1) { String chunk = new String(buffer, 0, readBytes, StandardCharsets.UTF_8); outputBuilder.append(chunk); } this.interactionHandler.printDebugMessage(outputBuilder.toString()); var res = process.waitFor(); this.interactionHandler.printDebugMessage("ReturnCode: " + res); return res == 0; } catch (Exception e) { System.err.println("Error while compiling the temporary file: " + e); return false; } } private void writeMinimizedFile(Path minimizedFile) { for (var dep : dependencies.getDependencyList()) { if (!dep.IsUnused) continue; replaceDependency(minimizedFile, dep.getSource(), "%" + dep.getSource()); } } private void replaceDependency(Path file, String dependency, String replaceWith) { this.interactionHandler.printDebugMessage("Replacing " + dependency + " with " + replaceWith); try { BufferedReader reader = Files.newBufferedReader(file); StringBuilder content = new StringBuilder(); String row; while ((row = reader.readLine()) != null) { content.append(row).append(System.lineSeparator()); } String newContent = content.toString().replace(dependency, replaceWith); BufferedWriter writer = Files.newBufferedWriter(file); writer.write(newContent); reader.close(); writer.close(); } catch (IOException e) { System.err.println("Error in the temporary file: " + e); } } private Path createTempFile(File file, String identifier) throws IOException { var extension = getFileExtension(file.getName()); return Files.copy(Paths.get(file.getAbsolutePath()), Paths.get(file.getPath().replace(extension, identifier + extension)), StandardCopyOption.REPLACE_EXISTING); } private Path createTempFolder(Path parentDirectory) throws IOException { return Files.createTempDirectory(parentDirectory, "LatexDependencyTemp"); } private void deleteTempFiles() throws IOException { FileSystemUtils.deleteRecursively(tempFolder.toFile()); Files.delete(tempFile); } }