Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,15 @@ private static boolean addPathToConfigFile(File configFile, File binDir, File ho
}

// Append PATH export to the config file (always at the end)
// Read current content to ensure clean trailing whitespace before appending
DebugLogger.log("Writing PATH export to: " + configFile.getAbsolutePath());
String pathExport = "\n# Added by jDeploy installer\nexport PATH=\"" + pathExportString + ":$PATH\"\n";
try (FileOutputStream fos = new FileOutputStream(configFile, true)) {
fos.write(pathExport.getBytes(StandardCharsets.UTF_8));
String currentContent = IOUtil.readToString(new FileInputStream(configFile));
String trimmedContent = currentContent.replaceAll("\\s+$", "");
// Use a blank line separator only when there's existing content
String separator = trimmedContent.isEmpty() ? "" : "\n\n";
String pathExport = separator + "# Added by jDeploy installer\nexport PATH=\"" + pathExportString + ":$PATH\"\n";
try (FileOutputStream fos = new FileOutputStream(configFile)) {
fos.write((trimmedContent + pathExport).getBytes(StandardCharsets.UTF_8));
}

System.out.println("Added " + displayPath + " to PATH in " + configFile.getName());
Expand Down Expand Up @@ -299,13 +304,22 @@ public static boolean removePathFromConfigFile(File configFile, File binDir, Fil
// Look ahead to see if the next line is an export for our binDir
if (i + 1 < lines.length) {
String nextLine = lines[i + 1].trim();
if (nextLine.startsWith("export PATH=\"") &&
if (nextLine.startsWith("export PATH=\"") &&
(nextLine.contains(pathExportString) || nextLine.contains(absolutePath))) {
// Skip this comment line and mark to skip the export line
skipNextExport = true;
removed = true;
continue;
}
// Orphaned comment: not followed by any export PATH line
if (!nextLine.startsWith("export PATH=\"")) {
removed = true;
continue;
}
} else {
// Comment at end of file with no following line - orphaned
removed = true;
continue;
}
}

Expand Down Expand Up @@ -335,8 +349,12 @@ public static boolean removePathFromConfigFile(File configFile, File binDir, Fil

if (removed) {
// Write back the modified content
// Preserve trailing newline if original had one
String newContent = result.toString();
// Collapse multiple consecutive blank lines into at most one
newContent = newContent.replaceAll("\n{3,}", "\n\n");
// Trim trailing blank lines, keeping at most one trailing newline
newContent = newContent.replaceAll("\n{2,}$", "\n");
// Preserve trailing newline if original had one
if (content.endsWith("\n") && !newContent.endsWith("\n")) {
newContent += "\n";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1092,4 +1092,113 @@ public void testAddToPathOnLinuxRespectsNoAutoPathInProfile() throws IOException
assertTrue(bashrcContent.contains(binDir.getAbsolutePath()),
".bashrc should contain the PATH export");
}

// ==================== Blank Line Cleanup Tests ====================

@Test
public void testRemovePathCollapsesConsecutiveBlankLines() throws IOException {
File bashrc = new File(homeDir, ".bashrc");
String existingPath = binDir.getAbsolutePath();
// Simulate a file with blank lines around jDeploy entries (from repeated install/uninstall)
String originalContent = "# Some config\nexport FOO=bar\n\n\n\n\n# Added by jDeploy installer\nexport PATH=\"" + existingPath + ":$PATH\"\n\n\n\n\nexport BAZ=qux\n";
Files.write(bashrc.toPath(), originalContent.getBytes(StandardCharsets.UTF_8));

boolean removed = UnixPathManager.removePathFromConfigFile(bashrc, binDir, homeDir);

assertTrue(removed, "Should return true when entry was removed");
String content = IOUtil.readToString(new FileInputStream(bashrc));
assertFalse(content.contains(existingPath), "PATH entry should be removed");
assertFalse(content.contains("\n\n\n"), "Should not have more than one consecutive blank line");
assertTrue(content.contains("export FOO=bar"), "Other content should be preserved");
assertTrue(content.contains("export BAZ=qux"), "Other content should be preserved");
}

@Test
public void testRemovePathRemovesOrphanedComments() throws IOException {
File bashrc = new File(homeDir, ".bashrc");
String existingPath = binDir.getAbsolutePath();
// Simulate orphaned comments (comment not followed by export PATH line)
String originalContent = "# Some config\nexport FOO=bar\n# Added by jDeploy installer\n\n# Added by jDeploy installer\n# Added by jDeploy installer\nexport PATH=\"" + existingPath + ":$PATH\"\nexport BAZ=qux\n";
Files.write(bashrc.toPath(), originalContent.getBytes(StandardCharsets.UTF_8));

boolean removed = UnixPathManager.removePathFromConfigFile(bashrc, binDir, homeDir);

assertTrue(removed, "Should return true when entries were removed");
String content = IOUtil.readToString(new FileInputStream(bashrc));
assertFalse(content.contains("# Added by jDeploy installer"), "All jDeploy comments should be removed");
assertFalse(content.contains(existingPath), "PATH entry should be removed");
assertTrue(content.contains("export FOO=bar"), "Other content should be preserved");
assertTrue(content.contains("export BAZ=qux"), "Other content should be preserved");
}

@Test
public void testRemovePathRemovesOrphanedCommentAtEndOfFile() throws IOException {
File bashrc = new File(homeDir, ".bashrc");
String existingPath = binDir.getAbsolutePath();
// Orphaned comment at end of file
String originalContent = "# Some config\nexport FOO=bar\n# Added by jDeploy installer\nexport PATH=\"" + existingPath + ":$PATH\"\n# Added by jDeploy installer\n";
Files.write(bashrc.toPath(), originalContent.getBytes(StandardCharsets.UTF_8));

boolean removed = UnixPathManager.removePathFromConfigFile(bashrc, binDir, homeDir);

assertTrue(removed, "Should return true when entries were removed");
String content = IOUtil.readToString(new FileInputStream(bashrc));
assertFalse(content.contains("# Added by jDeploy installer"), "All jDeploy comments should be removed");
assertFalse(content.contains(existingPath), "PATH entry should be removed");
assertTrue(content.contains("export FOO=bar"), "Other content should be preserved");
}

@Test
public void testRemovePathPreservesCommentsForOtherApps() throws IOException {
File bashrc = new File(homeDir, ".bashrc");
String existingPath = binDir.getAbsolutePath();
// Comment+export for a different app should be preserved
String originalContent = "# Some config\n# Added by jDeploy installer\nexport PATH=\"" + existingPath + ":$PATH\"\n# Added by jDeploy installer\nexport PATH=\"/some/other/app:$PATH\"\nexport FOO=bar\n";
Files.write(bashrc.toPath(), originalContent.getBytes(StandardCharsets.UTF_8));

boolean removed = UnixPathManager.removePathFromConfigFile(bashrc, binDir, homeDir);

assertTrue(removed, "Should return true when entry was removed");
String content = IOUtil.readToString(new FileInputStream(bashrc));
assertFalse(content.contains(existingPath), "Our PATH entry should be removed");
assertTrue(content.contains("# Added by jDeploy installer"), "Comment for other app should be preserved");
assertTrue(content.contains("/some/other/app"), "Other app's PATH should be preserved");
assertTrue(content.contains("export FOO=bar"), "Other content should be preserved");
}

@Test
public void testRemovePathTrimsTrailingBlankLines() throws IOException {
File bashrc = new File(homeDir, ".bashrc");
String existingPath = binDir.getAbsolutePath();
// Entry at end of file followed by blank lines
String originalContent = "# Some config\nexport FOO=bar\n# Added by jDeploy installer\nexport PATH=\"" + existingPath + ":$PATH\"\n\n\n\n";
Files.write(bashrc.toPath(), originalContent.getBytes(StandardCharsets.UTF_8));

boolean removed = UnixPathManager.removePathFromConfigFile(bashrc, binDir, homeDir);

assertTrue(removed, "Should return true when entry was removed");
String content = IOUtil.readToString(new FileInputStream(bashrc));
assertFalse(content.contains(existingPath), "PATH entry should be removed");
assertTrue(content.endsWith("\n"), "Should end with a single newline");
assertFalse(content.endsWith("\n\n"), "Should not end with multiple newlines");
}

@Test
public void testAddPathDoesNotAccumulateBlankLines() throws IOException {
File bashrc = new File(homeDir, ".bashrc");
String existingPath = binDir.getAbsolutePath();
// Simulate existing content with trailing blank lines
String originalContent = "# Some config\nexport FOO=bar\n\n\n\n";
Files.write(bashrc.toPath(), originalContent.getBytes(StandardCharsets.UTF_8));

// Add path entry
String shell = "/bin/bash";
String pathEnv = "/usr/bin:/bin";
UnixPathManager.addToPath(binDir, shell, pathEnv, homeDir);

String content = IOUtil.readToString(new FileInputStream(bashrc));
assertFalse(content.contains("\n\n\n"), "Should not have more than one consecutive blank line");
assertTrue(content.contains("# Added by jDeploy installer"), "Should have jDeploy comment");
assertTrue(content.contains(existingPath), "Should have PATH entry");
}
}
Loading