/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package hudson.plugins.disk_usage;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.model.Run;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
*
* @author Lucie Votypkova
*/
public class ProjectBuildChecker {
/*
* Check compatibility of data without loading any build into memory. This causes that it is not possible to check loadability of builds.
* This check only validy of disk usage data with data on disk
*/
protected static void checkBuildDataCompatibility(ProjectDiskUsage diskUsage){
for(DiskUsageBuildInformation info : diskUsage.getBuildDiskUsage(false)){
File build = new File(diskUsage.job.getBuildDir(),info.getId());
if(!build.exists()){
diskUsage.removeBuild(info);
continue;
}
File buildXML = new File(build, "build.xml");
if(!buildXML.exists()){
diskUsage.moveToUnloadedBuilds(info);
}
}
for(String buildId : diskUsage.getNotLoadedBuilds()){
File build = new File(diskUsage.job.getBuildDir(),buildId);
File buildXML = new File(build, "build.xml");
//check if all uloaded builds still exists
if(!build.exists() || !buildXML.exists()){
diskUsage.removeDeletedNotLoadedBuild(build);
continue;
}
}
}
public static int getNumberDirectoriesForBuilds(Job project) throws IOException{
int count = 0;
File builds = project.getBuildDir();
for(File file : builds.listFiles()){
if(!Util.isSymlink(file) && file.exists()){
count++;
}
}
return count;
}
/*
* Check if all builds contained in disk usage data exists and are loadable
* It forces loading of builds which have build.xml but are not contained into loaded builds data (in the past they were not loadable)
*/
private static void checkExistenceOfBuilds(ProjectDiskUsage diskUsage){
//check if directory and build.xml exists for loaded builds
for(DiskUsageBuildInformation info : diskUsage.getBuildDiskUsage(false)){
File build = new File(diskUsage.job.getBuildDir(),info.getId());
if(!build.exists()){
diskUsage.removeBuild(info);
continue;
}
File buildXML = new File(build, "build.xml");
if(!buildXML.exists()){
diskUsage.moveToUnloadedBuilds(info);
}
}
//check if unloaded builds still unloadable
for(String buildId : diskUsage.getNotLoadedBuilds()){
File build = new File(diskUsage.job.getBuildDir(),buildId);
File buildXML = new File(build, "build.xml");
//check if all uloaded builds still exists
if(!build.exists() || !buildXML.exists()){
diskUsage.removeDeletedNotLoadedBuild(build);
continue;
}
// directory exists and build.xml too - try to load
Run run = diskUsage.job.getBuild(buildId);
if(run!=null && run instanceof AbstractBuild){
diskUsage.moveToLoadedBuilds((AbstractBuild)run, diskUsage.getSizeOfNotLoadedBuild(buildId));
}
}
}
private static List<File> getFilesWhichAreNotTracked(ProjectDiskUsage usage) throws IOException{
List<File> notTrackedFiles = new ArrayList<File>();
for(File file : usage.job.getBuildDir().listFiles()){
if(Util.isSymlink(file) || !file.exists()){
continue;
}
if(!usage.containDataForBuildDirectory(file)){
notTrackedFiles.add(file);
}
}
return notTrackedFiles;
}
/*
* Check if data about builds are valid (do not check builds which are conatined in loaded builds and their data on disk seem alright)
* It causes loading of builds which have build.xml but are not contained into loaded builds data (in the past they were not loadable)
* Try to load build in directory which is not contained between tracked builds, if there is build.xml
*/
public static void checkValidityOfBuildData(ProjectDiskUsage diskUsage) throws IOException{
checkExistenceOfBuilds(diskUsage);
int directoriesForBuild = getNumberDirectoriesForBuilds(diskUsage.job);
int countBuildsInDiskUsage = diskUsage.getCountOfAllBuilds();
if(directoriesForBuild == countBuildsInDiskUsage){
return;
}
if(directoriesForBuild > countBuildsInDiskUsage){
List<File> notTrackedFiles = getFilesWhichAreNotTracked(diskUsage);
for(File file : notTrackedFiles){
File buildXML = new File(file, "build.xml");
if(buildXML.exists()){
//try to load
Run run = diskUsage.job.getBuild(file.getName());
if(run!=null && run instanceof AbstractBuild){
diskUsage.addBuild((AbstractBuild)run);
}
else{
diskUsage.addNotLoadedBuild(file, 0L);
}
}
else{
diskUsage.addNotLoadedBuild(file, 0L);
}
}
}
}
/*
* Check state of build directory and all builds
* Causes loading all builds into memory
* This method can takes long time
*/
public static void valideBuildData(AbstractProject project){
DiskUsageProperty property = (DiskUsageProperty) project.getProperty(DiskUsageProperty.class);
ProjectDiskUsage usage = property.getDiskUsage();
//loading all builds
Iterator<Run> iterator = project.getBuilds().iterator();
List<String> loadedBuildIds = new ArrayList<String>();
while(iterator.hasNext()){
Run run =iterator.next();
loadedBuildIds.add(run.getId());
if(run instanceof AbstractBuild){
AbstractBuild build = (AbstractBuild) run;
Long size = usage.getSizeOfNotLoadedBuild(build.getId());
if(size!=null){
usage.moveToLoadedBuilds(build, size);
continue;
}
DiskUsageBuildInformation information = usage.getDiskUsageBuildInformation(build.getId());
if(information==null){
usage.addBuild(build);
}
else{
//update info about locking
information.setLockState(build.isKeepLog());
}
}
}
if(loadedBuildIds.size() != usage.countLoadedBuilds()){
for(DiskUsageBuildInformation info : usage.getBuildDiskUsage(false)){
if(!loadedBuildIds.contains(info.getId())){
usage.moveToUnloadedBuilds(info);
}
}
}
for(String unloadedBuildId : usage.getNotLoadedBuilds()){
File file = new File(usage.job.getBuildDir(),unloadedBuildId);
if(!file.exists()){
usage.removeDeletedNotLoadedBuild(file);
}
}
if(project instanceof ItemGroup){
ItemGroup group = (ItemGroup) project;
for(Item item : (Collection<Item>) group.getItems()){
if(item instanceof AbstractProject){
valideBuildData((AbstractProject)item);
}
}
}
usage.save();
}
}