]> source.dussan.org Git - sonarqube.git/blob
129e7fdc7cb5459777bedb973dc440c1f273cd0f
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2021 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.ce.task.projectanalysis.step;
21
22 import com.google.common.base.Function;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.Multiset;
25 import com.google.common.collect.TreeMultiset;
26 import java.util.Map;
27 import java.util.Optional;
28 import javax.annotation.Nonnull;
29 import javax.annotation.Nullable;
30 import org.sonar.api.measures.CoreMetrics;
31 import org.sonar.api.utils.KeyValueFormat;
32 import org.sonar.ce.task.projectanalysis.component.Component;
33 import org.sonar.ce.task.projectanalysis.component.PathAwareCrawler;
34 import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
35 import org.sonar.ce.task.projectanalysis.formula.Counter;
36 import org.sonar.ce.task.projectanalysis.formula.CounterInitializationContext;
37 import org.sonar.ce.task.projectanalysis.formula.CreateMeasureContext;
38 import org.sonar.ce.task.projectanalysis.formula.Formula;
39 import org.sonar.ce.task.projectanalysis.formula.FormulaExecutorComponentVisitor;
40 import org.sonar.ce.task.projectanalysis.measure.Measure;
41 import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
42 import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
43 import org.sonar.ce.task.step.ComputationStep;
44
45 import static com.google.common.collect.Maps.asMap;
46 import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
47 import static org.sonar.api.utils.KeyValueFormat.format;
48 import static org.sonar.api.utils.KeyValueFormat.newIntegerConverter;
49 import static org.sonar.api.utils.KeyValueFormat.newStringConverter;
50 import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
51
52 public class LanguageDistributionMeasuresStep implements ComputationStep {
53
54   private static final String UNKNOWN_LANGUAGE_KEY = "<null>";
55
56   private static final ImmutableList<Formula> FORMULAS = ImmutableList.of(new LanguageDistributionFormula());
57
58   private static final String[] LANGUAGE_DISTRIBUTION_FORMULA_METRICS = new String[] {NCLOC_LANGUAGE_DISTRIBUTION_KEY};
59
60   private final TreeRootHolder treeRootHolder;
61   private final MetricRepository metricRepository;
62   private final MeasureRepository measureRepository;
63
64   public LanguageDistributionMeasuresStep(TreeRootHolder treeRootHolder, MetricRepository metricRepository, MeasureRepository measureRepository) {
65     this.treeRootHolder = treeRootHolder;
66     this.metricRepository = metricRepository;
67     this.measureRepository = measureRepository;
68   }
69
70   @Override
71   public void execute(ComputationStep.Context context) {
72     new PathAwareCrawler<>(FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository).buildFor(FORMULAS))
73       .visit(treeRootHolder.getRoot());
74   }
75
76   private static class LanguageDistributionFormula implements Formula<LanguageDistributionCounter> {
77
78     @Override
79     public LanguageDistributionCounter createNewCounter() {
80       return new LanguageDistributionCounter();
81     }
82
83     @Override
84     public Optional<Measure> createMeasure(LanguageDistributionCounter counter, CreateMeasureContext context) {
85       if (counter.multiset.isEmpty()) {
86         return Optional.empty();
87       }
88       return Optional.of(newMeasureBuilder().create(format(asMap(counter.multiset.elementSet(), new LanguageToTotalCount(counter.multiset)))));
89     }
90
91     @Override
92     public String[] getOutputMetricKeys() {
93       return LANGUAGE_DISTRIBUTION_FORMULA_METRICS;
94     }
95   }
96
97   private static class LanguageToTotalCount implements Function<String, Integer> {
98
99     private final Multiset<String> multiset;
100
101     public LanguageToTotalCount(Multiset<String> multiset) {
102       this.multiset = multiset;
103     }
104
105     @Nullable
106     @Override
107     public Integer apply(@Nonnull String language) {
108       return multiset.count(language);
109     }
110   }
111
112   private static class LanguageDistributionCounter implements Counter<LanguageDistributionCounter> {
113
114     private final Multiset<String> multiset = TreeMultiset.create();
115
116     @Override
117     public void aggregate(LanguageDistributionCounter counter) {
118       multiset.addAll(counter.multiset);
119     }
120
121     @Override
122     public void initialize(CounterInitializationContext context) {
123       if (context.getLeaf().getType() == Component.Type.FILE) {
124         initializeForFile(context);
125       }
126       initializeForOtherLeaf(context);
127     }
128
129     private void initializeForFile(CounterInitializationContext context) {
130       String language = context.getLeaf().getFileAttributes().getLanguageKey();
131       Optional<Measure> ncloc = context.getMeasure(CoreMetrics.NCLOC_KEY);
132       if (ncloc.isPresent()) {
133         multiset.add(language == null ? UNKNOWN_LANGUAGE_KEY : language, ncloc.get().getIntValue());
134       }
135     }
136
137     private void initializeForOtherLeaf(CounterInitializationContext context) {
138       Optional<Measure> measure = context.getMeasure(NCLOC_LANGUAGE_DISTRIBUTION_KEY);
139       if (measure.isPresent()) {
140         Map<String, Integer> parse = KeyValueFormat.parse(measure.get().getData(), newStringConverter(), newIntegerConverter());
141         for (Map.Entry<String, Integer> entry : parse.entrySet()) {
142           multiset.add(entry.getKey(), entry.getValue());
143         }
144       }
145     }
146   }
147
148   @Override
149   public String getDescription() {
150     return "Compute language distribution";
151   }
152 }