All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.takari.maven.builder.smart.ProjectComparator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2014-2024 Takari, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache Software License v2.0
 * which accompanies this distribution, and is available at
 * https://www.apache.org/licenses/LICENSE-2.0
 */
package io.takari.maven.builder.smart;

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.function.ToLongFunction;
import org.apache.maven.project.MavenProject;

/**
 * Project comparator (factory) that uses project build time to establish build order.
 * 

* Internally, each project is assigned a weight, which is calculated as sum of project build time * and maximum weight of any of the project's downstream dependencies. The project weights are * calculated by recursively traversing project dependency graph starting from build root projects, * i.e. projects that do not have any upstream dependencies. *

* Project build times are estimated based on values persisted during a previous build. Average * build time is used for projects that do not have persisted build time. *

* If there are no persisted build times, all projects build times are assumed the same (arbitrary) * value of 1. This means that the project with the longest downstream dependency trail will be * built first. *

* Currently, historical build times are stored in * ${session.request/baseDirectory}/.mvn/timing.properties file. The timings file is * written only if ${session.request/baseDirectory}/.mvn directory is already present. */ class ProjectComparator { public static Comparator create(DependencyGraph graph) { return create0(graph, Collections.emptyMap(), ProjectComparator::id); } static Comparator create0( DependencyGraph dependencyGraph, Map historicalServiceTimes, Function toKey) { final long defaultServiceTime = average(historicalServiceTimes.values()); final Map serviceTimes = new HashMap<>(); final Set rootProjects = new HashSet<>(); dependencyGraph.getProjects().forEach(project -> { long serviceTime = getServiceTime(historicalServiceTimes, project, defaultServiceTime, toKey); serviceTimes.put(project, serviceTime); if (dependencyGraph.isRoot(project)) { rootProjects.add(project); } }); final Map projectWeights = calculateWeights(dependencyGraph, serviceTimes, rootProjects); return Comparator.comparingLong((ToLongFunction) projectWeights::get) .thenComparing(toKey, String::compareTo) .reversed(); } private static long average(Collection values) { return (long) (values.stream().mapToLong(AtomicLong::longValue).average().orElse(1.0d)); } private static long getServiceTime( Map serviceTimes, K project, long defaultServiceTime, Function toKey) { AtomicLong serviceTime = serviceTimes.get(toKey.apply(project)); return serviceTime != null ? serviceTime.longValue() : defaultServiceTime; } private static Map calculateWeights( DependencyGraph dependencyGraph, Map serviceTimes, Collection rootProjects) { Map weights = new HashMap<>(); for (K rootProject : rootProjects) { calculateWeights(dependencyGraph, serviceTimes, rootProject, weights); } return weights; } /** * Returns the maximum sum of build time along a path from the project to an exit project. An * "exit project" is a project without downstream dependencies. */ private static long calculateWeights( DependencyGraph dependencyGraph, Map serviceTimes, K project, Map weights) { long weight = serviceTimes.get(project) + dependencyGraph .getDownstreamProjects(project) .mapToLong(successor -> { long successorWeight; if (weights.containsKey(successor)) { successorWeight = weights.get(successor); } else { successorWeight = calculateWeights(dependencyGraph, serviceTimes, successor, weights); } return successorWeight; }) .max() .orElse(0); weights.put(project, weight); return weight; } static String id(MavenProject project) { return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy