/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package illarion.download.cleanup;
import illarion.common.util.DirectoryManager;
import illarion.common.util.DirectoryManager.Directory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
/**
* This cleanup function is the one that takes care for the artifact repository and keeps things tidy there.
*
* @author Martin Karing <nitram@illarion.org>
*/
class ArtifactCleaner implements Callable<Void> {
/**
* The logger that takes care for the logging output of this class.
*/
@Nonnull
private static final Logger log = LoggerFactory.getLogger(ArtifactCleaner.class);
@Nonnull
private final Comparator<Path> versionComparator = new VersionComparator();
@Override
public Void call() throws Exception {
log.info("Starting cleanup of artifact directory.");
Collection<Path> removalTargets = getRemovalTargets();
Cleaner.printFileList(removalTargets);
/* And remove the stuff. */
for (Path file : removalTargets) {
Files.delete(file);
}
log.info("Removed {} files.", removalTargets.size());
return null;
}
/**
* This function creates a list of all files to be removed.
*
* @return the files that should be removed
*/
@Nonnull
private Collection<Path> getRemovalTargets() throws IOException {
DirectoryManager dm = DirectoryManager.getInstance();
Path dataDir = dm.getDirectory(Directory.Data);
Collection<Path> artifactDirectories = getArtifactDirectories(dataDir);
Collection<Path> resultList = new LinkedList<>();
for (Path artifactDir : artifactDirectories) {
resultList.addAll(getArtifactRemovalTargets(artifactDir));
}
return Collections.unmodifiableCollection(resultList);
}
@Nonnull
private static Collection<Path> getArtifactDirectories(@Nonnull Path rootDir) throws IOException {
ArtifactDirectoryVisitor visitor = new ArtifactDirectoryVisitor();
Files.walkFileTree(rootDir, visitor);
return visitor.getArtifactDirectories();
}
private static boolean isArtifactDirectory(@Nonnull Path dir) throws IOException {
//noinspection ConstantConditions
return Files.list(dir).filter(Files::isRegularFile).allMatch(path ->
path.getFileName().toString().endsWith(".jar"));
}
@Nonnull
private Collection<Path> getArtifactRemovalTargets(@Nonnull Path artifactDirectory) throws IOException {
List<Path> releaseVersions = new LinkedList<>();
List<Path> snapshotVersions = new LinkedList<>();
/* Group the files into two lists. One for the release versions and one for the snapshot versions. */
Files.list(artifactDirectory).filter(Files::isDirectory).forEach(path -> {
int nameCount = path.getNameCount();
Path lastSegment = path.getName(nameCount - 1);
if (lastSegment.toString().contains("SNAPSHOT")) {
snapshotVersions.add(path);
} else {
releaseVersions.add(path);
}
});
Collection<Path> result = new LinkedList<>();
/*
The next thing is to remove all but the newest version of each artifact, both for release and snapshot
versions. The snapshot may contain multiple versions in addition. We take care for this later on.
*/
for (List<Path> versionList : Arrays.asList(releaseVersions, snapshotVersions)) {
/* Sort the versions. The newest version will be at the end of the list. */
Collections.sort(versionList, versionComparator);
while (versionList.size() > 1) {
Path dir = versionList.remove(0);
if ((dir != null) && isArtifactDirectory(dir)) {
result.addAll(Cleaner.enlistRecursively(dir, (path) -> true));
}
}
}
if (!snapshotVersions.isEmpty()) {
//noinspection ConstantConditions
result.addAll(getOldSnapshots(snapshotVersions.get(0)));
}
return result;
}
@Nonnull
private static Collection<Path> getOldSnapshots(@Nonnull Path snapshotDir) throws IOException {
List<Path> snapshotJars = Files.list(snapshotDir)
.filter(Files::isRegularFile)
.filter(path -> {
//noinspection ConstantConditions
String fileName = path.getFileName().toString();
return fileName.endsWith(".jar") && !fileName.contains("SNAPSHOT");
})
.collect(Collectors.toList());
Collections.sort(snapshotJars);
snapshotJars.remove(snapshotJars.size() - 1);
if (snapshotJars.isEmpty()) {
return Collections.emptyList();
}
Collection<String> snapshotNames = snapshotJars.stream()
.filter(path -> path != null)
.map(path -> {
//noinspection ConstantConditions
return com.google.common.io.Files.getNameWithoutExtension(path.getFileName().toString());
})
.collect(Collectors.toList());
return Files.list(snapshotDir).filter(Files::isRegularFile)
.filter(path -> {
//noinspection ConstantConditions
String fileName = path.getFileName().toString();
return snapshotNames.stream().anyMatch(fileName::startsWith);
}).collect(Collectors.toList());
}
}