public void perform()

in core/src/main/java/hudson/tasks/LogRotator.java [144:225]


    public void perform(Job<?,?> job) throws IOException, InterruptedException {
        //Exceptions thrown by the deletion submethods are collated and reported
        HashMultimap<Run<?,?>, IOException> exceptionMap = HashMultimap.create();
        
        LOGGER.log(FINE, "Running the log rotation for {0} with numToKeep={1} daysToKeep={2} artifactNumToKeep={3} artifactDaysToKeep={4}", new Object[] {job, numToKeep, daysToKeep, artifactNumToKeep, artifactDaysToKeep});
        
        // always keep the last successful and the last stable builds
        Run lsb = job.getLastSuccessfulBuild();
        Run lstb = job.getLastStableBuild();

        if(numToKeep!=-1) {
            // Note that RunList.size is deprecated, and indeed here we are loading all the builds of the job.
            // However we would need to load the first numToKeep anyway, just to skip over them;
            // and we would need to load the rest anyway, to delete them.
            // (Using RunMap.headMap would not suffice, since we do not know if some recent builds have been deleted for other reasons,
            // so simply subtracting numToKeep from the currently last build number might cause us to delete too many.)
            List<? extends Run<?,?>> builds = job.getBuilds();
            for (Run r : copy(builds.subList(Math.min(builds.size(), numToKeep), builds.size()))) {
                if (shouldKeepRun(r, lsb, lstb)) {
                    continue;
                }
                LOGGER.log(FINE, "{0} is to be removed", r);
                try { r.delete(); }
                catch (IOException ex) { exceptionMap.put(r, ex); }
            }
        }

        if(daysToKeep!=-1) {
            Calendar cal = new GregorianCalendar();
            cal.add(Calendar.DAY_OF_YEAR,-daysToKeep);
            Run r = job.getFirstBuild();
            while (r != null) {
                if (tooNew(r, cal)) {
                    break;
                }
                if (!shouldKeepRun(r, lsb, lstb)) {
                    LOGGER.log(FINE, "{0} is to be removed", r);
                    try { r.delete(); }
                    catch (IOException ex) { exceptionMap.put(r, ex); }
                }
                r = r.getNextBuild();
            }
        }

        if(artifactNumToKeep!=null && artifactNumToKeep!=-1) {
            List<? extends Run<?,?>> builds = job.getBuilds();
            for (Run r : copy(builds.subList(Math.min(builds.size(), artifactNumToKeep), builds.size()))) {
                if (shouldKeepRun(r, lsb, lstb)) {
                    continue;
                }
                LOGGER.log(FINE, "{0} is to be purged of artifacts", r);
                try { r.deleteArtifacts(); }
                catch (IOException ex) { exceptionMap.put(r, ex); }
            }
        }

        if(artifactDaysToKeep!=null && artifactDaysToKeep!=-1) {
            Calendar cal = new GregorianCalendar();
            cal.add(Calendar.DAY_OF_YEAR,-artifactDaysToKeep);
            Run r = job.getFirstBuild();
            while (r != null) {
                if (tooNew(r, cal)) {
                    break;
                }
                if (!shouldKeepRun(r, lsb, lstb)) {
                    LOGGER.log(FINE, "{0} is to be purged of artifacts", r);
                    try { r.deleteArtifacts(); }
                    catch (IOException ex) { exceptionMap.put(r, ex); }
                }
                r = r.getNextBuild();
            }
        }
        
        if (!exceptionMap.isEmpty()) {
            //Collate all encountered exceptions into a single exception and throw that
            String msg = String.format(
                    "Failed to rotate logs for [%s]",
                    Joiner.on(", ").join(exceptionMap.keySet())
            );
            throw new CompositeIOException(msg, new ArrayList<>(exceptionMap.values()));
        }
    }