diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2014-07-25 16:31:45 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2014-07-30 18:03:36 +0200 |
commit | 6074164392edd3db2dfdfd21d05cd56c19e2b0e6 (patch) | |
tree | b9314796d68c4c396dcf45a1ab689b06490fd4a2 /sonar-batch | |
parent | 12f243728f42a5eb1e714ff15f0240109193f1d8 (diff) | |
download | sonarqube-6074164392edd3db2dfdfd21d05cd56c19e2b0e6.tar.gz sonarqube-6074164392edd3db2dfdfd21d05cd56c19e2b0e6.zip |
SONAR-5389 New duplication API
Diffstat (limited to 'sonar-batch')
47 files changed, 969 insertions, 755 deletions
diff --git a/sonar-batch/pom.xml b/sonar-batch/pom.xml index 1ba3a32d61f..89f7c9252a4 100644 --- a/sonar-batch/pom.xml +++ b/sonar-batch/pom.xml @@ -149,5 +149,10 @@ <artifactId>jsonassert</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.codehaus.sonar.plugins</groupId> + <artifactId>sonar-xoo-plugin</artifactId> + <scope>test</scope> + </dependency> </dependencies> </project> diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java index 7317c9afd08..32bebf6182e 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BatchExtensionDictionnary.java @@ -22,6 +22,7 @@ package org.sonar.batch.bootstrap; import com.google.common.collect.Lists; import org.apache.commons.lang.ClassUtils; import org.sonar.api.batch.CheckProject; +import org.sonar.api.batch.Phase; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.platform.ComponentContainer; @@ -56,6 +57,15 @@ public class BatchExtensionDictionnary extends org.sonar.api.batch.BatchExtensio return result; } + @Override + protected Phase.Name evaluatePhase(Object extension) { + if (extension instanceof SensorWrapper) { + return super.evaluatePhase(((SensorWrapper) extension).wrappedSensor()); + } else { + return super.evaluatePhase(extension); + } + } + private <T> List<T> getFilteredExtensions(Class<T> type, @Nullable Project project, @Nullable ExtensionMatcher matcher) { List<T> result = Lists.newArrayList(); for (Object extension : getExtensions(type)) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/BlockCache.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/BlockCache.java new file mode 100644 index 00000000000..f6a4e3d18bf --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/BlockCache.java @@ -0,0 +1,56 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import org.sonar.api.BatchComponent; +import org.sonar.batch.index.Cache; +import org.sonar.batch.index.Cache.Entry; +import org.sonar.batch.index.Caches; +import org.sonar.duplications.block.FileBlocks; + +import javax.annotation.CheckForNull; + +/** + * Cache of duplication blocks. This cache is shared amongst all project modules. + */ +public class BlockCache implements BatchComponent { + + private final Cache<FileBlocks> cache; + + public BlockCache(Caches caches) { + caches.registerValueCoder(FileBlocks.class, new FileBlocksValueCoder()); + cache = caches.createCache("blocks"); + } + + public Iterable<Entry<FileBlocks>> entries() { + return cache.entries(); + } + + @CheckForNull + public FileBlocks byComponent(String effectiveKey) { + return cache.get(effectiveKey); + } + + public BlockCache put(String effectiveKey, FileBlocks blocks) { + cache.put(effectiveKey, blocks); + return this; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationBuilder.java new file mode 100644 index 00000000000..d6dd18026a2 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultDuplicationBuilder.java @@ -0,0 +1,74 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import com.google.common.base.Preconditions; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; + +import java.util.ArrayList; + +public class DefaultDuplicationBuilder implements DuplicationBuilder { + + private final InputFile inputFile; + private final DuplicationCache duplicationCache; + private boolean done = false; + private DuplicationGroup current = null; + private ArrayList<DuplicationGroup> duplications; + + public DefaultDuplicationBuilder(InputFile inputFile, DuplicationCache duplicationCache) { + this.inputFile = inputFile; + this.duplicationCache = duplicationCache; + duplications = new ArrayList<DuplicationGroup>(); + } + + @Override + public DuplicationBuilder originBlock(int startLine, int endLine) { + if (current != null) { + duplications.add(current); + } + current = new DuplicationGroup(new DuplicationGroup.Block(((DefaultInputFile) inputFile).key(), startLine, endLine - startLine + 1)); + return this; + } + + @Override + public DuplicationBuilder isDuplicatedBy(InputFile sameOrOtherFile, int startLine, int endLine) { + return isDuplicatedBy(((DefaultInputFile) sameOrOtherFile).key(), startLine, endLine); + } + + /** + * For internal use. Global duplications are referencing files outside of current project so + * no way to manipulate an InputFile. + */ + public DuplicationBuilder isDuplicatedBy(String fileKey, int startLine, int endLine) { + Preconditions.checkNotNull(current, "Call originBlock() first"); + current.addDuplicate(new DuplicationGroup.Block(fileKey, startLine, endLine - startLine + 1)); + return this; + } + + @Override + public void done() { + Preconditions.checkState(!done, "done() already called"); + Preconditions.checkNotNull(current, "Call originBlock() first"); + duplications.add(current); + duplicationCache.put(((DefaultInputFile) inputFile).key(), duplications); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java new file mode 100644 index 00000000000..6c7836d9e39 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DefaultTokenBuilder.java @@ -0,0 +1,77 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import com.google.common.base.Preconditions; +import net.sourceforge.pmd.cpd.TokenEntry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.sensor.duplication.TokenBuilder; +import org.sonar.duplications.block.Block; +import org.sonar.duplications.block.FileBlocks; +import org.sonar.duplications.internal.pmd.PmdBlockChunker; +import org.sonar.duplications.internal.pmd.TokenizerBridge; +import org.sonar.duplications.internal.pmd.TokensLine; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultTokenBuilder implements TokenBuilder { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultTokenBuilder.class); + + private final BlockCache cache; + private final InputFile inputFile; + private final List<TokenEntry> tokens = new ArrayList<TokenEntry>(); + private final PmdBlockChunker blockChunker; + private boolean done = false; + private int previousLine = 0; + + public DefaultTokenBuilder(InputFile inputFile, BlockCache cache, PmdBlockChunker blockChunker) { + this.inputFile = inputFile; + this.cache = cache; + this.blockChunker = blockChunker; + TokenEntry.clearImages(); + } + + @Override + public DefaultTokenBuilder addToken(int line, String image) { + Preconditions.checkState(!done, "done() already called"); + Preconditions.checkState(line >= previousLine, "Token should be created in order. Previous line was " + previousLine + " and you tried to create a token at line " + line); + TokenEntry cpdToken = new TokenEntry(image, inputFile.absolutePath(), line); + tokens.add(cpdToken); + previousLine = line; + return this; + } + + @Override + public void done() { + Preconditions.checkState(!done, "done() already called"); + tokens.add(TokenEntry.getEOF()); + TokenEntry.clearImages(); + List<TokensLine> tokensLines = TokenizerBridge.convert(tokens); + ArrayList<Block> blocks = blockChunker.chunk(((DefaultInputFile) inputFile).key(), tokensLines); + + cache.put(((DefaultInputFile) inputFile).key(), new FileBlocks(((DefaultInputFile) inputFile).key(), blocks)); + tokens.clear(); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java index 1922fd7aa35..ab1dad47009 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationBlockValueCoder.java @@ -17,24 +17,27 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.mediumtest.xoo.plugin.base; +package org.sonar.batch.duplication; -import org.sonar.api.resources.AbstractLanguage; +import com.persistit.Value; +import com.persistit.encoding.CoderContext; +import com.persistit.encoding.ValueCoder; -public class Xoo extends AbstractLanguage { +class DuplicationBlockValueCoder implements ValueCoder { - public static final String KEY = "xoo"; - public static final String NAME = "Xoo"; - - public Xoo() { - super(KEY, NAME); + @Override + public void put(Value value, Object object, CoderContext context) { + DuplicationGroup.Block b = (DuplicationGroup.Block) object; + value.putUTF(b.resourceKey()); + value.put(b.startLine()); + value.put(b.length()); } - /** - * ${@inheritDoc} - */ - public String[] getFileSuffixes() { - return XooConstants.FILE_SUFFIXES; + @Override + public Object get(Value value, Class clazz, CoderContext context) { + String resourceKey = value.getString(); + int startLine = value.getInt(); + int length = value.getInt(); + return new DuplicationGroup.Block(resourceKey, startLine, length); } - } diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java new file mode 100644 index 00000000000..e0265215efc --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationCache.java @@ -0,0 +1,58 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import org.sonar.api.BatchComponent; +import org.sonar.batch.index.Cache; +import org.sonar.batch.index.Cache.Entry; +import org.sonar.batch.index.Caches; + +import javax.annotation.CheckForNull; + +import java.util.ArrayList; + +/** + * Cache of duplication blocks. This cache is shared amongst all project modules. + */ +public class DuplicationCache implements BatchComponent { + + private final Cache<ArrayList<DuplicationGroup>> cache; + + public DuplicationCache(Caches caches) { + caches.registerValueCoder(DuplicationGroup.class, new DuplicationGroupValueCoder()); + caches.registerValueCoder(DuplicationGroup.Block.class, new DuplicationBlockValueCoder()); + cache = caches.createCache("duplications"); + } + + public Iterable<Entry<ArrayList<DuplicationGroup>>> entries() { + return cache.entries(); + } + + @CheckForNull + public ArrayList<DuplicationGroup> byComponent(String effectiveKey) { + return cache.get(effectiveKey); + } + + public DuplicationCache put(String effectiveKey, ArrayList<DuplicationGroup> blocks) { + cache.put(effectiveKey, blocks); + return this; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java new file mode 100644 index 00000000000..dc9a7aa2602 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroup.java @@ -0,0 +1,76 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import java.util.ArrayList; +import java.util.List; + +public class DuplicationGroup { + + public static class Block { + private final String resourceKey; + private final int startLine; + private final int length; + + public Block(String resourceKey, int startLine, int length) { + this.resourceKey = resourceKey; + this.startLine = startLine; + this.length = length; + } + + public String resourceKey() { + return resourceKey; + } + + public int startLine() { + return startLine; + } + + public int length() { + return length; + } + } + + private final Block originBlock; + + private List<Block> duplicates = new ArrayList<DuplicationGroup.Block>(); + + public DuplicationGroup(Block originBlock) { + this.originBlock = originBlock; + } + + public void setDuplicates(List<Block> duplicates) { + this.duplicates = duplicates; + } + + public DuplicationGroup addDuplicate(Block anotherBlock) { + this.duplicates.add(anotherBlock); + return this; + } + + public Block originBlock() { + return originBlock; + } + + public List<Block> duplicates() { + return duplicates; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java new file mode 100644 index 00000000000..244cffccd5f --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/DuplicationGroupValueCoder.java @@ -0,0 +1,54 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import com.persistit.Value; +import com.persistit.encoding.CoderContext; +import com.persistit.encoding.ValueCoder; +import org.sonar.batch.duplication.DuplicationGroup.Block; + +import java.util.ArrayList; + +class DuplicationGroupValueCoder implements ValueCoder { + + private DuplicationBlockValueCoder blockCoder = new DuplicationBlockValueCoder(); + + @Override + public void put(Value value, Object object, CoderContext context) { + DuplicationGroup c = (DuplicationGroup) object; + value.put(c.originBlock()); + value.put(c.duplicates().size()); + for (DuplicationGroup.Block block : c.duplicates()) { + blockCoder.put(value, block, context); + } + } + + @Override + public Object get(Value value, Class clazz, CoderContext context) { + DuplicationGroup g = new DuplicationGroup((DuplicationGroup.Block) value.get()); + int count = value.getInt(); + ArrayList<DuplicationGroup.Block> blocks = new ArrayList<DuplicationGroup.Block>(count); + for (int i = 0; i < count; i++) { + blocks.add((Block) blockCoder.get(value, DuplicationGroup.Block.class, context)); + } + g.setDuplicates(blocks); + return g; + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/duplication/FileBlocksValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/FileBlocksValueCoder.java new file mode 100644 index 00000000000..99b3467c921 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/FileBlocksValueCoder.java @@ -0,0 +1,69 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import com.persistit.Value; +import com.persistit.encoding.CoderContext; +import com.persistit.encoding.ValueCoder; +import org.sonar.duplications.block.Block; +import org.sonar.duplications.block.ByteArray; +import org.sonar.duplications.block.FileBlocks; + +import java.util.ArrayList; +import java.util.List; + +class FileBlocksValueCoder implements ValueCoder { + + @Override + public void put(Value value, Object object, CoderContext context) { + FileBlocks blocks = (FileBlocks) object; + value.putUTF(blocks.resourceId()); + value.put(blocks.blocks().size()); + for (Block b : blocks.blocks()) { + value.putByteArray(b.getBlockHash().getBytes()); + value.put(b.getIndexInFile()); + value.put(b.getStartLine()); + value.put(b.getEndLine()); + value.put(b.getStartUnit()); + value.put(b.getEndUnit()); + } + } + + @Override + public Object get(Value value, Class clazz, CoderContext context) { + String resourceId = value.getString(); + int count = value.getInt(); + List<Block> blocks = new ArrayList<Block>(count); + for (int i = 0; i < count; i++) { + Block.Builder b = Block.builder(); + b.setResourceId(resourceId); + b.setBlockHash(new ByteArray(value.getByteArray())); + b.setIndexInFile(value.getInt()); + int startLine = value.getInt(); + int endLine = value.getInt(); + b.setLines(startLine, endLine); + int startUnit = value.getInt(); + int endUnit = value.getInt(); + b.setUnit(startUnit, endUnit); + blocks.add(b.build()); + } + return new FileBlocks(resourceId, blocks); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java b/sonar-batch/src/main/java/org/sonar/batch/duplication/package-info.java index c59091fb0f6..103e90ab281 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java +++ b/sonar-batch/src/main/java/org/sonar/batch/duplication/package-info.java @@ -17,20 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.mediumtest.xoo.plugin.base; +@ParametersAreNonnullByDefault +package org.sonar.batch.duplication; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public interface XooConstants { - - String PLUGIN_KEY = "xoo"; - String PLUGIN_NAME = "Xoo"; - - String REPOSITORY_KEY = PLUGIN_KEY; - String REPOSITORY_NAME = PLUGIN_NAME; - - String[] FILE_SUFFIXES = {"xoo"}; - - Logger LOG = LoggerFactory.getLogger("xoo"); -} +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java index 38ae875af98..3a74dbf4884 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java @@ -32,9 +32,6 @@ import java.util.List; import static com.google.common.collect.Lists.newArrayList; -/** - * @since 3.6 - */ public class SyntaxHighlightingDataBuilder { private List<SyntaxHighlightingRule> syntaxHighlightingRuleSet; diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java index 08985752d60..e6faa7651b4 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java @@ -21,9 +21,6 @@ package org.sonar.batch.highlighting; import java.io.Serializable; -/** - * @since 3.6 - */ public class SyntaxHighlightingRule implements Serializable { private final int startPosition; diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java b/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java index ff57e4c065d..c98b88773e6 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/Cache.java @@ -28,7 +28,6 @@ import org.apache.commons.lang.builder.ToStringBuilder; import javax.annotation.CheckForNull; -import java.io.Serializable; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; @@ -38,7 +37,7 @@ import java.util.Set; * This cache is not thread-safe, due to direct usage of {@link com.persistit.Exchange} * </p> */ -public class Cache<V extends Serializable> { +public class Cache<V> { private final String name; private final Exchange exchange; @@ -383,7 +382,7 @@ public class Cache<V extends Serializable> { // LAZY ITERATORS AND ITERABLES // - private static class ValueIterable<T extends Serializable> implements Iterable<T> { + private static class ValueIterable<T> implements Iterable<T> { private final Iterator<T> iterator; private ValueIterable(Exchange exchange, KeyFilter keyFilter) { @@ -396,7 +395,7 @@ public class Cache<V extends Serializable> { } } - private static class ValueIterator<T extends Serializable> implements Iterator<T> { + private static class ValueIterator<T> implements Iterator<T> { private final Exchange exchange; private final KeyFilter keyFilter; @@ -434,7 +433,7 @@ public class Cache<V extends Serializable> { } } - private static class EntryIterable<T extends Serializable> implements Iterable<Entry<T>> { + private static class EntryIterable<T> implements Iterable<Entry<T>> { private final EntryIterator<T> it; private EntryIterable(Exchange exchange, KeyFilter keyFilter) { @@ -447,7 +446,7 @@ public class Cache<V extends Serializable> { } } - private static class EntryIterator<T extends Serializable> implements Iterator<Entry<T>> { + private static class EntryIterator<T> implements Iterator<Entry<T>> { private final Exchange exchange; private final KeyFilter keyFilter; @@ -491,7 +490,7 @@ public class Cache<V extends Serializable> { } } - public static class Entry<V extends Serializable> { + public static class Entry<V> { private final Object[] key; private final V value; diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java b/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java index 1e8c53d8853..ca2a33a5014 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/Caches.java @@ -36,7 +36,6 @@ import org.sonar.api.BatchComponent; import org.sonar.api.utils.TempFolder; import java.io.File; -import java.io.Serializable; import java.util.Properties; import java.util.Set; @@ -85,7 +84,7 @@ public class Caches implements BatchComponent, Startable { cm.registerValueCoder(clazz, coder); } - public <V extends Serializable> Cache<V> createCache(String cacheName) { + public <V> Cache<V> createCache(String cacheName) { Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized"); Preconditions.checkState(!cacheNames.contains(cacheName), "Cache is already created: " + cacheName); try { diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java index 2a63d4b8b9e..0f7691728a1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/MeasurePersister.java @@ -20,10 +20,13 @@ package org.sonar.batch.index; import com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang.StringEscapeUtils; import org.sonar.api.database.model.MeasureMapper; import org.sonar.api.database.model.MeasureModel; import org.sonar.api.database.model.Snapshot; +import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; +import org.sonar.api.measures.PersistenceMode; import org.sonar.api.measures.RuleMeasure; import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; @@ -31,6 +34,8 @@ import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.technicaldebt.batch.Characteristic; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.duplication.DuplicationGroup; import org.sonar.batch.index.Cache.Entry; import org.sonar.batch.scan.measure.MeasureCache; import org.sonar.core.persistence.DbSession; @@ -38,20 +43,27 @@ import org.sonar.core.persistence.MyBatis; import javax.annotation.Nullable; +import java.util.ArrayList; + public final class MeasurePersister implements ScanPersister { private final MyBatis mybatis; private final RuleFinder ruleFinder; private final MeasureCache measureCache; private final SnapshotCache snapshotCache; private final ResourceCache resourceCache; + private final DuplicationCache duplicationCache; + private final org.sonar.api.measures.MetricFinder metricFinder; public MeasurePersister(MyBatis mybatis, RuleFinder ruleFinder, - MeasureCache measureCache, SnapshotCache snapshotCache, ResourceCache resourceCache) { + MeasureCache measureCache, SnapshotCache snapshotCache, ResourceCache resourceCache, + DuplicationCache duplicationCache, org.sonar.api.measures.MetricFinder metricFinder) { this.mybatis = mybatis; this.ruleFinder = ruleFinder; this.measureCache = measureCache; this.snapshotCache = snapshotCache; this.resourceCache = resourceCache; + this.duplicationCache = duplicationCache; + this.metricFinder = metricFinder; } @Override @@ -72,6 +84,19 @@ public final class MeasurePersister implements ScanPersister { } } + org.sonar.api.measures.Metric duplicationMetricWithId = metricFinder.findByKey(CoreMetrics.DUPLICATIONS_DATA_KEY); + for (Entry<ArrayList<DuplicationGroup>> entry : duplicationCache.entries()) { + String effectiveKey = entry.key()[0].toString(); + Measure measure = new Measure(duplicationMetricWithId, toXml(entry.value())).setPersistenceMode(PersistenceMode.DATABASE); + Resource resource = resourceCache.get(effectiveKey); + + if (shouldPersistMeasure(resource, measure)) { + Snapshot snapshot = snapshotCache.get(effectiveKey); + MeasureModel measureModel = model(measure).setSnapshotId(snapshot.getId()); + mapper.insert(measureModel); + } + } + session.commit(); } catch (Exception e) { throw new IllegalStateException("Unable to save some measures", e); @@ -80,6 +105,28 @@ public final class MeasurePersister implements ScanPersister { } } + private static String toXml(Iterable<DuplicationGroup> duplications) { + StringBuilder xml = new StringBuilder(); + xml.append("<duplications>"); + for (DuplicationGroup duplication : duplications) { + xml.append("<g>"); + toXml(xml, duplication.originBlock()); + for (DuplicationGroup.Block part : duplication.duplicates()) { + toXml(xml, part); + } + xml.append("</g>"); + } + xml.append("</duplications>"); + return xml.toString(); + } + + private static void toXml(StringBuilder xml, DuplicationGroup.Block part) { + xml.append("<b s=\"").append(part.startLine()) + .append("\" l=\"").append(part.length()) + .append("\" r=\"").append(StringEscapeUtils.escapeXml(part.resourceKey())) + .append("\"/>"); + } + @VisibleForTesting static boolean shouldPersistMeasure(@Nullable Resource resource, @Nullable Measure measure) { if (resource == null || measure == null) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java index fc7a89ebad8..58cc4f461af 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -41,8 +41,11 @@ import org.sonar.api.resources.Languages; import org.sonar.batch.bootstrap.PluginsReferential; import org.sonar.batch.bootstrapper.Batch; import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.duplication.DuplicationGroup; import org.sonar.batch.highlighting.SyntaxHighlightingData; import org.sonar.batch.highlighting.SyntaxHighlightingRule; +import org.sonar.batch.index.Cache.Entry; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.protocol.input.ActiveRule; import org.sonar.batch.protocol.input.GlobalReferentials; @@ -222,6 +225,7 @@ public class BatchMediumTester { private List<Issue> issues = new ArrayList<Issue>(); private List<Measure> measures = new ArrayList<Measure>(); + private Map<String, List<DuplicationGroup>> duplications = new HashMap<String, List<DuplicationGroup>>(); private List<InputFile> inputFiles = new ArrayList<InputFile>(); private List<InputDir> inputDirs = new ArrayList<InputDir>(); private Map<InputFile, SyntaxHighlightingData> highlightingPerFile = new HashMap<InputFile, SyntaxHighlightingData>(); @@ -259,6 +263,12 @@ public class BatchMediumTester { } } + DuplicationCache duplicationCache = container.getComponentByType(DuplicationCache.class); + for (Entry<ArrayList<DuplicationGroup>> entry : duplicationCache.entries()) { + String effectiveKey = entry.key()[0].toString(); + duplications.put(effectiveKey, entry.value()); + } + } public List<Issue> issues() { @@ -277,6 +287,10 @@ public class BatchMediumTester { return inputDirs; } + public List<DuplicationGroup> duplicationsFor(InputFile inputFile) { + return duplications.get(((DefaultInputFile) inputFile).key()); + } + /** * Get highlighting type at a given position in an inputfile * @param charIndex 0-based offset in file diff --git a/sonar-batch/src/main/java/org/sonar/batch/referential/ProjectReferentialsProvider.java b/sonar-batch/src/main/java/org/sonar/batch/referential/ProjectReferentialsProvider.java index 75a063eb119..ac08e40f5fa 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/referential/ProjectReferentialsProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/referential/ProjectReferentialsProvider.java @@ -20,14 +20,24 @@ package org.sonar.batch.referential; import org.picocontainer.injectors.ProviderAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.Settings; import org.sonar.api.resources.Languages; +import org.sonar.api.utils.TimeProfiler; import org.sonar.batch.protocol.input.ProjectReferentials; public class ProjectReferentialsProvider extends ProviderAdapter { + private static final Logger LOG = LoggerFactory.getLogger(ProjectReferentialsProvider.class); + public ProjectReferentials provide(ProjectReferentialsLoader loader, ProjectReactor reactor, Settings settings, Languages languages) { - return loader.load(reactor, settings, languages); + TimeProfiler profiler = new TimeProfiler(LOG).start("Load project referentials"); + try { + return loader.load(reactor, settings, languages); + } finally { + profiler.stop(); + } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java index c5e21b89a66..3a209b91961 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java @@ -42,6 +42,8 @@ import org.sonar.batch.bootstrap.MetricProvider; import org.sonar.batch.components.PeriodsDefinition; import org.sonar.batch.debt.DebtModelProvider; import org.sonar.batch.debt.IssueChangelogDebtCalculator; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.index.Caches; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.index.ComponentDataPersister; @@ -194,6 +196,10 @@ public class ProjectScanContainer extends ComponentContainer { new RulesProvider(), new DebtModelProvider(), + // Duplications + BlockCache.class, + DuplicationCache.class, + ProjectSettings.class); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java index 1de8fd7201c..d285a6c8646 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java @@ -27,6 +27,8 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; +import org.sonar.api.batch.sensor.duplication.TokenBuilder; import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.IssueBuilder; @@ -49,9 +51,14 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.Scopes; import org.sonar.api.rule.RuleKey; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DefaultDuplicationBuilder; +import org.sonar.batch.duplication.DefaultTokenBuilder; +import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.highlighting.DefaultHighlightingBuilder; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.symbol.DefaultSymbolTableBuilder; +import org.sonar.duplications.internal.pmd.PmdBlockChunker; import java.io.Serializable; @@ -61,17 +68,20 @@ import java.io.Serializable; */ public class SensorContextAdaptor implements SensorContext { - private org.sonar.api.batch.SensorContext sensorContext; - private MetricFinder metricFinder; - private Project project; - private ResourcePerspectives perspectives; - private Settings settings; - private FileSystem fs; - private ActiveRules activeRules; - private ComponentDataCache componentDataCache; + private final org.sonar.api.batch.SensorContext sensorContext; + private final MetricFinder metricFinder; + private final Project project; + private final ResourcePerspectives perspectives; + private final Settings settings; + private final FileSystem fs; + private final ActiveRules activeRules; + private final ComponentDataCache componentDataCache; + private final BlockCache blockCache; + private final DuplicationCache duplicationCache; public SensorContextAdaptor(org.sonar.api.batch.SensorContext sensorContext, MetricFinder metricFinder, Project project, ResourcePerspectives perspectives, - Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache) { + Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache, BlockCache blockCache, + DuplicationCache duplicationCache) { this.sensorContext = sensorContext; this.metricFinder = metricFinder; this.project = project; @@ -80,6 +90,8 @@ public class SensorContextAdaptor implements SensorContext { this.fs = fs; this.activeRules = activeRules; this.componentDataCache = componentDataCache; + this.blockCache = blockCache; + this.duplicationCache = duplicationCache; } @Override @@ -254,4 +266,33 @@ public class SensorContextAdaptor implements SensorContext { return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); } + @Override + public TokenBuilder tokenBuilder(InputFile inputFile) { + PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); + return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); + } + + @Override + public DuplicationBuilder duplicationBuilder(InputFile inputFile) { + return new DefaultDuplicationBuilder(inputFile, duplicationCache); + } + + private int getBlockSize(String languageKey) { + int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); + if (blockSize == 0) { + blockSize = getDefaultBlockSize(languageKey); + } + return blockSize; + } + + private static int getDefaultBlockSize(String languageKey) { + if ("cobol".equals(languageKey)) { + return 30; + } else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { + return 20; + } else { + return 10; + } + } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java index b5929008269..32a49a16492 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorWrapper.java @@ -33,19 +33,23 @@ import java.util.List; public class SensorWrapper implements org.sonar.api.batch.Sensor { - private Sensor analyzer; + private Sensor wrappedSensor; private SensorContext adaptor; private DefaultSensorDescriptor descriptor; private AnalyzerOptimizer optimizer; public SensorWrapper(Sensor newSensor, SensorContext adaptor, AnalyzerOptimizer optimizer) { - this.analyzer = newSensor; + this.wrappedSensor = newSensor; this.optimizer = optimizer; descriptor = new DefaultSensorDescriptor(); newSensor.describe(descriptor); this.adaptor = adaptor; } + public Sensor wrappedSensor() { + return wrappedSensor; + } + @DependedUpon public List<Metric> provides() { return Arrays.asList(descriptor.provides()); @@ -63,7 +67,7 @@ public class SensorWrapper implements org.sonar.api.batch.Sensor { @Override public void analyse(Project module, org.sonar.api.batch.SensorContext context) { - analyzer.execute(adaptor); + wrappedSensor.execute(adaptor); } @Override diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java new file mode 100644 index 00000000000..d60cbac0088 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java @@ -0,0 +1,76 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.scan.filesystem; + +import com.persistit.Value; +import com.persistit.encoding.CoderContext; +import com.persistit.encoding.ValueCoder; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile; + +import javax.annotation.Nullable; + +import java.io.File; + +class DefaultInputFileValueCoder implements ValueCoder { + + @Override + public void put(Value value, Object object, CoderContext context) { + DeprecatedDefaultInputFile f = (DeprecatedDefaultInputFile) object; + putUTFOrNull(value, f.relativePath()); + putUTFOrNull(value, f.getFileBaseDir().toString()); + putUTFOrNull(value, f.deprecatedKey()); + putUTFOrNull(value, f.sourceDirAbsolutePath()); + putUTFOrNull(value, f.pathRelativeToSourceDir()); + putUTFOrNull(value, f.absolutePath()); + putUTFOrNull(value, f.language()); + putUTFOrNull(value, f.type().name()); + putUTFOrNull(value, f.status().name()); + putUTFOrNull(value, f.hash()); + value.put(f.lines()); + putUTFOrNull(value, f.key()); + } + + private void putUTFOrNull(Value value, @Nullable String utfOrNull) { + if (utfOrNull != null) { + value.putUTF(utfOrNull); + } else { + value.putNull(); + } + } + + @Override + public Object get(Value value, Class clazz, CoderContext context) { + DeprecatedDefaultInputFile file = new DeprecatedDefaultInputFile(value.getString()); + file.setBasedir(new File(value.getString())); + file.setDeprecatedKey(value.getString()); + file.setSourceDirAbsolutePath(value.getString()); + file.setPathRelativeToSourceDir(value.getString()); + file.setAbsolutePath(value.getString()); + file.setLanguage(value.getString()); + file.setType(InputFile.Type.valueOf(value.getString())); + file.setStatus(InputFile.Status.valueOf(value.getString())); + file.setHash(value.getString()); + file.setLines(value.getInt()); + file.setKey(value.getString()); + return file; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java index 5d901a517ae..39672d7f7c5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputPathCache.java @@ -23,6 +23,7 @@ import org.sonar.api.BatchComponent; import org.sonar.api.batch.fs.InputDir; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputPath; +import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile; import org.sonar.batch.index.Cache; import org.sonar.batch.index.Caches; @@ -44,6 +45,7 @@ public class InputPathCache implements BatchComponent { private final Cache<InputPath> cache; public InputPathCache(Caches caches) { + caches.registerValueCoder(DeprecatedDefaultInputFile.class, new DefaultInputFileValueCoder()); cache = caches.createCache("inputFiles"); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureValueCoder.java index 7f010d97d0a..c0906b51d6d 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureValueCoder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/measure/MeasureValueCoder.java @@ -30,6 +30,8 @@ import org.sonar.api.technicaldebt.batch.Characteristic; import org.sonar.api.technicaldebt.batch.Requirement; import org.sonar.api.technicaldebt.batch.TechnicalDebtModel; +import javax.annotation.Nullable; + class MeasureValueCoder implements ValueCoder { private final MetricFinder metricFinder; @@ -42,12 +44,12 @@ class MeasureValueCoder implements ValueCoder { public void put(Value value, Object object, CoderContext context) { Measure<?> m = (Measure) object; - value.putString(m.getMetricKey()); + value.putUTF(m.getMetricKey()); value.put(m.getValue()); - value.putString(m.getData()); - value.putString(m.getDescription()); - value.putString(m.getAlertStatus() != null ? m.getAlertStatus().name() : null); - value.putString(m.getAlertText()); + putUTFOrNull(value, m.getData()); + putUTFOrNull(value, m.getDescription()); + putUTFOrNull(value, m.getAlertStatus() != null ? m.getAlertStatus().name() : null); + putUTFOrNull(value, m.getAlertText()); value.put(m.getTendency()); value.putDate(m.getDate()); value.put(m.getVariation1()); @@ -55,7 +57,7 @@ class MeasureValueCoder implements ValueCoder { value.put(m.getVariation3()); value.put(m.getVariation4()); value.put(m.getVariation5()); - value.putString(m.getUrl()); + putUTFOrNull(value, m.getUrl()); Characteristic characteristic = m.getCharacteristic(); value.put(characteristic != null ? characteristic.id() : null); Requirement requirement = m.getRequirement(); @@ -63,7 +65,15 @@ class MeasureValueCoder implements ValueCoder { Integer personId = m.getPersonId(); value.put(personId != null ? personId.intValue() : null); PersistenceMode persistenceMode = m.getPersistenceMode(); - value.putString(persistenceMode != null ? persistenceMode.name() : null); + putUTFOrNull(value, persistenceMode != null ? persistenceMode.name() : null); + } + + private void putUTFOrNull(Value value, @Nullable String utfOrNull) { + if (utfOrNull != null) { + value.putUTF(utfOrNull); + } else { + value.putNull(); + } } public Object get(Value value, Class clazz, CoderContext context) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java index 75d0e31932c..801744de2c7 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerMeasureCache.java @@ -19,10 +19,10 @@ */ package org.sonar.batch.scan2; -import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; - import com.google.common.base.Preconditions; import org.sonar.api.BatchComponent; +import org.sonar.api.batch.measure.MetricFinder; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.batch.index.Cache; import org.sonar.batch.index.Cache.Entry; import org.sonar.batch.index.Caches; @@ -35,7 +35,8 @@ public class AnalyzerMeasureCache implements BatchComponent { // project key -> component key -> metric key -> measure private final Cache<DefaultMeasure> cache; - public AnalyzerMeasureCache(Caches caches) { + public AnalyzerMeasureCache(Caches caches, MetricFinder metricFinder) { + caches.registerValueCoder(DefaultMeasure.class, new DefaultMeasureValueCoder(metricFinder)); cache = caches.createCache("measures"); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultMeasureValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultMeasureValueCoder.java new file mode 100644 index 00000000000..8b82a684dd0 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultMeasureValueCoder.java @@ -0,0 +1,64 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.scan2; + +import com.persistit.Value; +import com.persistit.encoding.CoderContext; +import com.persistit.encoding.ValueCoder; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.measure.Metric; +import org.sonar.api.batch.measure.MetricFinder; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; + +import java.io.Serializable; + +class DefaultMeasureValueCoder implements ValueCoder { + + private MetricFinder metricFinder; + + public DefaultMeasureValueCoder(MetricFinder metricFinder) { + this.metricFinder = metricFinder; + } + + @Override + public void put(Value value, Object object, CoderContext context) { + DefaultMeasure m = (DefaultMeasure) object; + value.put(m.inputFile()); + value.putUTF(m.metric().key()); + value.put(m.value()); + } + + @Override + public Object get(Value value, Class clazz, CoderContext context) { + DefaultMeasureBuilder builder = new DefaultMeasureBuilder(); + InputFile f = (InputFile) value.get(); + if (f != null) { + builder.onFile(f); + } else { + builder.onProject(); + } + Metric m = metricFinder.findByKey(value.getString()); + builder.forMetric(m); + builder.withValue((Serializable) value.get()); + return builder.build(); + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java index dcd6efd1ca4..73d6429bfcd 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java @@ -28,6 +28,8 @@ import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.rule.internal.DefaultActiveRule; import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.duplication.DuplicationBuilder; +import org.sonar.api.batch.sensor.duplication.TokenBuilder; import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.IssueBuilder; @@ -41,12 +43,17 @@ import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; import org.sonar.api.config.Settings; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.MessageException; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DefaultDuplicationBuilder; +import org.sonar.batch.duplication.DefaultTokenBuilder; +import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.highlighting.DefaultHighlightingBuilder; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.issue.IssueFilters; import org.sonar.batch.scan.SensorContextAdaptor; import org.sonar.batch.symbol.DefaultSymbolTableBuilder; import org.sonar.core.component.ComponentKeys; +import org.sonar.duplications.internal.pmd.PmdBlockChunker; import java.io.Serializable; @@ -60,9 +67,12 @@ public class DefaultSensorContext implements SensorContext { private final ActiveRules activeRules; private final IssueFilters issueFilters; private final ComponentDataCache componentDataCache; + private final BlockCache blockCache; + private final DuplicationCache duplicationCache; public DefaultSensorContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache, - Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache) { + Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache, + BlockCache blockCache, DuplicationCache duplicationCache) { this.def = def; this.measureCache = measureCache; this.issueCache = issueCache; @@ -71,6 +81,8 @@ public class DefaultSensorContext implements SensorContext { this.activeRules = activeRules; this.issueFilters = issueFilters; this.componentDataCache = componentDataCache; + this.blockCache = blockCache; + this.duplicationCache = duplicationCache; } @Override @@ -175,4 +187,34 @@ public class DefaultSensorContext implements SensorContext { return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); } + @Override + public TokenBuilder tokenBuilder(InputFile inputFile) { + PmdBlockChunker blockChunker = new PmdBlockChunker(getBlockSize(inputFile.language())); + + return new DefaultTokenBuilder(inputFile, blockCache, blockChunker); + } + + @Override + public DuplicationBuilder duplicationBuilder(InputFile inputFile) { + return new DefaultDuplicationBuilder(inputFile, duplicationCache); + } + + private int getBlockSize(String languageKey) { + int blockSize = settings.getInt("sonar.cpd." + languageKey + ".minimumLines"); + if (blockSize == 0) { + blockSize = getDefaultBlockSize(languageKey); + } + return blockSize; + } + + private static int getDefaultBlockSize(String languageKey) { + if ("cobol".equals(languageKey)) { + return 30; + } else if ("abap".equals(languageKey) || "natur".equals(languageKey)) { + return 20; + } else { + return 10; + } + } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java index e13fca37d28..b0a2b3e0af5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java @@ -33,6 +33,8 @@ import org.sonar.api.scan.filesystem.PathResolver; import org.sonar.batch.bootstrap.ExtensionInstaller; import org.sonar.batch.bootstrap.ExtensionMatcher; import org.sonar.batch.bootstrap.ExtensionUtils; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.index.Caches; import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.languages.DefaultLanguagesReferential; @@ -107,6 +109,10 @@ public class ProjectScanContainer extends ComponentContainer { ComponentDataCache.class, + // Duplications + BlockCache.class, + DuplicationCache.class, + ScanTaskObservers.class); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java index d437eadb6fd..ea872c4c1bf 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java @@ -53,7 +53,7 @@ public class SensorsExecutor implements BatchComponent { continue; } - LOG.info("Execute analyzer: " + descriptor.name()); + LOG.info("Execute sensor: " + descriptor.name()); executeSensor(context, analyzer); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java new file mode 100644 index 00000000000..ade701fce45 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/duplication/DuplicationCacheTest.java @@ -0,0 +1,82 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.duplication; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.sonar.batch.index.Caches; +import org.sonar.batch.index.CachesTest; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.fest.assertions.Assertions.assertThat; + +public class DuplicationCacheTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + Caches caches; + + @Before + public void start() throws Exception { + caches = CachesTest.createCacheOnTemp(temp); + caches.start(); + } + + @After + public void stop() { + caches.stop(); + } + + @Test + public void should_add_clone_groups() throws Exception { + DuplicationCache cache = new DuplicationCache(caches); + + DuplicationGroup group1 = new DuplicationGroup(new DuplicationGroup.Block("foo", 1, 2)) + .addDuplicate(new DuplicationGroup.Block("foo", 1, 2)) + .addDuplicate(new DuplicationGroup.Block("foo2", 12, 22)) + .addDuplicate(new DuplicationGroup.Block("foo3", 13, 23)); + + DuplicationGroup group2 = new DuplicationGroup(new DuplicationGroup.Block("2foo", 1, 2)) + .addDuplicate(new DuplicationGroup.Block("2foo", 1, 2)) + .addDuplicate(new DuplicationGroup.Block("2foo2", 12, 22)) + .addDuplicate(new DuplicationGroup.Block("2foo3", 13, 23)); + + assertThat(cache.entries()).hasSize(0); + + cache.put("foo", new ArrayList<DuplicationGroup>(Arrays.asList(group1, group2))); + + assertThat(cache.entries()).hasSize(1); + + ArrayList<DuplicationGroup> entry = cache.byComponent("foo"); + assertThat(entry.get(0).originBlock().resourceKey()).isEqualTo("foo"); + + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java index fe8a1a45a65..dfed349e696 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/MeasurePersisterTest.java @@ -27,6 +27,7 @@ import org.sonar.api.database.model.Snapshot; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; +import org.sonar.api.measures.MetricFinder; import org.sonar.api.measures.PersistenceMode; import org.sonar.api.measures.RuleMeasure; import org.sonar.api.resources.Directory; @@ -35,10 +36,14 @@ import org.sonar.api.resources.Project; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RulePriority; +import org.sonar.batch.duplication.DuplicationCache; +import org.sonar.batch.duplication.DuplicationGroup; import org.sonar.batch.scan.measure.MeasureCache; import org.sonar.core.persistence.AbstractDaoTestCase; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -70,6 +75,8 @@ public class MeasurePersisterTest extends AbstractDaoTestCase { public void mockResourcePersister() { snapshotCache = mock(SnapshotCache.class); measureCache = mock(MeasureCache.class); + DuplicationCache duplicationCache = mock(DuplicationCache.class); + when(duplicationCache.entries()).thenReturn(Collections.<Cache.Entry<ArrayList<DuplicationGroup>>>emptyList()); ResourceCache resourceCache = mock(ResourceCache.class); when(snapshotCache.get("foo")).thenReturn(projectSnapshot); when(snapshotCache.get("foo:org/foo")).thenReturn(packageSnapshot); @@ -77,7 +84,7 @@ public class MeasurePersisterTest extends AbstractDaoTestCase { when(resourceCache.get("foo:org/foo/Bar.java")).thenReturn(aFile); when(resourceCache.get("foo:org/foo")).thenReturn(aDirectory); - measurePersister = new MeasurePersister(getMyBatis(), ruleFinder, measureCache, snapshotCache, resourceCache); + measurePersister = new MeasurePersister(getMyBatis(), ruleFinder, measureCache, snapshotCache, resourceCache, duplicationCache, mock(MetricFinder.class)); } @Test diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java index 674f472d0b5..19d7aea020a 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/fs/FileSystemMediumTest.java @@ -31,8 +31,8 @@ import org.sonar.api.batch.fs.InputFile; import org.sonar.api.utils.MessageException; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; -import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.xoo.XooPlugin; import java.io.File; import java.io.IOException; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java index 259b2ffcec0..b9fab7ba450 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java @@ -29,7 +29,7 @@ import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; -import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; +import org.sonar.xoo.XooPlugin; import java.io.File; import java.io.IOException; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java index 875e7e6d510..f3eebf971e3 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesMediumTest.java @@ -29,8 +29,8 @@ import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; -import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.xoo.XooPlugin; import java.io.File; import java.io.IOException; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java index fdf6b15e857..fb3e8d16edd 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/issues/IssuesOnDirMediumTest.java @@ -28,8 +28,8 @@ import org.junit.rules.TemporaryFolder; import org.sonar.api.batch.fs.internal.DefaultInputDir; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; -import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; import org.sonar.batch.protocol.input.ActiveRule; +import org.sonar.xoo.XooPlugin; import java.io.File; import java.io.IOException; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java index bb93ae4b7ba..146b89eb316 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/measures/MeasuresMediumTest.java @@ -30,7 +30,7 @@ import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; import org.sonar.api.measures.CoreMetrics; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; -import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; +import org.sonar.xoo.XooPlugin; import java.io.File; import java.io.IOException; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java index c3875c625f3..8772d371ba2 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java @@ -28,7 +28,7 @@ import org.junit.rules.TemporaryFolder; import org.sonar.api.batch.fs.InputFile; import org.sonar.batch.mediumtest.BatchMediumTester; import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; -import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; +import org.sonar.xoo.XooPlugin; import java.io.File; import java.io.IOException; diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java deleted file mode 100644 index 78718da3682..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin; - -import org.sonar.api.SonarPlugin; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.lang.MeasureSensor; -import org.sonar.batch.mediumtest.xoo.plugin.lang.ScmActivitySensor; -import org.sonar.batch.mediumtest.xoo.plugin.lang.SymbolReferencesSensor; -import org.sonar.batch.mediumtest.xoo.plugin.lang.SyntaxHighlightingSensor; -import org.sonar.batch.mediumtest.xoo.plugin.rule.CreateIssueByInternalKeySensor; -import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssueOnDirPerFileSensor; -import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssuePerLineSensor; - -import java.util.Arrays; -import java.util.List; - -public final class XooPlugin extends SonarPlugin { - - @Override - public List getExtensions() { - return Arrays.asList( - // language - MeasureSensor.class, - ScmActivitySensor.class, - SyntaxHighlightingSensor.class, - SymbolReferencesSensor.class, - Xoo.class, - - // sensors - OneIssuePerLineSensor.class, - OneIssueOnDirPerFileSensor.class, - CreateIssueByInternalKeySensor.class - ); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java deleted file mode 100644 index c28ebd5a05c..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.lang; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.measure.MetricFinder; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.batch.sensor.measure.MeasureBuilder; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.util.List; - -/** - * Parse files *.xoo.measures - */ -public class MeasureSensor implements Sensor { - - private static final String MEASURES_EXTENSION = ".measures"; - - private MetricFinder metricFinder; - - public MeasureSensor(MetricFinder metricFinder) { - this.metricFinder = metricFinder; - } - - private void processFileMeasures(InputFile inputFile, SensorContext context) { - File ioFile = inputFile.file(); - File measureFile = new File(ioFile.getParentFile(), ioFile.getName() + MEASURES_EXTENSION); - if (measureFile.exists()) { - XooConstants.LOG.debug("Processing " + measureFile.getAbsolutePath()); - try { - List<String> lines = FileUtils.readLines(measureFile, context.fileSystem().encoding().name()); - int lineNumber = 0; - for (String line : lines) { - lineNumber++; - if (StringUtils.isBlank(line)) { - continue; - } - if (line.startsWith("#")) { - continue; - } - try { - String metricKey = StringUtils.substringBefore(line, ":"); - String value = line.substring(metricKey.length() + 1); - context.addMeasure(createMeasure(context, inputFile, metricKey, value)); - } catch (Exception e) { - throw new IllegalStateException("Error processing line " + lineNumber + " of file " + measureFile.getAbsolutePath(), e); - } - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - private Measure<?> createMeasure(SensorContext context, InputFile xooFile, String metricKey, String value) { - org.sonar.api.batch.measure.Metric<Serializable> metric = metricFinder.findByKey(metricKey); - MeasureBuilder<Serializable> builder = context.measureBuilder() - .forMetric(metric) - .onFile(xooFile); - if (Boolean.class.equals(metric.valueType())) { - builder.withValue(Boolean.parseBoolean(value)); - } else if (Integer.class.equals(metric.valueType())) { - builder.withValue(Integer.valueOf(value)); - } else if (Double.class.equals(metric.valueType())) { - builder.withValue(Double.valueOf(value)); - } else if (String.class.equals(metric.valueType())) { - builder.withValue(value); - } else if (Long.class.equals(metric.valueType())) { - builder.withValue(Long.valueOf(value)); - } else { - throw new UnsupportedOperationException("Unsupported type :" + metric.valueType()); - } - return builder.build(); - } - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name("Xoo Measure Sensor") - .provides(CoreMetrics.LINES) - .workOnLanguages(Xoo.KEY) - .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); - } - - @Override - public void execute(SensorContext context) { - for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { - processFileMeasures(file, context); - } - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivitySensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivitySensor.java deleted file mode 100644 index b3352dba62a..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/ScmActivitySensor.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.lang; - -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.measures.FileLinesContext; -import org.sonar.api.measures.FileLinesContextFactory; -import org.sonar.api.utils.DateUtils; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; - -import java.io.File; -import java.io.IOException; -import java.util.Date; -import java.util.List; - -public class ScmActivitySensor implements Sensor { - - private static final Logger LOG = LoggerFactory.getLogger(ScmActivitySensor.class); - - private static final String SCM_EXTENSION = ".scm"; - - private final FileSystem fs; - private final FileLinesContextFactory fileLinesContextFactory; - - public ScmActivitySensor(FileLinesContextFactory fileLinesContextFactory, FileSystem fileSystem) { - this.fs = fileSystem; - this.fileLinesContextFactory = fileLinesContextFactory; - } - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name(this.getClass().getSimpleName()) - .provides(CoreMetrics.SCM_AUTHORS_BY_LINE, - CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE, - CoreMetrics.SCM_REVISIONS_BY_LINE) - .workOnLanguages(Xoo.KEY); - } - - @Override - public void execute(SensorContext context) { - for (InputFile inputFile : fs.inputFiles(fs.predicates().hasLanguage(Xoo.KEY))) { - processFile(inputFile); - } - - } - - @VisibleForTesting - protected void processFile(InputFile inputFile) { - File ioFile = inputFile.file(); - File scmDataFile = new java.io.File(ioFile.getParentFile(), ioFile.getName() + SCM_EXTENSION); - if (!scmDataFile.exists()) { - LOG.debug("Skipping SCM data injection for " + inputFile.relativePath()); - return; - } - - FileLinesContext fileLinesContext = fileLinesContextFactory.createFor(inputFile); - try { - List<String> lines = FileUtils.readLines(scmDataFile, Charsets.UTF_8.name()); - int lineNumber = 0; - for (String line : lines) { - lineNumber++; - if (StringUtils.isNotBlank(line)) { - // revision,author,dateTime - String[] fields = StringUtils.split(line, ','); - if (fields.length < 3) { - throw new IllegalStateException("Not enough fields on line " + lineNumber); - } - String revision = fields[0]; - String author = fields[1]; - // Will throw an exception, when date is not in format "yyyy-MM-dd" - Date date = DateUtils.parseDate(fields[2]); - - fileLinesContext.setStringValue(CoreMetrics.SCM_REVISIONS_BY_LINE_KEY, lineNumber, revision); - fileLinesContext.setStringValue(CoreMetrics.SCM_AUTHORS_BY_LINE_KEY, lineNumber, author); - fileLinesContext.setStringValue(CoreMetrics.SCM_LAST_COMMIT_DATETIMES_BY_LINE_KEY, lineNumber, DateUtils.formatDateTime(date)); - } - } - } catch (IOException e) { - throw new IllegalStateException(e); - } - fileLinesContext.save(); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SymbolReferencesSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SymbolReferencesSensor.java deleted file mode 100644 index 91fa61e5c78..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SymbolReferencesSensor.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.lang; - -import com.google.common.base.Splitter; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.symbol.Symbol; -import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; - -import java.io.File; -import java.io.IOException; -import java.util.Iterator; -import java.util.List; - -/** - * Parse files *.xoo.symbol - */ -public class SymbolReferencesSensor implements Sensor { - - private static final String SYMBOL_EXTENSION = ".symbol"; - - private void processFileHighlighting(InputFile inputFile, SensorContext context) { - File ioFile = inputFile.file(); - File symbolFile = new File(ioFile.getParentFile(), ioFile.getName() + SYMBOL_EXTENSION); - if (symbolFile.exists()) { - XooConstants.LOG.debug("Processing " + symbolFile.getAbsolutePath()); - try { - List<String> lines = FileUtils.readLines(symbolFile, context.fileSystem().encoding().name()); - int lineNumber = 0; - SymbolTableBuilder symbolTableBuilder = context.symbolTableBuilder(inputFile); - for (String line : lines) { - lineNumber++; - if (StringUtils.isBlank(line)) { - continue; - } - if (line.startsWith("#")) { - continue; - } - try { - Iterator<String> split = Splitter.on(",").split(line).iterator(); - int startOffset = Integer.parseInt(split.next()); - int endOffset = Integer.parseInt(split.next()); - Symbol s = symbolTableBuilder.newSymbol(startOffset, endOffset); - while (split.hasNext()) { - symbolTableBuilder.newReference(s, Integer.parseInt(split.next())); - } - } catch (Exception e) { - throw new IllegalStateException("Error processing line " + lineNumber + " of file " + symbolFile.getAbsolutePath(), e); - } - } - symbolTableBuilder.done(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name("Xoo Highlighting Sensor") - .provides(CoreMetrics.LINES) - .workOnLanguages(Xoo.KEY) - .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); - } - - @Override - public void execute(SensorContext context) { - for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { - processFileHighlighting(file, context); - } - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SyntaxHighlightingSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SyntaxHighlightingSensor.java deleted file mode 100644 index 5b78759dbb9..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SyntaxHighlightingSensor.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.lang; - -import com.google.common.base.Splitter; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; - -import java.io.File; -import java.io.IOException; -import java.util.Iterator; -import java.util.List; - -/** - * Parse files *.xoo.highlighting - */ -public class SyntaxHighlightingSensor implements Sensor { - - private static final String HIGHLIGHTING_EXTENSION = ".highlighting"; - - private void processFileHighlighting(InputFile inputFile, SensorContext context) { - File ioFile = inputFile.file(); - File highlightingFile = new File(ioFile.getParentFile(), ioFile.getName() + HIGHLIGHTING_EXTENSION); - if (highlightingFile.exists()) { - XooConstants.LOG.debug("Processing " + highlightingFile.getAbsolutePath()); - try { - List<String> lines = FileUtils.readLines(highlightingFile, context.fileSystem().encoding().name()); - int lineNumber = 0; - HighlightingBuilder highlightingBuilder = context.highlightingBuilder(inputFile); - for (String line : lines) { - lineNumber++; - if (StringUtils.isBlank(line)) { - continue; - } - if (line.startsWith("#")) { - continue; - } - try { - Iterator<String> split = Splitter.on(":").split(line).iterator(); - int startOffset = Integer.parseInt(split.next()); - int endOffset = Integer.parseInt(split.next()); - HighlightingBuilder.TypeOfText type = HighlightingBuilder.TypeOfText.forCssClass(split.next()); - highlightingBuilder.highlight(startOffset, endOffset, type); - } catch (Exception e) { - throw new IllegalStateException("Error processing line " + lineNumber + " of file " + highlightingFile.getAbsolutePath(), e); - } - } - highlightingBuilder.done(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name("Xoo Highlighting Sensor") - .provides(CoreMetrics.LINES) - .workOnLanguages(Xoo.KEY) - .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); - } - - @Override - public void execute(SensorContext context) { - for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { - processFileHighlighting(file, context); - } - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/CreateIssueByInternalKeySensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/CreateIssueByInternalKeySensor.java deleted file mode 100644 index 1ee150a5c01..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/CreateIssueByInternalKeySensor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.rule; - -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.rule.ActiveRule; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; - -public class CreateIssueByInternalKeySensor implements Sensor { - - private static final String INTERNAL_KEY_PROPERTY = "sonar.xoo.internalKey"; - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name("CreateIssueByInternalKeySensor") - .workOnLanguages(Xoo.KEY) - .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); - } - - @Override - public void execute(SensorContext context) { - for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { - createIssues(file, context); - } - } - - private void createIssues(InputFile file, SensorContext context) { - ActiveRule rule = context.activeRules().findByInternalKey(XooConstants.REPOSITORY_KEY, - context.settings().getString(INTERNAL_KEY_PROPERTY)); - if (rule != null) { - context.addIssue(context.issueBuilder() - .ruleKey(rule.ruleKey()) - .onFile(file) - .message("This issue is generated on each file") - .build()); - } - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java deleted file mode 100644 index 2a02ebef9dd..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssueOnDirPerFileSensor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.rule; - -import org.sonar.api.batch.fs.InputDir; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.rule.RuleKey; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; - -public class OneIssueOnDirPerFileSensor implements Sensor { - - public static final String RULE_KEY = "OneIssueOnDirPerFile"; - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name("One Issue On Dir Per File") - .workOnLanguages(Xoo.KEY) - .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); - } - - @Override - public void execute(SensorContext context) { - for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { - createIssues(file, context); - } - } - - private void createIssues(InputFile file, SensorContext context) { - RuleKey ruleKey = RuleKey.of(XooConstants.REPOSITORY_KEY, RULE_KEY); - InputDir inputDir = context.fileSystem().inputDir(file.file().getParentFile()); - if (inputDir != null) { - context.addIssue(context.issueBuilder() - .ruleKey(ruleKey) - .onDir(inputDir) - .message("This issue is generated for file " + file.relativePath()) - .build()); - } - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java deleted file mode 100644 index 2a811068e54..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineSensor.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.batch.mediumtest.xoo.plugin.rule; - -import org.slf4j.LoggerFactory; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.batch.sensor.issue.IssueBuilder; -import org.sonar.api.batch.sensor.measure.Measure; -import org.sonar.api.measures.CoreMetrics; -import org.sonar.api.rule.RuleKey; -import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; -import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; - -public class OneIssuePerLineSensor implements Sensor { - - public static final String RULE_KEY = "OneIssuePerLine"; - private static final String EFFORT_TO_FIX_PROPERTY = "sonar.oneIssuePerLine.effortToFix"; - private static final String FORCE_SEVERITY_PROPERTY = "sonar.oneIssuePerLine.forceSeverity"; - - @Override - public void describe(SensorDescriptor descriptor) { - descriptor - .name("One Issue Per Line") - .dependsOn(CoreMetrics.LINES) - .workOnLanguages(Xoo.KEY) - .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); - } - - @Override - public void execute(SensorContext context) { - for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { - createIssues(file, context); - } - } - - private void createIssues(InputFile file, SensorContext context) { - RuleKey ruleKey = RuleKey.of(XooConstants.REPOSITORY_KEY, RULE_KEY); - Measure<Integer> linesMeasure = context.getMeasure(file, CoreMetrics.LINES); - if (linesMeasure == null) { - LoggerFactory.getLogger(getClass()).warn("Missing measure " + CoreMetrics.LINES_KEY + " on " + file); - } else { - IssueBuilder issueBuilder = context.issueBuilder(); - for (int line = 1; line <= (Integer) linesMeasure.value(); line++) { - context.addIssue(issueBuilder - .ruleKey(ruleKey) - .onFile(file) - .atLine(line) - .effortToFix(context.settings().getDouble(EFFORT_TO_FIX_PROPERTY)) - .severity(context.settings().getString(FORCE_SEVERITY_PROPERTY)) - .message("This issue is generated on each line") - .build()); - } - } - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java index 7b7eb21ee58..a93bf9bae83 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java @@ -42,6 +42,8 @@ import org.sonar.api.measures.MetricFinder; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.rule.RuleKey; +import org.sonar.batch.duplication.BlockCache; +import org.sonar.batch.duplication.DuplicationCache; import org.sonar.batch.index.ComponentDataCache; import static org.fest.assertions.Assertions.assertThat; @@ -71,8 +73,9 @@ public class SensorContextAdapterTest { settings = new Settings(); resourcePerspectives = mock(ResourcePerspectives.class); ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + BlockCache blockCache = mock(BlockCache.class); adaptor = new SensorContextAdaptor(sensorContext, metricFinder, new Project("myProject"), - resourcePerspectives, settings, fs, activeRules, componentDataCache); + resourcePerspectives, settings, fs, activeRules, componentDataCache, blockCache, mock(DuplicationCache.class)); } @Test diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java index f1bf43f37e3..03dbec79af8 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/InputPathCacheTest.java @@ -24,6 +24,8 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.InputFile.Status; +import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.fs.InputPath; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.DeprecatedDefaultInputFile; @@ -55,7 +57,18 @@ public class InputPathCacheTest { InputPathCache cache = new InputPathCache(caches); DefaultInputFile fooFile = new DefaultInputFile("src/main/java/Foo.java").setFile(temp.newFile("Foo.java")); cache.put("struts", fooFile); - cache.put("struts-core", new DeprecatedDefaultInputFile("src/main/java/Bar.java").setFile(temp.newFile("Bar.java"))); + cache.put("struts-core", new DeprecatedDefaultInputFile("src/main/java/Bar.java") + .setBasedir(temp.newFolder()) + .setDeprecatedKey("foo") + .setSourceDirAbsolutePath("foo") + .setPathRelativeToSourceDir("foo") + .setLanguage("bla") + .setType(Type.MAIN) + .setStatus(Status.ADDED) + .setHash("xyz") + .setLines(1) + .setKey("foo") + .setFile(temp.newFile("Bar.java"))); assertThat(cache.getFile("struts", "src/main/java/Foo.java").relativePath()) .isEqualTo("src/main/java/Foo.java"); @@ -75,5 +88,4 @@ public class InputPathCacheTest { assertThat(cache.filesByModule("struts-core")).hasSize(1); assertThat(cache.all()).hasSize(1); } - } |