1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.lifecycle.internal.concurrent;
20
21 import javax.inject.Named;
22
23 import java.util.Comparator;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Optional;
28 import java.util.Set;
29 import java.util.function.Consumer;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32
33 import org.apache.maven.plugin.MojoExecution;
34 import org.apache.maven.project.MavenProject;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41
42
43
44
45
46 @Named
47 public class BuildPlanLogger {
48 private final Logger logger = LoggerFactory.getLogger(getClass());
49
50 public void writePlan(BuildPlan plan) {
51 if (logger.isDebugEnabled()) {
52 writePlan(logger::debug, plan);
53 }
54 }
55
56 public void writePlan(BuildPlan plan, MavenProject project) {
57 if (logger.isDebugEnabled()) {
58 writePlan(logger::debug, plan, project);
59 }
60 }
61
62 public void writePlan(Consumer<String> writer, BuildPlan plan) {
63 plan.projects().forEach(project -> writePlan(writer, plan, project));
64 }
65
66 public void writePlan(Consumer<String> writer, BuildPlan plan, MavenProject project) {
67 writer.accept("=== PROJECT BUILD PLAN ================================================");
68 writer.accept("Project: " + getKey(project));
69 writer.accept("Repositories (dependencies): " + project.getRemoteProjectRepositories());
70 writer.accept("Repositories (plugins): " + project.getRemotePluginRepositories());
71
72 Optional<BuildStep> planStep = plan.step(project, BuildStep.PLAN);
73 if (planStep.isPresent() && planStep.get().status.get() == BuildStep.PLANNING) {
74 writer.accept("Build plan will be lazily computed");
75 } else {
76 plan.steps(project)
77 .filter(step ->
78 step.phase != null && step.executions().findAny().isPresent())
79 .sorted(Comparator.comparingInt(plan.sortedNodes()::indexOf))
80 .forEach(step -> {
81 writer.accept("\t-----------------------------------------------------------------------");
82 writer.accept("\tPhase: " + step.name);
83 if (!step.predecessors.isEmpty()) {
84 writer.accept("\tPredecessors: "
85 + nonEmptyPredecessors(step)
86 .map(n -> phase(project, n, plan.duplicateIds()))
87 .collect(Collectors.joining(", ")));
88 }
89 step.mojos.values().stream()
90 .flatMap(m -> m.values().stream())
91 .forEach(mojo -> mojo(writer, mojo));
92 });
93 }
94
95 writer.accept("=======================================================================");
96 }
97
98 protected Stream<BuildStep> nonEmptyPredecessors(BuildStep step) {
99 HashSet<BuildStep> preds = new HashSet<>();
100 nonEmptyPredecessors(step, preds, new HashSet<>());
101 return preds.stream();
102 }
103
104 private void nonEmptyPredecessors(BuildStep step, Set<BuildStep> preds, Set<BuildStep> visited) {
105 if (visited.add(step)) {
106 step.predecessors.forEach(ch -> {
107 if (ch.executions().findAny().isPresent()) {
108 preds.add(ch);
109 } else {
110 nonEmptyPredecessors(ch, preds, visited);
111 }
112 });
113 }
114 }
115
116 protected String phase(MavenProject currentProject, BuildStep step, Set<String> duplicateIds) {
117 if (step.project == currentProject) {
118 return step.name;
119 } else {
120 String artifactId = step.project.getArtifactId();
121 if (duplicateIds.contains(artifactId)) {
122 return step.name + "(" + step.project.getGroupId() + ":" + artifactId + ")";
123 } else {
124 return step.name + "(:" + artifactId + ")";
125 }
126 }
127 }
128
129 protected void mojo(Consumer<String> writer, MojoExecution mojoExecution) {
130 String mojoExecId =
131 mojoExecution.getGroupId() + ':' + mojoExecution.getArtifactId() + ':' + mojoExecution.getVersion()
132 + ':' + mojoExecution.getGoal() + " (" + mojoExecution.getExecutionId() + ')';
133
134 Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
135 if (!forkedExecutions.isEmpty()) {
136 for (Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet()) {
137 writer.accept("\t--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---");
138
139 for (MojoExecution forkedExecution : fork.getValue()) {
140 mojo(writer, forkedExecution);
141 }
142
143 writer.accept("\t--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---");
144 }
145 }
146
147 writer.accept("\t\t-----------------------------------------------------------------------");
148 if (mojoExecution.getMojoDescriptor().isAggregator()) {
149 writer.accept("\t\tAggregator goal: " + mojoExecId);
150 } else {
151 writer.accept("\t\tGoal: " + mojoExecId);
152 }
153 if (mojoExecution.getConfiguration() != null) {
154 writer.accept("\t\tConfiguration: " + mojoExecution.getConfiguration());
155 }
156 if (mojoExecution.getMojoDescriptor().getDependencyCollectionRequired() != null) {
157 writer.accept("\t\tDependencies (collect): "
158 + mojoExecution.getMojoDescriptor().getDependencyCollectionRequired());
159 }
160 if (mojoExecution.getMojoDescriptor().getDependencyResolutionRequired() != null) {
161 writer.accept("\t\tDependencies (resolve): "
162 + mojoExecution.getMojoDescriptor().getDependencyResolutionRequired());
163 }
164 }
165
166 protected String getKey(MavenProject project) {
167 return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
168 }
169 }