All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.telenav.cactus.maven.tree.ProjectTree Maven / Gradle / Ivy
Go to download
The cactus-maven-plugin project codifies Telenav Open Source processes.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// © 2011-2022 Telenav, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package com.telenav.cactus.maven.tree;
import com.mastfrog.function.optional.ThrowingOptional;
import com.telenav.cactus.scope.ProjectFamily;
import com.telenav.cactus.git.Branches;
import com.telenav.cactus.git.GitCheckout;
import com.telenav.cactus.git.Heads;
import com.telenav.cactus.maven.model.Pom;
import com.telenav.cactus.scope.Scope;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.maven.project.MavenProject;
/**
*
* @author Tim Boudreau
*/
public class ProjectTree
{
final GitCheckout root;
private final AtomicBoolean upToDate = new AtomicBoolean();
private final ProjectTreeCache cache = new ProjectTreeCache(this);
static
{
try
{
// Force this into the maven classloader as well
Object o = ProjectTree.class.getClassLoader().loadClass(
"com.telenav.cactus.maven.tree.ProjectTree$1");
}
catch (ClassNotFoundException ex)
{
ex.printStackTrace(System.out);
}
}
ProjectTree(GitCheckout root)
{
this.root = root;
}
public boolean isSubmoduleRoot(GitCheckout co) {
return root.equals(co)
&& withCache(ProjectTreeCache::rootIsSubmoduleRoot);
}
public GitCheckout root()
{
return root;
}
public static ThrowingOptional from(MavenProject project)
{
return from(project.getBasedir().toPath());
}
public static ThrowingOptional from(Path fileOrFolder)
{
return ThrowingOptional.from(GitCheckout.checkout(fileOrFolder))
.flatMapThrowing(GitCheckout::submoduleRoot)
.map(ProjectTree::new);
}
public void invalidateCache()
{
if (upToDate.compareAndSet(true, false))
{
cache.clear();
}
}
private synchronized T withCache(Function func)
{
if (upToDate.compareAndSet(false, true))
{
cache.populate();
}
return func.apply(cache);
}
public Optional findProject(String groupId, String artifactId)
{
return withCache(c ->
{
return c.project(groupId, artifactId);
});
}
public boolean areVersionsConsistent()
{
return allVersions().size() <= 1;
}
public Set allBranches(Predicate pred)
{
return allCheckouts().stream()
// filter to the checkouts we want
.filter(pred)
// map to the branch, which may not be present
.map(co -> co.branch().orElse(""))
// prune those that are not on a branch
.filter(s -> !s.isEmpty())
.collect(Collectors.toCollection(HashSet::new));
}
public Set allBranches()
{
Set branches = new HashSet<>();
this.allCheckouts().forEach(checkout ->
{
checkout.branch().ifPresent(branches::add);
});
return branches;
}
public Set allVersions()
{
Set result = new HashSet<>();
allProjects().forEach(pom ->
{
result.add(pom.version().text());
});
return result;
}
public Set allVersions(Predicate test)
{
Set result = new HashSet<>();
allProjects().forEach(pom ->
{
if (test.test(pom))
{
result.add(pom.version().text());
}
});
return result;
}
public Set allProjects()
{
return withCache(ProjectTreeCache::allPoms);
}
public Set projectsForGroupId(String groupId)
{
Set result = new TreeSet<>();
allProjects().forEach(project ->
{
if (groupId.equals(project.coordinates().groupId))
{
result.add(project);
}
});
return result;
}
public Set projectsForFamily(ProjectFamily fam)
{
Set result = new TreeSet<>();
allProjects().forEach(project ->
{
if (fam.equals(ProjectFamily.fromGroupId(project.groupId().text())))
{
result.add(project);
}
});
return result;
}
public Map> branchesByGroupId()
{
return withCache(c ->
{
Map> result = new TreeMap<>();
c.allPoms().forEach(pom ->
{
GitCheckout.checkout(pom.path()).ifPresent(checkout ->
{
Set branches = result.computeIfAbsent(
pom.groupId().text(), g -> new TreeSet<>());
checkout.branches().localBranches().forEach(br ->
{
branches.add(br.trackingName());
});
checkout.branches().remoteBranches().forEach(br ->
{
branches.add(br.trackingName());
});
});
});
return result;
});
}
public Map>> projectsByBranchByGroupId(
Predicate filter)
{
return withCache(c ->
{
Map>> result = new TreeMap<>();
for (Pom pom : c.allPoms())
{
if (!filter.test(pom))
{
continue;
}
Map> infosByBranch = result.computeIfAbsent(
pom.groupId().text(), id -> new TreeMap<>());
GitCheckout.checkout(pom.path()).ifPresent(checkout ->
{
c.branchFor(checkout).ifPresent(branch ->
{
Set set = infosByBranch.computeIfAbsent(branch,
b -> new TreeSet<>());
set.add(pom);
});
});
}
return result;
});
}
public Map>> projectsByGroupIdAndVersion()
{
Map>> result = new TreeMap<>();
projectsByGroupId().forEach((gid, poms) ->
{
Map> subMap = result.computeIfAbsent(gid,
g -> new TreeMap<>());
for (Pom info : poms)
{
Set pomSet = subMap.computeIfAbsent(info.version()
.text(),
v -> new TreeSet<>());
pomSet.add(info);
}
});
return result;
}
public Set groupIdsIn(GitCheckout checkout)
{
return withCache(c ->
{
return c.projectsWithin(checkout).stream().map(
info -> info.groupId().toString())
.collect(Collectors.toCollection(HashSet::new));
});
}
public Map> projectsByGroupId()
{
Map> result = new TreeMap<>();
allProjects().forEach(pom ->
{
Set set = result.computeIfAbsent(pom.groupId().text(),
x -> new TreeSet<>());
set.add(pom);
});
return result;
}
public Set allProjectFolders()
{
return withCache(c ->
{
Set result = new HashSet<>();
c.allPoms().forEach(pom -> result.add(pom.projectFolder()));
return result;
});
}
public Map> projectsByVersion(Predicate filter)
{
return withCache(c ->
{
Map> result = new TreeMap<>();
c.allPoms().forEach(pom ->
{
if (filter.test(pom))
{
Set infos = result.computeIfAbsent(pom.version()
.text(),
v -> new TreeSet<>());
infos.add(pom);
}
});
return result;
});
}
public Optional projectOf(Path file)
{
withCache(c ->
{
Path realFile;
if (Files.isDirectory(file) && Files.exists(file.resolve("pom.xml")))
{
realFile = file.resolve("pom.xml");
}
else
{
realFile = file;
}
if ("pom.xml".equals(realFile.getFileName()))
{
for (Pom pom : c.allPoms())
{
if (pom.path().equals(realFile))
{
return Optional.of(pom);
}
}
}
List paths = new ArrayList<>();
Map candidateItems = new HashMap<>();
c.projectFolders().forEach((dir, pomInfo) ->
{
if (realFile.startsWith(dir))
{
candidateItems.put(dir, pomInfo);
paths.add(dir);
}
});
if (paths.isEmpty())
{
return Optional.empty();
}
Collections.sort(paths, (a, b) ->
{
// reverse sort
return Integer.compare(b.getNameCount(), a.getNameCount());
});
return Optional.of(candidateItems.get(paths.get(0)));
});
return Optional.empty();
}
public GitCheckout checkoutFor(Pom info)
{
return withCache(c -> c.checkoutForPom.get(info));
}
public Set allCheckouts()
{
return withCache(ProjectTreeCache::allCheckouts);
}
public Optional branchFor(GitCheckout checkout)
{
return withCache(c -> c.branchFor(checkout));
}
public boolean isDirty(GitCheckout checkout)
{
return withCache(c -> c.isDirty(checkout));
}
public boolean isDirtyIgnoringSubmoduleCommits(GitCheckout checkout)
{
return withCache(c -> c.isDirtyIgnoringSubmoduleCommits(checkout));
}
public Set checkoutsFor(Collection extends Pom> infos)
{
return withCache(c ->
{
Set result = new TreeSet<>();
infos.forEach(pom -> c.checkoutFor(pom).ifPresent(result::add));
return result;
});
}
public Branches branches(GitCheckout checkout)
{
return withCache(c -> c.branches(checkout));
}
public Optional mostCommonBranchForGroupId(String groupId)
{
return withCache(c -> c.mostCommonBranchForGroupId(groupId));
}
public boolean isDetachedHead(GitCheckout checkout)
{
return withCache(c -> c.isDetachedHead(checkout));
}
public Set projectsWithin(GitCheckout checkout)
{
return withCache(c -> c.projectsWithin(checkout));
}
public Set nonMavenCheckouts()
{
return withCache(ProjectTreeCache::nonMavenCheckouts);
}
public Set checkoutsContainingGroupId(String groupId)
{
return withCache(c -> c.checkoutsContainingGroupId(groupId));
}
public Set checkoutsInProjectFamily(Set family)
{
return withCache(c -> c.checkoutsInProjectFamily(family));
}
public Set checkoutsInProjectFamilyOrChildProjectFamily(
String gid, Set family)
{
return withCache(c -> c.checkoutsInProjectFamilyOrChildProjectFamily(
gid));
}
public Set checkoutsInProjectFamily(ProjectFamily family)
{
return withCache(c -> c.checkoutsInProjectFamily(family));
}
public Heads remoteHeads(GitCheckout checkout)
{
return withCache(c -> c.remoteHeads(checkout));
}
public Set allProjectFamilies() {
return withCache(ProjectTreeCache::allProjectFamilies);
}
public void invalidateBranches(GitCheckout co) {
withCache(cache -> cache.invalidateBranches(co));
}
/**
* Get a depth-first list of checkouts matching this scope, given the passed
* contextual criteria.
*
* @param scope A scope
* @param callingProjectsCheckout The checkout of the a mojo is currently
* being run against.
* @param includeRoot If true, include the root (submodule parent) checkout
* in the returned list regardless of whether it directly contains a maven
* project matching the other criteria (needed for operations that change
* the head commit of a submodule, which will generate modifications in the
* submodule parent project.
* @param callingProjectsGroupId The group id of the project whose mojo is
* being invoked
* @return A list of checkouts
*/
public List matchCheckouts(Scope scope,
GitCheckout callingProjectsCheckout, boolean includeRoot,
Set family, String callingProjectsGroupId)
{
Set checkouts;
switch (scope)
{
case FAMILY:
checkouts = checkoutsInProjectFamily(family);
break;
case FAMILY_OR_CHILD_FAMILY:
checkouts = checkoutsInProjectFamilyOrChildProjectFamily(
callingProjectsGroupId,
family);
break;
case SAME_GROUP_ID:
checkouts = checkoutsContainingGroupId(
callingProjectsGroupId);
break;
case JUST_THIS:
checkouts = new HashSet<>(Arrays.asList(callingProjectsCheckout));
break;
case ALL_PROJECT_FAMILIES:
checkouts = new HashSet<>(allCheckouts());
break;
case ALL:
checkouts = new HashSet<>(allCheckouts());
checkouts.addAll(nonMavenCheckouts());
break;
default:
throw new AssertionError(this);
}
checkouts = new LinkedHashSet<>(checkouts);
if (!includeRoot)
{
callingProjectsCheckout.submoduleRoot().ifPresent(checkouts::remove);
}
else
{
if (!checkouts.isEmpty()) // don't generate a push of _just_ the root checkout
{
callingProjectsCheckout.submoduleRoot()
.ifPresent(checkouts::add);
}
}
return GitCheckout.depthFirstSort(checkouts);
}
}