package org.graalvm.component.installer.commands;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.graalvm.component.installer.CommonConstants;
import org.graalvm.component.installer.Feedback;
import org.graalvm.component.installer.FileOperations;
import org.graalvm.component.installer.SystemUtils;
import org.graalvm.component.installer.model.ComponentInfo;
import org.graalvm.component.installer.model.ComponentRegistry;
public class Uninstaller {
private final Feedback feedback;
private final ComponentInfo componentInfo;
private final ComponentRegistry registry;
private final FileOperations fileOps;
private PreRemoveProcess preRemove;
private Set<String> preservePaths = Collections.emptySet();
private boolean dryRun;
private boolean ignoreFailedDeletions;
private Path installPath;
private boolean rebuildPolyglot;
private final Set<String> directoriesToDelete = new HashSet<>();
public Uninstaller(Feedback feedback, FileOperations fops, ComponentInfo componentInfo, ComponentRegistry registry) {
this.feedback = feedback;
this.componentInfo = componentInfo;
this.registry = registry;
this.fileOps = fops;
}
public void uninstall() throws IOException {
uninstallContent();
if (!isDryRun()) {
registry.removeComponent(componentInfo);
}
}
public boolean isRebuildPolyglot() {
return rebuildPolyglot;
}
void uninstallContent() throws IOException {
preRemove = new PreRemoveProcess(installPath, fileOps, feedback)
.setDryRun(isDryRun())
.setIgnoreFailedDeletions(isIgnoreFailedDeletions());
O: for (String p : componentInfo.getPaths()) {
if (preservePaths.contains(p)) {
feedback.verboseOutput("INSTALL_SkippingSharedFile", p);
continue;
}
Path toDelete = installPath.resolve(SystemUtils.fromCommonRelative(p));
if (Files.isDirectory(toDelete)) {
for (String s : preservePaths) {
Path x = SystemUtils.fromCommonRelative(s);
if (x.startsWith(p)) {
continue O;
}
}
directoriesToDelete.add(p);
continue;
}
feedback.verboseOutput("UNINSTALL_DeletingFile", p);
if (!dryRun) {
preRemove.deleteOneFile(toDelete);
}
}
List<String> dirNames = new ArrayList<>(directoriesToDelete);
preRemove.processComponent(componentInfo);
Collections.sort(dirNames);
Collections.reverse(dirNames);
for (String s : dirNames) {
Path p = installPath.resolve(SystemUtils.fromCommonRelative(s));
feedback.verboseOutput("UNINSTALL_DeletingDirectory", p);
if (!dryRun) {
try {
fileOps.deleteFile(p);
} catch (IOException ex) {
if (ignoreFailedDeletions) {
feedback.error("INSTALL_FailedToDeleteDirectory", ex, p, ex.getLocalizedMessage());
} else {
throw ex;
}
}
}
}
rebuildPolyglot = componentInfo.isPolyglotRebuild() ||
componentInfo.getPaths().stream().filter(p -> !p.endsWith("/") && p.startsWith(CommonConstants.PATH_POLYGLOT_REGISTRY))
.findAny()
.isPresent();
}
public boolean isIgnoreFailedDeletions() {
return ignoreFailedDeletions;
}
public void setIgnoreFailedDeletions(boolean ignoreFailedDeletions) {
this.ignoreFailedDeletions = ignoreFailedDeletions;
}
public boolean isDryRun() {
return dryRun;
}
public void setDryRun(boolean dryRun) {
this.dryRun = dryRun;
}
public Path getInstallPath() {
return installPath;
}
public void setInstallPath(Path installPath) {
this.installPath = installPath;
}
public Set<String> getPreservePaths() {
return preservePaths;
}
public void setPreservePaths(Set<String> preservePaths) {
this.preservePaths = preservePaths;
}
public ComponentInfo getComponentInfo() {
return componentInfo;
}
}