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
90
91
92
93
94
95
96
97 step.mojos.values().stream()
98 .flatMap(m -> m.values().stream())
99 .forEach(mojo -> mojo(writer, mojo));
100 });
101 }
102
103 writer.accept("=======================================================================");
104 }
105
106 protected Stream<BuildStep> nonEmptyPredecessors(BuildStep step) {
107 HashSet<BuildStep> preds = new HashSet<>();
108 nonEmptyPredecessors(step, preds, new HashSet<>());
109 return preds.stream();
110 }
111
112 private void nonEmptyPredecessors(BuildStep step, Set<BuildStep> preds, Set<BuildStep> visited) {
113 if (visited.add(step)) {
114 step.predecessors.forEach(ch -> {
115 if (ch.executions().findAny().isPresent()) {
116 preds.add(ch);
117 } else {
118 nonEmptyPredecessors(ch, preds, visited);
119 }
120 });
121 }
122 }
123
124 protected String phase(MavenProject currentProject, BuildStep step, Set<String> duplicateIds) {
125 if (step.project == currentProject) {
126 return step.name;
127 } else {
128 String artifactId = step.project.getArtifactId();
129 if (duplicateIds.contains(artifactId)) {
130 return step.name + "(" + step.project.getGroupId() + ":" + artifactId + ")";
131 } else {
132 return step.name + "(:" + artifactId + ")";
133 }
134 }
135 }
136
137 protected void mojo(Consumer<String> writer, MojoExecution mojoExecution) {
138 String mojoExecId =
139 mojoExecution.getGroupId() + ':' + mojoExecution.getArtifactId() + ':' + mojoExecution.getVersion()
140 + ':' + mojoExecution.getGoal() + " (" + mojoExecution.getExecutionId() + ')';
141
142 Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
143 if (!forkedExecutions.isEmpty()) {
144 for (Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet()) {
145 writer.accept("\t--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---");
146
147 for (MojoExecution forkedExecution : fork.getValue()) {
148 mojo(writer, forkedExecution);
149 }
150
151 writer.accept("\t--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---");
152 }
153 }
154
155 writer.accept("\t\t-----------------------------------------------------------------------");
156 if (mojoExecution.getMojoDescriptor().isAggregator()) {
157 writer.accept("\t\tAggregator goal: " + mojoExecId);
158 } else {
159 writer.accept("\t\tGoal: " + mojoExecId);
160 }
161 if (mojoExecution.getConfiguration() != null) {
162 writer.accept("\t\tConfiguration: " + mojoExecution.getConfiguration());
163 }
164 if (mojoExecution.getMojoDescriptor().getDependencyCollectionRequired() != null) {
165 writer.accept("\t\tDependencies (collect): "
166 + mojoExecution.getMojoDescriptor().getDependencyCollectionRequired());
167 }
168 if (mojoExecution.getMojoDescriptor().getDependencyResolutionRequired() != null) {
169 writer.accept("\t\tDependencies (resolve): "
170 + mojoExecution.getMojoDescriptor().getDependencyResolutionRequired());
171 }
172 }
173
174 protected String getKey(MavenProject project) {
175 return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
176 }
177 }